source: MondoRescue/branches/stable/mindi-busybox/libbb/parse_mode.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 3.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * parse_mode implementation for busybox
4 *
5 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
24
25#include <stdlib.h>
26#include <assert.h>
27#include <sys/stat.h>
28#include "libbb.h"
29
30#define FILEMODEBITS    (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
31
32int bb_parse_mode(const char *s, mode_t *current_mode)
33{
34    static const mode_t who_mask[] = {
35        S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
36        S_ISUID | S_IRWXU,      /* u */
37        S_ISGID | S_IRWXG,      /* g */
38        S_IRWXO                 /* o */
39    };
40
41    static const mode_t perm_mask[] = {
42        S_IRUSR | S_IRGRP | S_IROTH, /* r */
43        S_IWUSR | S_IWGRP | S_IWOTH, /* w */
44        S_IXUSR | S_IXGRP | S_IXOTH, /* x */
45        S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
46        S_ISUID | S_ISGID,      /* s */
47        S_ISVTX                 /* t */
48    };
49
50    static const char who_chars[] = "augo";
51    static const char perm_chars[] = "rwxXst";
52
53    const char *p;
54
55    mode_t wholist;
56    mode_t permlist;
57    mode_t mask;
58    mode_t new_mode;
59    char op;
60
61    assert(s);
62
63    if (((unsigned int)(*s - '0')) < 8) {
64        unsigned long tmp;
65        char *e;
66
67        tmp = strtol(s, &e, 8);
68        if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
69            return 0;
70        }
71        *current_mode = tmp;
72        return 1;
73    }
74
75    mask = umask(0);
76    umask(mask);
77
78    new_mode = *current_mode;
79
80    /* Note: We allow empty clauses, and hence empty modes.
81     * We treat an empty mode as no change to perms. */
82
83    while (*s) {    /* Process clauses. */
84
85        if (*s == ',') {    /* We allow empty clauses. */
86            ++s;
87            continue;
88        }
89
90        /* Get a wholist. */
91        wholist = 0;
92
93    WHO_LIST:
94        p = who_chars;
95        do {
96            if (*p == *s) {
97                wholist |= who_mask[(int)(p-who_chars)];
98                if (!*++s) {
99                    return 0;
100                }
101                goto WHO_LIST;
102            }
103        } while (*++p);
104
105        do {    /* Process action list. */
106            if ((*s != '+') && (*s != '-')) {
107                if (*s != '=') {
108                    return 0;
109                }
110                /* Since op is '=', clear all bits corresponding to the
111                 * wholist, of all file bits if wholist is empty. */
112                permlist = ~FILEMODEBITS;
113                if (wholist) {
114                    permlist = ~wholist;
115                }
116                new_mode &= permlist;
117            }
118            op = *s++;
119
120            /* Check for permcopy. */
121            p = who_chars + 1;  /* Skip 'a' entry. */
122            do {
123                if (*p == *s) {
124                    int i = 0;
125                    permlist = who_mask[(int)(p-who_chars)]
126                             & (S_IRWXU | S_IRWXG | S_IRWXO)
127                             & new_mode;
128                    do {
129                        if (permlist & perm_mask[i]) {
130                            permlist |= perm_mask[i];
131                        }
132                    } while (++i < 3);
133                    ++s;
134                    goto GOT_ACTION;
135                }
136            } while (*++p);
137
138            /* It was not a permcopy, so get a permlist. */
139            permlist = 0;
140
141        PERM_LIST:
142            p = perm_chars;
143            do {
144                if (*p == *s) {
145                    if ((*p != 'X')
146                        || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
147                    ) {
148                        permlist |= perm_mask[(int)(p-perm_chars)];
149                    }
150                    if (!*++s) {
151                        break;
152                    }
153                    goto PERM_LIST;
154                }
155            } while (*++p);
156
157        GOT_ACTION:
158            if (permlist) { /* The permlist was nonempty. */
159                mode_t tmp = ~mask;
160                if (wholist) {
161                    tmp = wholist;
162                }
163                permlist &= tmp;
164
165                if (op == '-') {
166                    new_mode &= ~permlist;
167                } else {
168                    new_mode |= permlist;
169                }
170            }
171        } while (*s && (*s != ','));
172    }
173
174    *current_mode = new_mode;
175
176    return 1;
177}
Note: See TracBrowser for help on using the repository browser.