/* 'rm' file deletion utility for GNU.                                          This is the rm utility
   Copyright (C) 1988-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
                                                                                
/* Initially written by Paul Rubin, David MacKenzie, and Richard Stallman.      
   Reworked to use chdir and avoid recursion, and later, rewritten              
   once again, to use fts, by Jim Meyering.  */                                 
                                                                                
#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 <assert.h>                                                             ...!includes auto-comment...
                                                                                
#include "system.h"                                                             ...!includes auto-comment...
#include "argmatch.h"                                                           ...!includes auto-comment...
#include "die.h"                                                                ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "remove.h"                                                             ...!includes auto-comment...
#include "root-dev-ino.h"                                                       ...!includes auto-comment......!includes auto-comment...
#include "yesno.h"                                                              ...!includes auto-comment...
#include "priv-set.h"                                                           ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "rm"                                                       Line 37
                                                                                
#define AUTHORS \                                                               Line 39
  proper_name ("Paul Rubin"), \                                                 Line 40
  proper_name ("David MacKenzie"), \                                            Line 41
  proper_name ("Richard M. Stallman"), \                                        Line 42
  proper_name ("Jim Meyering")                                                  Line 43
                                                                                
/* For long options that have no equivalent short option, use a                 
   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */      
enum                                                                            Line 47
{                                                                               
  INTERACTIVE_OPTION = CHAR_MAX + 1,                                            Line 49
  ONE_FILE_SYSTEM,                                                              Line 50
  NO_PRESERVE_ROOT,                                                             Line 51
  PRESERVE_ROOT,                                                                Line 52
  PRESUME_INPUT_TTY_OPTION                                                      Line 53
};                                                                              Block 1
                                                                                
enum interactive_type                                                           Line 56
  {                                                                             
    interactive_never,  /* 0: no option or --interactive=never */               Line 58
    interactive_once,  /* 1: -I or --interactive=once */                        Line 59
    interactive_always  /* 2: default, -i or --interactive=always */            Line 60
  };                                                                            Block 2
                                                                                
static struct option const long_opts[] =                                        Line 63
{                                                                               
  {"force", no_argument, NULL, 'f'},                                            Line 65
  {"interactive", optional_argument, NULL, INTERACTIVE_OPTION},                 Line 66
                                                                                
  {"one-file-system", no_argument, NULL, ONE_FILE_SYSTEM},                      Line 68
  {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},                    Line 69
  {"preserve-root", optional_argument, NULL, PRESERVE_ROOT},                    Line 70
                                                                                
  /* This is solely for testing.  Do not document.  */                          
  /* It is relatively difficult to ensure that there is a tty on stdin.         
     Since rm acts differently depending on that, without this option,          
     it'd be harder to test the parts of rm that depend on that setting.  */    
  {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},          Line 76
                                                                                
  {"recursive", no_argument, NULL, 'r'},                                        Line 78
  {"dir", no_argument, NULL, 'd'},                                              Line 79
  {"verbose", no_argument, NULL, 'v'},                                          Line 80
  {GETOPT_HELP_OPTION_DECL},                                                    Line 81
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 82
  {NULL, 0, NULL, 0}                                                            Line 83
};                                                                              Block 3
                                                                                
static char const *const interactive_args[] =                                   Line 86
{                                                                               
  "never", "no", "none",                                                        Line 88
  "once",                                                                       Line 89
  "always", "yes", NULL                                                         Line 90
};                                                                              Block 4
static enum interactive_type const interactive_types[] =                        Line 92
{                                                                               
  interactive_never, interactive_never, interactive_never,                      Line 94
  interactive_once,                                                             Line 95
  interactive_always, interactive_always                                        Line 96
};                                                                              Block 5
ARGMATCH_VERIFY (interactive_args, interactive_types);                          Line 98
                                                                                
/* Advise the user about invalid usages like "rm -foo" if the file              
   "-foo" exists, assuming ARGC and ARGV are as with 'main'.  */                
                                                                                
static void                                                                     Line 103
diagnose_leading_hyphen (int argc, char **argv)                                 Line 104
{                                                                               
  /* OPTIND is unreliable, so iterate through the arguments looking             
     for a file name that looks like an option.  */                             
                                                                                
  for (int i = 1; i < argc; i++)                                                Line 109
    {                                                                           
      char const *arg = argv[i];                                                Line 111
      struct stat st;                                                           Line 112
                                                                                
      if (arg[0] == '-' && arg[1] && lstat (arg, &st) == 0)                     Line 114...!syscalls auto-comment...
        {                                                                       
          fprintf (stderr,                                                      Line 116
                   _("Try '%s ./%s' to remove the file %s.\n"),                 Line 117
                   argv[0],                                                     Line 118
                   quotearg_n_style (1, shell_escape_quoting_style, arg),       Line 119
                   quoteaf (arg));                                              Line 120
          break;                                                                Line 121
        }                                                                       
    }                                                                           
}                                                                               
                                                                                
