1 /* @(#)umask.c 1.7 16/01/04 Copyright 2004-2016 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef RES
4 static UConst char sccsid[] =
5 "@(#)umask.c 1.7 16/01/04 Copyright 2004-2016 J. Schilling";
6 /*
7 * Parser for chmod(1)/find(1)-perm, ....
8 * The code has been taken from libschily/getperm.c and adopted to
9 * avoid stdio for the Bourne Shell.
10 *
11 * Copyright (c) 2004-2016 J. Schilling
12 */
13 /*
14 * The contents of this file are subject to the terms of the
15 * Common Development and Distribution License, Version 1.0 only
16 * (the "License"). You may not use this file except in compliance
17 * with the License.
18 *
19 * See the file CDDL.Schily.txt in this distribution for details.
20 * A copy of the CDDL is also available via the Internet at
21 * http://www.opensource.org/licenses/cddl1.txt
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
27 #include "defs.h"
28
29 #define LOCAL static
30
31 /*
32 * getperm() flags:
33 */
34 #define GP_NOX 0 /* This is not a dir and 'X' is not valid */
35 #define GP_DOX 1 /* 'X' perm character is valid */
36 #define GP_XERR 2 /* 'X' perm characters are invalid */
37 #define GP_FPERM 4 /* TRUE if we implement find -perm */
38
39 #ifdef DO_UMASK_S
40 LOCAL int getperm __PR((char *perm, mode_t *modep,
41 int smode, int flag));
42 LOCAL char *getsperm __PR((char *p, mode_t *mp, int smode, int isX));
43 LOCAL mode_t iswho __PR((int c));
44 LOCAL int isop __PR((int c));
45 LOCAL mode_t isperm __PR((int c, int isX));
46 LOCAL int mval __PR((mode_t m));
47 #endif
48 LOCAL void promask __PR((void));
49 void sysumask __PR((int argc, char **argv));
50
51 /*
52 * This is the mode bit translation code stolen from star...
53 */
54 #define TSUID 04000 /* Set UID on execution */
55 #define TSGID 02000 /* Set GID on execution */
56 #define TSVTX 01000 /* On directories, restricted deletion flag */
57 #define TUREAD 00400 /* Read by owner */
58 #define TUWRITE 00200 /* Write by owner special */
59 #define TUEXEC 00100 /* Execute/search by owner */
60 #define TGREAD 00040 /* Read by group */
61 #define TGWRITE 00020 /* Write by group */
62 #define TGEXEC 00010 /* Execute/search by group */
63 #define TOREAD 00004 /* Read by other */
64 #define TOWRITE 00002 /* Write by other */
65 #define TOEXEC 00001 /* Execute/search by other */
66
67 #define TALLMODES 07777 /* The low 12 bits mentioned in the standard */
68
69 #define S_ALLPERM (S_IRWXU|S_IRWXG|S_IRWXO)
70 #define S_ALLFLAGS (S_ISUID|S_ISGID|S_ISVTX)
71 #define S_ALLMODES (S_ALLFLAGS | S_ALLPERM)
72
73 #if S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX && \
74 S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC && \
75 S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC && \
76 S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
77
78 #define HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
79 #endif
80
81 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
82 #define OSMODE(xmode) (xmode)
83 #define TARMODE(xmode) (xmode)
84 #else
85 #define OSMODE(xmode) ((xmode & TSUID ? S_ISUID : 0) \
86 | (xmode & TSGID ? S_ISGID : 0) \
87 | (xmode & TSVTX ? S_ISVTX : 0) \
88 | (xmode & TUREAD ? S_IRUSR : 0) \
89 | (xmode & TUWRITE ? S_IWUSR : 0) \
90 | (xmode & TUEXEC ? S_IXUSR : 0) \
91 | (xmode & TGREAD ? S_IRGRP : 0) \
92 | (xmode & TGWRITE ? S_IWGRP : 0) \
93 | (xmode & TGEXEC ? S_IXGRP : 0) \
94 | (xmode & TOREAD ? S_IROTH : 0) \
95 | (xmode & TOWRITE ? S_IWOTH : 0) \
96 | (xmode & TOEXEC ? S_IXOTH : 0))
97
98 #define TARMODE(xmode) ((xmode & S_ISUID ? TSUID : 0) \
99 | (xmode & S_ISGID ? TSGID : 0) \
100 | (xmode & S_ISVTX ? TSVTX : 0) \
101 | (xmode & S_IRUSR ? TUREAD : 0) \
102 | (xmode & S_IWUSR ? TUWRITE : 0) \
103 | (xmode & S_IXUSR ? TUEXEC : 0) \
104 | (xmode & S_IRGRP ? TGREAD : 0) \
105 | (xmode & S_IWGRP ? TGWRITE : 0) \
106 | (xmode & S_IXGRP ? TGEXEC : 0) \
107 | (xmode & S_IROTH ? TOREAD : 0) \
108 | (xmode & S_IWOTH ? TOWRITE : 0) \
109 | (xmode & S_IXOTH ? TOEXEC : 0))
110 #endif
111
112 #ifdef DO_UMASK_S
113 LOCAL int
getperm(perm,modep,smode,flag)114 getperm(perm, modep, smode, flag)
115 char *perm; /* Perm string to parse */
116 mode_t *modep; /* The mode result */
117 int smode; /* The start mode for the computation */
118 int flag; /* Flags, see getperm() flag defs */
119 {
120 char *p;
121 #ifdef DO_OCTAL
122 Llong ll;
123 mode_t mm;
124 #endif
125
126 p = perm;
127 if ((flag & GP_FPERM) && *p == '-')
128 p++;
129
130 #ifdef DO_OCTAL
131 if (*p >= '0' && *p <= '7') {
132 p = astollb(p, &ll, 8);
133 if (*p) {
134 return (-1);
135 }
136 mm = ll & TALLMODES;
137 *modep = OSMODE(mm);
138 return (0);
139 }
140 #endif
141 flag &= ~GP_FPERM;
142 if (flag & GP_XERR)
143 flag = -1;
144 p = getsperm(p, modep, smode, flag);
145 if (p && *p != '\0') {
146 return (-1);
147 }
148 return (0);
149 }
150
151 LOCAL char *
getsperm(p,mp,smode,isX)152 getsperm(p, mp, smode, isX)
153 char *p; /* The perm input string */
154 mode_t *mp; /* To set the mode */
155 int smode; /* The start mode for the computation */
156 int isX; /* -1: Ignore X, 0: no dir/X 1: X OK */
157 {
158 mode_t permval = smode; /* POSIX start value for "find" */
159 mode_t who;
160 mode_t m;
161 int op;
162 mode_t perms;
163 mode_t pm;
164
165 nextclause:
166 who = 0;
167 while ((m = iswho(*p)) != 0) {
168 p++;
169 who |= m;
170 }
171 if (who == 0) {
172 #ifndef BOURNE_SHELL
173 mode_t mask = umask(0);
174
175 umask(mask);
176 who = ~mask;
177 who &= (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
178 #else
179 who = (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
180 #endif
181 }
182
183 nextop:
184 if ((op = isop(*p)) != '\0')
185 p++;
186 if (op == 0) {
187 return (p);
188 }
189
190 perms = 0;
191 while ((pm = isperm(*p, isX)) != (mode_t)-1) {
192 p++;
193 perms |= pm;
194 }
195 if ((perms == 0) && (*p == 'u' || *p == 'g' || *p == 'o')) {
196 mode_t what = 0;
197
198 /*
199 * First select the bit triple we like to copy.
200 */
201 switch (*p) {
202
203 case 'u':
204 what = permval & S_IRWXU;
205 break;
206 case 'g':
207 what = permval & S_IRWXG;
208 break;
209 case 'o':
210 what = permval & S_IRWXO;
211 break;
212 }
213 /*
214 * Now copy over bit by bit without relying on shifts
215 * that would make implicit assumptions on values.
216 */
217 if (what & (S_IRUSR|S_IRGRP|S_IROTH))
218 perms |= (who & (S_IRUSR|S_IRGRP|S_IROTH));
219 if (what & (S_IWUSR|S_IWGRP|S_IWOTH))
220 perms |= (who & (S_IWUSR|S_IWGRP|S_IWOTH));
221 if (what & (S_IXUSR|S_IXGRP|S_IXOTH))
222 perms |= (who & (S_IXUSR|S_IXGRP|S_IXOTH));
223 p++;
224 }
225 switch (op) {
226
227 case '=':
228 permval &= ~who;
229 /* FALLTHRU */
230 case '+':
231 permval |= (who & perms);
232 break;
233
234 case '-':
235 permval &= ~(who & perms);
236 break;
237 }
238 if (isop(*p))
239 goto nextop;
240 if (*p == ',') {
241 p++;
242 goto nextclause;
243 }
244 *mp = permval;
245 return (p);
246 }
247
248 LOCAL mode_t
iswho(c)249 iswho(c)
250 int c;
251 {
252 switch (c) {
253
254 case 'u': /* user */
255 return (S_ISUID|S_ISVTX|S_IRWXU);
256 case 'g': /* group */
257 return (S_ISGID|S_ISVTX|S_IRWXG);
258 case 'o': /* other */
259 return (S_ISVTX|S_IRWXO);
260 case 'a': /* all */
261 return (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
262 default:
263 return (0);
264 }
265 }
266
267 LOCAL int
isop(c)268 isop(c)
269 int c; /* The current perm character to parse */
270 {
271 switch (c) {
272
273 case '+':
274 case '-':
275 case '=':
276 return (c);
277 default:
278 return (0);
279 }
280 }
281
282 LOCAL mode_t
isperm(c,isX)283 isperm(c, isX)
284 int c; /* The current perm character to parse */
285 int isX; /* -1: Ignore X, 0: no dir/X 1: X OK */
286 {
287 switch (c) {
288
289 case 'r':
290 return (S_IRUSR|S_IRGRP|S_IROTH);
291 case 'w':
292 return (S_IWUSR|S_IWGRP|S_IWOTH);
293 case 'X':
294 if (isX < 0)
295 return ((mode_t)-1); /* Singnal parse error */
296 if (isX == 0)
297 return ((mode_t)0); /* No 'X' handling here */
298 /* FALLTHRU */
299 case 'x':
300 return (S_IXUSR|S_IXGRP|S_IXOTH);
301 case 's':
302 return (S_ISUID|S_ISGID);
303 case 'l':
304 return (S_ISGID);
305 case 't':
306 return (S_ISVTX);
307 default:
308 return ((mode_t)-1);
309 }
310 }
311
312 static char *umodtab[] =
313 {"", "x", "w", "wx", "r", "rx", "rw", "rwx"};
314
315 #ifdef PROTOTYPES
316 LOCAL int
mval(mode_t m)317 mval(mode_t m)
318 #else
319 LOCAL int
320 mval(m)
321 mode_t m;
322 #endif
323 {
324 int ret = 0;
325
326 if (m & (S_IRUSR|S_IRGRP|S_IROTH))
327 ret |= 4;
328 if (m & (S_IWUSR|S_IWGRP|S_IWOTH))
329 ret |= 2;
330 if (m & (S_IXUSR|S_IXGRP|S_IXOTH))
331 ret |= 1;
332
333 return (ret);
334 }
335 #endif /* DO_UMASK_S */
336
337 LOCAL void
promask()338 promask()
339 {
340 mode_t i;
341 int j;
342
343 umask(i = umask(0));
344 i = TARMODE(i);
345 prc_buff('0');
346 for (j = 6; j >= 0; j -= 3)
347 prc_buff(((i >> j) & 07) +'0');
348 prc_buff(NL);
349 }
350
351 void
sysumask(argc,argv)352 sysumask(argc, argv)
353 int argc;
354 char **argv;
355 {
356 char *a1 = argv[1];
357
358 #ifdef DO_UMASK_S
359 if (argc == 2 && eq(a1, "-S")) {
360 mode_t m;
361
362 umask(m = umask(0));
363 m = ~m;
364
365 prs_buff((unsigned char *)"u=");
366 prs_buff((unsigned char *)umodtab[mval(m & S_IRWXU)]);
367 prs_buff((unsigned char *)",g=");
368 prs_buff((unsigned char *)umodtab[mval(m & S_IRWXG)]);
369 prs_buff((unsigned char *)",o=");
370 prs_buff((unsigned char *)umodtab[mval(m & S_IRWXO)]);
371 prc_buff(NL);
372 } else if (a1) {
373 int c;
374 mode_t i;
375
376 /*
377 * POSIX requires "umask -r" to fail.
378 * Must use "umask -- -r" to set this mode.
379 */
380 if (a1[0] == '-') {
381 if (a1[1] == '-' && a1[2] == '\0') { /* found -- */
382 if (argc <= 2) { /* umask -- */
383 promask();
384 return;
385 }
386 argv++;
387 a1 = argv[1];
388 } else {
389 /*
390 * This is a "bad option".
391 */
392 failure((unsigned char *)&badumask[4],
393 badumask);
394 }
395 }
396 i = 0;
397 while ((c = *a1++) >= '0' && c <= '7')
398 i = (i << 3) + c - '0';
399
400 if (c == '\0') { /* Fully octal arg */
401 umask(OSMODE(i));
402 return;
403 }
404
405 umask(i = umask(0));
406 i = ~i;
407 if (getperm(argv[1], &i, i, GP_NOX)) {
408 failure((unsigned char *)&badumask[4], badumask);
409 }
410 umask(~i);
411 } else {
412 promask();
413 }
414 #else
415 if (a1) {
416 int c;
417 mode_t i;
418
419 i = 0;
420 while ((c = *a1++) >= '0' && c <= '7')
421 i = (i << 3) + c - '0';
422
423 umask(OSMODE(i));
424 } else {
425 promask();
426 }
427 #endif
428 }
429
430 #endif /* RES */
431