summaryrefslogtreecommitdiff
path: root/src/chown.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2003-10-15 21:16:46 +0000
committerJim Meyering <jim@meyering.net>2003-10-15 21:16:46 +0000
commitfe9f5bdf77653c54bb6cd05faea98e6252558ccd (patch)
treee2b9f370ad35e014734f78bf5a72dd9210360444 /src/chown.c
parenta2740f057aa9d65c7a1fb507e3e0dabb761d4a54 (diff)
downloadcoreutils-fe9f5bdf77653c54bb6cd05faea98e6252558ccd.tar.xz
chown now accepts POSIX-mandated -H, -L, -P options and uses
fts to perform a directory traversal when -R is specified. Before, it used explicit recursion, and as such was limited by the user's stack size to handling hierarchies no deeper than about 30,000 levels. Include "userspec.h" and "fts_.h". (WRITTEN_BY): Add my name. (getpwnam, getgrnam, getgrgid): Remove declarations. (endpwent): Remove definition. (usage): Update (main): Handle new options. Call new function, chown_files rather than change_file_owner.
Diffstat (limited to 'src/chown.c')
-rw-r--r--src/chown.c100
1 files changed, 65 insertions, 35 deletions
diff --git a/src/chown.c b/src/chown.c
index 5d22de812..debd020f4 100644
--- a/src/chown.c
+++ b/src/chown.c
@@ -34,27 +34,17 @@
#include <getopt.h>
#include "system.h"
+#include "chown-core.h"
#include "error.h"
+#include "fts_.h"
#include "lchown.h"
#include "quote.h"
-#include "chown-core.h"
+#include "userspec.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "chown"
-#define WRITTEN_BY _("Written by David MacKenzie.")
-
-#ifndef _POSIX_VERSION
-struct passwd *getpwnam ();
-struct group *getgrnam ();
-struct group *getgrgid ();
-#endif
-
-#if ! HAVE_ENDPWENT
-# define endpwent() ((void) 0)
-#endif
-
-char *parse_user_spec ();
+#define WRITTEN_BY _("Written by David MacKenzie and Jim Meyering.")
/* The name the program was run with. */
char *program_name;
@@ -67,9 +57,9 @@ static char *reference_file;
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
- REFERENCE_FILE_OPTION = CHAR_MAX + 1,
+ FROM_OPTION = CHAR_MAX + 1,
DEREFERENCE_OPTION,
- FROM_OPTION
+ REFERENCE_FILE_OPTION
};
static struct option const long_options[] =
@@ -104,14 +94,15 @@ Usage: %s [OPTION]... OWNER[:[GROUP]] FILE...\n\
program_name, program_name, program_name);
fputs (_("\
Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
+With --reference, change the owner and group of each FILE to those of RFILE.\n\
\n\
-c, --changes like verbose but report only when a change is made\n\
--dereference affect the referent of each symbolic link, rather\n\
than the symbolic link itself\n\
"), stdout);
fputs (_("\
- -h, --no-dereference affect symbolic links instead of any referenced file\n\
- (available only on systems that can change the\n\
+ -h, --no-dereference affect each symbolic link instead of any referenced\n\
+ file (useful only on systems that can change the\n\
ownership of a symlink)\n\
"), stdout);
fputs (_("\
@@ -124,9 +115,22 @@ Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
fputs (_("\
-f, --silent, --quiet suppress most error messages\n\
--reference=RFILE use RFILE's owner and group rather than\n\
- the specified OWNER:GROUP values\n\
+ the specifying OWNER:GROUP values\n\
-R, --recursive operate on files and directories recursively\n\
-v, --verbose output a diagnostic for every file processed\n\
+\n\
+"), stdout);
+ fputs (_("\
+The following options modify how a hierarchy is traversed when the -R\n\
+option is also specified. If more than one is specified, only the final\n\
+one takes effect.\n\
+\n\
+ -H if a command line argument is a symbolic link\n\
+ to a directory, traverse it\n\
+ -L traverse every symbolic link to a directory\n\
+ encountered\n\
+ -P do not traverse any symbolic links (default)\n\
+\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -148,9 +152,10 @@ main (int argc, char **argv)
gid_t gid = (uid_t) -1; /* New gid; -1 if not to be changed. */
uid_t old_uid = (uid_t) -1; /* Old uid; -1 if unrestricted. */
gid_t old_gid = (uid_t) -1; /* Old gid; -1 if unrestricted. */
+ /* Bit flags that control how fts works. */
+ int bit_flags = FTS_PHYSICAL;
struct Chown_option chopt;
-
- int errors = 0;
+ int fail = 0;
int optc;
initialize_main (&argc, &argv);
@@ -163,18 +168,42 @@ main (int argc, char **argv)
chopt_init (&chopt);
- while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1)
+ while ((optc = getopt_long (argc, argv, "HLPRcfhv", long_options, NULL))
+ != -1)
{
switch (optc)
{
case 0:
break;
+
+ case 'H': /* Traverse command-line symlinks-to-directories. */
+ bit_flags |= FTS_COMFOLLOW;
+ break;
+
+ case 'L': /* Traverse all symlinks-to-directories. */
+ bit_flags &= ~FTS_PHYSICAL;
+ bit_flags |= FTS_LOGICAL;
+ break;
+
+ case 'P': /* Traverse no symlinks-to-directories. */
+ bit_flags |= FTS_PHYSICAL;
+ bit_flags &= ~FTS_LOGICAL;
+ bit_flags &= ~FTS_COMFOLLOW;
+ break;
+
+ case 'h': /* --no-dereference: affect symlinks */
+ chopt.affect_symlink_referent = false;
+ break;
+
+ case DEREFERENCE_OPTION: /* --dereference: affect the referent
+ of each symlink */
+ chopt.affect_symlink_referent = true;
+ break;
+
case REFERENCE_FILE_OPTION:
reference_file = optarg;
break;
- case DEREFERENCE_OPTION:
- chopt.dereference = DEREF_ALWAYS;
- break;
+
case FROM_OPTION:
{
char *u_dummy, *g_dummy;
@@ -185,21 +214,23 @@ main (int argc, char **argv)
error (EXIT_FAILURE, 0, "%s: %s", quote (optarg), e);
break;
}
+
case 'R':
- chopt.recurse = 1;
+ chopt.recurse = true;
break;
+
case 'c':
chopt.verbosity = V_changes_only;
break;
+
case 'f':
- chopt.force_silent = 1;
- break;
- case 'h':
- chopt.dereference = DEREF_NEVER;
+ chopt.force_silent = true;
break;
+
case 'v':
chopt.verbosity = V_high;
break;
+
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY);
default:
@@ -216,7 +247,6 @@ main (int argc, char **argv)
if (reference_file)
{
struct stat ref_stats;
-
if (stat (reference_file, &ref_stats))
error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
quote (reference_file));
@@ -240,11 +270,11 @@ main (int argc, char **argv)
optind++;
}
- for (; optind < argc; ++optind)
- errors |= change_file_owner (1, argv[optind], uid, gid,
- old_uid, old_gid, &chopt);
+ fail = chown_files (argv + optind, bit_flags,
+ uid, gid,
+ old_uid, old_gid, &chopt);
chopt_free (&chopt);
- exit (errors);
+ exit (fail ? EXIT_FAILURE : EXIT_SUCCESS);
}