/* mkdir -- make directories This is the mkdir utility
Copyright (C) 1990-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* David MacKenzie <djm@ai.mit.edu> */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <getopt.h> ...!includes auto-comment...
#include <sys/types.h> Provides system data types
#include <selinux/selinux.h> ...!includes auto-comment......!includes auto-comment...
#include "system.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "mkdir-p.h" ...!includes auto-comment...
#include "modechange.h" ...!includes auto-comment...
#include "prog-fprintf.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "savewd.h" ...!includes auto-comment...
#include "selinux.h" ...!includes auto-comment...
#include "smack.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "mkdir" Line 37
#define AUTHORS proper_name ("David MacKenzie") Line 39
static struct option const longopts[] = Line 41
{
{GETOPT_SELINUX_CONTEXT_OPTION_DECL}, Line 43
{"mode", required_argument, NULL, 'm'}, Line 44
{"parents", no_argument, NULL, 'p'}, Line 45
{"verbose", no_argument, NULL, 'v'}, Line 46
{GETOPT_HELP_OPTION_DECL}, Line 47
{GETOPT_VERSION_OPTION_DECL}, Line 48
{NULL, 0, NULL, 0} Line 49
}; Block 1
void Line 52
usage (int status) Line 53
{
if (status != EXIT_SUCCESS) Line 55
emit_try_help (); ...!common auto-comment...
else Line 57
{
printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name); Line 59
fputs (_("\ Line 60
Create the DIRECTORY(ies), if they do not already exist.\n\ Line 61
"), stdout); Line 62
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 66
-m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\ Line 67
-p, --parents no error if existing, make parent directories as needed\n\ Line 68
-v, --verbose print a message for each created directory\n\ Line 69
"), stdout); Line 70
fputs (_("\ Line 71
-Z set SELinux security context of each created directory\n\Line 72
to the default type\n\ Line 73
--context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ Line 74
or SMACK security context to CTX\n\ Line 75
"), stdout); Line 76
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 77
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 78
emit_ancillary_info (PROGRAM_NAME); Line 79
}
exit (status); Line 81
} Block 2
/* Options passed to subsidiary functions. */
struct mkdir_options Line 85
{
/* Function to make an ancestor, or NULL if ancestors should not be
made. */
int (*make_ancestor_function) (char const *, char const *, void *); Line 89
/* Umask value in effect. */
mode_t umask_value; Line 92
/* Mode for directory itself. */
mode_t mode; Line 95
/* File mode bits affected by MODE. */
mode_t mode_bits; Line 98
/* Set the SELinux File Context. */
bool set_security_context; Line 101
/* If not null, format to use when reporting newly made directories. */
char const *created_directory_format; Line 104
};
/* Report that directory DIR was made, if OPTIONS requests this. */
static void Line 108
announce_mkdir (char const *dir, void *options) Line 109...!syscalls auto-comment...
{
struct mkdir_options const *o = options; Line 111
if (o->created_directory_format) Line 112
prog_fprintf (stdout, o->created_directory_format, quoteaf (dir)); Line 113
} Block 4
/* Make ancestor directory DIR, whose last component is COMPONENT,
with options OPTIONS. Assume the working directory is COMPONENT's
parent. Return 0 if successful and the resulting directory is
readable, 1 if successful but the resulting directory is not
readable, -1 (setting errno) otherwise. */
static int Line 121
make_ancestor (char const *dir, char const *component, void *options) Line 122
{
struct mkdir_options const *o = options; Line 124
if (o->set_security_context && defaultcon (component, S_IFDIR) < 0 Line 126
&& ! ignorable_ctx_err (errno)) Line 127
error (0, errno, _("failed to set default creation context for %s"), Line 128
quoteaf (dir)); Line 129
mode_t user_wx = S_IWUSR | S_IXUSR; Line 131
bool self_denying_umask = (o->umask_value & user_wx) != 0; Line 132
if (self_denying_umask) Line 133
umask (o->umask_value & ~user_wx); Line 134
int r = mkdir (component, S_IRWXUGO); Line 135...!syscalls auto-comment...
if (self_denying_umask) Line 136
{
int mkdir_errno = errno; Line 138
umask (o->umask_value); Line 139
errno = mkdir_errno; Line 140
}
if (r == 0) Line 142
{
r = (o->umask_value & S_IRUSR) != 0; Line 144
announce_mkdir (dir, options); Line 145...!syscalls auto-comment...
}
return r; Line 147
} Block 5
/* Process a command-line file name. */
static int Line 151
process_dir (char *dir, struct savewd *wd, void *options) Line 152
{
struct mkdir_options const *o = options; Line 154
/* If possible set context before DIR created. */
if (o->set_security_context) Line 157
{
if (! o->make_ancestor_function && defaultcon (dir, S_IFDIR) < 0 Line 159
&& ! ignorable_ctx_err (errno)) Line 160
error (0, errno, _("failed to set default creation context for %s"), Line 161
quoteaf (dir)); Line 162
}
int ret = (make_dir_parents (dir, wd, o->make_ancestor_function, options, Line 165
o->mode, announce_mkdir, Line 166
o->mode_bits, (uid_t) -1, (gid_t) -1, true) Line 167
? EXIT_SUCCESS Line 168
: EXIT_FAILURE); Line 169
/* FIXME: Due to the current structure of make_dir_parents()
we don't have the facility to call defaultcon() before the
final component of DIR is created. So for now, create the
final component with the context from previous component
and here we set the context for the final component. */
if (ret == EXIT_SUCCESS && o->set_security_context Line 176
&& o->make_ancestor_function) Line 177
{
if (! restorecon (last_component (dir), false, false) Line 179
&& ! ignorable_ctx_err (errno)) Line 180
error (0, errno, _("failed to restore context for %s"), Line 181
quoteaf (dir)); Line 182
}
return ret; Line 185
} Block 6
int
main (int argc, char **argv) Line 189
{
const char *specified_mode = NULL; Line 191
int optc; Line 192
char const *scontext = NULL; Line 193
struct mkdir_options options; Line 194
options.make_ancestor_function = NULL; Line 196
options.mode = S_IRWXUGO; Line 197
options.mode_bits = 0; Line 198
options.created_directory_format = NULL; Line 199
options.set_security_context = false; Line 200
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
while ((optc = getopt_long (argc, argv, "pm:vZ", longopts, NULL)) != -1) Line 210
{
switch (optc) Line 212
{
case 'p': Line 214
options.make_ancestor_function = make_ancestor; Line 215
break; Line 216
case 'm': Line 217
specified_mode = optarg; Line 218
break; Line 219
case 'v': /* --verbose */ Line 220
options.created_directory_format = _("created directory %s"); Line 221
break; Line 222
case 'Z': Line 223
if (is_smack_enabled ()) ...!common auto-comment...
{
/* We don't yet support -Z to restore context with SMACK. */
scontext = optarg; Line 227
}
else if (is_selinux_enabled () > 0) ...!common auto-comment...
{
if (optarg) Line 231
scontext = optarg; Line 232
else Line 233
options.set_security_context = true; Line 234
}
else if (optarg) Line 236
{
error (0, 0, Line 238
_("warning: ignoring --context; " Line 239
"it requires an SELinux/SMACK-enabled kernel")); Line 240
}
break; Line 242
case_GETOPT_HELP_CHAR; Line 243
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 244
default: Line 245
usage (EXIT_FAILURE); Line 246
}
}
if (optind == argc) Line 250
{
error (0, 0, _("missing operand")); Line 252
usage (EXIT_FAILURE); Line 253
}
/* FIXME: This assumes mkdir() is done in the same process.
If that's not always the case we would need to call this
like we do when options.set_security_context == true. */
if (scontext) Line 259
{
int ret = 0; Line 261
if (is_smack_enabled ()) ...!common auto-comment...
ret = smack_set_label_for_self (scontext); Line 263
else Line 264
ret = setfscreatecon (se_const (scontext)); Line 265
if (ret < 0) Line 267
die (EXIT_FAILURE, errno, Line 268
_("failed to set default file creation context to %s"), Line 269
quote (scontext)); Line 270
}
if (options.make_ancestor_function || specified_mode) Line 274
{
mode_t umask_value = umask (0); Line 276
umask (umask_value); Line 277
options.umask_value = umask_value; Line 278
if (specified_mode) Line 280
{
struct mode_change *change = mode_compile (specified_mode); Line 282
if (!change) Line 283
die (EXIT_FAILURE, 0, _("invalid mode %s"), Line 284
quote (specified_mode)); Line 285
options.mode = mode_adjust (S_IRWXUGO, true, umask_value, change, Line 286
&options.mode_bits); Line 287
free (change); Line 288
}
else Line 290
options.mode = S_IRWXUGO; Line 291
}
return savewd_process_files (argc - optind, argv + optind, Line 294
process_dir, &options); Line 295
} Block 7