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 }