]>
Commit | Line | Data |
---|---|---|
44a7a5ab A |
1 | /* |
2 | * Copyright (c) 1983, 1992, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
44a7a5ab | 34 | #ifndef lint |
6c780a1f A |
35 | static char const copyright[] = |
36 | "@(#) Copyright (c) 1983, 1992, 1993\n\ | |
37 | The Regents of the University of California. All rights reserved.\n"; | |
44a7a5ab A |
38 | #endif /* not lint */ |
39 | ||
40 | #ifndef lint | |
41 | #if 0 | |
42 | static char sccsid[] = "@(#)mkdir.c 8.2 (Berkeley) 1/25/94"; | |
44a7a5ab A |
43 | #endif |
44 | #endif /* not lint */ | |
6c780a1f A |
45 | #include <sys/cdefs.h> |
46 | __RCSID("$FreeBSD: src/bin/mkdir/mkdir.c,v 1.26 2002/06/30 05:13:54 obrien Exp $"); | |
44a7a5ab A |
47 | |
48 | #include <sys/types.h> | |
49 | #include <sys/stat.h> | |
50 | ||
51 | #include <err.h> | |
52 | #include <errno.h> | |
6c780a1f | 53 | #include <libgen.h> |
44a7a5ab A |
54 | #include <stdio.h> |
55 | #include <stdlib.h> | |
56 | #include <string.h> | |
6c780a1f | 57 | #include <sysexits.h> |
44a7a5ab A |
58 | #include <unistd.h> |
59 | ||
6c780a1f A |
60 | static int build(char *, mode_t); |
61 | static void usage(void); | |
62 | ||
63 | int vflag; | |
44a7a5ab A |
64 | |
65 | int | |
6c780a1f | 66 | main(int argc, char *argv[]) |
44a7a5ab | 67 | { |
6c780a1f A |
68 | int ch, exitval, success, pflag; |
69 | mode_t omode, *set = (mode_t *)NULL; | |
70 | char *mode; | |
44a7a5ab | 71 | |
6c780a1f A |
72 | omode = pflag = 0; |
73 | mode = NULL; | |
74 | while ((ch = getopt(argc, argv, "m:pv")) != -1) | |
44a7a5ab | 75 | switch(ch) { |
6c780a1f A |
76 | case 'm': |
77 | mode = optarg; | |
78 | break; | |
44a7a5ab A |
79 | case 'p': |
80 | pflag = 1; | |
81 | break; | |
6c780a1f A |
82 | case 'v': |
83 | vflag = 1; | |
44a7a5ab A |
84 | break; |
85 | case '?': | |
86 | default: | |
87 | usage(); | |
88 | } | |
6c780a1f | 89 | |
44a7a5ab A |
90 | argc -= optind; |
91 | argv += optind; | |
6c780a1f | 92 | if (argv[0] == NULL) |
44a7a5ab | 93 | usage(); |
44a7a5ab | 94 | |
6c780a1f A |
95 | if (mode == NULL) { |
96 | omode = S_IRWXU | S_IRWXG | S_IRWXO; | |
97 | } else { | |
98 | if ((set = setmode(mode)) == NULL) | |
99 | errx(1, "invalid file mode: %s", mode); | |
100 | omode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); | |
101 | free(set); | |
102 | } | |
44a7a5ab | 103 | |
6c780a1f A |
104 | for (exitval = 0; *argv != NULL; ++argv) { |
105 | success = 1; | |
44a7a5ab | 106 | if (pflag) { |
6c780a1f A |
107 | if (build(*argv, omode)) |
108 | success = 0; | |
109 | } else if (mkdir(*argv, omode) < 0) { | |
110 | if (errno == ENOTDIR || errno == ENOENT) | |
111 | warn("%s", dirname(*argv)); | |
112 | else | |
44a7a5ab | 113 | warn("%s", *argv); |
6c780a1f A |
114 | success = 0; |
115 | } else if (vflag) | |
116 | (void)printf("%s\n", *argv); | |
117 | ||
118 | if (!success) | |
119 | exitval = 1; | |
120 | /* | |
121 | * The mkdir() and umask() calls both honor only the low | |
122 | * nine bits, so if you try to set a mode including the | |
123 | * sticky, setuid, setgid bits you lose them. Don't do | |
124 | * this unless the user has specifically requested a mode, | |
125 | * as chmod will (obviously) ignore the umask. | |
126 | */ | |
127 | if (success && mode != NULL && chmod(*argv, omode) == -1) { | |
128 | warn("%s", *argv); | |
129 | exitval = 1; | |
44a7a5ab A |
130 | } |
131 | } | |
132 | exit(exitval); | |
44a7a5ab A |
133 | } |
134 | ||
44a7a5ab | 135 | int |
6c780a1f | 136 | build(char *path, mode_t omode) |
44a7a5ab A |
137 | { |
138 | struct stat sb; | |
6c780a1f A |
139 | mode_t numask, oumask; |
140 | int first, last, retval; | |
141 | char *p; | |
142 | ||
143 | p = path; | |
144 | oumask = 0; | |
145 | retval = 0; | |
146 | if (p[0] == '/') /* Skip leading '/'. */ | |
147 | ++p; | |
148 | for (first = 1, last = 0; !last ; ++p) { | |
149 | if (p[0] == '\0') | |
150 | last = 1; | |
151 | else if (p[0] != '/') | |
152 | continue; | |
153 | *p = '\0'; | |
154 | if (p[1] == '\0') | |
155 | last = 1; | |
156 | if (first) { | |
157 | /* | |
158 | * POSIX 1003.2: | |
159 | * For each dir operand that does not name an existing | |
160 | * directory, effects equivalent to those cased by the | |
161 | * following command shall occcur: | |
162 | * | |
163 | * mkdir -p -m $(umask -S),u+wx $(dirname dir) && | |
164 | * mkdir [-m mode] dir | |
165 | * | |
166 | * We change the user's umask and then restore it, | |
167 | * instead of doing chmod's. | |
168 | */ | |
169 | oumask = umask(0); | |
170 | numask = oumask & ~(S_IWUSR | S_IXUSR); | |
171 | (void)umask(numask); | |
172 | first = 0; | |
44a7a5ab | 173 | } |
6c780a1f A |
174 | if (last) |
175 | (void)umask(oumask); | |
176 | if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0) { | |
177 | if (errno == EEXIST || errno == EISDIR) { | |
178 | if (stat(path, &sb) < 0) { | |
179 | warn("%s", path); | |
180 | retval = 1; | |
181 | break; | |
182 | } else if (!S_ISDIR(sb.st_mode)) { | |
183 | if (last) | |
184 | errno = EEXIST; | |
185 | else | |
186 | errno = ENOTDIR; | |
187 | warn("%s", path); | |
188 | retval = 1; | |
189 | break; | |
190 | } | |
191 | } else { | |
192 | warn("%s", path); | |
193 | retval = 1; | |
194 | break; | |
195 | } | |
196 | } else if (vflag) | |
197 | printf("%s\n", path); | |
198 | if (!last) | |
199 | *p = '/'; | |
44a7a5ab | 200 | } |
6c780a1f A |
201 | if (!first && !last) |
202 | (void)umask(oumask); | |
203 | return (retval); | |
44a7a5ab A |
204 | } |
205 | ||
206 | void | |
6c780a1f | 207 | usage(void) |
44a7a5ab A |
208 | { |
209 | ||
6c780a1f A |
210 | (void)fprintf(stderr, "usage: mkdir [-pv] [-m mode] directory ...\n"); |
211 | exit (EX_USAGE); | |
44a7a5ab | 212 | } |