1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "file_mode.h"
static mode_t leaf_mode, subdir_mode;
static int p_flag;
char *progname;
static __noreturn usage(void)
{
fprintf(stderr, "Usage: %s [-p] [-m mode] dir...\n", progname);
exit(1);
}
static int make_one_dir(char *dir, mode_t mode)
{
struct stat stbuf;
if (mkdir(dir, mode) == -1) {
int err = errno;
/*
* Ignore the error if it all of the following
* are satisfied:
* - error was EEXIST
* - -p was specified
* - stat indicates that its a directory
*/
if (p_flag && errno == EEXIST &&
stat(dir, &stbuf) == 0 && S_ISDIR(stbuf.st_mode))
return 1;
errno = err;
fprintf(stderr, "%s: ", progname);
perror(dir);
return -1;
}
return 0;
}
static int make_dir(char *dir)
{
int ret;
if (p_flag) {
char *s, *p;
/*
* Recurse each directory, trying to make it
* as we go. Should we check to see if it
* exists, and if so if it's a directory
* before calling mkdir?
*/
s = dir;
while ((p = strchr(s, '/')) != NULL) {
/*
* Ignore the leading /
*/
if (p != dir) {
*p = '\0';
/*
* Make the intermediary directory. POSIX
* says that these directories are created
* with umask,u+wx
*/
if (make_one_dir(dir, subdir_mode) == -1)
return -1;
*p = '/';
}
s = p + 1;
}
}
/*
* Make the final target. Only complain if the
* target already exists if -p was not specified.
* This is created with the asked for mode & ~umask
*/
ret = make_one_dir(dir, leaf_mode);
if (ret == -1)
return -1;
/*
* We might not set all the permission bits. Do that
* here (but only if we did create it.)
*/
if (ret == 0 && chmod(dir, leaf_mode) == -1) {
int err_save = errno;
/*
* We failed, remove the directory we created
*/
rmdir(dir);
errno = err_save;
fprintf(stderr, "%s: ", progname);
perror(dir);
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int c, ret = 0;
mode_t saved_umask;
progname = argv[0];
saved_umask = umask(0);
leaf_mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~saved_umask;
subdir_mode = (saved_umask ^ (S_IRWXU | S_IRWXG | S_IRWXO))
| S_IWUSR | S_IXUSR;
do {
c = getopt(argc, argv, "pm:");
if (c == EOF)
break;
switch (c) {
case 'm':
leaf_mode =
parse_file_mode(optarg, leaf_mode, saved_umask);
break;
case 'p':
p_flag = 1;
break;
case '?':
fprintf(stderr, "%s: invalid option -%c\n",
progname, optopt);
usage();
}
} while (1);
if (optind == argc)
usage();
while (optind < argc) {
if (make_dir(argv[optind]))
ret = 255; /* seems to be what gnu mkdir does */
optind++;
}
return ret;
}
|