sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

mode.c (2784B)


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