morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base.git
Log | Files | Refs

mode.c (3093B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 #include <sys/stat.h>
      4 #include <unistd.h>
      5 
      6 #include "../util.h"
      7 
      8 mode_t
      9 getumask(void)
     10 {
     11 	mode_t mask = umask(0);
     12 	umask(mask);
     13 	return mask;
     14 }
     15 
     16 mode_t
     17 parsemode(const char *str, mode_t mode, mode_t mask)
     18 {
     19 	char *end;
     20 	const char *p = str;
     21 	int octal, op;
     22 	mode_t who, perm, clear;
     23 
     24 	octal = strtol(str, &end, 8);
     25 	if (*end == '\0') {
     26 		if (octal < 0 || octal > 07777) {
     27 			eprintf("%s: invalid mode\n", str);
     28 			return -1;
     29 		}
     30 		mode = 0;
     31 		if (octal & 04000) mode |= S_ISUID;
     32 		if (octal & 02000) mode |= S_ISGID;
     33 		if (octal & 01000) mode |= S_ISVTX;
     34 		if (octal & 00400) mode |= S_IRUSR;
     35 		if (octal & 00200) mode |= S_IWUSR;
     36 		if (octal & 00100) mode |= S_IXUSR;
     37 		if (octal & 00040) mode |= S_IRGRP;
     38 		if (octal & 00020) mode |= S_IWGRP;
     39 		if (octal & 00010) mode |= S_IXGRP;
     40 		if (octal & 00004) mode |= S_IROTH;
     41 		if (octal & 00002) mode |= S_IWOTH;
     42 		if (octal & 00001) mode |= S_IXOTH;
     43 		return mode;
     44 	}
     45 next:
     46 	/* first, determine which bits we will be modifying */
     47 	for (who = 0; *p; p++) {
     48 		switch (*p) {
     49 		/* masks */
     50 		case 'u':
     51 			who |= S_IRWXU|S_ISUID;
     52 			continue;
     53 		case 'g':
     54 			who |= S_IRWXG|S_ISGID;
     55 			continue;
     56 		case 'o':
     57 			who |= S_IRWXO;
     58 			continue;
     59 		case 'a':
     60 			who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO;
     61 			continue;
     62 		}
     63 		break;
     64 	}
     65 	if (who) {
     66 		clear = who;
     67 	} else {
     68 		clear = S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
     69 		who = ~mask;
     70 	}
     71 	while (*p) {
     72 		switch (*p) {
     73 		/* opers */
     74 		case '=':
     75 		case '+':
     76 		case '-':
     77 			op = (int)*p;
     78 			break;
     79 		default:
     80 			eprintf("%s: invalid mode\n", str);
     81 			return -1;
     82 		}
     83 
     84 		perm = 0;
     85 		switch (*++p) {
     86 		/* copy */
     87 		case 'u':
     88 			if (mode & S_IRUSR)
     89 				perm |= S_IRUSR|S_IRGRP|S_IROTH;
     90 			if (mode & S_IWUSR)
     91 				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
     92 			if (mode & S_IXUSR)
     93 				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
     94 			if (mode & S_ISUID)
     95 				perm |= S_ISUID|S_ISGID;
     96 			p++;
     97 			break;
     98 		case 'g':
     99 			if (mode & S_IRGRP)
    100 				perm |= S_IRUSR|S_IRGRP|S_IROTH;
    101 			if (mode & S_IWGRP)
    102 				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
    103 			if (mode & S_IXGRP)
    104 				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
    105 			if (mode & S_ISGID)
    106 				perm |= S_ISUID|S_ISGID;
    107 			p++;
    108 			break;
    109 		case 'o':
    110 			if (mode & S_IROTH)
    111 				perm |= S_IRUSR|S_IRGRP|S_IROTH;
    112 			if (mode & S_IWOTH)
    113 				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
    114 			if (mode & S_IXOTH)
    115 				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
    116 			p++;
    117 			break;
    118 		default:
    119 			for (; *p; p++) {
    120 				switch (*p) {
    121 				/* modes */
    122 				case 'r':
    123 					perm |= S_IRUSR|S_IRGRP|S_IROTH;
    124 					break;
    125 				case 'w':
    126 					perm |= S_IWUSR|S_IWGRP|S_IWOTH;
    127 					break;
    128 				case 'x':
    129 					perm |= S_IXUSR|S_IXGRP|S_IXOTH;
    130 					break;
    131 				case 's':
    132 					perm |= S_ISUID|S_ISGID;
    133 					break;
    134 				case 't':
    135 					perm |= S_ISVTX;
    136 					break;
    137 				default:
    138 					goto apply;
    139 				}
    140 			}
    141 		}
    142 
    143 	apply:
    144 		/* apply */
    145 		switch (op) {
    146 		case '=':
    147 			mode &= ~clear;
    148 			/* fallthrough */
    149 		case '+':
    150 			mode |= perm & who;
    151 			break;
    152 		case '-':
    153 			mode &= ~(perm & who);
    154 			break;
    155 		}
    156 		/* if we hit a comma, move on to the next clause */
    157 		if (*p == ',') {
    158 			p++;
    159 			goto next;
    160 		}
    161 	}
    162 	return mode;
    163 }