diff options
Diffstat (limited to 'libbb/parse_mode.c')
-rw-r--r-- | libbb/parse_mode.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c new file mode 100644 index 000000000..356d95db6 --- /dev/null +++ b/libbb/parse_mode.c | |||
@@ -0,0 +1,164 @@ | |||
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 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */ | ||
11 | |||
12 | #include <stdlib.h> | ||
13 | #include <assert.h> | ||
14 | #include <sys/stat.h> | ||
15 | #include "libbb.h" | ||
16 | |||
17 | #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) | ||
18 | |||
19 | int bb_parse_mode(const char *s, mode_t *current_mode) | ||
20 | { | ||
21 | static const mode_t who_mask[] = { | ||
22 | S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ | ||
23 | S_ISUID | S_IRWXU, /* u */ | ||
24 | S_ISGID | S_IRWXG, /* g */ | ||
25 | S_IRWXO /* o */ | ||
26 | }; | ||
27 | |||
28 | static const mode_t perm_mask[] = { | ||
29 | S_IRUSR | S_IRGRP | S_IROTH, /* r */ | ||
30 | S_IWUSR | S_IWGRP | S_IWOTH, /* w */ | ||
31 | S_IXUSR | S_IXGRP | S_IXOTH, /* x */ | ||
32 | S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */ | ||
33 | S_ISUID | S_ISGID, /* s */ | ||
34 | S_ISVTX /* t */ | ||
35 | }; | ||
36 | |||
37 | static const char who_chars[] = "augo"; | ||
38 | static const char perm_chars[] = "rwxXst"; | ||
39 | |||
40 | const char *p; | ||
41 | |||
42 | mode_t wholist; | ||
43 | mode_t permlist; | ||
44 | mode_t mask; | ||
45 | mode_t new_mode; | ||
46 | char op; | ||
47 | |||
48 | assert(s); | ||
49 | |||
50 | if (((unsigned int)(*s - '0')) < 8) { | ||
51 | unsigned long tmp; | ||
52 | char *e; | ||
53 | |||
54 | tmp = strtol(s, &e, 8); | ||
55 | if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */ | ||
56 | return 0; | ||
57 | } | ||
58 | *current_mode = tmp; | ||
59 | return 1; | ||
60 | } | ||
61 | |||
62 | mask = umask(0); | ||
63 | umask(mask); | ||
64 | |||
65 | new_mode = *current_mode; | ||
66 | |||
67 | /* Note: We allow empty clauses, and hence empty modes. | ||
68 | * We treat an empty mode as no change to perms. */ | ||
69 | |||
70 | while (*s) { /* Process clauses. */ | ||
71 | |||
72 | if (*s == ',') { /* We allow empty clauses. */ | ||
73 | ++s; | ||
74 | continue; | ||
75 | } | ||
76 | |||
77 | /* Get a wholist. */ | ||
78 | wholist = 0; | ||
79 | |||
80 | WHO_LIST: | ||
81 | p = who_chars; | ||
82 | do { | ||
83 | if (*p == *s) { | ||
84 | wholist |= who_mask[(int)(p-who_chars)]; | ||
85 | if (!*++s) { | ||
86 | return 0; | ||
87 | } | ||
88 | goto WHO_LIST; | ||
89 | } | ||
90 | } while (*++p); | ||
91 | |||
92 | do { /* Process action list. */ | ||
93 | if ((*s != '+') && (*s != '-')) { | ||
94 | if (*s != '=') { | ||
95 | return 0; | ||
96 | } | ||
97 | /* Since op is '=', clear all bits corresponding to the | ||
98 | * wholist, of all file bits if wholist is empty. */ | ||
99 | permlist = ~FILEMODEBITS; | ||
100 | if (wholist) { | ||
101 | permlist = ~wholist; | ||
102 | } | ||
103 | new_mode &= permlist; | ||
104 | } | ||
105 | op = *s++; | ||
106 | |||
107 | /* Check for permcopy. */ | ||
108 | p = who_chars + 1; /* Skip 'a' entry. */ | ||
109 | do { | ||
110 | if (*p == *s) { | ||
111 | int i = 0; | ||
112 | permlist = who_mask[(int)(p-who_chars)] | ||
113 | & (S_IRWXU | S_IRWXG | S_IRWXO) | ||
114 | & new_mode; | ||
115 | do { | ||
116 | if (permlist & perm_mask[i]) { | ||
117 | permlist |= perm_mask[i]; | ||
118 | } | ||
119 | } while (++i < 3); | ||
120 | ++s; | ||
121 | goto GOT_ACTION; | ||
122 | } | ||
123 | } while (*++p); | ||
124 | |||
125 | /* It was not a permcopy, so get a permlist. */ | ||
126 | permlist = 0; | ||
127 | |||
128 | PERM_LIST: | ||
129 | p = perm_chars; | ||
130 | do { | ||
131 | if (*p == *s) { | ||
132 | if ((*p != 'X') | ||
133 | || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH)) | ||
134 | ) { | ||
135 | permlist |= perm_mask[(int)(p-perm_chars)]; | ||
136 | } | ||
137 | if (!*++s) { | ||
138 | break; | ||
139 | } | ||
140 | goto PERM_LIST; | ||
141 | } | ||
142 | } while (*++p); | ||
143 | |||
144 | GOT_ACTION: | ||
145 | if (permlist) { /* The permlist was nonempty. */ | ||
146 | mode_t tmp = ~mask; | ||
147 | if (wholist) { | ||
148 | tmp = wholist; | ||
149 | } | ||
150 | permlist &= tmp; | ||
151 | |||
152 | if (op == '-') { | ||
153 | new_mode &= ~permlist; | ||
154 | } else { | ||
155 | new_mode |= permlist; | ||
156 | } | ||
157 | } | ||
158 | } while (*s && (*s != ',')); | ||
159 | } | ||
160 | |||
161 | *current_mode = new_mode; | ||
162 | |||
163 | return 1; | ||
164 | } | ||