void                                                                            Line 126
usage (int status)                                                              Line 127
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 129
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 131
    {                                                                           
      printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);            Line 133
      fputs (_("\                                                               Line 134
Remove (unlink) the FILE(s).\n\                                                 Line 135
\n\                                                                             
  -f, --force           ignore nonexistent files and arguments, never prompt\n\ Line 137
  -i                    prompt before every removal\n\                          Line 138
"), stdout);                                                                    Line 139
      fputs (_("\                                                               Line 140
  -I                    prompt once before removing more than three files, or\n\Line 141
                          when removing recursively; less intrusive than -i,\n\ Line 142
                          while still giving protection against most mistakes\n\Line 143
      --interactive[=WHEN]  prompt according to WHEN: never, once (-I), or\n\   Line 144
                          always (-i); without WHEN, prompt always\n\           Line 145
"), stdout);                                                                    Line 146
      fputs (_("\                                                               Line 147
      --one-file-system  when removing a hierarchy recursively, skip any\n\     Line 148
                          directory that is on a file system different from\n\  Line 149
                          that of the corresponding command line argument\n\    Line 150
"), stdout);                                                                    Line 151
      fputs (_("\                                                               Line 152
      --no-preserve-root  do not treat '/' specially\n\                         Line 153
      --preserve-root[=all]  do not remove '/' (default);\n\                    Line 154
                              with 'all', reject any command line argument\n\   Line 155
                              on a separate device from its parent\n\           Line 156
"), stdout);                                                                    Line 157
      fputs (_("\                                                               Line 158
  -r, -R, --recursive   remove directories and their contents recursively\n\    Line 159
  -d, --dir             remove empty directories\n\                             Line 160
  -v, --verbose         explain what is being done\n\                           Line 161
"), stdout);                                                                    Line 162
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 163
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 164
      fputs (_("\                                                               Line 165
\n\                                                                             
By default, rm does not remove directories.  Use the --recursive (-r or -R)\n\  Line 167
option to remove each listed directory, too, along with all of its contents.\n\ Line 168
"), stdout);                                                                    Line 169
      printf (_("\                                                              Line 170
\n\                                                                             
To remove a file whose name starts with a '-', for example '-foo',\n\           Line 172
use one of these commands:\n\                                                   Line 173
  %s -- -foo\n\                                                                 Line 174
\n\                                                                             
  %s ./-foo\n\                                                                  Line 176
"),                                                                             Line 177
              program_name, program_name);                                      Line 178
      fputs (_("\                                                               Line 179
\n\                                                                             
Note that if you use rm to remove a file, it might be possible to recover\n\    Line 181
some of its contents, given sufficient expertise and/or time.  For greater\n\   Line 182
assurance that the contents are truly unrecoverable, consider using shred.\n\   Line 183
"), stdout);                                                                    Line 184
      emit_ancillary_info (PROGRAM_NAME);                                       Line 185
    }                                                                           
  exit (status);                                                                Line 187
}                                                                               Block 7
                                                                                
static void                                                                     Line 190
rm_option_init (struct rm_options *x)                                           Line 191
{                                                                               
  x->ignore_missing_files = false;                                              Line 193
  x->interactive = RMI_SOMETIMES;                                               Line 194
  x->one_file_system = false;                                                   Line 195
  x->remove_empty_directories = false;                                          Line 196
  x->recursive = false;                                                         Line 197
  x->root_dev_ino = NULL;                                                       Line 198
  x->preserve_all_root = false;                                                 Line 199
  x->stdin_tty = isatty (STDIN_FILENO);                                         Line 200
  x->verbose = false;                                                           Line 201
                                                                                
  /* Since this program exits immediately after calling 'rm', rm need not       
     expend unnecessary effort to preserve the initial working directory.  */   
  x->require_restore_cwd = false;                                               Line 205
}                                                                               Block 8
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 209
{                                                                               
  bool preserve_root = true;                                                    Line 211
  struct rm_options x;                                                          Line 212
  bool prompt_once = false;                                                     Line 213
  int c;                                                                        Line 214
                                                                                
  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_stdin);                                                         Close stdout on exit (see gnulib)
                                                                                
  rm_option_init (&x);                                                          Line 224
                                                                                
  /* Try to disable the ability to unlink a directory.  */                      
  priv_set_remove_linkdir ();                                                   Line 227
                                                                                
  while ((c = getopt_long (argc, argv, "dfirvIR", long_opts, NULL)) != -1)      Line 229
    {                                                                           
      switch (c)                                                                Line 231
        {                                                                       
        case 'd':                                                               Line 233
          x.remove_empty_directories = true;                                    Line 234
          break;                                                                Line 235
                                                                                
        case 'f':                                                               Line 237
          x.interactive = RMI_NEVER;                                            Line 238
          x.ignore_missing_files = true;                                        Line 239
          prompt_once = false;                                                  Line 240
          break;                                                                Line 241
                                                                                
        case 'i':                                                               Line 243
          x.interactive = RMI_ALWAYS;                                           Line 244
          x.ignore_missing_files = false;                                       Line 245
          prompt_once = false;                                                  Line 246
          break;                                                                Line 247
                                                                                
        case 'I':                                                               Line 249
          x.interactive = RMI_SOMETIMES;                                        Line 250
          x.ignore_missing_files = false;                                       Line 251
          prompt_once = true;                                                   Line 252
          break;                                                                Line 253
                                                                                
        case 'r':                                                               Line 255
        case 'R':                                                               Line 256
          x.recursive = true;                                                   Line 257
          break;                                                                Line 258
                                                                                
        case INTERACTIVE_OPTION:                                                Line 260
          {                                                                     
            int i;                                                              Line 262
            if (optarg)                                                         Line 263
              i = XARGMATCH ("--interactive", optarg, interactive_args,         Line 264
                             interactive_types);                                Line 265
            else                                                                Line 266
              i = interactive_always;                                           Line 267
            switch (i)                                                          Line 268
              {                                                                 
              case interactive_never:                                           Line 270
                x.interactive = RMI_NEVER;                                      Line 271
                prompt_once = false;                                            Line 272
                break;                                                          Line 273
                                                                                
              case interactive_once:                                            Line 275
                x.interactive = RMI_SOMETIMES;                                  Line 276
                x.ignore_missing_files = false;                                 Line 277
                prompt_once = true;                                             Line 278
                break;                                                          Line 279
                                                                                
              case interactive_always:                                          Line 281
                x.interactive = RMI_ALWAYS;                                     Line 282
                x.ignore_missing_files = false;                                 Line 283
                prompt_once = false;                                            Line 284
                break;                                                          Line 285
              }                                                                 
            break;                                                              Line 287
          }                                                                     
                                                                                
        case ONE_FILE_SYSTEM:                                                   Line 290
          x.one_file_system = true;                                             Line 291
          break;                                                                Line 292
                                                                                
        case NO_PRESERVE_ROOT:                                                  Line 294
          if (! STREQ (argv[optind - 1], "--no-preserve-root"))                 Line 295
            die (EXIT_FAILURE, 0,                                               Line 296
                 _("you may not abbreviate the --no-preserve-root option"));    Line 297
          preserve_root = false;                                                Line 298
          break;                                                                Line 299
                                                                                
        case PRESERVE_ROOT:                                                     Line 301
          if (optarg)                                                           Line 302
            {                                                                   
              if STREQ (optarg, "all")                                          Line 304
                x.preserve_all_root = true;                                     Line 305
              else                                                              Line 306
                {                                                               
                  die (EXIT_FAILURE, 0,                                         Line 308
                       _("unrecognized --preserve-root argument: %s"),          Line 309
                       quoteaf (optarg));                                       Line 310
                }                                                               
            }                                                                   
          preserve_root = true;                                                 Line 313
          break;                                                                Line 314
                                                                                
        case PRESUME_INPUT_TTY_OPTION:                                          Line 316
          x.stdin_tty = true;                                                   Line 317
          break;                                                                Line 318
                                                                                
        case 'v':                                                               Line 320
          x.verbose = true;                                                     Line 321
          break;                                                                Line 322
                                                                                
        case_GETOPT_HELP_CHAR;                                                  Line 324
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                       Line 325
        default:                                                                Line 326
          diagnose_leading_hyphen (argc, argv);                                 Line 327
          usage (EXIT_FAILURE);                                                 Line 328
        }                                                                       
    }                                                                           
                                                                                
  if (argc <= optind)                                                           Line 332
    {                                                                           
      if (x.ignore_missing_files)                                               Line 334
        return EXIT_SUCCESS;                                                    Line 335
      else                                                                      Line 336
        {                                                                       
          error (0, 0, _("missing operand"));                                   Line 338
          usage (EXIT_FAILURE);                                                 Line 339
        }                                                                       
    }                                                                           
                                                                                
  if (x.recursive && preserve_root)                                             Line 343
    {                                                                           
      static struct dev_ino dev_ino_buf;                                        Line 345
      x.root_dev_ino = get_root_dev_ino (&dev_ino_buf);                         Line 346
      if (x.root_dev_ino == NULL)                                               Line 347
        die (EXIT_FAILURE, errno, _("failed to get attributes of %s"),          Line 348
             quoteaf ("/"));                                                    Line 349
    }                                                                           
                                                                                
  uintmax_t n_files = argc - optind;                                            Line 352
  char **file =  argv + optind;                                                 Line 353
                                                                                
  if (prompt_once && (x.recursive || 3 < n_files))                              Line 355
    {                                                                           
      fprintf (stderr,                                                          Line 357
               (x.recursive                                                     Line 358
                ? ngettext ("%s: remove %"PRIuMAX" argument recursively? ",     Line 359
                            "%s: remove %"PRIuMAX" arguments recursively? ",    Line 360
                            select_plural (n_files))                            Line 361
                : ngettext ("%s: remove %"PRIuMAX" argument? ",                 Line 362
                            "%s: remove %"PRIuMAX" arguments? ",                Line 363
                            select_plural (n_files))),                          Line 364
               program_name, n_files);                                          Line 365
      if (!yesno ())                                                            Line 366
        return EXIT_SUCCESS;                                                    Line 367
    }                                                                           
                                                                                
  enum RM_status status = rm (file, &x);                                        Line 370
  assert (VALID_STATUS (status));                                               Line 371
  return status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS;                      Line 372
}                                                                               Block 9