LCOV - code coverage report
Current view: top level - src - chgrp.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 100 103 97.1 %
Date: 2018-01-30 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* chgrp -- change group ownership of files
       2             :    Copyright (C) 89, 90, 91, 1995-2007 Free Software Foundation, Inc.
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
      18             : 
      19             : #include <config.h>
      20             : #include <stdio.h>
      21             : #include <sys/types.h>
      22             : #include <grp.h>
      23             : #include <getopt.h>
      24             : 
      25             : #include "system.h"
      26             : #include "chown-core.h"
      27             : #include "error.h"
      28             : #include "fts_.h"
      29             : #include "group-member.h"
      30             : #include "quote.h"
      31             : #include "root-dev-ino.h"
      32             : #include "xstrtol.h"
      33             : 
      34             : /* The official name of this program (e.g., no `g' prefix).  */
      35             : #define PROGRAM_NAME "chgrp"
      36             : 
      37             : #define AUTHORS "David MacKenzie", "Jim Meyering"
      38             : 
      39             : #if ! HAVE_ENDGRENT
      40             : # define endgrent() ((void) 0)
      41             : #endif
      42             : 
      43             : /* The name the program was run with. */
      44             : char *program_name;
      45             : 
      46             : /* The argument to the --reference option.  Use the group ID of this file.
      47             :    This file must exist.  */
      48             : static char *reference_file;
      49             : 
      50             : /* For long options that have no equivalent short option, use a
      51             :    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
      52             : enum
      53             : {
      54             :   DEREFERENCE_OPTION = CHAR_MAX + 1,
      55             :   NO_PRESERVE_ROOT,
      56             :   PRESERVE_ROOT,
      57             :   REFERENCE_FILE_OPTION
      58             : };
      59             : 
      60             : static struct option const long_options[] =
      61             : {
      62             :   {"recursive", no_argument, NULL, 'R'},
      63             :   {"changes", no_argument, NULL, 'c'},
      64             :   {"dereference", no_argument, NULL, DEREFERENCE_OPTION},
      65             :   {"no-dereference", no_argument, NULL, 'h'},
      66             :   {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
      67             :   {"preserve-root", no_argument, NULL, PRESERVE_ROOT},
      68             :   {"quiet", no_argument, NULL, 'f'},
      69             :   {"silent", no_argument, NULL, 'f'},
      70             :   {"reference", required_argument, NULL, REFERENCE_FILE_OPTION},
      71             :   {"verbose", no_argument, NULL, 'v'},
      72             :   {GETOPT_HELP_OPTION_DECL},
      73             :   {GETOPT_VERSION_OPTION_DECL},
      74             :   {NULL, 0, NULL, 0}
      75             : };
      76             : 
      77             : /* Return the group ID of NAME, or -1 if no name was specified.  */
      78             : 
      79             : static gid_t
      80          46 : parse_group (const char *name)
      81             : {
      82          46 :   gid_t gid = -1;
      83             : 
      84          46 :   if (*name)
      85             :     {
      86          12 :       struct group *grp = getgrnam (name);
      87          12 :       if (grp)
      88           1 :         gid = grp->gr_gid;
      89             :       else
      90             :         {
      91             :           unsigned long int tmp;
      92          12 :           if (! (xstrtoul (name, NULL, 10, &tmp, "") == LONGINT_OK
      93           1 :                  && tmp <= GID_T_MAX))
      94          10 :             error (EXIT_FAILURE, 0, _("invalid group: %s"), quote (name));
      95           1 :           gid = tmp;
      96             :         }
      97           2 :       endgrent ();              /* Save a file descriptor. */
      98             :     }
      99             : 
     100          36 :   return gid;
     101             : }
     102             : 
     103             : void
     104          41 : usage (int status)
     105             : {
     106          41 :   if (status != EXIT_SUCCESS)
     107          39 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
     108             :              program_name);
     109             :   else
     110             :     {
     111           2 :       printf (_("\
     112             : Usage: %s [OPTION]... GROUP FILE...\n\
     113             :   or:  %s [OPTION]... --reference=RFILE FILE...\n\
     114             : "),
     115             :               program_name, program_name);
     116           2 :       fputs (_("\
     117             : Change the group of each FILE to GROUP.\n\
     118             : With --reference, change the group of each FILE to that of RFILE.\n\
     119             : \n\
     120             :   -c, --changes          like verbose but report only when a change is made\n\
     121             :       --dereference      affect the referent of each symbolic link (this is\n\
     122             :                          the default), rather than the symbolic link itself\n\
     123             : "), stdout);
     124           2 :       fputs (_("\
     125             :   -h, --no-dereference   affect each symbolic link instead of any referenced\n\
     126             :                          file (useful only on systems that can change the\n\
     127             :                          ownership of a symlink)\n\
     128             : "), stdout);
     129           2 :       fputs (_("\
     130             :       --no-preserve-root  do not treat `/' specially (the default)\n\
     131             :       --preserve-root    fail to operate recursively on `/'\n\
     132             : "), stdout);
     133           2 :       fputs (_("\
     134             :   -f, --silent, --quiet  suppress most error messages\n\
     135             :       --reference=RFILE  use RFILE's group rather than specifying a\n\
     136             :                          GROUP value\n\
     137             :   -R, --recursive        operate on files and directories recursively\n\
     138             :   -v, --verbose          output a diagnostic for every file processed\n\
     139             : \n\
     140             : "), stdout);
     141           2 :       fputs (_("\
     142             : The following options modify how a hierarchy is traversed when the -R\n\
     143             : option is also specified.  If more than one is specified, only the final\n\
     144             : one takes effect.\n\
     145             : \n\
     146             :   -H                     if a command line argument is a symbolic link\n\
     147             :                          to a directory, traverse it\n\
     148             :   -L                     traverse every symbolic link to a directory\n\
     149             :                          encountered\n\
     150             :   -P                     do not traverse any symbolic links (default)\n\
     151             : \n\
     152             : "), stdout);
     153           2 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     154           2 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     155           2 :       printf (_("\
     156             : \n\
     157             : Examples:\n\
     158             :   %s staff /u      Change the group of /u to \"staff\".\n\
     159             :   %s -hR staff /u  Change the group of /u and subfiles to \"staff\".\n\
     160             : "),
     161             :               program_name, program_name);
     162           2 :       emit_bug_reporting_address ();
     163             :     }
     164          41 :   exit (status);
     165             : }
     166             : 
     167             : int
     168          95 : main (int argc, char **argv)
     169             : {
     170          95 :   bool preserve_root = false;
     171             :   gid_t gid;
     172             : 
     173             :   /* Bit flags that control how fts works.  */
     174          95 :   int bit_flags = FTS_PHYSICAL;
     175             : 
     176             :   /* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
     177             :      specified.  */
     178          95 :   int dereference = -1;
     179             : 
     180             :   struct Chown_option chopt;
     181             :   bool ok;
     182             :   int optc;
     183             : 
     184             :   initialize_main (&argc, &argv);
     185          95 :   program_name = argv[0];
     186          95 :   setlocale (LC_ALL, "");
     187             :   bindtextdomain (PACKAGE, LOCALEDIR);
     188             :   textdomain (PACKAGE);
     189             : 
     190          95 :   atexit (close_stdout);
     191             : 
     192          95 :   chopt_init (&chopt);
     193             : 
     194         242 :   while ((optc = getopt_long (argc, argv, "HLPRcfhv", long_options, NULL))
     195             :          != -1)
     196             :     {
     197          63 :       switch (optc)
     198             :         {
     199           9 :         case 'H': /* Traverse command-line symlinks-to-directories.  */
     200           9 :           bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
     201           9 :           break;
     202             : 
     203           6 :         case 'L': /* Traverse all symlinks-to-directories.  */
     204           6 :           bit_flags = FTS_LOGICAL;
     205           6 :           break;
     206             : 
     207           1 :         case 'P': /* Traverse no symlinks-to-directories.  */
     208           1 :           bit_flags = FTS_PHYSICAL;
     209           1 :           break;
     210             : 
     211           1 :         case 'h': /* --no-dereference: affect symlinks */
     212           1 :           dereference = 0;
     213           1 :           break;
     214             : 
     215           2 :         case DEREFERENCE_OPTION: /* --dereference: affect the referent
     216             :                                     of each symlink */
     217           2 :           dereference = 1;
     218           2 :           break;
     219             : 
     220           1 :         case NO_PRESERVE_ROOT:
     221           1 :           preserve_root = false;
     222           1 :           break;
     223             : 
     224           1 :         case PRESERVE_ROOT:
     225           1 :           preserve_root = true;
     226           1 :           break;
     227             : 
     228           7 :         case REFERENCE_FILE_OPTION:
     229           7 :           reference_file = optarg;
     230           7 :           break;
     231             : 
     232          15 :         case 'R':
     233          15 :           chopt.recurse = true;
     234          15 :           break;
     235             : 
     236           4 :         case 'c':
     237           4 :           chopt.verbosity = V_changes_only;
     238           4 :           break;
     239             : 
     240           2 :         case 'f':
     241           2 :           chopt.force_silent = true;
     242           2 :           break;
     243             : 
     244           3 :         case 'v':
     245           3 :           chopt.verbosity = V_high;
     246           3 :           break;
     247             : 
     248           2 :         case_GETOPT_HELP_CHAR;
     249           1 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     250           8 :         default:
     251           8 :           usage (EXIT_FAILURE);
     252             :         }
     253             :     }
     254             : 
     255          84 :   if (chopt.recurse)
     256             :     {
     257          15 :       if (bit_flags == FTS_PHYSICAL)
     258             :         {
     259           7 :           if (dereference == 1)
     260           1 :             error (EXIT_FAILURE, 0,
     261             :                    _("-R --dereference requires either -H or -L"));
     262           6 :           dereference = 0;
     263             :         }
     264             :     }
     265             :   else
     266             :     {
     267          69 :       bit_flags = FTS_PHYSICAL;
     268             :     }
     269          83 :   chopt.affect_symlink_referent = (dereference != 0);
     270             : 
     271          83 :   if (argc - optind < (reference_file ? 1 : 2))
     272             :     {
     273          31 :       if (argc <= optind)
     274          17 :         error (0, 0, _("missing operand"));
     275             :       else
     276          14 :         error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
     277          31 :       usage (EXIT_FAILURE);
     278             :     }
     279             : 
     280          52 :   if (reference_file)
     281             :     {
     282             :       struct stat ref_stats;
     283           6 :       if (stat (reference_file, &ref_stats))
     284           2 :         error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
     285             :                quote (reference_file));
     286             : 
     287           4 :       gid = ref_stats.st_gid;
     288           4 :       chopt.group_name = gid_to_name (ref_stats.st_gid);
     289             :     }
     290             :   else
     291             :     {
     292          46 :       char *group_name = argv[optind++];
     293          46 :       chopt.group_name = (*group_name ? group_name : NULL);
     294          46 :       gid = parse_group (group_name);
     295             :     }
     296             : 
     297          40 :   if (chopt.recurse & preserve_root)
     298             :     {
     299             :       static struct dev_ino dev_ino_buf;
     300           0 :       chopt.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
     301           0 :       if (chopt.root_dev_ino == NULL)
     302           0 :         error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
     303             :                quote ("/"));
     304             :     }
     305             : 
     306          40 :   ok = chown_files (argv + optind, bit_flags,
     307             :                     (uid_t) -1, gid,
     308             :                     (uid_t) -1, (gid_t) -1, &chopt);
     309             : 
     310          35 :   chopt_free (&chopt);
     311             : 
     312          35 :   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
     313             : }

Generated by: LCOV version 1.10