mkdir.c revision 50471
1134459Siedowse/*
2134459Siedowse * Copyright (c) 1983, 1992, 1993
3134459Siedowse *	The Regents of the University of California.  All rights reserved.
4134459Siedowse *
5134459Siedowse * Redistribution and use in source and binary forms, with or without
6134459Siedowse * modification, are permitted provided that the following conditions
7134459Siedowse * are met:
8134459Siedowse * 1. Redistributions of source code must retain the above copyright
9134459Siedowse *    notice, this list of conditions and the following disclaimer.
10134459Siedowse * 2. Redistributions in binary form must reproduce the above copyright
11134459Siedowse *    notice, this list of conditions and the following disclaimer in the
12134459Siedowse *    documentation and/or other materials provided with the distribution.
13134459Siedowse * 3. All advertising materials mentioning features or use of this software
14134459Siedowse *    must display the following acknowledgement:
15134459Siedowse *	This product includes software developed by the University of
16134459Siedowse *	California, Berkeley and its contributors.
17134459Siedowse * 4. Neither the name of the University nor the names of its contributors
18134459Siedowse *    may be used to endorse or promote products derived from this software
19134459Siedowse *    without specific prior written permission.
20134459Siedowse *
21134459Siedowse * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22134459Siedowse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23134459Siedowse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24134459Siedowse * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25134459Siedowse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26134459Siedowse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27134459Siedowse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28134459Siedowse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29134459Siedowse * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30134459Siedowse * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31134459Siedowse * SUCH DAMAGE.
32134459Siedowse */
33134459Siedowse
34134459Siedowse#ifndef lint
35134459Siedowsestatic char const copyright[] =
36134459Siedowse"@(#) Copyright (c) 1983, 1992, 1993\n\
37134459Siedowse	The Regents of the University of California.  All rights reserved.\n";
38134459Siedowse#endif /* not lint */
39134459Siedowse
40134459Siedowse#ifndef lint
41134459Siedowse#if 0
42134459Siedowsestatic char sccsid[] = "@(#)mkdir.c	8.2 (Berkeley) 1/25/94";
43134459Siedowse#endif
44134459Siedowsestatic const char rcsid[] =
45134459Siedowse  "$FreeBSD: head/bin/mkdir/mkdir.c 50471 1999-08-27 23:15:48Z peter $";
46134459Siedowse#endif /* not lint */
47134459Siedowse
48134459Siedowse#include <sys/types.h>
49134459Siedowse#include <sys/stat.h>
50134459Siedowse
51134459Siedowse#include <err.h>
52134459Siedowse#include <errno.h>
53134459Siedowse#include <stdio.h>
54134459Siedowse#include <stdlib.h>
55134459Siedowse#include <string.h>
56134459Siedowse#include <unistd.h>
57134459Siedowse
58134459Siedowseint	build __P((char *, mode_t));
59134459Siedowsevoid	usage __P((void));
60134459Siedowse
61134459Siedowseint
62134459Siedowsemain(argc, argv)
63134459Siedowse	int argc;
64134459Siedowse	char *argv[];
65134459Siedowse{
66134459Siedowse	int ch, exitval, success, omode, pflag;
67134459Siedowse	mode_t *set = (mode_t *)NULL;
68134459Siedowse	char *mode;
69134459Siedowse
70134459Siedowse	omode = pflag = 0;
71134459Siedowse	mode = NULL;
72134459Siedowse	while ((ch = getopt(argc, argv, "m:p")) != -1)
73153504Smarcel		switch(ch) {
74134459Siedowse		case 'p':
75134459Siedowse			pflag = 1;
76134459Siedowse			break;
77134459Siedowse		case 'm':
78134459Siedowse			mode = optarg;
79134459Siedowse			break;
80134459Siedowse		case '?':
81134459Siedowse		default:
82134459Siedowse			usage();
83134459Siedowse		}
84134459Siedowse
85134459Siedowse	argc -= optind;
86134459Siedowse	argv += optind;
87134459Siedowse	if (argv[0] == NULL)
88134459Siedowse		usage();
89134459Siedowse
90134459Siedowse	if (mode == NULL) {
91134459Siedowse		omode = S_IRWXU | S_IRWXG | S_IRWXO;
92134459Siedowse	} else {
93134459Siedowse		if ((set = setmode(mode)) == NULL)
94134459Siedowse			errx(1, "invalid file mode: %s", mode);
95134459Siedowse		omode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
96134459Siedowse		free(set);
97134459Siedowse	}
98134459Siedowse
99134459Siedowse	for (exitval = 0; *argv != NULL; ++argv) {
100134459Siedowse		success = 1;
101134459Siedowse		if (pflag) {
102134459Siedowse			if (build(*argv, omode))
103134459Siedowse				success = 0;
104134459Siedowse		} else if (mkdir(*argv, omode) < 0) {
105134459Siedowse			warn("%s", *argv);
106134459Siedowse			success = 0;
107134459Siedowse		}
108134459Siedowse		if (!success)
109134459Siedowse			exitval = 1;
110134459Siedowse		/*
111134459Siedowse		 * The mkdir() and umask() calls both honor only the low
112134459Siedowse		 * nine bits, so if you try to set a mode including the
113134459Siedowse		 * sticky, setuid, setgid bits you lose them.  Don't do
114134459Siedowse		 * this unless the user has specifically requested a mode,
115134459Siedowse		 * as chmod will (obviously) ignore the umask.
116134459Siedowse		 */
117134459Siedowse		if (success && mode != NULL && chmod(*argv, omode) == -1) {
118134459Siedowse			warn("%s", *argv);
119134459Siedowse			exitval = 1;
120134459Siedowse		}
121134459Siedowse	}
122134459Siedowse	exit(exitval);
123134459Siedowse}
124134459Siedowse
125134459Siedowseint
126134459Siedowsebuild(path, omode)
127134459Siedowse	char *path;
128134459Siedowse	mode_t omode;
129134459Siedowse{
130134459Siedowse	struct stat sb;
131134459Siedowse	mode_t numask, oumask;
132134459Siedowse	int first, last, retval;
133134459Siedowse	char *p;
134134459Siedowse
135134459Siedowse	p = path;
136134459Siedowse	oumask = 0;
137134459Siedowse	retval = 0;
138134459Siedowse	if (p[0] == '/')		/* Skip leading '/'. */
139134459Siedowse		++p;
140134459Siedowse	for (first = 1, last = 0; !last ; ++p) {
141134459Siedowse		if (p[0] == '\0')
142134459Siedowse			last = 1;
143134459Siedowse		else if (p[0] != '/')
144134459Siedowse			continue;
145134459Siedowse		*p = '\0';
146134459Siedowse		if (p[1] == '\0')
147220311Smarcel			last = 1;
148220311Smarcel		if (first) {
149220311Smarcel			/*
150220311Smarcel			 * POSIX 1003.2:
151134459Siedowse			 * For each dir operand that does not name an existing
152134459Siedowse			 * directory, effects equivalent to those cased by the
153134459Siedowse			 * following command shall occcur:
154134459Siedowse			 *
155134459Siedowse			 * mkdir -p -m $(umask -S),u+wx $(dirname dir) &&
156134459Siedowse			 *    mkdir [-m mode] dir
157134459Siedowse			 *
158134459Siedowse			 * We change the user's umask and then restore it,
159134459Siedowse			 * instead of doing chmod's.
160134459Siedowse			 */
161134459Siedowse			oumask = umask(0);
162134459Siedowse			numask = oumask & ~(S_IWUSR | S_IXUSR);
163134459Siedowse			(void)umask(numask);
164134459Siedowse			first = 0;
165134459Siedowse		}
166134459Siedowse		if (last)
167134459Siedowse			(void)umask(oumask);
168134459Siedowse		if (stat(path, &sb)) {
169134459Siedowse			if (errno != ENOENT ||
170134459Siedowse			    mkdir(path, last ? omode :
171134459Siedowse				  S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
172134459Siedowse				warn("%s", path);
173134459Siedowse				retval = 1;
174134459Siedowse				break;
175134459Siedowse			}
176134459Siedowse		}
177134459Siedowse		else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
178134459Siedowse			if (last)
179134459Siedowse				errno = EEXIST;
180134459Siedowse			else
181134459Siedowse				errno = ENOTDIR;
182134459Siedowse			warn("%s", path);
183134459Siedowse			retval = 1;
184134459Siedowse			break;
185134459Siedowse		}
186134459Siedowse		if (!last)
187134459Siedowse		    *p = '/';
188134459Siedowse	}
189134459Siedowse	if (!first && !last)
190134459Siedowse		(void)umask(oumask);
191134459Siedowse	return (retval);
192134459Siedowse}
193134459Siedowse
194134459Siedowsevoid
195134459Siedowseusage()
196134459Siedowse{
197134459Siedowse	(void)fprintf(stderr, "usage: mkdir [-p] [-m mode] directory ...\n");
198134459Siedowse	exit (1);
199223295Skan}
200134459Siedowse