VirtualBox

source: kBuild/trunk/src/gmake/kmkbuiltin/setmode.c@ 615

最後變更 在這個檔案從615是 615,由 bird 提交於 18 年 前

NetBSD: /setmode.c/1.30/Thu Aug 7 16:42:56 2003

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 11.1 KB
 
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 <sys/types.h>
46#include <sys/stat.h>
47
48#include <assert.h>
49#include <ctype.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdlib.h>
53#include <unistd.h>
54
55#ifdef SETMODE_DEBUG
56#include <stdio.h>
57#endif
58
59#ifdef __weak_alias
60__weak_alias(getmode,_getmode)
61__weak_alias(setmode,_setmode)
62#endif
63
64#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
65#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
66
67typedef struct bitcmd {
68 char cmd;
69 char cmd2;
70 mode_t bits;
71} BITCMD;
72
73#define CMD2_CLR 0x01
74#define CMD2_SET 0x02
75#define CMD2_GBITS 0x04
76#define CMD2_OBITS 0x08
77#define CMD2_UBITS 0x10
78
79static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int));
80static void compress_mode __P((BITCMD *));
81#ifdef SETMODE_DEBUG
82static void dumpmode __P((BITCMD *));
83#endif
84
85/*
86 * Given the old mode and an array of bitcmd structures, apply the operations
87 * described in the bitcmd structures to the old mode, and return the new mode.
88 * Note that there is no '=' command; a strict assignment is just a '-' (clear
89 * bits) followed by a '+' (set bits).
90 */
91mode_t
92getmode(bbox, omode)
93 const void *bbox;
94 mode_t omode;
95{
96 const BITCMD *set;
97 mode_t clrval, newmode, value;
98
99 _DIAGASSERT(bbox != NULL);
100
101 set = (const BITCMD *)bbox;
102 newmode = omode;
103 for (value = 0;; set++)
104 switch(set->cmd) {
105 /*
106 * When copying the user, group or other bits around, we "know"
107 * where the bits are in the mode so that we can do shifts to
108 * copy them around. If we don't use shifts, it gets real
109 * grundgy with lots of single bit checks and bit sets.
110 */
111 case 'u':
112 value = (newmode & S_IRWXU) >> 6;
113 goto common;
114
115 case 'g':
116 value = (newmode & S_IRWXG) >> 3;
117 goto common;
118
119 case 'o':
120 value = newmode & S_IRWXO;
121common: if (set->cmd2 & CMD2_CLR) {
122 clrval =
123 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
124 if (set->cmd2 & CMD2_UBITS)
125 newmode &= ~((clrval<<6) & set->bits);
126 if (set->cmd2 & CMD2_GBITS)
127 newmode &= ~((clrval<<3) & set->bits);
128 if (set->cmd2 & CMD2_OBITS)
129 newmode &= ~(clrval & set->bits);
130 }
131 if (set->cmd2 & CMD2_SET) {
132 if (set->cmd2 & CMD2_UBITS)
133 newmode |= (value<<6) & set->bits;
134 if (set->cmd2 & CMD2_GBITS)
135 newmode |= (value<<3) & set->bits;
136 if (set->cmd2 & CMD2_OBITS)
137 newmode |= value & set->bits;
138 }
139 break;
140
141 case '+':
142 newmode |= set->bits;
143 break;
144
145 case '-':
146 newmode &= ~set->bits;
147 break;
148
149 case 'X':
150 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
151 newmode |= set->bits;
152 break;
153
154 case '\0':
155 default:
156#ifdef SETMODE_DEBUG
157 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
158#endif
159 return (newmode);
160 }
161}
162
163#define ADDCMD(a, b, c, d) do { \
164 if (set >= endset) { \
165 BITCMD *newset; \
166 setlen += SET_LEN_INCR; \
167 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
168 if (newset == NULL) { \
169 free(saveset); \
170 return (NULL); \
171 } \
172 set = newset + (set - saveset); \
173 saveset = newset; \
174 endset = newset + (setlen - 2); \
175 } \
176 set = addcmd(set, (a), (b), (c), (d)); \
177} while (/*CONSTCOND*/0)
178
179#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
180
181void *
182setmode(p)
183 const char *p;
184{
185 int perm, who;
186 char op, *ep;
187 BITCMD *set, *saveset, *endset;
188 sigset_t signset, sigoset;
189 mode_t mask;
190 int equalopdone = 0; /* pacify gcc */
191 int permXbits, setlen;
192
193 if (!*p)
194 return (NULL);
195
196 /*
197 * Get a copy of the mask for the permissions that are mask relative.
198 * Flip the bits, we want what's not set. Since it's possible that
199 * the caller is opening files inside a signal handler, protect them
200 * as best we can.
201 */
202 sigfillset(&signset);
203 (void)sigprocmask(SIG_BLOCK, &signset, &sigoset);
204 (void)umask(mask = umask(0));
205 mask = ~mask;
206 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
207
208 setlen = SET_LEN + 2;
209
210 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
211 return (NULL);
212 saveset = set;
213 endset = set + (setlen - 2);
214
215 /*
216 * If an absolute number, get it and return; disallow non-octal digits
217 * or illegal bits.
218 */
219 if (isdigit((unsigned char)*p)) {
220 perm = (mode_t)strtol(p, &ep, 8);
221 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
222 free(saveset);
223 return (NULL);
224 }
225 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
226 set->cmd = 0;
227 return (saveset);
228 }
229
230 /*
231 * Build list of structures to set/clear/copy bits as described by
232 * each clause of the symbolic mode.
233 */
234 for (;;) {
235 /* First, find out which bits might be modified. */
236 for (who = 0;; ++p) {
237 switch (*p) {
238 case 'a':
239 who |= STANDARD_BITS;
240 break;
241 case 'u':
242 who |= S_ISUID|S_IRWXU;
243 break;
244 case 'g':
245 who |= S_ISGID|S_IRWXG;
246 break;
247 case 'o':
248 who |= S_IRWXO;
249 break;
250 default:
251 goto getop;
252 }
253 }
254
255getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
256 free(saveset);
257 return (NULL);
258 }
259 if (op == '=')
260 equalopdone = 0;
261
262 who &= ~S_ISTXT;
263 for (perm = 0, permXbits = 0;; ++p) {
264 switch (*p) {
265 case 'r':
266 perm |= S_IRUSR|S_IRGRP|S_IROTH;
267 break;
268 case 's':
269 /*
270 * If specific bits where requested and
271 * only "other" bits ignore set-id.
272 */
273 if (who == 0 || (who & ~S_IRWXO))
274 perm |= S_ISUID|S_ISGID;
275 break;
276 case 't':
277 /*
278 * If specific bits where requested and
279 * only "other" bits ignore set-id.
280 */
281 if (who == 0 || (who & ~S_IRWXO)) {
282 who |= S_ISTXT;
283 perm |= S_ISTXT;
284 }
285 break;
286 case 'w':
287 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
288 break;
289 case 'X':
290 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
291 break;
292 case 'x':
293 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
294 break;
295 case 'u':
296 case 'g':
297 case 'o':
298 /*
299 * When ever we hit 'u', 'g', or 'o', we have
300 * to flush out any partial mode that we have,
301 * and then do the copying of the mode bits.
302 */
303 if (perm) {
304 ADDCMD(op, who, perm, mask);
305 perm = 0;
306 }
307 if (op == '=')
308 equalopdone = 1;
309 if (op == '+' && permXbits) {
310 ADDCMD('X', who, permXbits, mask);
311 permXbits = 0;
312 }
313 ADDCMD(*p, who, op, mask);
314 break;
315
316 default:
317 /*
318 * Add any permissions that we haven't already
319 * done.
320 */
321 if (perm || (op == '=' && !equalopdone)) {
322 if (op == '=')
323 equalopdone = 1;
324 ADDCMD(op, who, perm, mask);
325 perm = 0;
326 }
327 if (permXbits) {
328 ADDCMD('X', who, permXbits, mask);
329 permXbits = 0;
330 }
331 goto apply;
332 }
333 }
334
335apply: if (!*p)
336 break;
337 if (*p != ',')
338 goto getop;
339 ++p;
340 }
341 set->cmd = 0;
342#ifdef SETMODE_DEBUG
343 (void)printf("Before compress_mode()\n");
344 dumpmode(saveset);
345#endif
346 compress_mode(saveset);
347#ifdef SETMODE_DEBUG
348 (void)printf("After compress_mode()\n");
349 dumpmode(saveset);
350#endif
351 return (saveset);
352}
353
354static BITCMD *
355addcmd(set, op, who, oparg, mask)
356 BITCMD *set;
357 int oparg, who;
358 int op;
359 u_int mask;
360{
361
362 _DIAGASSERT(set != NULL);
363
364 switch (op) {
365 case '=':
366 set->cmd = '-';
367 set->bits = who ? who : STANDARD_BITS;
368 set++;
369
370 op = '+';
371 /* FALLTHROUGH */
372 case '+':
373 case '-':
374 case 'X':
375 set->cmd = op;
376 set->bits = (who ? who : mask) & oparg;
377 break;
378
379 case 'u':
380 case 'g':
381 case 'o':
382 set->cmd = op;
383 if (who) {
384 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
385 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
386 ((who & S_IROTH) ? CMD2_OBITS : 0);
387 set->bits = (mode_t)~0;
388 } else {
389 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
390 set->bits = mask;
391 }
392
393 if (oparg == '+')
394 set->cmd2 |= CMD2_SET;
395 else if (oparg == '-')
396 set->cmd2 |= CMD2_CLR;
397 else if (oparg == '=')
398 set->cmd2 |= CMD2_SET|CMD2_CLR;
399 break;
400 }
401 return (set + 1);
402}
403
404#ifdef SETMODE_DEBUG
405static void
406dumpmode(set)
407 BITCMD *set;
408{
409
410 _DIAGASSERT(set != NULL);
411
412 for (; set->cmd; ++set)
413 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
414 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
415 set->cmd2 & CMD2_CLR ? " CLR" : "",
416 set->cmd2 & CMD2_SET ? " SET" : "",
417 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
418 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
419 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
420}
421#endif
422
423/*
424 * Given an array of bitcmd structures, compress by compacting consecutive
425 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
426 * 'g' and 'o' commands continue to be separate. They could probably be
427 * compacted, but it's not worth the effort.
428 */
429static void
430compress_mode(set)
431 BITCMD *set;
432{
433 BITCMD *nset;
434 int setbits, clrbits, Xbits, op;
435
436 _DIAGASSERT(set != NULL);
437
438 for (nset = set;;) {
439 /* Copy over any 'u', 'g' and 'o' commands. */
440 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
441 *set++ = *nset++;
442 if (!op)
443 return;
444 }
445
446 for (setbits = clrbits = Xbits = 0;; nset++) {
447 if ((op = nset->cmd) == '-') {
448 clrbits |= nset->bits;
449 setbits &= ~nset->bits;
450 Xbits &= ~nset->bits;
451 } else if (op == '+') {
452 setbits |= nset->bits;
453 clrbits &= ~nset->bits;
454 Xbits &= ~nset->bits;
455 } else if (op == 'X')
456 Xbits |= nset->bits & ~setbits;
457 else
458 break;
459 }
460 if (clrbits) {
461 set->cmd = '-';
462 set->cmd2 = 0;
463 set->bits = clrbits;
464 set++;
465 }
466 if (setbits) {
467 set->cmd = '+';
468 set->cmd2 = 0;
469 set->bits = setbits;
470 set++;
471 }
472 if (Xbits) {
473 set->cmd = 'X';
474 set->cmd2 = 0;
475 set->bits = Xbits;
476 set++;
477 }
478 }
479}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette