sbase

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

mode.c (3116B)


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