[BACK]Return to setmode.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / gen

Annotation of src/lib/libc/gen/setmode.c, Revision 1.27

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

CVSweb <webmaster@jp.NetBSD.org>