diff options
Diffstat (limited to 'libbb/parse_mode.c')
-rw-r--r-- | libbb/parse_mode.c | 215 |
1 files changed, 129 insertions, 86 deletions
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c index ba34ea929..49573dfbb 100644 --- a/libbb/parse_mode.c +++ b/libbb/parse_mode.c | |||
@@ -1,134 +1,177 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Utility routines. | 3 | * parse_mode implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) many different people. If you wrote this, please | 5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> |
6 | * acknowledge your work. | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 9 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 10 | * (at your option) any later version. |
12 | * | 11 | * |
13 | * This program is distributed in the hope that it will be useful, but | 12 | * This program is distributed in the hope that it will be useful, |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * General Public License for more details. | 15 | * General Public License for more details. |
17 | * | 16 | * |
18 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | * USA | 20 | * |
22 | */ | 21 | */ |
23 | 22 | ||
24 | #include <stdio.h> | 23 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */ |
24 | |||
25 | #include <stdlib.h> | 25 | #include <stdlib.h> |
26 | #include <assert.h> | ||
27 | #include <sys/stat.h> | ||
26 | #include "libbb.h" | 28 | #include "libbb.h" |
27 | 29 | ||
30 | #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) | ||
28 | 31 | ||
29 | /* This function parses the sort of string you might pass | 32 | extern int bb_parse_mode(const char *s, mode_t *current_mode) |
30 | * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the | ||
31 | * correct mode described by the string. */ | ||
32 | extern int parse_mode(const char *s, mode_t * theMode) | ||
33 | { | 33 | { |
34 | static const mode_t group_set[] = { | 34 | static const mode_t who_mask[] = { |
35 | S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ | ||
35 | S_ISUID | S_IRWXU, /* u */ | 36 | S_ISUID | S_IRWXU, /* u */ |
36 | S_ISGID | S_IRWXG, /* g */ | 37 | S_ISGID | S_IRWXG, /* g */ |
37 | S_IRWXO, /* o */ | 38 | S_IRWXO /* o */ |
38 | S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */ | ||
39 | }; | 39 | }; |
40 | 40 | ||
41 | static const mode_t mode_set[] = { | 41 | static const mode_t perm_mask[] = { |
42 | S_IRUSR | S_IRGRP | S_IROTH, /* r */ | 42 | S_IRUSR | S_IRGRP | S_IROTH, /* r */ |
43 | S_IWUSR | S_IWGRP | S_IWOTH, /* w */ | 43 | S_IWUSR | S_IWGRP | S_IWOTH, /* w */ |
44 | S_IXUSR | S_IXGRP | S_IXOTH, /* x */ | 44 | S_IXUSR | S_IXGRP | S_IXOTH, /* x */ |
45 | S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */ | ||
45 | S_ISUID | S_ISGID, /* s */ | 46 | S_ISUID | S_ISGID, /* s */ |
46 | S_ISVTX /* t */ | 47 | S_ISVTX /* t */ |
47 | }; | 48 | }; |
48 | 49 | ||
49 | static const char group_chars[] = "ugoa"; | 50 | static const char who_chars[] = "augo"; |
50 | static const char mode_chars[] = "rwxst"; | 51 | static const char perm_chars[] = "rwxXst"; |
51 | 52 | ||
52 | const char *p; | 53 | const char *p; |
53 | 54 | ||
54 | mode_t andMode = | 55 | mode_t wholist; |
55 | S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; | 56 | mode_t permlist; |
56 | mode_t orMode = 0; | 57 | mode_t mask; |
57 | mode_t mode; | 58 | mode_t new_mode; |
58 | mode_t groups; | 59 | char op; |
59 | char type; | 60 | |
60 | char c; | 61 | assert(s); |
62 | |||
63 | if (((unsigned int)(*s - '0')) < 8) { | ||
64 | unsigned long tmp; | ||
65 | char *e; | ||
61 | 66 | ||
62 | if (s==NULL) { | 67 | tmp = strtol(s, &e, 8); |
63 | return (FALSE); | 68 | if (*e || (tmp > 0xffffU)) { /* Check range and trailing chars. */ |
69 | return 0; | ||
70 | } | ||
71 | *current_mode = tmp; | ||
72 | return 1; | ||
64 | } | 73 | } |
65 | 74 | ||
66 | do { | 75 | mask = umask(0); |
67 | mode = 0; | 76 | umask(mask); |
68 | groups = 0; | 77 | |
69 | NEXT_GROUP: | 78 | new_mode = *current_mode; |
70 | if ((c = *s++) == '\0') { | 79 | |
71 | return -1; | 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; | ||
72 | } | 88 | } |
73 | for (p=group_chars ; *p ; p++) { | 89 | |
74 | if (*p == c) { | 90 | /* Get a wholist. */ |
75 | groups |= group_set[(int)(p-group_chars)]; | 91 | wholist = 0; |
76 | goto NEXT_GROUP; | 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; | ||
77 | } | 102 | } |
78 | } | 103 | } while (*++p); |
79 | switch (c) { | 104 | |
80 | case '=': | 105 | do { /* Process action list. */ |
81 | case '+': | 106 | if ((*s != '+') && (*s != '-')) { |
82 | case '-': | 107 | if (*s != '=') { |
83 | type = c; | 108 | return 0; |
84 | if (groups == 0) { /* The default is "all" */ | ||
85 | groups |= S_ISUID | S_ISGID | S_ISVTX | ||
86 | | S_IRWXU | S_IRWXG | S_IRWXO; | ||
87 | } | 109 | } |
88 | break; | 110 | /* Since op is '=', clear all bits corresponding to the |
89 | default: | 111 | * wholist, of all file bits if wholist is empty. */ |
90 | if ((c < '0') || (c > '7') || (mode | groups)) { | 112 | permlist = ~FILEMODEBITS; |
91 | return (FALSE); | 113 | if (wholist) { |
92 | } else { | 114 | permlist = ~wholist; |
93 | *theMode = strtol(--s, NULL, 8); | ||
94 | return (TRUE); | ||
95 | } | 115 | } |
96 | } | 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); | ||
97 | 137 | ||
98 | NEXT_MODE: | 138 | /* It was not a permcopy, so get a permlist. */ |
99 | if (((c = *s++) != '\0') && (c != ',')) { | 139 | permlist = 0; |
100 | for (p=mode_chars ; *p ; p++) { | 140 | |
101 | if (*p == c) { | 141 | PERM_LIST: |
102 | mode |= mode_set[(int)(p-mode_chars)]; | 142 | p = perm_chars; |
103 | goto NEXT_MODE; | 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; | ||
104 | } | 169 | } |
105 | } | 170 | } |
106 | break; /* We're done so break out of loop.*/ | 171 | } while (*s && (*s != ',')); |
107 | } | 172 | } |
108 | switch (type) { | ||
109 | case '=': | ||
110 | andMode &= ~(groups); /* Now fall through. */ | ||
111 | case '+': | ||
112 | orMode |= mode & groups; | ||
113 | break; | ||
114 | case '-': | ||
115 | andMode &= ~(mode & groups); | ||
116 | orMode &= ~(mode & groups); | ||
117 | break; | ||
118 | } | ||
119 | } while (c == ','); | ||
120 | 173 | ||
121 | *theMode &= andMode; | 174 | *current_mode = new_mode; |
122 | *theMode |= orMode; | ||
123 | 175 | ||
124 | return TRUE; | 176 | return 1; |
125 | } | 177 | } |
126 | |||
127 | /* END CODE */ | ||
128 | /* | ||
129 | Local Variables: | ||
130 | c-file-style: "linux" | ||
131 | c-basic-offset: 4 | ||
132 | tab-width: 4 | ||
133 | End: | ||
134 | */ | ||