doc: clarify the operation of wc -L
[coreutils.git] / src / mkdir.c
blob404a04a71e2cb2c82177cdb07da8bb8afc8c947d
1 /* mkdir -- make directories
2 Copyright (C) 1990-2015 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* David MacKenzie <djm@ai.mit.edu> */
19 #include <config.h>
20 #include <stdio.h>
21 #include <getopt.h>
22 #include <sys/types.h>
23 #include <selinux/selinux.h>
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 #include "selinux.h"
33 #include "smack.h"
35 /* The official name of this program (e.g., no 'g' prefix). */
36 #define PROGRAM_NAME "mkdir"
38 #define AUTHORS proper_name ("David MacKenzie")
40 static struct option const longopts[] =
42 {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
43 {"mode", required_argument, NULL, 'm'},
44 {"parents", no_argument, NULL, 'p'},
45 {"verbose", no_argument, NULL, 'v'},
46 {GETOPT_HELP_OPTION_DECL},
47 {GETOPT_VERSION_OPTION_DECL},
48 {NULL, 0, NULL, 0}
51 void
52 usage (int status)
54 if (status != EXIT_SUCCESS)
55 emit_try_help ();
56 else
58 printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name);
59 fputs (_("\
60 Create the DIRECTORY(ies), if they do not already exist.\n\
61 "), stdout);
63 emit_mandatory_arg_note ();
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 "), stdout);
70 fputs (_("\
71 -Z set SELinux security context of each created directory\n\
72 to the default type\n\
73 --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\
74 or SMACK security context to CTX\n\
75 "), stdout);
76 fputs (HELP_OPTION_DESCRIPTION, stdout);
77 fputs (VERSION_OPTION_DESCRIPTION, stdout);
78 emit_ancillary_info (PROGRAM_NAME);
80 exit (status);
83 /* Options passed to subsidiary functions. */
84 struct mkdir_options
86 /* Function to make an ancestor, or NULL if ancestors should not be
87 made. */
88 int (*make_ancestor_function) (char const *, char const *, void *);
90 /* Umask value in effect. */
91 mode_t umask_value;
93 /* Mode for directory itself. */
94 mode_t mode;
96 /* File mode bits affected by MODE. */
97 mode_t mode_bits;
99 /* Set the SELinux File Context. */
100 bool set_security_context;
102 /* If not null, format to use when reporting newly made directories. */
103 char const *created_directory_format;
106 /* Report that directory DIR was made, if OPTIONS requests this. */
107 static void
108 announce_mkdir (char const *dir, void *options)
110 struct mkdir_options const *o = options;
111 if (o->created_directory_format)
112 prog_fprintf (stdout, o->created_directory_format, quote (dir));
115 /* Make ancestor directory DIR, whose last component is COMPONENT,
116 with options OPTIONS. Assume the working directory is COMPONENT's
117 parent. Return 0 if successful and the resulting directory is
118 readable, 1 if successful but the resulting directory is not
119 readable, -1 (setting errno) otherwise. */
120 static int
121 make_ancestor (char const *dir, char const *component, void *options)
123 struct mkdir_options const *o = options;
125 if (o->set_security_context && defaultcon (dir, S_IFDIR) < 0
126 && ! ignorable_ctx_err (errno))
127 error (0, errno, _("failed to set default creation context for %s"),
128 quote (dir));
130 mode_t user_wx = S_IWUSR | S_IXUSR;
131 bool self_denying_umask = (o->umask_value & user_wx) != 0;
132 if (self_denying_umask)
133 umask (o->umask_value & ~user_wx);
134 int r = mkdir (component, S_IRWXUGO);
135 if (self_denying_umask)
137 int mkdir_errno = errno;
138 umask (o->umask_value);
139 errno = mkdir_errno;
141 if (r == 0)
143 r = (o->umask_value & S_IRUSR) != 0;
144 announce_mkdir (dir, options);
146 return r;
149 /* Process a command-line file name. */
150 static int
151 process_dir (char *dir, struct savewd *wd, void *options)
153 struct mkdir_options const *o = options;
154 bool set_defaultcon = false;
156 /* If possible set context before DIR created. */
157 if (o->set_security_context)
159 if (! o->make_ancestor_function)
160 set_defaultcon = true;
161 else
163 char *pdir = dir_name (dir);
164 struct stat st;
165 if (STREQ (pdir, ".")
166 || (stat (pdir, &st) == 0 && S_ISDIR (st.st_mode)))
167 set_defaultcon = true;
168 free (pdir);
170 if (set_defaultcon && defaultcon (dir, S_IFDIR) < 0
171 && ! ignorable_ctx_err (errno))
172 error (0, errno, _("failed to set default creation context for %s"),
173 quote (dir));
176 int ret = (make_dir_parents (dir, wd, o->make_ancestor_function, options,
177 o->mode, announce_mkdir,
178 o->mode_bits, (uid_t) -1, (gid_t) -1, true)
179 ? EXIT_SUCCESS
180 : EXIT_FAILURE);
182 /* FIXME: Due to the current structure of make_dir_parents()
183 we don't have the facility to call defaultcon() before the
184 final component of DIR is created. So for now, create the
185 final component with the context from previous component
186 and here we set the context for the final component. */
187 if (ret == EXIT_SUCCESS && o->set_security_context && ! set_defaultcon)
189 if (! restorecon (last_component (dir), false, false)
190 && ! ignorable_ctx_err (errno))
191 error (0, errno, _("failed to restore context for %s"),
192 quote (dir));
195 return ret;
199 main (int argc, char **argv)
201 const char *specified_mode = NULL;
202 int optc;
203 char const *scontext = NULL;
204 struct mkdir_options options;
206 options.make_ancestor_function = NULL;
207 options.mode = S_IRWXUGO;
208 options.mode_bits = 0;
209 options.created_directory_format = NULL;
210 options.set_security_context = false;
212 initialize_main (&argc, &argv);
213 set_program_name (argv[0]);
214 setlocale (LC_ALL, "");
215 bindtextdomain (PACKAGE, LOCALEDIR);
216 textdomain (PACKAGE);
218 atexit (close_stdout);
220 while ((optc = getopt_long (argc, argv, "pm:vZ", longopts, NULL)) != -1)
222 switch (optc)
224 case 'p':
225 options.make_ancestor_function = make_ancestor;
226 break;
227 case 'm':
228 specified_mode = optarg;
229 break;
230 case 'v': /* --verbose */
231 options.created_directory_format = _("created directory %s");
232 break;
233 case 'Z':
234 if (is_smack_enabled ())
236 /* We don't yet support -Z to restore context with SMACK. */
237 scontext = optarg;
239 else if (is_selinux_enabled () > 0)
241 if (optarg)
242 scontext = optarg;
243 else
244 options.set_security_context = true;
246 else if (optarg)
248 error (0, 0,
249 _("warning: ignoring --context; "
250 "it requires an SELinux/SMACK-enabled kernel"));
252 break;
253 case_GETOPT_HELP_CHAR;
254 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
255 default:
256 usage (EXIT_FAILURE);
260 if (optind == argc)
262 error (0, 0, _("missing operand"));
263 usage (EXIT_FAILURE);
266 /* FIXME: This assumes mkdir() is done in the same process.
267 If that's not always the case we would need to call this
268 like we do when options.set_security_context == true. */
269 if (scontext)
271 int ret = 0;
272 if (is_smack_enabled ())
273 ret = smack_set_label_for_self (scontext);
274 else
275 ret = setfscreatecon (se_const (scontext));
277 if (ret < 0)
278 error (EXIT_FAILURE, errno,
279 _("failed to set default file creation context to %s"),
280 quote (scontext));
284 if (options.make_ancestor_function || specified_mode)
286 mode_t umask_value = umask (0);
287 umask (umask_value);
288 options.umask_value = umask_value;
290 if (specified_mode)
292 struct mode_change *change = mode_compile (specified_mode);
293 if (!change)
294 error (EXIT_FAILURE, 0, _("invalid mode %s"),
295 quote (specified_mode));
296 options.mode = mode_adjust (S_IRWXUGO, true, umask_value, change,
297 &options.mode_bits);
298 free (change);
300 else
301 options.mode = S_IRWXUGO;
304 return savewd_process_files (argc - optind, argv + optind,
305 process_dir, &options);