source: MondoRescue/branches/3.3/mindi-busybox/libbb/parse_mode.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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