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 }