/* 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