/* mknod -- make special files                                                  This is the mknod 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
                                                                                
/* Written by 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 "modechange.h"                                                         ...!includes auto-comment...
#include "quote.h"                                                              ...!includes auto-comment...
#include "selinux.h"                                                            ...!includes auto-comment...
#include "smack.h"                                                              ...!includes auto-comment...
#include "xstrtol.h"                                                            ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "mknod"                                                    Line 35
                                                                                
#define AUTHORS proper_name ("David MacKenzie")                                 Line 37
                                                                                
static struct option const longopts[] =                                         Line 39
{                                                                               
  {GETOPT_SELINUX_CONTEXT_OPTION_DECL},                                         Line 41
  {"mode", required_argument, NULL, 'm'},                                       Line 42
  {GETOPT_HELP_OPTION_DECL},                                                    Line 43
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 44
  {NULL, 0, NULL, 0}                                                            Line 45
};                                                                              Block 1
                                                                                
void                                                                            Line 48
usage (int status)                                                              Line 49
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 51
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 53
    {                                                                           
      printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"),             Line 55
              program_name);                                                    Line 56
      fputs (_("\                                                               Line 57
Create the special file NAME of the given TYPE.\n\                              Line 58
"), stdout);                                                                    Line 59
                                                                                
      emit_mandatory_arg_note ();                                               ...!common auto-comment...
                                                                                
      fputs (_("\                                                               Line 63
  -m, --mode=MODE    set file permission bits to MODE, not a=rw - umask\n\      Line 64
"), stdout);                                                                    Line 65
      fputs (_("\                                                               Line 66
  -Z                   set the SELinux security context to default type\n\      Line 67
      --context[=CTX]  like -Z, or if CTX is specified then set the SELinux\n\  Line 68
                         or SMACK security context to CTX\n\                    Line 69
"), stdout);                                                                    Line 70
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 71
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 72
      fputs (_("\                                                               Line 73
\n\                                                                             
Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they\n\     Line 75
must be omitted when TYPE is p.  If MAJOR or MINOR begins with 0x or 0X,\n\     Line 76
it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;\n\  Line 77
otherwise, as decimal.  TYPE may be:\n\                                         Line 78
"), stdout);                                                                    Line 79
      fputs (_("\                                                               Line 80
\n\                                                                             
  b      create a block (buffered) special file\n\                              Line 82
  c, u   create a character (unbuffered) special file\n\                        Line 83
  p      create a FIFO\n\                                                       Line 84
"), stdout);                                                                    Line 85
      printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);                             Line 86
      emit_ancillary_info (PROGRAM_NAME);                                       Line 87
    }                                                                           
  exit (status);                                                                Line 89
}                                                                               Block 2
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 93
{                                                                               
  mode_t newmode;                                                               Line 95
  char const *specified_mode = NULL;                                            Line 96
  int optc;                                                                     Line 97
  size_t expected_operands;                                                     Line 98
  mode_t node_type;                                                             Line 99
  char const *scontext = NULL;                                                  Line 100
  bool set_security_context = false;                                            Line 101
                                                                                
  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, "m:Z", longopts, NULL)) != -1)        Line 111
    {                                                                           
      switch (optc)                                                             Line 113
        {                                                                       
        case 'm':                                                               Line 115
          specified_mode = optarg;                                              Line 116
          break;                                                                Line 117
        case 'Z':                                                               Line 118
          if (is_smack_enabled ())                                              ...!common auto-comment...
            {                                                                   
              /* We don't yet support -Z to restore context with SMACK.  */     
              scontext = optarg;                                                Line 122
            }                                                                   
          else if (is_selinux_enabled () > 0)                                   ...!common auto-comment...
            {                                                                   
              if (optarg)                                                       Line 126
                scontext = optarg;                                              Line 127
              else                                                              Line 128
                set_security_context = true;                                    Line 129
            }                                                                   
          else if (optarg)                                                      Line 131
            {                                                                   
              error (0, 0,                                                      Line 133
                     _("warning: ignoring --context; "                          Line 134
                       "it requires an SELinux/SMACK-enabled kernel"));         Line 135
            }                                                                   
          break;                                                                Line 137
        case_GETOPT_HELP_CHAR;                                                  Line 138
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                       Line 139
        default:                                                                Line 140
          usage (EXIT_FAILURE);                                                 Line 141
        }                                                                       
    }                                                                           
                                                                                
  newmode = MODE_RW_UGO;                                                        Line 145
  if (specified_mode)                                                           Line 146
    {                                                                           
      mode_t umask_value;                                                       Line 148
      struct mode_change *change = mode_compile (specified_mode);               Line 149
      if (!change)                                                              Line 150
        die (EXIT_FAILURE, 0, _("invalid mode"));                               Line 151
      umask_value = umask (0);                                                  Line 152
      umask (umask_value);                                                      Line 153
      newmode = mode_adjust (newmode, false, umask_value, change, NULL);        Line 154
      free (change);                                                            Line 155
      if (newmode & ~S_IRWXUGO)                                                 Line 156
        die (EXIT_FAILURE, 0,                                                   Line 157
             _("mode must specify only file permission bits"));                 Line 158
    }                                                                           
                                                                                
  /* If the number of arguments is 0 or 1,                                      
     or (if it's 2 or more and the second one starts with 'p'), then there      
     must be exactly two operands.  Otherwise, there must be four.  */          
  expected_operands = (argc <= optind                                           Line 164
                       || (optind + 1 < argc && argv[optind + 1][0] == 'p')     Line 165
                       ? 2 : 4);                                                Line 166
                                                                                
  if (argc - optind < expected_operands)                                        Line 168
    {                                                                           
      if (argc <= optind)                                                       Line 170
        error (0, 0, _("missing operand"));                                     Line 171
      else                                                                      Line 172
        error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));    Line 173
      if (expected_operands == 4 && argc - optind == 2)                         Line 174
        fprintf (stderr, "%s\n",                                                Line 175
                 _("Special files require major and minor device numbers."));   Line 176
      usage (EXIT_FAILURE);                                                     Line 177
    }                                                                           
                                                                                
  if (expected_operands < argc - optind)                                        Line 180
    {                                                                           
      error (0, 0, _("extra operand %s"),                                       Line 182
             quote (argv[optind + expected_operands]));                         Line 183
      if (expected_operands == 2 && argc - optind == 4)                         Line 184
        fprintf (stderr, "%s\n",                                                Line 185
                 _("Fifos do not have major and minor device numbers."));       Line 186
      usage (EXIT_FAILURE);                                                     Line 187
    }                                                                           
                                                                                
  if (scontext)                                                                 Line 190
    {                                                                           
      int ret = 0;                                                              Line 192
      if (is_smack_enabled ())                                                  ...!common auto-comment...
        ret = smack_set_label_for_self (scontext);                              Line 194
      else                                                                      Line 195
        ret = setfscreatecon (se_const (scontext));                             Line 196
                                                                                
      if (ret < 0)                                                              Line 198
        die (EXIT_FAILURE, errno,                                               Line 199
             _("failed to set default file creation context to %s"),            Line 200
             quote (scontext));                                                 Line 201
    }                                                                           
                                                                                
  /* Only check the first character, to allow mnemonic usage like               
     'mknod /dev/rst0 character 18 0'. */                                       
                                                                                
  switch (argv[optind + 1][0])                                                  Line 207
    {                                                                           
    case 'b':   /* 'block' or 'buffered' */                                     Line 209
#ifndef S_IFBLK                                                                 Line 210
      die (EXIT_FAILURE, 0, _("block special files not supported"));            Line 211
#else                                                                           Line 212
      node_type = S_IFBLK;                                                      Line 213
#endif                                                                          Line 214
      goto block_or_character;                                                  Line 215
                                                                                
    case 'c':   /* 'character' */                                               Line 217
    case 'u':   /* 'unbuffered' */                                              Line 218
#ifndef S_IFCHR                                                                 Line 219
      die (EXIT_FAILURE, 0, _("character special files not supported"));        Line 220
#else                                                                           Line 221
      node_type = S_IFCHR;                                                      Line 222
#endif                                                                          Line 223
      goto block_or_character;                                                  Line 224
                                                                                
    block_or_character:                                                         Line 226
      {                                                                         
        char const *s_major = argv[optind + 2];                                 Line 228
        char const *s_minor = argv[optind + 3];                                 Line 229
        uintmax_t i_major, i_minor;                                             Line 230
        dev_t device;                                                           Line 231
                                                                                
        if (xstrtoumax (s_major, NULL, 0, &i_major, NULL) != LONGINT_OK         Line 233
            || i_major != (major_t) i_major)                                    Line 234
          die (EXIT_FAILURE, 0,                                                 Line 235
               _("invalid major device number %s"), quote (s_major));           Line 236
                                                                                
        if (xstrtoumax (s_minor, NULL, 0, &i_minor, NULL) != LONGINT_OK         Line 238
            || i_minor != (minor_t) i_minor)                                    Line 239
          die (EXIT_FAILURE, 0,                                                 Line 240
               _("invalid minor device number %s"), quote (s_minor));           Line 241
                                                                                
        device = makedev (i_major, i_minor);                                    Line 243
#ifdef NODEV                                                                    Line 244
        if (device == NODEV)                                                    Line 245
          die (EXIT_FAILURE, 0, _("invalid device %s %s"),                      Line 246
               s_major, s_minor);                                               Line 247
#endif                                                                          Line 248
                                                                                
        if (set_security_context)                                               Line 250
          defaultcon (argv[optind], node_type);                                 Line 251
                                                                                
        if (mknod (argv[optind], newmode | node_type, device) != 0)             Line 253...!syscalls auto-comment...
          die (EXIT_FAILURE, errno, "%s", quotef (argv[optind]));               Line 254
      }                                                                         
      break;                                                                    Line 256
                                                                                
    case 'p':   /* 'pipe' */                                                    Line 258
      if (set_security_context)                                                 Line 259
        defaultcon (argv[optind], S_IFIFO);                                     Line 260
      if (mkfifo (argv[optind], newmode) != 0)                                  Line 261
        die (EXIT_FAILURE, errno, "%s", quotef (argv[optind]));                 Line 262
      break;                                                                    Line 263
                                                                                
    default:                                                                    Line 265
      error (0, 0, _("invalid device type %s"), quote (argv[optind + 1]));      Line 266
      usage (EXIT_FAILURE);                                                     Line 267
    }                                                                           
                                                                                
  if (specified_mode && lchmod (argv[optind], newmode) != 0)                    Line 270
    die (EXIT_FAILURE, errno, _("cannot set permissions of %s"),                Line 271
         quoteaf (argv[optind]));                                               Line 272
                                                                                
  return EXIT_SUCCESS;                                                          Line 274
}                                                                               Block 3