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