diff options
-rw-r--r-- | src/chgrp.c | 241 |
1 files changed, 18 insertions, 223 deletions
diff --git a/src/chgrp.c b/src/chgrp.c index 79048534c..e1689d8cc 100644 --- a/src/chgrp.c +++ b/src/chgrp.c @@ -30,6 +30,7 @@ #include "quote.h" #include "savedir.h" #include "xstrtol.h" +#include "chown-core.h" /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "chgrp" @@ -52,54 +53,11 @@ struct group *getgrnam (); # define endgrent() ((void) 0) #endif -enum Change_status -{ - CH_NOT_APPLIED, - CH_SUCCEEDED, - CH_FAILED, - CH_NO_CHANGE_REQUESTED -}; - -enum Verbosity -{ - /* Print a message for each file that is processed. */ - V_high, - - /* Print a message for each file whose attributes we change. */ - V_changes_only, - - /* Do not be verbose. This is the default. */ - V_off -}; - int lstat (); -static int change_dir_group PARAMS ((const char *dir, gid_t group, - const struct stat *statp)); - /* The name the program was run with. */ char *program_name; -/* If nonzero, and the systems has support for it, change the ownership - of symbolic links rather than any files they point to. */ -static int change_symlinks = 1; - -/* When change_symlinks is set, this should be set to `lstat', otherwise, - it should be `stat'. */ -static int (*xstat) (); - -/* If nonzero, change the ownership of directories recursively. */ -static int recurse; - -/* If nonzero, force silence (no error messages). */ -static int force_silent; - -/* Level of verbosity. */ -static enum Verbosity verbosity = V_off; - -/* The name of the group to which ownership of the files is being given. */ -static const char *groupname; - /* The argument to the --reference option. Use the group ID of this file. This file must exist. */ static char *reference_file; @@ -127,38 +85,6 @@ static struct option const long_options[] = {0, 0, 0, 0} }; -/* Tell the user how/if the group of FILE has been changed. - CHANGED describes what (if anything) has happened. */ - -static void -describe_change (const char *file, enum Change_status changed) -{ - const char *fmt; - - if (changed == CH_NOT_APPLIED) - { - printf (_("neither symbolic link %s nor referent has been changed\n"), - quote (file)); - return; - } - - switch (changed) - { - case CH_SUCCEEDED: - fmt = _("group of %s changed to %s\n"); - break; - case CH_FAILED: - fmt = _("failed to change group of %s to %s\n"); - break; - case CH_NO_CHANGE_REQUESTED: - fmt = _("group of %s retained as %s\n"); - break; - default: - abort (); - } - printf (fmt, quote (file), groupname); -} - /* Set *G according to NAME. */ static void @@ -166,7 +92,6 @@ parse_group (const char *name, gid_t *g) { struct group *grp; - groupname = name; if (*name == '\0') error (1, 0, _("can not change to null group")); @@ -193,139 +118,6 @@ parse_group (const char *name, gid_t *g) endgrent (); /* Save a file descriptor. */ } -/* Change the ownership of FILE to GID GROUP. - If it is a directory and -R is given, recurse. - Return 0 if successful, 1 if errors occurred. */ - -static int -change_file_group (int cmdline_arg, const char *file, gid_t group) -{ - struct stat file_stats; - int errors = 0; - - if ((*xstat) (file, &file_stats)) - { - if (force_silent == 0) - error (0, errno, _("getting attributes of %s"), quote (file)); - return 1; - } - - if (group != file_stats.st_gid) - { - int fail; - int symlink_changed = 1; - int saved_errno; - - if (S_ISLNK (file_stats.st_mode) && change_symlinks) - { - fail = lchown (file, (uid_t) -1, group); - - /* Ignore the failure if it's due to lack of support (ENOSYS) - and this is not a command line argument. */ - if (!cmdline_arg && fail && errno == ENOSYS) - { - fail = 0; - symlink_changed = 0; - } - } - else - { - fail = chown (file, (uid_t) -1, group); - } - - /* Save errno, since in verbose mode, describe_change might change it. */ - saved_errno = errno; - - if (verbosity == V_high || (verbosity == V_changes_only && !fail)) - { - enum Change_status ch_status = (! symlink_changed ? CH_NOT_APPLIED - : (fail ? CH_FAILED : CH_SUCCEEDED)); - describe_change (file, ch_status); - } - - if (fail) - { - errors = 1; - if (force_silent == 0) - { - /* Give a more specific message. Some systems set errno - to EPERM for both `inaccessible file' and `user not a member - of the specified group' errors. */ - if (saved_errno == EPERM && !group_member (group)) - { - error (0, saved_errno, _("you are not a member of group %s"), - quote (groupname)); - } - else if (saved_errno == EINVAL && group > MAXUID) - { - error (0, 0, _("%s: invalid group number"), - quote (groupname)); - } - else - { - error (0, saved_errno, _("changing group of %s"), - quote (file)); - } - } - } - } - else if (verbosity == V_high) - { - describe_change (file, CH_NO_CHANGE_REQUESTED); - } - - if (recurse && S_ISDIR (file_stats.st_mode)) - errors |= change_dir_group (file, group, &file_stats); - - return errors; -} - -/* Recursively change the ownership of the files in directory DIR - to GID GROUP. - STATP points to the results of lstat on DIR. - Return 0 if successful, 1 if errors occurred. */ - -static int -change_dir_group (const char *dir, gid_t group, const struct stat *statp) -{ - char *name_space, *namep; - char *path; /* Full path of each entry to process. */ - unsigned dirlength; /* Length of `dir' and '\0'. */ - unsigned filelength; /* Length of each pathname to process. */ - unsigned pathlength; /* Bytes allocated for `path'. */ - int errors = 0; - - name_space = savedir (dir, statp->st_size); - if (name_space == NULL) - { - if (force_silent == 0) - error (0, errno, "%s", quote (dir)); - return 1; - } - - dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ - pathlength = dirlength + 1; - /* Give `path' a dummy value; it will be reallocated before first use. */ - path = xmalloc (pathlength); - strcpy (path, dir); - path[dirlength - 1] = '/'; - - for (namep = name_space; *namep; namep += filelength - dirlength) - { - filelength = dirlength + strlen (namep) + 1; - if (filelength > pathlength) - { - pathlength = filelength * 2; - path = xrealloc (path, pathlength); - } - strcpy (path + dirlength, namep); - errors |= change_file_group (0, path, group); - } - free (path); - free (name_space); - return errors; -} - void usage (int status) { @@ -367,6 +159,7 @@ main (int argc, char **argv) gid_t group; int errors = 0; int optc; + struct Chown_option chopt; program_name = argv[0]; setlocale (LC_ALL, ""); @@ -375,7 +168,7 @@ main (int argc, char **argv) atexit (close_stdout); - recurse = force_silent = 0; + chopt_init (&chopt); while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1) { @@ -387,22 +180,22 @@ main (int argc, char **argv) reference_file = optarg; break; case DEREFERENCE_OPTION: - change_symlinks = 0; + chopt.change_symlinks = 0; break; case 'R': - recurse = 1; + chopt.recurse = 1; break; case 'c': - verbosity = V_changes_only; + chopt.verbosity = V_changes_only; break; case 'f': - force_silent = 1; + chopt.force_silent = 1; break; case 'h': - change_symlinks = 1; + chopt.change_symlinks = 1; break; case 'v': - verbosity = V_high; + chopt.verbosity = V_high; break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -417,24 +210,26 @@ main (int argc, char **argv) usage (1); } - if (change_symlinks) - xstat = lstat; - else - xstat = stat; - if (reference_file) { struct stat ref_stats; if (stat (reference_file, &ref_stats)) error (1, errno, _("getting attributes of %s"), quote (reference_file)); + chopt.group_name = gid_to_name (ref_stats.st_gid); group = ref_stats.st_gid; } else - parse_group (argv[optind++], &group); + { + chopt.group_name = argv[optind++]; + parse_group (chopt.group_name, &group); + } for (; optind < argc; ++optind) - errors |= change_file_group (1, argv[optind], group); + errors |= change_file_owner (1, argv[optind], (uid_t) -1, group, + (uid_t) -1, (gid_t) -1, &chopt); + + chopt_free (&chopt); exit (errors); } |