break out special local mail processing (e.g., mapping to the
[unix-history] / usr / src / bin / mkdir / mkdir.c
CommitLineData
bcf1365c 1/*
59d11f9a
KB
2 * Copyright (c) 1983, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
0f38f750 4 *
27c71911 5 * %sccs.include.redist.c%
bcf1365c
DF
6 */
7
8#ifndef lint
59d11f9a
KB
9static char copyright[] =
10"@(#) Copyright (c) 1983, 1992, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
0f38f750 12#endif /* not lint */
bcf1365c
DF
13
14#ifndef lint
4af6b121 15static char sccsid[] = "@(#)mkdir.c 8.2 (Berkeley) %G%";
0f38f750 16#endif /* not lint */
bcf1365c 17
937fdd8f
KB
18#include <sys/types.h>
19#include <sys/stat.h>
779eba17 20
2de05b7b 21#include <err.h>
937fdd8f 22#include <errno.h>
a645d56b 23#include <stdio.h>
779eba17 24#include <stdlib.h>
6ebcb998 25#include <string.h>
4af6b121 26#include <unistd.h>
fe19c180 27
2de05b7b
KB
28int build __P((char *));
29void usage __P((void));
ea857b71 30
779eba17 31int
fe19c180 32main(argc, argv)
0f38f750 33 int argc;
779eba17 34 char *argv[];
fe19c180 35{
4af6b121
KB
36 int ch, exitval, oct, omode, pflag;
37 mode_t *set;
38 char *ep, *mode;
fe19c180 39
937fdd8f 40 pflag = 0;
4af6b121
KB
41 mode = NULL;
42 while ((ch = getopt(argc, argv, "m:p")) != EOF)
937fdd8f
KB
43 switch(ch) {
44 case 'p':
45 pflag = 1;
46 break;
4af6b121
KB
47 case 'm':
48 mode = optarg;
49 break;
937fdd8f
KB
50 case '?':
51 default:
52 usage();
53 }
54
4af6b121
KB
55 argc -= optind;
56 argv += optind;
57 if (argv[0] == NULL)
937fdd8f
KB
58 usage();
59
4af6b121
KB
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) {
2de05b7b
KB
81 warn("%s", *argv);
82 exitval = 1;
83 }
4af6b121 84 }
937fdd8f
KB
85 exit(exitval);
86}
87
2de05b7b 88int
937fdd8f
KB
89build(path)
90 char *path;
91{
937fdd8f 92 struct stat sb;
4af6b121
KB
93 mode_t numask, oumask;
94 int first;
95 char *p;
937fdd8f 96
779eba17 97 p = path;
4af6b121 98 if (p[0] == '/') /* Skip leading '/'. */
779eba17 99 ++p;
4af6b121
KB
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);
937fdd8f 129 }
937fdd8f 130 }
4af6b121 131 *p = '/';
2de05b7b 132 }
4af6b121
KB
133 if (!first)
134 (void)umask(oumask);
2de05b7b 135 return (0);
937fdd8f
KB
136}
137
779eba17 138void
937fdd8f
KB
139usage()
140{
4af6b121 141 (void)fprintf(stderr, "usage: mkdir [-p] [-m mode] directory ...\n");
2de05b7b 142 exit (1);
779eba17 143}