1/* mkdir -- make directories 2 Copyright (C) 1990, 1995-2002, 2004-2010 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17/* David MacKenzie <djm@ai.mit.edu> */ 18 19#include <config.h> 20#include <stdio.h> 21#include <getopt.h> 22#include <sys/types.h> 23#include <selinux/selinux.h> 24 25#include "system.h" 26#include "error.h" 27#include "mkdir-p.h" 28#include "modechange.h" 29#include "prog-fprintf.h" 30#include "quote.h" 31#include "savewd.h" 32 33/* The official name of this program (e.g., no `g' prefix). */ 34#define PROGRAM_NAME "mkdir" 35 36#define AUTHORS proper_name ("David MacKenzie") 37 38static struct option const longopts[] = 39{ 40 {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, 41 {"mode", required_argument, NULL, 'm'}, 42 {"parents", no_argument, NULL, 'p'}, 43 {"verbose", no_argument, NULL, 'v'}, 44 {GETOPT_HELP_OPTION_DECL}, 45 {GETOPT_VERSION_OPTION_DECL}, 46 {NULL, 0, NULL, 0} 47}; 48 49void 50usage (int status) 51{ 52 if (status != EXIT_SUCCESS) 53 fprintf (stderr, _("Try `%s --help' for more information.\n"), 54 program_name); 55 else 56 { 57 printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name); 58 fputs (_("\ 59Create the DIRECTORY(ies), if they do not already exist.\n\ 60\n\ 61"), stdout); 62 fputs (_("\ 63Mandatory arguments to long options are mandatory for short options too.\n\ 64"), stdout); 65 fputs (_("\ 66 -m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\ 67 -p, --parents no error if existing, make parent directories as needed\n\ 68 -v, --verbose print a message for each created directory\n\ 69 -Z, --context=CTX set the SELinux security context of each created\n\ 70 directory to CTX\n\ 71"), stdout); 72 fputs (HELP_OPTION_DESCRIPTION, stdout); 73 fputs (VERSION_OPTION_DESCRIPTION, stdout); 74 emit_ancillary_info (); 75 } 76 exit (status); 77} 78 79/* Options passed to subsidiary functions. */ 80struct mkdir_options 81{ 82 /* Function to make an ancestor, or NULL if ancestors should not be 83 made. */ 84 int (*make_ancestor_function) (char const *, char const *, void *); 85 86 /* Mode for ancestor directory. */ 87 mode_t ancestor_mode; 88 89 /* Mode for directory itself. */ 90 mode_t mode; 91 92 /* File mode bits affected by MODE. */ 93 mode_t mode_bits; 94 95 /* If not null, format to use when reporting newly made directories. */ 96 char const *created_directory_format; 97}; 98 99/* Report that directory DIR was made, if OPTIONS requests this. */ 100static void 101announce_mkdir (char const *dir, void *options) 102{ 103 struct mkdir_options const *o = options; 104 if (o->created_directory_format) 105 prog_fprintf (stdout, o->created_directory_format, quote (dir)); 106} 107 108/* Make ancestor directory DIR, whose last component is COMPONENT, 109 with options OPTIONS. Assume the working directory is COMPONENT's 110 parent. Return 0 if successful and the resulting directory is 111 readable, 1 if successful but the resulting directory is not 112 readable, -1 (setting errno) otherwise. */ 113static int 114make_ancestor (char const *dir, char const *component, void *options) 115{ 116 struct mkdir_options const *o = options; 117 int r = mkdir (component, o->ancestor_mode); 118 if (r == 0) 119 { 120 r = ! (o->ancestor_mode & S_IRUSR); 121 announce_mkdir (dir, options); 122 } 123 return r; 124} 125 126/* Process a command-line file name. */ 127static int 128process_dir (char *dir, struct savewd *wd, void *options) 129{ 130 struct mkdir_options const *o = options; 131 return (make_dir_parents (dir, wd, o->make_ancestor_function, options, 132 o->mode, announce_mkdir, 133 o->mode_bits, (uid_t) -1, (gid_t) -1, true) 134 ? EXIT_SUCCESS 135 : EXIT_FAILURE); 136} 137 138int 139main (int argc, char **argv) 140{ 141 const char *specified_mode = NULL; 142 int optc; 143 security_context_t scontext = NULL; 144 struct mkdir_options options; 145 146 options.make_ancestor_function = NULL; 147 options.mode = S_IRWXUGO; 148 options.mode_bits = 0; 149 options.created_directory_format = NULL; 150 151 initialize_main (&argc, &argv); 152 set_program_name (argv[0]); 153 setlocale (LC_ALL, ""); 154 bindtextdomain (PACKAGE, LOCALEDIR); 155 textdomain (PACKAGE); 156 157 atexit (close_stdout); 158 159 while ((optc = getopt_long (argc, argv, "pm:vZ:", longopts, NULL)) != -1) 160 { 161 switch (optc) 162 { 163 case 'p': 164 options.make_ancestor_function = make_ancestor; 165 break; 166 case 'm': 167 specified_mode = optarg; 168 break; 169 case 'v': /* --verbose */ 170 options.created_directory_format = _("created directory %s"); 171 break; 172 case 'Z': 173 scontext = optarg; 174 break; 175 case_GETOPT_HELP_CHAR; 176 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); 177 default: 178 usage (EXIT_FAILURE); 179 } 180 } 181 182 if (optind == argc) 183 { 184 error (0, 0, _("missing operand")); 185 usage (EXIT_FAILURE); 186 } 187 188 if (scontext && setfscreatecon (scontext) < 0) 189 error (EXIT_FAILURE, errno, 190 _("failed to set default file creation context to %s"), 191 quote (scontext)); 192 193 if (options.make_ancestor_function || specified_mode) 194 { 195 mode_t umask_value = umask (0); 196 197 options.ancestor_mode = (S_IRWXUGO & ~umask_value) | (S_IWUSR | S_IXUSR); 198 199 if (specified_mode) 200 { 201 struct mode_change *change = mode_compile (specified_mode); 202 if (!change) 203 error (EXIT_FAILURE, 0, _("invalid mode %s"), 204 quote (specified_mode)); 205 options.mode = mode_adjust (S_IRWXUGO, true, umask_value, change, 206 &options.mode_bits); 207 free (change); 208 } 209 else 210 options.mode = S_IRWXUGO & ~umask_value; 211 } 212 213 exit (savewd_process_files (argc - optind, argv + optind, 214 process_dir, &options)); 215} 216