remove traces of benchmarks from test/.
[minix.git] / commands / simple / mkdir.c
blobd02734676128b1e0c68b347da0ffbace66fee449
1 /* mkdir - Make directories Author: V. Archer */
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 */
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>
19 extern int optind, opterr;
20 extern char *optarg;
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)
34 /* Global variables */
35 int pflag;
36 char *symbolic;
37 mode_t u_mask;
38 struct stat st;
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));
46 /* Parse a P1003.2 4.7.7-conformant symbolic mode. */
47 mode_t parsemode(char *symbolic, mode_t oldmode)
49 mode_t who, mask, newmode, tmpmask;
50 char action;
51 char *end;
52 unsigned long octalmode;
54 octalmode = strtoul(symbolic, &end, 010);
55 if (octalmode < ALL_MODES && *end == 0 && end != symbolic) return octalmode;
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;
65 if (*symbolic == 'u') {
66 who |= USR_MODES;
67 continue;
69 if (*symbolic == 'g') {
70 who |= GRP_MODES;
71 continue;
73 if (*symbolic == 'o') {
74 who |= S_IRWXO;
75 continue;
77 break;
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++;
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;
97 if (*symbolic == 'g') {
98 tmpmask = newmode & S_IRWXG;
99 mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3);
100 symbolic++;
101 break;
103 if (*symbolic == 'o') {
104 tmpmask = newmode & S_IRWXO;
105 mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6);
106 symbolic++;
107 break;
109 if (*symbolic == 'r') {
110 mask |= S_IRUSR | S_IRGRP | S_IROTH;
111 continue;
113 if (*symbolic == 'w') {
114 mask |= S_IWUSR | S_IWGRP | S_IWOTH;
115 continue;
117 if (*symbolic == 'x') {
118 mask |= EXE_MODES;
119 continue;
121 if (*symbolic == 's') {
122 mask |= S_ISUID | S_ISGID;
123 continue;
125 if (*symbolic == 'X') {
126 if (S_ISDIR(oldmode) || (oldmode & EXE_MODES))
127 mask |= EXE_MODES;
128 continue;
130 #ifdef S_ISVTX
131 if (*symbolic == 't') {
132 mask |= S_ISVTX;
133 who |= S_ISVTX;
134 continue;
136 #endif
137 break;
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;
158 if (*symbolic) symbolic++;
160 return(newmode);
164 /* Main module. */
165 int main(argc, argv)
166 int argc;
167 char **argv;
169 int error, c;
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();
181 if (optind >= argc) usage();
183 error = 0;
184 while (optind < argc) error |= makedir(argv[optind++]);
185 return(error);
189 /* P1003.2 requires that missing intermediate pathname components should be
190 * created if the -p option is specified (4.40.3).
192 int makepath(fordir)
193 char *fordir;
195 char parent[PATH_MAX + 1], *end, *last;
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, "."));
204 if (!stat(parent, &st)) {
205 if (S_ISDIR(st.st_mode)) return(0);
206 errno = ENOTDIR;
207 perror(parent);
208 return(1);
210 if (mkdir(parent, DEFAULT_MODE)) {
211 if (makepath(parent)) return(1);
212 if (mkdir(parent, DEFAULT_MODE)) {
213 perror(parent);
214 return(1);
218 /* P1003.2 states that, regardless of umask() value, intermediate paths
219 * should have at least write and search (x) permissions (4.40.10).
221 if ((u_mask & USER_WX) &&
222 chmod(parent, ((~u_mask) | USER_WX)) & DEFAULT_MODE) {
223 perror(parent);
224 return(1);
226 return(0);
230 /* Actual directory creation, using a mkdir() system call. */
231 int makedir(dirname)
232 char *dirname;
234 if (mkdir(dirname, DEFAULT_MODE)) {
235 if (!pflag) {
236 perror(dirname);
237 return(1);
239 if (!stat(dirname, &st)) {
240 if (S_ISDIR(st.st_mode)) return(0);
241 errno = ENOTDIR;
242 perror(dirname);
243 return(1);
245 if (makepath(dirname)) return(1);
246 if (mkdir(dirname, DEFAULT_MODE)) {
247 perror(dirname);
248 return(1);
251 if (symbolic && (stat(dirname, &st) ||
252 chmod(dirname, parsemode(symbolic, st.st_mode)))) {
253 perror(dirname);
254 return(1);
256 return(0);
260 /* Posix command prototype. */
261 void usage()
263 std_err("Usage: mkdir [-p] [-m mode] dir...\n");
264 exit(1);