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 }