1 1.39 kre /* $NetBSD: mkdir.c,v 1.39 2021/09/13 22:46:02 kre Exp $ */ 2 1.11 jtc 3 1.1 cgd /* 4 1.12 cgd * Copyright (c) 1983, 1992, 1993 5 1.12 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.31 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.17 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.37 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\ 35 1.37 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.11 jtc #if 0 40 1.12 cgd static char sccsid[] = "@(#)mkdir.c 8.2 (Berkeley) 1/25/94"; 41 1.12 cgd #else 42 1.39 kre __RCSID("$NetBSD: mkdir.c,v 1.39 2021/09/13 22:46:02 kre Exp $"); 43 1.11 jtc #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.30 jschauma #include <sys/param.h> 47 1.30 jschauma #include <sys/stat.h> 48 1.12 cgd #include <sys/types.h> 49 1.12 cgd 50 1.12 cgd #include <err.h> 51 1.12 cgd #include <errno.h> 52 1.12 cgd #include <locale.h> 53 1.1 cgd #include <stdio.h> 54 1.7 jtc #include <stdlib.h> 55 1.1 cgd #include <string.h> 56 1.6 jtc #include <unistd.h> 57 1.1 cgd 58 1.38 joerg static int mkpath(char *, mode_t, mode_t); 59 1.38 joerg __dead static void usage(void); 60 1.12 cgd 61 1.12 cgd int 62 1.25 wiz main(int argc, char *argv[]) 63 1.1 cgd { 64 1.11 jtc int ch, exitval, pflag; 65 1.24 enami void *set; 66 1.11 jtc mode_t mode, dir_mode; 67 1.1 cgd 68 1.25 wiz setprogname(argv[0]); 69 1.18 cgd (void)setlocale(LC_ALL, ""); 70 1.7 jtc 71 1.14 mycroft /* 72 1.14 mycroft * The default file mode is a=rwx (0777) with selected permissions 73 1.14 mycroft * removed in accordance with the file mode creation mask. For 74 1.14 mycroft * intermediate path name components, the mode is the default modified 75 1.14 mycroft * by u+wx so that the subdirectories can always be created. 76 1.14 mycroft */ 77 1.23 kleink mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~umask(0); 78 1.11 jtc dir_mode = mode | S_IWUSR | S_IXUSR; 79 1.11 jtc 80 1.1 cgd pflag = 0; 81 1.14 mycroft while ((ch = getopt(argc, argv, "m:p")) != -1) 82 1.26 enami switch (ch) { 83 1.1 cgd case 'p': 84 1.1 cgd pflag = 1; 85 1.1 cgd break; 86 1.4 jtc case 'm': 87 1.30 jschauma if ((set = setmode(optarg)) == NULL) { 88 1.36 christos err(EXIT_FAILURE, "Cannot set file mode `%s'", 89 1.36 christos optarg); 90 1.30 jschauma /* NOTREACHED */ 91 1.30 jschauma } 92 1.14 mycroft mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); 93 1.24 enami free(set); 94 1.4 jtc break; 95 1.1 cgd case '?': 96 1.1 cgd default: 97 1.1 cgd usage(); 98 1.30 jschauma /* NOTREACHED */ 99 1.1 cgd } 100 1.14 mycroft argc -= optind; 101 1.14 mycroft argv += optind; 102 1.1 cgd 103 1.30 jschauma if (*argv == NULL) { 104 1.1 cgd usage(); 105 1.30 jschauma /* NOTREACHED */ 106 1.30 jschauma } 107 1.30 jschauma 108 1.23 kleink for (exitval = EXIT_SUCCESS; *argv != NULL; ++argv) { 109 1.33 christos #ifdef notdef 110 1.16 tls char *slash; 111 1.11 jtc 112 1.33 christos /* Kernel takes care of this */ 113 1.14 mycroft /* Remove trailing slashes, per POSIX. */ 114 1.11 jtc slash = strrchr(*argv, '\0'); 115 1.11 jtc while (--slash > *argv && *slash == '/') 116 1.11 jtc *slash = '\0'; 117 1.33 christos #endif 118 1.11 jtc 119 1.11 jtc if (pflag) { 120 1.14 mycroft if (mkpath(*argv, mode, dir_mode) < 0) 121 1.23 kleink exitval = EXIT_FAILURE; 122 1.14 mycroft } else { 123 1.14 mycroft if (mkdir(*argv, mode) < 0) { 124 1.14 mycroft warn("%s", *argv); 125 1.23 kleink exitval = EXIT_FAILURE; 126 1.21 scw } else { 127 1.21 scw /* 128 1.21 scw * The mkdir() and umask() calls both honor 129 1.23 kleink * only the file permission bits, so if you try 130 1.23 kleink * to set a mode including the sticky, setuid, 131 1.21 scw * setgid bits you lose them. So chmod(). 132 1.21 scw */ 133 1.23 kleink if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) != 0 && 134 1.23 kleink chmod(*argv, mode) == -1) { 135 1.34 jschauma warn("%s", *argv); 136 1.23 kleink exitval = EXIT_FAILURE; 137 1.21 scw } 138 1.14 mycroft } 139 1.1 cgd } 140 1.4 jtc } 141 1.1 cgd exit(exitval); 142 1.18 cgd /* NOTREACHED */ 143 1.1 cgd } 144 1.1 cgd 145 1.11 jtc /* 146 1.26 enami * mkpath -- create directories. 147 1.11 jtc * path - path 148 1.11 jtc * mode - file mode of terminal directory 149 1.11 jtc * dir_mode - file mode of intermediate directories 150 1.11 jtc */ 151 1.38 joerg static int 152 1.25 wiz mkpath(char *path, mode_t mode, mode_t dir_mode) 153 1.1 cgd { 154 1.1 cgd struct stat sb; 155 1.34 jschauma char *slash; 156 1.27 chs int done, rv; 157 1.11 jtc 158 1.25 wiz done = 0; 159 1.11 jtc slash = path; 160 1.11 jtc 161 1.27 chs for (;;) { 162 1.13 mycroft slash += strspn(slash, "/"); 163 1.13 mycroft slash += strcspn(slash, "/"); 164 1.13 mycroft 165 1.39 kre done = (*(slash + strspn(slash, "/")) == '\0'); 166 1.11 jtc *slash = '\0'; 167 1.11 jtc 168 1.27 chs rv = mkdir(path, done ? mode : dir_mode); 169 1.28 lukem if (rv < 0) { 170 1.28 lukem /* 171 1.28 lukem * Can't create; path exists or no perms. 172 1.28 lukem * stat() path to determine what's there now. 173 1.28 lukem */ 174 1.28 lukem int sverrno; 175 1.28 lukem 176 1.28 lukem sverrno = errno; 177 1.28 lukem if (stat(path, &sb) < 0) { 178 1.28 lukem /* Not there; use mkdir()s error */ 179 1.28 lukem errno = sverrno; 180 1.34 jschauma warn("%s", path); 181 1.28 lukem return -1; 182 1.28 lukem } 183 1.28 lukem if (!S_ISDIR(sb.st_mode)) { 184 1.28 lukem /* Is there, but isn't a directory */ 185 1.28 lukem errno = ENOTDIR; 186 1.34 jschauma warn("%s", path); 187 1.28 lukem return -1; 188 1.28 lukem } 189 1.28 lukem } else if (done) { 190 1.28 lukem /* 191 1.28 lukem * Created ok, and this is the last element 192 1.28 lukem */ 193 1.28 lukem /* 194 1.28 lukem * The mkdir() and umask() calls both honor only the 195 1.28 lukem * file permission bits, so if you try to set a mode 196 1.28 lukem * including the sticky, setuid, setgid bits you lose 197 1.28 lukem * them. So chmod(). 198 1.28 lukem */ 199 1.29 lukem if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) != 0 && 200 1.28 lukem chmod(path, mode) == -1) { 201 1.34 jschauma warn("%s", path); 202 1.28 lukem return -1; 203 1.28 lukem } 204 1.1 cgd } 205 1.28 lukem 206 1.27 chs if (done) { 207 1.27 chs break; 208 1.27 chs } 209 1.27 chs *slash = '/'; 210 1.27 chs } 211 1.30 jschauma 212 1.28 lukem return 0; 213 1.1 cgd } 214 1.1 cgd 215 1.38 joerg static void 216 1.25 wiz usage(void) 217 1.1 cgd { 218 1.26 enami 219 1.26 enami (void)fprintf(stderr, "usage: %s [-p] [-m mode] dirname ...\n", 220 1.26 enami getprogname()); 221 1.23 kleink exit(EXIT_FAILURE); 222 1.19 mycroft /* NOTREACHED */ 223 1.1 cgd } 224