Home | History | Annotate | Line # | Download | only in mkdir
mkdir.c revision 1.20
      1 /*	$NetBSD: mkdir.c,v 1.20 1998/10/08 02:14:16 wsanchez Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 __COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\n\
     39 	The Regents of the University of California.  All rights reserved.\n");
     40 #endif /* not lint */
     41 
     42 #ifndef lint
     43 #if 0
     44 static char sccsid[] = "@(#)mkdir.c	8.2 (Berkeley) 1/25/94";
     45 #else
     46 __RCSID("$NetBSD: mkdir.c,v 1.20 1998/10/08 02:14:16 wsanchez Exp $");
     47 #endif
     48 #endif /* not lint */
     49 
     50 #include <sys/types.h>
     51 #include <sys/stat.h>
     52 
     53 #include <err.h>
     54 #include <errno.h>
     55 #include <locale.h>
     56 #include <stdio.h>
     57 #include <stdlib.h>
     58 #include <string.h>
     59 #include <unistd.h>
     60 
     61 int	mkpath __P((char *, mode_t, mode_t));
     62 void	usage __P((void));
     63 int	main __P((int, char *[]));
     64 
     65 int
     66 main(argc, argv)
     67 	int argc;
     68 	char *argv[];
     69 {
     70 	int ch, exitval, pflag;
     71 	mode_t *set;
     72 	mode_t mode, dir_mode;
     73 
     74 	(void)setlocale(LC_ALL, "");
     75 
     76 	/*
     77 	 * The default file mode is a=rwx (0777) with selected permissions
     78 	 * removed in accordance with the file mode creation mask.  For
     79 	 * intermediate path name components, the mode is the default modified
     80 	 * by u+wx so that the subdirectories can always be created.
     81 	 */
     82 	mode = 0777 & ~umask(0);
     83 	dir_mode = mode | S_IWUSR | S_IXUSR;
     84 
     85 	pflag = 0;
     86 	while ((ch = getopt(argc, argv, "m:p")) != -1)
     87 		switch(ch) {
     88 		case 'p':
     89 			pflag = 1;
     90 			break;
     91 		case 'm':
     92 			if ((set = setmode(optarg)) == NULL)
     93 				errx(1, "invalid file mode: %s", optarg);
     94 			mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
     95 			break;
     96 		case '?':
     97 		default:
     98 			usage();
     99 		}
    100 	argc -= optind;
    101 	argv += optind;
    102 
    103 	if (*argv == NULL)
    104 		usage();
    105 
    106 	for (exitval = 0; *argv != NULL; ++argv) {
    107 		char *slash;
    108 
    109 		/* Remove trailing slashes, per POSIX. */
    110 		slash = strrchr(*argv, '\0');
    111 		while (--slash > *argv && *slash == '/')
    112 			*slash = '\0';
    113 
    114 		if (pflag) {
    115 			if (mkpath(*argv, mode, dir_mode) < 0)
    116 				exitval = 1;
    117 		} else {
    118 			if (mkdir(*argv, mode) < 0) {
    119 				warn("%s", *argv);
    120 				exitval = 1;
    121 			}
    122                 	/*
    123                          * The mkdir() and umask() calls both honor only the low
    124                 	 * nine bits, so if you try to set a mode including the
    125                     	 * sticky, setuid, setgid bits you lose them. So chmod().
    126                          */
    127                     	if (chmod(*argv, mode) == -1) {
    128 				warn("%s", *argv);
    129 				exitval = 1;
    130                         }
    131 		}
    132 	}
    133 	exit(exitval);
    134 	/* NOTREACHED */
    135 }
    136 
    137 /*
    138  * mkpath -- create directories.
    139  *	path     - path
    140  *	mode     - file mode of terminal directory
    141  *	dir_mode - file mode of intermediate directories
    142  */
    143 int
    144 mkpath(path, mode, dir_mode)
    145 	char *path;
    146 	mode_t mode;
    147 	mode_t dir_mode;
    148 {
    149 	struct stat sb;
    150 	char *slash;
    151 	int done = 0;
    152 
    153 	slash = path;
    154 
    155 	while (!done) {
    156 		slash += strspn(slash, "/");
    157 		slash += strcspn(slash, "/");
    158 
    159 		done = (*slash == '\0');
    160 		*slash = '\0';
    161 
    162 		if (stat(path, &sb)) {
    163 			if (errno != ENOENT
    164 			    || mkdir(path, done ? mode : dir_mode)) {
    165 				warn("%s", path);
    166 				return (-1);
    167 			}
    168                 	/*
    169                          * The mkdir() and umask() calls both honor only the low
    170                 	 * nine bits, so if you try to set a mode including the
    171                     	 * sticky, setuid, setgid bits you lose them. So chmod().
    172                          */
    173                     	if (chmod(path, done ? mode : dir_mode) == -1) {
    174                             	warn("%s", path);
    175                             	return (-1);
    176                         }
    177 		} else if (!S_ISDIR(sb.st_mode)) {
    178 		        warnx("%s: %s", path, strerror(ENOTDIR));
    179 			return (-1);
    180 		}
    181 
    182 		*slash = '/';
    183 	}
    184 
    185 	return (0);
    186 }
    187 
    188 void
    189 usage()
    190 {
    191 
    192 	(void)fprintf(stderr, "usage: mkdir [-p] [-m mode] dirname ...\n");
    193 	exit(1);
    194 	/* NOTREACHED */
    195 }
    196