xref: /original-bsd/bin/mkdir/mkdir.c (revision f737e041)
1 /*
2  * Copyright (c) 1983, 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1983, 1992, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)mkdir.c	8.2 (Berkeley) 01/25/94";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 
21 #include <err.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 int	build __P((char *));
29 void	usage __P((void));
30 
31 int
32 main(argc, argv)
33 	int argc;
34 	char *argv[];
35 {
36 	int ch, exitval, oct, omode, pflag;
37 	mode_t *set;
38 	char *ep, *mode;
39 
40 	pflag = 0;
41 	mode = NULL;
42 	while ((ch = getopt(argc, argv, "m:p")) != EOF)
43 		switch(ch) {
44 		case 'p':
45 			pflag = 1;
46 			break;
47 		case 'm':
48 			mode = optarg;
49 			break;
50 		case '?':
51 		default:
52 			usage();
53 		}
54 
55 	argc -= optind;
56 	argv += optind;
57 	if (argv[0] == NULL)
58 		usage();
59 
60 	if (mode == NULL) {
61 		omode = S_IRWXU | S_IRWXG | S_IRWXO;
62 		oct = 1;
63 	} else if (*mode >= '0' && *mode <= '7') {
64 		omode = (int)strtol(mode, &ep, 8);
65 		if (omode < 0 || *ep)
66 			errx(1, "invalid file mode: %s", mode);
67 		oct = 1;
68 	} else {
69 		if ((set = setmode(mode)) == NULL)
70 			errx(1, "invalid file mode: %s", mode);
71 		oct = 0;
72 	}
73 
74 	for (exitval = 0; *argv != NULL; ++argv) {
75 		if (pflag && build(*argv)) {
76 			exitval = 1;
77 			continue;
78 		}
79 		if (mkdir(*argv, oct ?
80 		    omode : getmode(set, S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
81 			warn("%s", *argv);
82 			exitval = 1;
83 		}
84 	}
85 	exit(exitval);
86 }
87 
88 int
89 build(path)
90 	char *path;
91 {
92 	struct stat sb;
93 	mode_t numask, oumask;
94 	int first;
95 	char *p;
96 
97 	p = path;
98 	if (p[0] == '/')		/* Skip leading '/'. */
99 		++p;
100 	for (first = 1;; ++p) {
101 		if (p[0] == '\0' || p[0] == '/' && p[1] == '\0')
102 			break;
103 		if (p[0] != '/')
104 			continue;
105 		*p = '\0';
106 		if (first) {
107 			/*
108 			 * POSIX 1003.2:
109 			 * For each dir operand that does not name an existing
110 			 * directory, effects equivalent to those cased by the
111 			 * following command shall occcur:
112 			 *
113 			 * mkdir -p -m $(umask -S),u+wx $(dirname dir) &&
114 			 *    mkdir [-m mode] dir
115 			 *
116 			 * We change the user's umask and then restore it,
117 			 * instead of doing chmod's.
118 			 */
119 			oumask = umask(0);
120 			numask = oumask & ~(S_IWUSR | S_IXUSR);
121 			(void)umask(numask);
122 			first = 0;
123 		}
124 		if (stat(path, &sb)) {
125 			if (errno != ENOENT ||
126 			    mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
127 				warn("%s", path);
128 				return (1);
129 			}
130 		}
131 		*p = '/';
132 	}
133 	if (!first)
134 		(void)umask(oumask);
135 	return (0);
136 }
137 
138 void
139 usage()
140 {
141 	(void)fprintf(stderr, "usage: mkdir [-p] [-m mode] directory ...\n");
142 	exit (1);
143 }
144