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 }