date and time created 95/05/04 17:59:12 by christos
[unix-history] / usr / src / bin / mkdir / mkdir.c
index 0ad1511..3fa8689 100644 (file)
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1983, 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1992, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)mkdir.c    5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)mkdir.c    8.2 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int    build __P((char *));
+void   usage __P((void));
 
 
+int
 main(argc, argv)
        int argc;
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
 {
-       int err;
+       int ch, exitval, oct, omode, pflag;
+       mode_t *set;
+       char *ep, *mode;
+
+       pflag = 0;
+       mode = NULL;
+       while ((ch = getopt(argc, argv, "m:p")) != EOF)
+               switch(ch) {
+               case 'p':
+                       pflag = 1;
+                       break;
+               case 'm':
+                       mode = optarg;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+
+       argc -= optind;
+       argv += optind;
+       if (argv[0] == NULL)
+               usage();
 
 
-       if (argc < 2) {
-               fputs("usage: mkdir directory ...\n", stderr);
-               exit(1);
+       if (mode == NULL) {
+               omode = S_IRWXU | S_IRWXG | S_IRWXO;
+               oct = 1;
+       } else if (*mode >= '0' && *mode <= '7') {
+               omode = (int)strtol(mode, &ep, 8);
+               if (omode < 0 || *ep)
+                       errx(1, "invalid file mode: %s", mode);
+               oct = 1;
+       } else {
+               if ((set = setmode(mode)) == NULL)
+                       errx(1, "invalid file mode: %s", mode);
+               oct = 0;
+       }
+
+       for (exitval = 0; *argv != NULL; ++argv) {
+               if (pflag && build(*argv)) {
+                       exitval = 1;
+                       continue;
+               }
+               if (mkdir(*argv, oct ?
+                   omode : getmode(set, S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
+                       warn("%s", *argv);
+                       exitval = 1;
+               }
        }
        }
-       for (err = 0; *++argv;)
-               if (mkdir(*argv, 0777) < 0) {
-                       fputs("mkdir: ", stderr);
-                       perror(*argv);
-                       ++err;
+       exit(exitval);
+}
+
+int
+build(path)
+       char *path;
+{
+       struct stat sb;
+       mode_t numask, oumask;
+       int first;
+       char *p;
+
+       p = path;
+       if (p[0] == '/')                /* Skip leading '/'. */
+               ++p;
+       for (first = 1;; ++p) {
+               if (p[0] == '\0' || p[0] == '/' && p[1] == '\0')
+                       break;
+               if (p[0] != '/')
+                       continue;
+               *p = '\0';
+               if (first) {
+                       /*
+                        * POSIX 1003.2:
+                        * For each dir operand that does not name an existing
+                        * directory, effects equivalent to those cased by the
+                        * following command shall occcur:
+                        *
+                        * mkdir -p -m $(umask -S),u+wx $(dirname dir) &&
+                        *    mkdir [-m mode] dir
+                        *
+                        * We change the user's umask and then restore it,
+                        * instead of doing chmod's.
+                        */
+                       oumask = umask(0);
+                       numask = oumask & ~(S_IWUSR | S_IXUSR);
+                       (void)umask(numask);
+                       first = 0;
+               }
+               if (stat(path, &sb)) {
+                       if (errno != ENOENT ||
+                           mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
+                               warn("%s", path);
+                               return (1);
+                       }
                }
                }
-       exit(err ? 1 : 0);
+               *p = '/';
+       }
+       if (!first)
+               (void)umask(oumask);
+       return (0);
+}
+
+void
+usage()
+{
+       (void)fprintf(stderr, "usage: mkdir [-p] [-m mode] directory ...\n");
+       exit (1);
 }
 }