OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

[/] [eco32/] [tags/] [eco32-0.24/] [disk/] [tools/] [fs-NetBSD/] [makefs/] [setmode.c] - Blame information for rev 211

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.