stty: fix sane setting of susp to ^z on Solaris
[coreutils.git] / src / mkdir.c
blob60fc08a8f005fbb460c07ebf42318d94c186bc41
1 /* mkdir -- make directories
2 Copyright (C) 1990-2016 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, quoteaf (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 quoteaf (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;
155 /* If possible set context before DIR created. */
156 if (o->set_security_context)
158 if (! o->make_ancestor_function && defaultcon (dir, S_IFDIR) < 0
159 && ! ignorable_ctx_err (errno))
160 error (0, errno, _("failed to set default creation context for %s"),
161 quoteaf (dir));
164 int ret = (make_dir_parents (dir, wd, o->make_ancestor_function, options,
165 o->mode, announce_mkdir,
166 o->mode_bits, (uid_t) -1, (gid_t) -1, true)
167 ? EXIT_SUCCESS
168 : EXIT_FAILURE);
170 /* FIXME: Due to the current structure of make_dir_parents()
171 we don't have the facility to call defaultcon() before the
172 final component of DIR is created. So for now, create the
173 final component with the context from previous component
174 and here we set the context for the final component. */
175 if (ret == EXIT_SUCCESS && o->set_security_context
176 && o->make_ancestor_function)
178 if (! restorecon (last_component (dir), false, false)
179 && ! ignorable_ctx_err (errno))
180 error (0, errno, _("failed to restore context for %s"),
181 quoteaf (dir));
184 return ret;
188 main (int argc, char **argv)
190 const char *specified_mode = NULL;
191 int optc;
192 char const *scontext = NULL;
193 struct mkdir_options options;
195 options.make_ancestor_function = NULL;
196 options.mode = S_IRWXUGO;
197 options.mode_bits = 0;
198 options.created_directory_format = NULL;
199 options.set_security_context = false;
201 initialize_main (&argc, &argv);
202 set_program_name (argv[0]);
203 setlocale (LC_ALL, "");
204 bindtextdomain (PACKAGE, LOCALEDIR);
205 textdomain (PACKAGE);
207 atexit (close_stdout);
209 while ((optc = getopt_long (argc, argv, "pm:vZ", longopts, NULL)) != -1)
211 switch (optc)
213 case 'p':
214 options.make_ancestor_function = make_ancestor;
215 break;
216 case 'm':
217 specified_mode = optarg;
218 break;
219 case 'v': /* --verbose */
220 options.created_directory_format = _("created directory %s");
221 break;
222 case 'Z':
223 if (is_smack_enabled ())
225 /* We don't yet support -Z to restore context with SMACK. */
226 scontext = optarg;
228 else if (is_selinux_enabled () > 0)
230 if (optarg)
231 scontext = optarg;
232 else
233 options.set_security_context = true;
235 else if (optarg)
237 error (0, 0,
238 _("warning: ignoring --context; "
239 "it requires an SELinux/SMACK-enabled kernel"));
241 break;
242 case_GETOPT_HELP_CHAR;
243 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
244 default:
245 usage (EXIT_FAILURE);
249 if (optind == argc)
251 error (0, 0, _("missing operand"));
252 usage (EXIT_FAILURE);
255 /* FIXME: This assumes mkdir() is done in the same process.
256 If that's not always the case we would need to call this
257 like we do when options.set_security_context == true. */
258 if (scontext)
260 int ret = 0;
261 if (is_smack_enabled ())
262 ret = smack_set_label_for_self (scontext);
263 else
264 ret = setfscreatecon (se_const (scontext));
266 if (ret < 0)
267 error (EXIT_FAILURE, errno,
268 _("failed to set default file creation context to %s"),
269 quote (scontext));
273 if (options.make_ancestor_function || specified_mode)
275 mode_t umask_value = umask (0);
276 umask (umask_value);
277 options.umask_value = umask_value;
279 if (specified_mode)
281 struct mode_change *change = mode_compile (specified_mode);
282 if (!change)
283 error (EXIT_FAILURE, 0, _("invalid mode %s"),
284 quote (specified_mode));
285 options.mode = mode_adjust (S_IRWXUGO, true, umask_value, change,
286 &options.mode_bits);
287 free (change);
289 else
290 options.mode = S_IRWXUGO;
293 return savewd_process_files (argc - optind, argv + optind,
294 process_dir, &options);