*
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
/* BB_AUDIT SUSv3 defects - none? */
-/* BB_AUDIT GNU defects - unsupported long options. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */
+//usage:#define chown_trivial_usage
+//usage: "[-RhLHP"IF_DESKTOP("cvf")"]... OWNER[<.|:>[GROUP]] FILE..."
+//usage:#define chown_full_usage "\n\n"
+//usage: "Change the owner and/or group of each FILE to OWNER and/or GROUP\n"
+//usage: "\n -R Recurse"
+//usage: "\n -h Affect symlinks instead of symlink targets"
+//usage: "\n -L Traverse all symlinks to directories"
+//usage: "\n -H Traverse symlinks on command line only"
+//usage: "\n -P Don't traverse symlinks (default)"
+//usage: IF_DESKTOP(
+//usage: "\n -c List changed files"
+//usage: "\n -v List all files"
+//usage: "\n -f Hide errors"
+//usage: )
+//usage:
+//usage:#define chown_example_usage
+//usage: "$ ls -l /tmp/foo\n"
+//usage: "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n"
+//usage: "$ chown root /tmp/foo\n"
+//usage: "$ ls -l /tmp/foo\n"
+//usage: "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n"
+//usage: "$ chown root.root /tmp/foo\n"
+//usage: "ls -l /tmp/foo\n"
+//usage: "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
+
#include "libbb.h"
/* This is a NOEXEC applet. Be very careful! */
#define BIT_TRAVERSE_TOP (0x20|0x40)
#define OPT_TRAVERSE_TOP (IF_DESKTOP(opt & BIT_TRAVERSE_TOP) IF_NOT_DESKTOP(0))
+#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS
+static const char chown_longopts[] ALIGN1 =
+ "recursive\0" No_argument "R"
+ "dereference\0" No_argument "\xff"
+ "no-dereference\0" No_argument "h"
+# if ENABLE_DESKTOP
+ "changes\0" No_argument "c"
+ "silent\0" No_argument "f"
+ "quiet\0" No_argument "f"
+ "verbose\0" No_argument "v"
+# endif
+ ;
+#endif
+
typedef int (*chown_fptr)(const char *, uid_t, gid_t);
struct param_t {
{
#define param (*(struct param_t*)vparam)
#define opt option_mask32
- uid_t u = (param.ugid.uid == (uid_t)-1) ? statbuf->st_uid : param.ugid.uid;
- gid_t g = (param.ugid.gid == (gid_t)-1) ? statbuf->st_gid : param.ugid.gid;
+ uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid;
+ gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid;
if (param.chown_func(fileName, u, g) == 0) {
if (OPT_VERBOSE
return TRUE;
}
if (!OPT_QUIET)
- bb_simple_perror_msg(fileName); /* A filename can have % in it... */
+ bb_simple_perror_msg(fileName);
return FALSE;
#undef opt
#undef param
int opt, flags;
struct param_t param;
- param.ugid.uid = -1;
- param.ugid.gid = -1;
- param.chown_func = chown;
+ /* Just -1 might not work: uid_t may be unsigned long */
+ param.ugid.uid = -1L;
+ param.ugid.gid = -1L;
+#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS
+ applet_long_options = chown_longopts;
+#endif
opt_complementary = "-2";
opt = getopt32(argv, OPT_STR);
argv += optind;
/* This matches coreutils behavior (almost - see below) */
+ param.chown_func = chown;
if (OPT_NODEREF
/* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */
IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
parse_chown_usergroup_or_die(¶m.ugid, argv[0]);
/* Ok, ready to do the deed now */
- argv++;
- do {
+ while (*++argv) {
if (!recursive_action(*argv,
flags, /* flags */
fileAction, /* file action */
) {
retval = EXIT_FAILURE;
}
- } while (*++argv);
+ }
return retval;
}