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> */
22 #include <sys/types.h>
23 #include <selinux/selinux.h>
28 #include "modechange.h"
29 #include "prog-fprintf.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
},
54 if (status
!= EXIT_SUCCESS
)
58 printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name
);
60 Create the DIRECTORY(ies), if they do not already exist.\n\
63 emit_mandatory_arg_note ();
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\
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\
76 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
77 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
78 emit_ancillary_info (PROGRAM_NAME
);
83 /* Options passed to subsidiary functions. */
86 /* Function to make an ancestor, or NULL if ancestors should not be
88 int (*make_ancestor_function
) (char const *, char const *, void *);
90 /* Umask value in effect. */
93 /* Mode for directory itself. */
96 /* File mode bits affected by MODE. */
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. */
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. */
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"),
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
);
143 r
= (o
->umask_value
& S_IRUSR
) != 0;
144 announce_mkdir (dir
, options
);
149 /* Process a command-line file name. */
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;
163 char *pdir
= dir_name (dir
);
165 if (STREQ (pdir
, ".")
166 || (stat (pdir
, &st
) == 0 && S_ISDIR (st
.st_mode
)))
167 set_defaultcon
= true;
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"),
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)
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"),
199 main (int argc
, char **argv
)
201 const char *specified_mode
= NULL
;
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)
225 options
.make_ancestor_function
= make_ancestor
;
228 specified_mode
= optarg
;
230 case 'v': /* --verbose */
231 options
.created_directory_format
= _("created directory %s");
234 if (is_smack_enabled ())
236 /* We don't yet support -Z to restore context with SMACK. */
239 else if (is_selinux_enabled () > 0)
244 options
.set_security_context
= true;
249 _("warning: ignoring --context; "
250 "it requires an SELinux/SMACK-enabled kernel"));
253 case_GETOPT_HELP_CHAR
;
254 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
256 usage (EXIT_FAILURE
);
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. */
272 if (is_smack_enabled ())
273 ret
= smack_set_label_for_self (scontext
);
275 ret
= setfscreatecon (se_const (scontext
));
278 error (EXIT_FAILURE
, errno
,
279 _("failed to set default file creation context to %s"),
284 if (options
.make_ancestor_function
|| specified_mode
)
286 mode_t umask_value
= umask (0);
288 options
.umask_value
= umask_value
;
292 struct mode_change
*change
= mode_compile (specified_mode
);
294 error (EXIT_FAILURE
, 0, _("invalid mode %s"),
295 quote (specified_mode
));
296 options
.mode
= mode_adjust (S_IRWXUGO
, true, umask_value
, change
,
301 options
.mode
= S_IRWXUGO
;
304 return savewd_process_files (argc
- optind
, argv
+ optind
,
305 process_dir
, &options
);