tests: avoid false df failure with nfs and lofs
[coreutils.git] / src / mkdir.c
blobadc29301904df5ef432710a49b0e9ce9e0d5a585
1 /* mkdir -- make directories
2 Copyright (C) 1990-2013 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 -Z, --context[=CTX] set the SELinux security context of each created\n\
70 directory to default type or to CTX if specified\n\
71 "), stdout);
72 fputs (HELP_OPTION_DESCRIPTION, stdout);
73 fputs (VERSION_OPTION_DESCRIPTION, stdout);
74 emit_ancillary_info ();
76 exit (status);
79 /* Options passed to subsidiary functions. */
80 struct mkdir_options
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 *);
86 /* Umask value in effect. */
87 mode_t umask_value;
89 /* Mode for directory itself. */
90 mode_t mode;
92 /* File mode bits affected by MODE. */
93 mode_t mode_bits;
95 /* Set the SELinux File Context. */
96 bool set_security_context;
98 /* If not null, format to use when reporting newly made directories. */
99 char const *created_directory_format;
102 /* Report that directory DIR was made, if OPTIONS requests this. */
103 static void
104 announce_mkdir (char const *dir, void *options)
106 struct mkdir_options const *o = options;
107 if (o->created_directory_format)
108 prog_fprintf (stdout, o->created_directory_format, quote (dir));
111 /* Make ancestor directory DIR, whose last component is COMPONENT,
112 with options OPTIONS. Assume the working directory is COMPONENT's
113 parent. Return 0 if successful and the resulting directory is
114 readable, 1 if successful but the resulting directory is not
115 readable, -1 (setting errno) otherwise. */
116 static int
117 make_ancestor (char const *dir, char const *component, void *options)
119 struct mkdir_options const *o = options;
121 if (o->set_security_context && defaultcon (dir, S_IFDIR) < 0
122 && ! ignorable_ctx_err (errno))
123 error (0, errno, _("failed to set default creation context for %s"),
124 quote (dir));
126 mode_t user_wx = S_IWUSR | S_IXUSR;
127 bool self_denying_umask = (o->umask_value & user_wx) != 0;
128 if (self_denying_umask)
129 umask (o->umask_value & ~user_wx);
130 int r = mkdir (component, S_IRWXUGO);
131 if (self_denying_umask)
133 int mkdir_errno = errno;
134 umask (o->umask_value);
135 errno = mkdir_errno;
137 if (r == 0)
139 r = (o->umask_value & S_IRUSR) != 0;
140 announce_mkdir (dir, options);
142 return r;
145 /* Process a command-line file name. */
146 static int
147 process_dir (char *dir, struct savewd *wd, void *options)
149 struct mkdir_options const *o = options;
150 bool set_defaultcon = false;
152 /* If possible set context before DIR created. */
153 if (o->set_security_context)
155 if (! o->make_ancestor_function)
156 set_defaultcon = true;
157 else
159 char *pdir = dir_name (dir);
160 struct stat st;
161 if (STREQ (pdir, ".")
162 || (stat (pdir, &st) == 0 && S_ISDIR (st.st_mode)))
163 set_defaultcon = true;
164 free (pdir);
166 if (set_defaultcon && defaultcon (dir, S_IFDIR) < 0
167 && ! ignorable_ctx_err (errno))
168 error (0, errno, _("failed to set default creation context for %s"),
169 quote (dir));
172 int ret = (make_dir_parents (dir, wd, o->make_ancestor_function, options,
173 o->mode, announce_mkdir,
174 o->mode_bits, (uid_t) -1, (gid_t) -1, true)
175 ? EXIT_SUCCESS
176 : EXIT_FAILURE);
178 /* FIXME: Due to the current structure of make_dir_parents()
179 we don't have the facility to call defaultcon() before the
180 final component of DIR is created. So for now, create the
181 final component with the context from previous component
182 and here we set the context for the final component. */
183 if (ret == EXIT_SUCCESS && o->set_security_context && ! set_defaultcon)
185 if (! restorecon (last_component (dir), false, false)
186 && ! ignorable_ctx_err (errno))
187 error (0, errno, _("failed to restore context for %s"),
188 quote (dir));
191 return ret;
195 main (int argc, char **argv)
197 const char *specified_mode = NULL;
198 int optc;
199 security_context_t scontext = NULL;
200 struct mkdir_options options;
202 options.make_ancestor_function = NULL;
203 options.mode = S_IRWXUGO;
204 options.mode_bits = 0;
205 options.created_directory_format = NULL;
206 options.set_security_context = false;
208 initialize_main (&argc, &argv);
209 set_program_name (argv[0]);
210 setlocale (LC_ALL, "");
211 bindtextdomain (PACKAGE, LOCALEDIR);
212 textdomain (PACKAGE);
214 atexit (close_stdout);
216 while ((optc = getopt_long (argc, argv, "pm:vZ", longopts, NULL)) != -1)
218 switch (optc)
220 case 'p':
221 options.make_ancestor_function = make_ancestor;
222 break;
223 case 'm':
224 specified_mode = optarg;
225 break;
226 case 'v': /* --verbose */
227 options.created_directory_format = _("created directory %s");
228 break;
229 case 'Z':
230 if (is_smack_enabled ())
232 /* We don't yet support -Z to restore context with SMACK. */
233 scontext = optarg;
235 else if (is_selinux_enabled () > 0)
237 if (optarg)
238 scontext = optarg;
239 else
240 options.set_security_context = true;
242 else if (optarg)
244 error (0, 0,
245 _("warning: ignoring --context; "
246 "it requires an SELinux/SMACK-enabled kernel"));
248 break;
249 case_GETOPT_HELP_CHAR;
250 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
251 default:
252 usage (EXIT_FAILURE);
256 if (optind == argc)
258 error (0, 0, _("missing operand"));
259 usage (EXIT_FAILURE);
262 /* FIXME: This assumes mkdir() is done in the same process.
263 If that's not always the case we would need to call this
264 like we do when options.set_security_context == true. */
265 if (scontext)
267 int ret = 0;
268 if (is_smack_enabled ())
269 ret = smack_set_label_for_self (scontext);
270 else
271 ret = setfscreatecon (scontext);
273 if (ret < 0)
274 error (EXIT_FAILURE, errno,
275 _("failed to set default file creation context to %s"),
276 quote (scontext));
280 if (options.make_ancestor_function || specified_mode)
282 mode_t umask_value = umask (0);
283 umask (umask_value);
284 options.umask_value = umask_value;
286 if (specified_mode)
288 struct mode_change *change = mode_compile (specified_mode);
289 if (!change)
290 error (EXIT_FAILURE, 0, _("invalid mode %s"),
291 quote (specified_mode));
292 options.mode = mode_adjust (S_IRWXUGO, true, umask_value, change,
293 &options.mode_bits);
294 free (change);
296 else
297 options.mode = S_IRWXUGO;
300 exit (savewd_process_files (argc - optind, argv + optind,
301 process_dir, &options));