mkdir.c revision 41842
143725Syokota/*
243725Syokota * Copyright (c) 1983, 1992, 1993
343725Syokota *	The Regents of the University of California.  All rights reserved.
443725Syokota *
543725Syokota * Redistribution and use in source and binary forms, with or without
643725Syokota * modification, are permitted provided that the following conditions
743725Syokota * are met:
843725Syokota * 1. Redistributions of source code must retain the above copyright
943725Syokota *    notice, this list of conditions and the following disclaimer.
1043725Syokota * 2. Redistributions in binary form must reproduce the above copyright
1143725Syokota *    notice, this list of conditions and the following disclaimer in the
1243725Syokota *    documentation and/or other materials provided with the distribution.
1343725Syokota * 3. All advertising materials mentioning features or use of this software
1443725Syokota *    must display the following acknowledgement:
1543725Syokota *	This product includes software developed by the University of
1643725Syokota *	California, Berkeley and its contributors.
1743725Syokota * 4. Neither the name of the University nor the names of its contributors
1843725Syokota *    may be used to endorse or promote products derived from this software
1943725Syokota *    without specific prior written permission.
2043725Syokota *
2143725Syokota * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2243725Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2343725Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2443725Syokota * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2543725Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2643725Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2750476Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2843725Syokota * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29222793Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3053200Sphantom * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3179538Sru * SUCH DAMAGE.
3243725Syokota */
3343725Syokota
3453200Sphantom#ifndef lint
3543725Syokotastatic char const copyright[] =
3647571Syokota"@(#) Copyright (c) 1983, 1992, 1993\n\
3756188Sasmodai	The Regents of the University of California.  All rights reserved.\n";
3847571Syokota#endif /* not lint */
3984877Syokota
4084877Syokota#ifndef lint
4184877Syokota#if 0
4284877Syokotastatic char sccsid[] = "@(#)mkdir.c	8.2 (Berkeley) 1/25/94";
4384877Syokota#endif
4484877Syokotastatic const char rcsid[] =
4543725Syokota	"$Id: mkdir.c,v 1.15 1998/10/23 06:28:40 msmith Exp $";
4643725Syokota#endif /* not lint */
4743725Syokota
4843725Syokota#include <sys/types.h>
4943725Syokota#include <sys/stat.h>
5043725Syokota
5143725Syokota#include <err.h>
5243725Syokota#include <errno.h>
53158687Sphk#include <stdio.h>
54162404Sru#include <stdlib.h>
5543725Syokota#include <string.h>
5643844Syokota#include <unistd.h>
5743725Syokota
58117011Sruint	build __P((char *, mode_t));
59117011Sruvoid	usage __P((void));
6043725Syokota
6143844Syokotaint
6243844Syokotamain(argc, argv)
6343844Syokota	int argc;
6443844Syokota	char *argv[];
6548634Syokota{
6648634Syokota	int ch, exitval, success, omode, pflag;
6748634Syokota	mode_t *set = (mode_t *)NULL;
6848634Syokota	char *mode;
6948634Syokota
7048634Syokota	omode = pflag = 0;
71175799Strhodes	mode = NULL;
72175799Strhodes	while ((ch = getopt(argc, argv, "m:p")) != -1)
73175799Strhodes		switch(ch) {
74175799Strhodes		case 'p':
75175799Strhodes			pflag = 1;
7648634Syokota			break;
7770466Sru		case 'm':
7849282Smpp			mode = optarg;
7949282Smpp			break;
8049282Smpp		case '?':
81131530Sru		default:
8249282Smpp			usage();
83131530Sru		}
8449282Smpp
85131530Sru	argc -= optind;
8649282Smpp	argv += optind;
87131530Sru	if (argv[0] == NULL)
8849282Smpp		usage();
8949282Smpp
9049282Smpp	if (mode == NULL) {
9149282Smpp		omode = S_IRWXU | S_IRWXG | S_IRWXO;
9249282Smpp	} else {
9349282Smpp		if ((set = setmode(mode)) == NULL)
9449282Smpp			errx(1, "invalid file mode: %s", mode);
9549282Smpp		omode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
9649282Smpp		free(set);
9749282Smpp	}
9849282Smpp
9949282Smpp	for (exitval = 0; *argv != NULL; ++argv) {
10049282Smpp		success = 1;
10149282Smpp		if (pflag) {
10249282Smpp			if (build(*argv, omode))
10379727Sschweikh				success = 0;
10449282Smpp		} else if (mkdir(*argv, omode) < 0) {
10549282Smpp			warn("%s", *argv);
10649282Smpp			success = 0;
10749282Smpp		}
10849282Smpp		if (!success)
10949282Smpp			exitval = 1;
11049282Smpp		/*
11149282Smpp		 * The mkdir() and umask() calls both honor only the low
11249282Smpp		 * nine bits, so if you try to set a mode including the
11349282Smpp		 * sticky, setuid, setgid bits you lose them.  Don't do
11449282Smpp		 * this unless the user has specifically requested a mode,
11549282Smpp		 * as chmod will (obviously) ignore the umask.
11649282Smpp		 */
11749282Smpp		if (success && mode != NULL && chmod(*argv, omode) == -1) {
11849282Smpp			warn("%s", *argv);
11949282Smpp			exitval = 1;
120175799Strhodes		}
121175799Strhodes	}
12249282Smpp	exit(exitval);
12348634Syokota}
12448634Syokota
12548634Syokotaint
12648634Syokotabuild(path, omode)
12743725Syokota	char *path;
12847571Syokota	mode_t omode;
12947571Syokota{
13047571Syokota	struct stat sb;
13147571Syokota	mode_t numask, oumask;
13247571Syokota	int first, last, retval;
13347571Syokota	char *p;
13489610Smpp
13547571Syokota	p = path;
13647571Syokota	oumask = 0;
13747571Syokota	retval = 0;
13868854Sru	if (p[0] == '/')		/* Skip leading '/'. */
13947571Syokota		++p;
14047571Syokota	for (first = 1, last = 0; !last ; ++p) {
14147571Syokota		if (p[0] == '\0')
14247571Syokota			last = 1;
14347571Syokota		else if (p[0] != '/')
14447571Syokota			continue;
14547571Syokota		*p = '\0';
14647571Syokota		if (p[1] == '\0')
14743725Syokota			last = 1;
14843725Syokota		if (first) {
14943725Syokota			/*
15084877Syokota			 * POSIX 1003.2:
15184877Syokota			 * For each dir operand that does not name an existing
15284877Syokota			 * directory, effects equivalent to those cased by the
15384877Syokota			 * following command shall occcur:
15481251Sru			 *
15584877Syokota			 * mkdir -p -m $(umask -S),u+wx $(dirname dir) &&
15643844Syokota			 *    mkdir [-m mode] dir
15743844Syokota			 *
15843725Syokota			 * We change the user's umask and then restore it,
15943725Syokota			 * instead of doing chmod's.
16043725Syokota			 */
16143725Syokota			oumask = umask(0);
16243844Syokota			numask = oumask & ~(S_IWUSR | S_IXUSR);
16343844Syokota			(void)umask(numask);
16443725Syokota			first = 0;
16543725Syokota		}
16643725Syokota		if (last)
16743725Syokota			(void)umask(oumask);
16843844Syokota		if (stat(path, &sb)) {
16943725Syokota			if (errno != ENOENT ||
17043844Syokota			    mkdir(path, last ? omode :
17179727Sschweikh				  S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
17243725Syokota				warn("%s", path);
173138901Sjhb				retval = 1;
174138901Sjhb				break;
175138901Sjhb			}
176138901Sjhb		}
177138901Sjhb		else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
17843725Syokota			if (last)
17943725Syokota				errno = EEXIST;
18068854Sru			else
18179727Sschweikh				errno = ENOTDIR;
18247571Syokota			warn("%s", path);
18347571Syokota			retval = 1;
18447571Syokota			break;
18547571Syokota		}
18647571Syokota		if (!last)
18784877Syokota		    *p = '/';
18884877Syokota	}
18947571Syokota	if (!first && !last)
19047571Syokota		(void)umask(oumask);
19147571Syokota	return (retval);
19247571Syokota}
19347571Syokota
19484877Syokotavoid
19547571Syokotausage()
19656188Sasmodai{
19784877Syokota	(void)fprintf(stderr, "usage: mkdir [-p] [-m mode] directory ...\n");
19847571Syokota	exit (1);
19984877Syokota}
20084877Syokota