source: trunk/minix/commands/simple/mkdir.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 5.4 KB
Line 
1/* mkdir - Make directories Author: V. Archer */
2
3/* Copyright 1991 by Vincent Archer
4 * You may freely redistribute this software, in source or binary
5 * form, provided that you do not alter this copyright mention in any
6 * way.
7 */
8
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <minix/minlib.h>
12#include <limits.h>
13#include <errno.h>
14#include <string.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <stdio.h>
18
19extern int optind, opterr;
20extern char *optarg;
21
22#define USR_MODES (S_ISUID|S_IRWXU)
23#define GRP_MODES (S_ISGID|S_IRWXG)
24#define EXE_MODES (S_IXUSR|S_IXGRP|S_IXOTH)
25#ifdef S_ISVTX
26#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO|S_ISVTX)
27#else
28#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO)
29#endif
30#define DEFAULT_MODE (S_IRWXU|S_IRWXG|S_IRWXO)
31#define USER_WX (S_IWUSR|S_IXUSR)
32
33
34/* Global variables */
35int pflag;
36char *symbolic;
37mode_t u_mask;
38struct stat st;
39
40_PROTOTYPE(int main, (int argc, char **argv));
41_PROTOTYPE(mode_t parsemode, (char *symbolic, mode_t oldmode));
42_PROTOTYPE(int makepath, (char *fordir));
43_PROTOTYPE(int makedir, (char *dirname));
44_PROTOTYPE(void usage, (void));
45
46/* Parse a P1003.2 4.7.7-conformant symbolic mode. */
47mode_t parsemode(char *symbolic, mode_t oldmode)
48{
49 mode_t who, mask, newmode, tmpmask;
50 char action;
51 char *end;
52 unsigned long octalmode;
53
54 octalmode = strtoul(symbolic, &end, 010);
55 if (octalmode < ALL_MODES && *end == 0 && end != symbolic) return octalmode;
56
57 newmode = oldmode & ALL_MODES;
58 while (*symbolic) {
59 who = 0;
60 for (; *symbolic; symbolic++) {
61 if (*symbolic == 'a') {
62 who |= ALL_MODES;
63 continue;
64 }
65 if (*symbolic == 'u') {
66 who |= USR_MODES;
67 continue;
68 }
69 if (*symbolic == 'g') {
70 who |= GRP_MODES;
71 continue;
72 }
73 if (*symbolic == 'o') {
74 who |= S_IRWXO;
75 continue;
76 }
77 break;
78 }
79 if (!*symbolic || *symbolic == ',') usage();
80 while (*symbolic) {
81 if (*symbolic == ',') break;
82 switch (*symbolic) {
83 default:
84 usage();
85 case '+':
86 case '-':
87 case '=': action = *symbolic++;
88 }
89 mask = 0;
90 for (; *symbolic; symbolic++) {
91 if (*symbolic == 'u') {
92 tmpmask = newmode & S_IRWXU;
93 mask |= tmpmask | (tmpmask << 3) | (tmpmask << 6);
94 symbolic++;
95 break;
96 }
97 if (*symbolic == 'g') {
98 tmpmask = newmode & S_IRWXG;
99 mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3);
100 symbolic++;
101 break;
102 }
103 if (*symbolic == 'o') {
104 tmpmask = newmode & S_IRWXO;
105 mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6);
106 symbolic++;
107 break;
108 }
109 if (*symbolic == 'r') {
110 mask |= S_IRUSR | S_IRGRP | S_IROTH;
111 continue;
112 }
113 if (*symbolic == 'w') {
114 mask |= S_IWUSR | S_IWGRP | S_IWOTH;
115 continue;
116 }
117 if (*symbolic == 'x') {
118 mask |= EXE_MODES;
119 continue;
120 }
121 if (*symbolic == 's') {
122 mask |= S_ISUID | S_ISGID;
123 continue;
124 }
125 if (*symbolic == 'X') {
126 if (S_ISDIR(oldmode) || (oldmode & EXE_MODES))
127 mask |= EXE_MODES;
128 continue;
129 }
130#ifdef S_ISVTX
131 if (*symbolic == 't') {
132 mask |= S_ISVTX;
133 who |= S_ISVTX;
134 continue;
135 }
136#endif
137 break;
138 }
139 switch (action) {
140 case '=':
141 if (who)
142 newmode &= ~who;
143 else
144 newmode = 0;
145 case '+':
146 if (who)
147 newmode |= who & mask;
148 else
149 newmode |= mask & (~u_mask);
150 break;
151 case '-':
152 if (who)
153 newmode &= ~(who & mask);
154 else
155 newmode &= ~mask | u_mask;
156 }
157 }
158 if (*symbolic) symbolic++;
159 }
160 return(newmode);
161}
162
163
164/* Main module. */
165int main(argc, argv)
166int argc;
167char **argv;
168{
169 int error, c;
170
171 opterr = 0;
172 pflag = 0;
173 symbolic = (char *) 0;
174 u_mask = umask(0);
175 umask(u_mask);
176 while ((c = getopt(argc, argv, "m:p")) != EOF) switch (c) {
177 case 'm': symbolic = optarg; break;
178 case 'p': pflag = 1; break;
179 default: usage();
180 }
181 if (optind >= argc) usage();
182
183 error = 0;
184 while (optind < argc) error |= makedir(argv[optind++]);
185 return(error);
186}
187
188
189/* P1003.2 requires that missing intermediate pathname components should be
190 * created if the -p option is specified (4.40.3).
191 */
192int makepath(fordir)
193char *fordir;
194{
195 char parent[PATH_MAX + 1], *end, *last;
196
197 strcpy(parent, fordir);
198 do {
199 if (!(end = strrchr(parent, '/'))) return(0);
200 *end = '\0';
201 if (!parent[0] || !strcmp(parent, ".")) return(0);
202 } while((last = strrchr(parent, '/')) && !strcmp(last+1, "."));
203
204 if (!stat(parent, &st)) {
205 if (S_ISDIR(st.st_mode)) return(0);
206 errno = ENOTDIR;
207 perror(parent);
208 return(1);
209 }
210 if (mkdir(parent, DEFAULT_MODE)) {
211 if (makepath(parent)) return(1);
212 if (mkdir(parent, DEFAULT_MODE)) {
213 perror(parent);
214 return(1);
215 }
216 }
217
218/* P1003.2 states that, regardless of umask() value, intermediate paths
219 * should have at least write and search (x) permissions (4.40.10).
220 */
221 if ((u_mask & USER_WX) &&
222 chmod(parent, ((~u_mask) | USER_WX)) & DEFAULT_MODE) {
223 perror(parent);
224 return(1);
225 }
226 return(0);
227}
228
229
230/* Actual directory creation, using a mkdir() system call. */
231int makedir(dirname)
232char *dirname;
233{
234 if (mkdir(dirname, DEFAULT_MODE)) {
235 if (!pflag) {
236 perror(dirname);
237 return(1);
238 }
239 if (!stat(dirname, &st)) {
240 if (S_ISDIR(st.st_mode)) return(0);
241 errno = ENOTDIR;
242 perror(dirname);
243 return(1);
244 }
245 if (makepath(dirname)) return(1);
246 if (mkdir(dirname, DEFAULT_MODE)) {
247 perror(dirname);
248 return(1);
249 }
250 }
251 if (symbolic && (stat(dirname, &st) ||
252 chmod(dirname, parsemode(symbolic, st.st_mode)))) {
253 perror(dirname);
254 return(1);
255 }
256 return(0);
257}
258
259
260/* Posix command prototype. */
261void usage()
262{
263 std_err("Usage: mkdir [-p] [-m mode] dir...\n");
264 exit(1);
265}
Note: See TracBrowser for help on using the repository browser.