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