1 /* mkdir -- make directories
2 Copyright (C) 1990-2022 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 <https://www.gnu.org/licenses/>. */
17 /* David MacKenzie <djm@ai.mit.edu> */
22 #include <sys/types.h>
23 #include <selinux/label.h>
29 #include "modechange.h"
30 #include "prog-fprintf.h"
36 /* The official name of this program (e.g., no 'g' prefix). */
37 #define PROGRAM_NAME "mkdir"
39 #define AUTHORS proper_name ("David MacKenzie")
41 static struct option
const longopts
[] =
43 {GETOPT_SELINUX_CONTEXT_OPTION_DECL
},
44 {"mode", required_argument
, NULL
, 'm'},
45 {"parents", no_argument
, NULL
, 'p'},
46 {"verbose", no_argument
, NULL
, 'v'},
47 {GETOPT_HELP_OPTION_DECL
},
48 {GETOPT_VERSION_OPTION_DECL
},
55 if (status
!= EXIT_SUCCESS
)
59 printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name
);
61 Create the DIRECTORY(ies), if they do not already exist.\n\
64 emit_mandatory_arg_note ();
67 -m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\
68 -p, --parents no error if existing, make parent directories as needed,\n\
69 with their file modes unaffected by any -m option.\n\
70 -v, --verbose print a message for each created directory\n\
73 -Z set SELinux security context of each created directory\n\
74 to the default type\n\
75 --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\
76 or SMACK security context to CTX\n\
78 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
79 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
80 emit_ancillary_info (PROGRAM_NAME
);
85 /* Options passed to subsidiary functions. */
88 /* Function to make an ancestor, or NULL if ancestors should not be
90 int (*make_ancestor_function
) (char const *, char const *, void *);
92 /* Umask value for when making an ancestor. */
93 mode_t umask_ancestor
;
95 /* Umask value for when making the directory itself. */
98 /* Mode for directory itself. */
101 /* File mode bits affected by MODE. */
104 /* Set the SELinux File Context. */
105 struct selabel_handle
*set_security_context
;
107 /* If not null, format to use when reporting newly made directories. */
108 char const *created_directory_format
;
111 /* Report that directory DIR was made, if OPTIONS requests this. */
113 announce_mkdir (char const *dir
, void *options
)
115 struct mkdir_options
const *o
= options
;
116 if (o
->created_directory_format
)
117 prog_fprintf (stdout
, o
->created_directory_format
, quoteaf (dir
));
120 /* Make ancestor directory DIR, whose last component is COMPONENT,
121 with options OPTIONS. Assume the working directory is COMPONENT's
122 parent. Return 0 if successful and the resulting directory is
123 readable, 1 if successful but the resulting directory is not
124 readable, -1 (setting errno) otherwise. */
126 make_ancestor (char const *dir
, char const *component
, void *options
)
128 struct mkdir_options
const *o
= options
;
130 if (o
->set_security_context
131 && defaultcon (o
->set_security_context
, component
, S_IFDIR
) < 0
132 && ! ignorable_ctx_err (errno
))
133 error (0, errno
, _("failed to set default creation context for %s"),
136 if (o
->umask_ancestor
!= o
->umask_self
)
137 umask (o
->umask_ancestor
);
138 int r
= mkdir (component
, S_IRWXUGO
);
139 if (o
->umask_ancestor
!= o
->umask_self
)
141 int mkdir_errno
= errno
;
142 umask (o
->umask_self
);
147 r
= (o
->umask_ancestor
& S_IRUSR
) != 0;
148 announce_mkdir (dir
, options
);
153 /* Process a command-line file name. */
155 process_dir (char *dir
, struct savewd
*wd
, void *options
)
157 struct mkdir_options
const *o
= options
;
159 /* If possible set context before DIR created. */
160 if (o
->set_security_context
)
162 if (! o
->make_ancestor_function
163 && defaultcon (o
->set_security_context
, dir
, S_IFDIR
) < 0
164 && ! ignorable_ctx_err (errno
))
165 error (0, errno
, _("failed to set default creation context for %s"),
169 int ret
= (make_dir_parents (dir
, wd
, o
->make_ancestor_function
, options
,
170 o
->mode
, announce_mkdir
,
171 o
->mode_bits
, (uid_t
) -1, (gid_t
) -1, true)
175 /* FIXME: Due to the current structure of make_dir_parents()
176 we don't have the facility to call defaultcon() before the
177 final component of DIR is created. So for now, create the
178 final component with the context from previous component
179 and here we set the context for the final component. */
180 if (ret
== EXIT_SUCCESS
&& o
->set_security_context
181 && o
->make_ancestor_function
)
183 if (! restorecon (o
->set_security_context
, last_component (dir
), false)
184 && ! ignorable_ctx_err (errno
))
185 error (0, errno
, _("failed to restore context for %s"),
193 main (int argc
, char **argv
)
195 char const *specified_mode
= NULL
;
197 char const *scontext
= NULL
;
198 struct mkdir_options options
;
200 options
.make_ancestor_function
= NULL
;
201 options
.mode
= S_IRWXUGO
;
202 options
.mode_bits
= 0;
203 options
.created_directory_format
= NULL
;
204 options
.set_security_context
= NULL
;
206 initialize_main (&argc
, &argv
);
207 set_program_name (argv
[0]);
208 setlocale (LC_ALL
, "");
209 bindtextdomain (PACKAGE
, LOCALEDIR
);
210 textdomain (PACKAGE
);
212 atexit (close_stdout
);
214 while ((optc
= getopt_long (argc
, argv
, "pm:vZ", longopts
, NULL
)) != -1)
219 options
.make_ancestor_function
= make_ancestor
;
222 specified_mode
= optarg
;
224 case 'v': /* --verbose */
225 options
.created_directory_format
= _("created directory %s");
228 if (is_smack_enabled ())
230 /* We don't yet support -Z to restore context with SMACK. */
233 else if (is_selinux_enabled () > 0)
239 options
.set_security_context
= selabel_open (SELABEL_CTX_FILE
,
241 if (! options
.set_security_context
)
242 error (0, errno
, _("warning: ignoring --context"));
248 _("warning: ignoring --context; "
249 "it requires an SELinux/SMACK-enabled kernel"));
252 case_GETOPT_HELP_CHAR
;
253 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
255 usage (EXIT_FAILURE
);
261 error (0, 0, _("missing operand"));
262 usage (EXIT_FAILURE
);
265 /* FIXME: This assumes mkdir() is done in the same process.
266 If that's not always the case we would need to call this
267 like we do when options.set_security_context. */
271 if (is_smack_enabled ())
272 ret
= smack_set_label_for_self (scontext
);
274 ret
= setfscreatecon (scontext
);
277 die (EXIT_FAILURE
, errno
,
278 _("failed to set default file creation context to %s"),
283 if (options
.make_ancestor_function
|| specified_mode
)
285 mode_t umask_value
= umask (0);
286 options
.umask_ancestor
= umask_value
& ~(S_IWUSR
| S_IXUSR
);
290 struct mode_change
*change
= mode_compile (specified_mode
);
292 die (EXIT_FAILURE
, 0, _("invalid mode %s"),
293 quote (specified_mode
));
294 options
.mode
= mode_adjust (S_IRWXUGO
, true, umask_value
, change
,
296 options
.umask_self
= umask_value
& ~options
.mode
;
301 options
.mode
= S_IRWXUGO
;
302 options
.umask_self
= umask_value
;
305 umask (options
.umask_self
);
308 return savewd_process_files (argc
- optind
, argv
+ optind
,
309 process_dir
, &options
);