LCOV - code coverage report
Current view: top level - src - chown.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 95 107 88.8 %
Date: 2018-01-30 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* chown -- change user and 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             : /*
      18             :               |                       user
      19             :               | unchanged                 explicit
      20             :  -------------|-------------------------+-------------------------|
      21             :  g unchanged  | ---                     | chown u                 |
      22             :  r            |-------------------------+-------------------------|
      23             :  o explicit   | chgrp g or chown .g     | chown u.g               |
      24             :  u            |-------------------------+-------------------------|
      25             :  p from passwd| ---                     | chown u.                |
      26             :               |-------------------------+-------------------------|
      27             : 
      28             :    Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
      29             : 
      30             : #include <config.h>
      31             : #include <stdio.h>
      32             : #include <sys/types.h>
      33             : #include <getopt.h>
      34             : 
      35             : #include "system.h"
      36             : #include "chown-core.h"
      37             : #include "error.h"
      38             : #include "fts_.h"
      39             : #include "quote.h"
      40             : #include "root-dev-ino.h"
      41             : #include "userspec.h"
      42             : 
      43             : /* The official name of this program (e.g., no `g' prefix).  */
      44             : #define PROGRAM_NAME "chown"
      45             : 
      46             : #define AUTHORS "David MacKenzie", "Jim Meyering"
      47             : 
      48             : /* The name the program was run with. */
      49             : char *program_name;
      50             : 
      51             : /* The argument to the --reference option.  Use the owner and group IDs
      52             :    of this file.  This file must exist.  */
      53             : static char *reference_file;
      54             : 
      55             : /* For long options that have no equivalent short option, use a
      56             :    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
      57             : enum
      58             : {
      59             :   DEREFERENCE_OPTION = CHAR_MAX + 1,
      60             :   FROM_OPTION,
      61             :   NO_PRESERVE_ROOT,
      62             :   PRESERVE_ROOT,
      63             :   REFERENCE_FILE_OPTION
      64             : };
      65             : 
      66             : static struct option const long_options[] =
      67             : {
      68             :   {"recursive", no_argument, NULL, 'R'},
      69             :   {"changes", no_argument, NULL, 'c'},
      70             :   {"dereference", no_argument, NULL, DEREFERENCE_OPTION},
      71             :   {"from", required_argument, NULL, FROM_OPTION},
      72             :   {"no-dereference", no_argument, NULL, 'h'},
      73             :   {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
      74             :   {"preserve-root", no_argument, NULL, PRESERVE_ROOT},
      75             :   {"quiet", no_argument, NULL, 'f'},
      76             :   {"silent", no_argument, NULL, 'f'},
      77             :   {"reference", required_argument, NULL, REFERENCE_FILE_OPTION},
      78             :   {"verbose", no_argument, NULL, 'v'},
      79             :   {GETOPT_HELP_OPTION_DECL},
      80             :   {GETOPT_VERSION_OPTION_DECL},
      81             :   {NULL, 0, NULL, 0}
      82             : };
      83             : 
      84             : void
      85          42 : usage (int status)
      86             : {
      87          42 :   if (status != EXIT_SUCCESS)
      88          41 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      89             :              program_name);
      90             :   else
      91             :     {
      92           1 :       printf (_("\
      93             : Usage: %s [OPTION]... [OWNER][:[GROUP]] FILE...\n\
      94             :   or:  %s [OPTION]... --reference=RFILE FILE...\n\
      95             : "),
      96             :               program_name, program_name);
      97           1 :       fputs (_("\
      98             : Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
      99             : With --reference, change the owner and group of each FILE to those of RFILE.\n\
     100             : \n\
     101             :   -c, --changes          like verbose but report only when a change is made\n\
     102             :       --dereference      affect the referent of each symbolic link (this is\n\
     103             :                          the default), rather than the symbolic link itself\n\
     104             : "), stdout);
     105           1 :       fputs (_("\
     106             :   -h, --no-dereference   affect each symbolic link instead of any referenced\n\
     107             :                          file (useful only on systems that can change the\n\
     108             :                          ownership of a symlink)\n\
     109             : "), stdout);
     110           1 :       fputs (_("\
     111             :       --from=CURRENT_OWNER:CURRENT_GROUP\n\
     112             :                          change the owner and/or group of each file only if\n\
     113             :                          its current owner and/or group match those specified\n\
     114             :                          here.  Either may be omitted, in which case a match\n\
     115             :                          is not required for the omitted attribute.\n\
     116             : "), stdout);
     117           1 :       fputs (_("\
     118             :       --no-preserve-root  do not treat `/' specially (the default)\n\
     119             :       --preserve-root    fail to operate recursively on `/'\n\
     120             : "), stdout);
     121           1 :       fputs (_("\
     122             :   -f, --silent, --quiet  suppress most error messages\n\
     123             :       --reference=RFILE  use RFILE's owner and group rather than\n\
     124             :                          specifying OWNER:GROUP values\n\
     125             :   -R, --recursive        operate on files and directories recursively\n\
     126             :   -v, --verbose          output a diagnostic for every file processed\n\
     127             : \n\
     128             : "), stdout);
     129           1 :       fputs (_("\
     130             : The following options modify how a hierarchy is traversed when the -R\n\
     131             : option is also specified.  If more than one is specified, only the final\n\
     132             : one takes effect.\n\
     133             : \n\
     134             :   -H                     if a command line argument is a symbolic link\n\
     135             :                          to a directory, traverse it\n\
     136             :   -L                     traverse every symbolic link to a directory\n\
     137             :                          encountered\n\
     138             :   -P                     do not traverse any symbolic links (default)\n\
     139             : \n\
     140             : "), stdout);
     141           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     142           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     143           1 :       fputs (_("\
     144             : \n\
     145             : Owner is unchanged if missing.  Group is unchanged if missing, but changed\n\
     146             : to login group if implied by a `:' following a symbolic OWNER.\n\
     147             : OWNER and GROUP may be numeric as well as symbolic.\n\
     148             : "), stdout);
     149           1 :       printf (_("\
     150             : \n\
     151             : Examples:\n\
     152             :   %s root /u        Change the owner of /u to \"root\".\n\
     153             :   %s root:staff /u  Likewise, but also change its group to \"staff\".\n\
     154             :   %s -hR root /u    Change the owner of /u and subfiles to \"root\".\n\
     155             : "),
     156             :               program_name, program_name, program_name);
     157           1 :       emit_bug_reporting_address ();
     158             :     }
     159          42 :   exit (status);
     160             : }
     161             : 
     162             : int
     163          85 : main (int argc, char **argv)
     164             : {
     165          85 :   bool preserve_root = false;
     166             : 
     167          85 :   uid_t uid = -1;       /* Specified uid; -1 if not to be changed. */
     168          85 :   gid_t gid = -1;       /* Specified gid; -1 if not to be changed. */
     169             : 
     170             :   /* Change the owner (group) of a file only if it has this uid (gid).
     171             :      -1 means there's no restriction.  */
     172          85 :   uid_t required_uid = -1;
     173          85 :   gid_t required_gid = -1;
     174             : 
     175             :   /* Bit flags that control how fts works.  */
     176          85 :   int bit_flags = FTS_PHYSICAL;
     177             : 
     178             :   /* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
     179             :      specified.  */
     180          85 :   int dereference = -1;
     181             : 
     182             :   struct Chown_option chopt;
     183             :   bool ok;
     184             :   int optc;
     185             : 
     186             :   initialize_main (&argc, &argv);
     187          85 :   program_name = argv[0];
     188          85 :   setlocale (LC_ALL, "");
     189             :   bindtextdomain (PACKAGE, LOCALEDIR);
     190             :   textdomain (PACKAGE);
     191             : 
     192          85 :   atexit (close_stdout);
     193             : 
     194          85 :   chopt_init (&chopt);
     195             : 
     196         199 :   while ((optc = getopt_long (argc, argv, "HLPRcfhv", long_options, NULL))
     197             :          != -1)
     198             :     {
     199          39 :       switch (optc)
     200             :         {
     201           6 :         case 'H': /* Traverse command-line symlinks-to-directories.  */
     202           6 :           bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
     203           6 :           break;
     204             : 
     205           4 :         case 'L': /* Traverse all symlinks-to-directories.  */
     206           4 :           bit_flags = FTS_LOGICAL;
     207           4 :           break;
     208             : 
     209           1 :         case 'P': /* Traverse no symlinks-to-directories.  */
     210           1 :           bit_flags = FTS_PHYSICAL;
     211           1 :           break;
     212             : 
     213           1 :         case 'h': /* --no-dereference: affect symlinks */
     214           1 :           dereference = 0;
     215           1 :           break;
     216             : 
     217           1 :         case DEREFERENCE_OPTION: /* --dereference: affect the referent
     218             :                                     of each symlink */
     219           1 :           dereference = 1;
     220           1 :           break;
     221             : 
     222           0 :         case NO_PRESERVE_ROOT:
     223           0 :           preserve_root = false;
     224           0 :           break;
     225             : 
     226           1 :         case PRESERVE_ROOT:
     227           1 :           preserve_root = true;
     228           1 :           break;
     229             : 
     230           2 :         case REFERENCE_FILE_OPTION:
     231           2 :           reference_file = optarg;
     232           2 :           break;
     233             : 
     234           3 :         case FROM_OPTION:
     235             :           {
     236             :             char *u_dummy, *g_dummy;
     237           3 :             const char *e = parse_user_spec (optarg,
     238             :                                              &required_uid, &required_gid,
     239             :                                              &u_dummy, &g_dummy);
     240           3 :             if (e)
     241           1 :               error (EXIT_FAILURE, 0, "%s: %s", e, quote (optarg));
     242           2 :             break;
     243             :           }
     244             : 
     245           5 :         case 'R':
     246           5 :           chopt.recurse = true;
     247           5 :           break;
     248             : 
     249           3 :         case 'c':
     250           3 :           chopt.verbosity = V_changes_only;
     251           3 :           break;
     252             : 
     253           1 :         case 'f':
     254           1 :           chopt.force_silent = true;
     255           1 :           break;
     256             : 
     257           2 :         case 'v':
     258           2 :           chopt.verbosity = V_high;
     259           2 :           break;
     260             : 
     261           1 :         case_GETOPT_HELP_CHAR;
     262           0 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     263           8 :         default:
     264           8 :           usage (EXIT_FAILURE);
     265             :         }
     266             :     }
     267             : 
     268          75 :   if (chopt.recurse)
     269             :     {
     270           5 :       if (bit_flags == FTS_PHYSICAL)
     271             :         {
     272           2 :           if (dereference == 1)
     273           0 :             error (EXIT_FAILURE, 0,
     274             :                    _("-R --dereference requires either -H or -L"));
     275           2 :           dereference = 0;
     276             :         }
     277             :     }
     278             :   else
     279             :     {
     280          70 :       bit_flags = FTS_PHYSICAL;
     281             :     }
     282          75 :   chopt.affect_symlink_referent = (dereference != 0);
     283             : 
     284          75 :   if (argc - optind < (reference_file ? 1 : 2))
     285             :     {
     286          33 :       if (argc <= optind)
     287          16 :         error (0, 0, _("missing operand"));
     288             :       else
     289          17 :         error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
     290          33 :       usage (EXIT_FAILURE);
     291             :     }
     292             : 
     293          42 :   if (reference_file)
     294             :     {
     295             :       struct stat ref_stats;
     296           1 :       if (stat (reference_file, &ref_stats))
     297           1 :         error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
     298             :                quote (reference_file));
     299             : 
     300           0 :       uid = ref_stats.st_uid;
     301           0 :       gid = ref_stats.st_gid;
     302           0 :       chopt.user_name = uid_to_name (ref_stats.st_uid);
     303           0 :       chopt.group_name = gid_to_name (ref_stats.st_gid);
     304             :     }
     305             :   else
     306             :     {
     307          41 :       const char *e = parse_user_spec (argv[optind], &uid, &gid,
     308             :                                        &chopt.user_name, &chopt.group_name);
     309          41 :       if (e)
     310          14 :         error (EXIT_FAILURE, 0, "%s: %s", e, quote (argv[optind]));
     311             : 
     312             :       /* If a group is specified but no user, set the user name to the
     313             :          empty string so that diagnostics say "ownership :GROUP"
     314             :          rather than "group GROUP".  */
     315          27 :       if (!chopt.user_name && chopt.group_name)
     316           3 :         chopt.user_name = "";
     317             : 
     318          27 :       optind++;
     319             :     }
     320             : 
     321          27 :   if (chopt.recurse & preserve_root)
     322             :     {
     323             :       static struct dev_ino dev_ino_buf;
     324           0 :       chopt.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
     325           0 :       if (chopt.root_dev_ino == NULL)
     326           0 :         error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
     327             :                quote ("/"));
     328             :     }
     329             : 
     330          27 :   ok = chown_files (argv + optind, bit_flags,
     331             :                     uid, gid,
     332             :                     required_uid, required_gid, &chopt);
     333             : 
     334          21 :   chopt_free (&chopt);
     335             : 
     336          21 :   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
     337             : }

Generated by: LCOV version 1.10