VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/setmode.c@ 3387

Last change on this file since 3387 was 2113, checked in by bird, 15 years ago

kmkbuiltin: include config.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1/* $NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $ */
2
3/*
4 * Copyright (c) 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Dave Borman at Cray Research, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35/*#include <sys/cdefs.h>*/
36#if defined(LIBC_SCCS) && !defined(lint)
37#if 0
38static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94";
39#else
40__RCSID("$NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $");
41#endif
42#endif /* LIBC_SCCS and not lint */
43
44/*#include "namespace.h"*/
45#include "config.h"
46#include <sys/types.h>
47#include <sys/stat.h>
48
49#include <assert.h>
50#include <ctype.h>
51#include <errno.h>
52#include <signal.h>
53#include <stdlib.h>
54#ifndef _MSC_VER
55#include <unistd.h>
56#else
57#include "mscfakes.h"
58#endif
59
60#ifdef SETMODE_DEBUG
61#include <stdio.h>
62#endif
63
64/*#ifdef __weak_alias
65__weak_alias(getmode,_getmode)
66__weak_alias(setmode,_setmode)
67#endif*/
68
69#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
70#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
71
72typedef struct bitcmd {
73 char cmd;
74 char cmd2;
75 mode_t bits;
76} BITCMD;
77
78#define CMD2_CLR 0x01
79#define CMD2_SET 0x02
80#define CMD2_GBITS 0x04
81#define CMD2_OBITS 0x08
82#define CMD2_UBITS 0x10
83
84static BITCMD *addcmd(BITCMD *, int, int, int, u_int);
85static void compress_mode(BITCMD *);
86#ifdef SETMODE_DEBUG
87static void dumpmode(BITCMD *);
88#endif
89
90#ifndef _DIAGASSERT
91# define _DIAGASSERT assert
92#endif
93
94#ifndef S_ISTXT
95# ifdef S_ISVTX
96# define S_ISTXT S_ISVTX
97# else
98# define S_ISTXT 0
99# endif
100#endif /* !S_ISTXT */
101
102/*
103 * Given the old mode and an array of bitcmd structures, apply the operations
104 * described in the bitcmd structures to the old mode, and return the new mode.
105 * Note that there is no '=' command; a strict assignment is just a '-' (clear
106 * bits) followed by a '+' (set bits).
107 */
108mode_t
109bsd_getmode(bbox, omode)
110 const void *bbox;
111 mode_t omode;
112{
113 const BITCMD *set;
114 mode_t clrval, newmode, value;
115
116 _DIAGASSERT(bbox != NULL);
117
118 set = (const BITCMD *)bbox;
119 newmode = omode;
120 for (value = 0;; set++)
121 switch(set->cmd) {
122 /*
123 * When copying the user, group or other bits around, we "know"
124 * where the bits are in the mode so that we can do shifts to
125 * copy them around. If we don't use shifts, it gets real
126 * grundgy with lots of single bit checks and bit sets.
127 */
128 case 'u':
129 value = (newmode & S_IRWXU) >> 6;
130 goto common;
131
132 case 'g':
133 value = (newmode & S_IRWXG) >> 3;
134 goto common;
135
136 case 'o':
137 value = newmode & S_IRWXO;
138common: if (set->cmd2 & CMD2_CLR) {
139 clrval =
140 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
141 if (set->cmd2 & CMD2_UBITS)
142 newmode &= ~((clrval<<6) & set->bits);
143 if (set->cmd2 & CMD2_GBITS)
144 newmode &= ~((clrval<<3) & set->bits);
145 if (set->cmd2 & CMD2_OBITS)
146 newmode &= ~(clrval & set->bits);
147 }
148 if (set->cmd2 & CMD2_SET) {
149 if (set->cmd2 & CMD2_UBITS)
150 newmode |= (value<<6) & set->bits;
151 if (set->cmd2 & CMD2_GBITS)
152 newmode |= (value<<3) & set->bits;
153 if (set->cmd2 & CMD2_OBITS)
154 newmode |= value & set->bits;
155 }
156 break;
157
158 case '+':
159 newmode |= set->bits;
160 break;
161
162 case '-':
163 newmode &= ~set->bits;
164 break;
165
166 case 'X':
167 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
168 newmode |= set->bits;
169 break;
170
171 case '\0':
172 default:
173#ifdef SETMODE_DEBUG
174 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
175#endif
176 return (newmode);
177 }
178}
179
180#define ADDCMD(a, b, c, d) do { \
181 if (set >= endset) { \
182 BITCMD *newset; \
183 setlen += SET_LEN_INCR; \
184 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
185 if (newset == NULL) { \
186 free(saveset); \
187 return (NULL); \
188 } \
189 set = newset + (set - saveset); \
190 saveset = newset; \
191 endset = newset + (setlen - 2); \
192 } \
193 set = addcmd(set, (a), (b), (c), (d)); \
194} while (/*CONSTCOND*/0)
195
196#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
197
198void *
199bsd_setmode(p)
200 const char *p;
201{
202 int perm, who;
203 char op, *ep;
204 BITCMD *set, *saveset, *endset;
205#ifndef _MSC_VER
206 sigset_t signset, sigoset;
207#endif
208 mode_t mask;
209 int equalopdone = 0; /* pacify gcc */
210 int permXbits, setlen;
211
212 if (!*p)
213 return (NULL);
214
215 /*
216 * Get a copy of the mask for the permissions that are mask relative.
217 * Flip the bits, we want what's not set. Since it's possible that
218 * the caller is opening files inside a signal handler, protect them
219 * as best we can.
220 */
221#ifndef _MSC_VER
222 sigfillset(&signset);
223 (void)sigprocmask(SIG_BLOCK, &signset, &sigoset);
224#endif
225 (void)umask(mask = umask(0));
226 mask = ~mask;
227#ifndef _MSC_VER
228 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
229#endif
230
231 setlen = SET_LEN + 2;
232
233 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
234 return (NULL);
235 saveset = set;
236 endset = set + (setlen - 2);
237
238 /*
239 * If an absolute number, get it and return; disallow non-octal digits
240 * or illegal bits.
241 */
242 if (isdigit((unsigned char)*p)) {
243 perm = (mode_t)strtol(p, &ep, 8);
244 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
245 free(saveset);
246 return (NULL);
247 }
248 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
249 set->cmd = 0;
250 return (saveset);
251 }
252
253 /*
254 * Build list of structures to set/clear/copy bits as described by
255 * each clause of the symbolic mode.
256 */
257 for (;;) {
258 /* First, find out which bits might be modified. */
259 for (who = 0;; ++p) {
260 switch (*p) {
261 case 'a':
262 who |= STANDARD_BITS;
263 break;
264 case 'u':
265 who |= S_ISUID|S_IRWXU;
266 break;
267 case 'g':
268 who |= S_ISGID|S_IRWXG;
269 break;
270 case 'o':
271 who |= S_IRWXO;
272 break;
273 default:
274 goto getop;
275 }
276 }
277
278getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
279 free(saveset);
280 return (NULL);
281 }
282 if (op == '=')
283 equalopdone = 0;
284
285 who &= ~S_ISTXT;
286 for (perm = 0, permXbits = 0;; ++p) {
287 switch (*p) {
288 case 'r':
289 perm |= S_IRUSR|S_IRGRP|S_IROTH;
290 break;
291 case 's':
292 /*
293 * If specific bits where requested and
294 * only "other" bits ignore set-id.
295 */
296 if (who == 0 || (who & ~S_IRWXO))
297 perm |= S_ISUID|S_ISGID;
298 break;
299 case 't':
300 /*
301 * If specific bits where requested and
302 * only "other" bits ignore set-id.
303 */
304 if (who == 0 || (who & ~S_IRWXO)) {
305 who |= S_ISTXT;
306 perm |= S_ISTXT;
307 }
308 break;
309 case 'w':
310 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
311 break;
312 case 'X':
313 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
314 break;
315 case 'x':
316 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
317 break;
318 case 'u':
319 case 'g':
320 case 'o':
321 /*
322 * When ever we hit 'u', 'g', or 'o', we have
323 * to flush out any partial mode that we have,
324 * and then do the copying of the mode bits.
325 */
326 if (perm) {
327 ADDCMD(op, who, perm, mask);
328 perm = 0;
329 }
330 if (op == '=')
331 equalopdone = 1;
332 if (op == '+' && permXbits) {
333 ADDCMD('X', who, permXbits, mask);
334 permXbits = 0;
335 }
336 ADDCMD(*p, who, op, mask);
337 break;
338
339 default:
340 /*
341 * Add any permissions that we haven't already
342 * done.
343 */
344 if (perm || (op == '=' && !equalopdone)) {
345 if (op == '=')
346 equalopdone = 1;
347 ADDCMD(op, who, perm, mask);
348 perm = 0;
349 }
350 if (permXbits) {
351 ADDCMD('X', who, permXbits, mask);
352 permXbits = 0;
353 }
354 goto apply;
355 }
356 }
357
358apply: if (!*p)
359 break;
360 if (*p != ',')
361 goto getop;
362 ++p;
363 }
364 set->cmd = 0;
365#ifdef SETMODE_DEBUG
366 (void)printf("Before compress_mode()\n");
367 dumpmode(saveset);
368#endif
369 compress_mode(saveset);
370#ifdef SETMODE_DEBUG
371 (void)printf("After compress_mode()\n");
372 dumpmode(saveset);
373#endif
374 return (saveset);
375}
376
377static BITCMD *
378addcmd(set, op, who, oparg, mask)
379 BITCMD *set;
380 int oparg, who;
381 int op;
382 u_int mask;
383{
384
385 _DIAGASSERT(set != NULL);
386
387 switch (op) {
388 case '=':
389 set->cmd = '-';
390 set->bits = who ? who : STANDARD_BITS;
391 set++;
392
393 op = '+';
394 /* FALLTHROUGH */
395 case '+':
396 case '-':
397 case 'X':
398 set->cmd = op;
399 set->bits = (who ? (mode_t)who : mask) & oparg;
400 break;
401
402 case 'u':
403 case 'g':
404 case 'o':
405 set->cmd = op;
406 if (who) {
407 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
408 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
409 ((who & S_IROTH) ? CMD2_OBITS : 0);
410 set->bits = (mode_t)~0;
411 } else {
412 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
413 set->bits = mask;
414 }
415
416 if (oparg == '+')
417 set->cmd2 |= CMD2_SET;
418 else if (oparg == '-')
419 set->cmd2 |= CMD2_CLR;
420 else if (oparg == '=')
421 set->cmd2 |= CMD2_SET|CMD2_CLR;
422 break;
423 }
424 return (set + 1);
425}
426
427#ifdef SETMODE_DEBUG
428static void
429dumpmode(set)
430 BITCMD *set;
431{
432
433 _DIAGASSERT(set != NULL);
434
435 for (; set->cmd; ++set)
436 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
437 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
438 set->cmd2 & CMD2_CLR ? " CLR" : "",
439 set->cmd2 & CMD2_SET ? " SET" : "",
440 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
441 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
442 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
443}
444#endif
445
446/*
447 * Given an array of bitcmd structures, compress by compacting consecutive
448 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
449 * 'g' and 'o' commands continue to be separate. They could probably be
450 * compacted, but it's not worth the effort.
451 */
452static void
453compress_mode(set)
454 BITCMD *set;
455{
456 BITCMD *nset;
457 int setbits, clrbits, Xbits, op;
458
459 _DIAGASSERT(set != NULL);
460
461 for (nset = set;;) {
462 /* Copy over any 'u', 'g' and 'o' commands. */
463 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
464 *set++ = *nset++;
465 if (!op)
466 return;
467 }
468
469 for (setbits = clrbits = Xbits = 0;; nset++) {
470 if ((op = nset->cmd) == '-') {
471 clrbits |= nset->bits;
472 setbits &= ~nset->bits;
473 Xbits &= ~nset->bits;
474 } else if (op == '+') {
475 setbits |= nset->bits;
476 clrbits &= ~nset->bits;
477 Xbits &= ~nset->bits;
478 } else if (op == 'X')
479 Xbits |= nset->bits & ~setbits;
480 else
481 break;
482 }
483 if (clrbits) {
484 set->cmd = '-';
485 set->cmd2 = 0;
486 set->bits = clrbits;
487 set++;
488 }
489 if (setbits) {
490 set->cmd = '+';
491 set->cmd2 = 0;
492 set->bits = setbits;
493 set++;
494 }
495 if (Xbits) {
496 set->cmd = 'X';
497 set->cmd2 = 0;
498 set->bits = Xbits;
499 set++;
500 }
501 }
502}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use