Commit | Line | Data |
---|---|---|
0dfc069b KB |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
269a7923 | 5 | * %sccs.include.redist.c% |
0dfc069b KB |
6 | */ |
7 | ||
8 | #if defined(LIBC_SCCS) && !defined(lint) | |
269a7923 | 9 | static char sccsid[] = "@(#)setmode.c 5.3 (Berkeley) %G%"; |
0dfc069b KB |
10 | #endif /* LIBC_SCCS and not lint */ |
11 | ||
12 | #include <sys/types.h> | |
13 | #include <sys/stat.h> | |
840c650e KB |
14 | #include <errno.h> |
15 | #include <stdio.h> | |
0dfc069b | 16 | |
840c650e KB |
17 | #define setbits set[0] |
18 | #define clrbits set[1] | |
19 | #define Xbits set[2] | |
0dfc069b KB |
20 | |
21 | mode_t | |
840c650e KB |
22 | getmode(set, omode) |
23 | mode_t *set, omode; | |
0dfc069b KB |
24 | { |
25 | register mode_t newmode; | |
26 | ||
27 | newmode = omode & clrbits; | |
28 | newmode |= setbits; | |
29 | if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) | |
30 | newmode |= Xbits; | |
31 | return(newmode); | |
32 | } | |
33 | ||
34 | #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) | |
35 | #define CLR(a) { clrbits |= a; setbits &= ~(a); Xbits &= ~(a); } | |
36 | ||
840c650e | 37 | mode_t * |
0dfc069b KB |
38 | setmode(p) |
39 | register char *p; | |
40 | { | |
840c650e | 41 | extern int errno; |
0dfc069b KB |
42 | register int perm, who; |
43 | register char op; | |
840c650e | 44 | mode_t mask, *set; |
0dfc069b | 45 | int permXbits; |
840c650e | 46 | char *malloc(); |
0dfc069b KB |
47 | |
48 | /* | |
49 | * get a copy of the mask for the permissions that are mask | |
50 | * relative. Flip the bits, we want what's not set. | |
51 | */ | |
52 | (void)umask(mask = umask(0)); | |
53 | mask = ~mask; | |
54 | ||
840c650e KB |
55 | if (!(set = (mode_t *)malloc((u_int)(sizeof(mode_t) * 3)))) { |
56 | errno = ENOMEM; | |
57 | return(NULL); | |
58 | } | |
59 | ||
0dfc069b KB |
60 | setbits = clrbits = Xbits = 0; |
61 | ||
62 | /* | |
63 | * if an absolute number, get it and return; disallow non-octal | |
64 | * digits or illegal bits. | |
65 | */ | |
66 | if (isdigit(*p)) { | |
67 | setbits = (mode_t)strtol(p, (char **)0, 8); | |
68 | clrbits = ~(STANDARD_BITS|S_ISTXT); | |
69 | Xbits = 0; | |
70 | while (*++p) | |
71 | if (*p < '0' || *p > '7') | |
840c650e | 72 | return(NULL); |
0dfc069b | 73 | if (setbits & clrbits) |
840c650e KB |
74 | return(NULL); |
75 | return(set); | |
0dfc069b KB |
76 | } |
77 | ||
78 | if (!*p) | |
840c650e | 79 | return(NULL); |
0dfc069b KB |
80 | /* |
81 | * accumulate bits to add and subtract from each clause of | |
82 | * the symbolic mode | |
83 | */ | |
84 | for (;;) { | |
85 | for (who = 0;; ++p) | |
86 | switch (*p) { | |
87 | case 'a': | |
88 | who |= STANDARD_BITS; | |
89 | break; | |
90 | case 'u': | |
91 | who |= S_ISUID|S_IRWXU; | |
92 | break; | |
93 | case 'g': | |
94 | who |= S_ISGID|S_IRWXG; | |
95 | break; | |
96 | case 'o': | |
97 | who |= S_IRWXO; | |
98 | break; | |
99 | default: | |
100 | goto getop; | |
101 | } | |
102 | ||
103 | getop: if ((op = *p++) != '+' && op != '-' && op != '=') | |
840c650e | 104 | return(NULL); |
0dfc069b KB |
105 | |
106 | who &= ~S_ISTXT; | |
107 | for (perm = 0;; ++p) | |
108 | switch (*p) { | |
109 | case 'r': | |
110 | perm |= S_IRUSR|S_IRGRP|S_IROTH; | |
111 | break; | |
112 | case 's': | |
113 | /* if only "other" bits ignore set-id */ | |
114 | if (who & ~S_IRWXO) | |
115 | perm |= S_ISUID|S_ISGID; | |
116 | break; | |
117 | case 't': | |
118 | /* if only "other" bits ignore sticky */ | |
119 | if (who & ~S_IRWXO) { | |
120 | who |= S_ISTXT; | |
121 | perm |= S_ISTXT; | |
122 | } | |
123 | break; | |
124 | case 'w': | |
125 | perm |= S_IWUSR|S_IWGRP|S_IWOTH; | |
126 | break; | |
127 | case 'X': | |
128 | permXbits = S_IXUSR|S_IXGRP|S_IXOTH; | |
129 | break; | |
130 | case 'x': | |
131 | perm |= S_IXUSR|S_IXGRP|S_IXOTH; | |
132 | break; | |
133 | default: | |
134 | goto apply; | |
135 | } | |
136 | ||
137 | apply: switch(op) { | |
138 | case '+': | |
139 | /* | |
140 | * If no perm value, skip. If no who value, use umask | |
141 | * bits. Don't bother clearing any bits, getmode | |
142 | * clears first, then sets. | |
143 | */ | |
144 | if (perm || permXbits) { | |
145 | if (!who) | |
146 | who = mask; | |
147 | if (permXbits) | |
148 | Xbits |= who & permXbits; | |
149 | setbits |= who & perm; | |
150 | } | |
151 | break; | |
152 | case '-': | |
153 | /* | |
154 | * If no perm value, skip. If no who value, use | |
155 | * owner, group, and other. | |
156 | */ | |
157 | if (perm) { | |
158 | if (!who) | |
159 | who = S_IRWXU|S_IRWXG|S_IRWXO; | |
160 | CLR(who & perm); | |
161 | } | |
162 | break; | |
163 | case '=': | |
164 | /* | |
165 | * If no who value, clear all the bits. Otherwise, | |
166 | * clear the bits specified by who. | |
167 | */ | |
168 | if (!who) { | |
169 | CLR(STANDARD_BITS); | |
170 | who = mask; | |
171 | } else | |
172 | CLR(who); | |
173 | if (perm) | |
174 | setbits |= who & perm; | |
175 | break; | |
176 | } | |
177 | ||
178 | if (!*p) | |
179 | break; | |
180 | if (*p != ',') | |
181 | goto getop; | |
182 | ++p; | |
183 | } | |
184 | clrbits = ~clrbits; | |
840c650e | 185 | return(set); |
0dfc069b | 186 | } |