mode.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       mode.c (2800B)
       ---
            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|S_ISVTX;
           44                         continue;
           45                 case 'a':
           46                         who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO|S_ISVTX;
           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 }