8 |
*/ |
*/ |
9 |
|
|
10 |
/* BB_AUDIT SUSv3 defects - none? */ |
/* BB_AUDIT SUSv3 defects - none? */ |
|
/* BB_AUDIT GNU defects - unsupported long options. */ |
|
11 |
/* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */ |
/* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */ |
12 |
|
|
13 |
#include "libbb.h" |
#include "libbb.h" |
15 |
/* This is a NOEXEC applet. Be very careful! */ |
/* This is a NOEXEC applet. Be very careful! */ |
16 |
|
|
17 |
|
|
18 |
#define OPT_STR ("Rh" USE_DESKTOP("vcfLHP")) |
#define OPT_STR ("Rh" IF_DESKTOP("vcfLHP")) |
19 |
#define BIT_RECURSE 1 |
#define BIT_RECURSE 1 |
20 |
#define OPT_RECURSE (opt & 1) |
#define OPT_RECURSE (opt & 1) |
21 |
#define OPT_NODEREF (opt & 2) |
#define OPT_NODEREF (opt & 2) |
22 |
#define OPT_VERBOSE (USE_DESKTOP(opt & 0x04) SKIP_DESKTOP(0)) |
#define OPT_VERBOSE (IF_DESKTOP(opt & 0x04) IF_NOT_DESKTOP(0)) |
23 |
#define OPT_CHANGED (USE_DESKTOP(opt & 0x08) SKIP_DESKTOP(0)) |
#define OPT_CHANGED (IF_DESKTOP(opt & 0x08) IF_NOT_DESKTOP(0)) |
24 |
#define OPT_QUIET (USE_DESKTOP(opt & 0x10) SKIP_DESKTOP(0)) |
#define OPT_QUIET (IF_DESKTOP(opt & 0x10) IF_NOT_DESKTOP(0)) |
25 |
/* POSIX options |
/* POSIX options |
26 |
* -L traverse every symbolic link to a directory encountered |
* -L traverse every symbolic link to a directory encountered |
27 |
* -H if a command line argument is a symbolic link to a directory, traverse it |
* -H if a command line argument is a symbolic link to a directory, traverse it |
31 |
* The last option specified shall determine the behavior of the utility." */ |
* The last option specified shall determine the behavior of the utility." */ |
32 |
/* -L */ |
/* -L */ |
33 |
#define BIT_TRAVERSE 0x20 |
#define BIT_TRAVERSE 0x20 |
34 |
#define OPT_TRAVERSE (USE_DESKTOP(opt & BIT_TRAVERSE) SKIP_DESKTOP(0)) |
#define OPT_TRAVERSE (IF_DESKTOP(opt & BIT_TRAVERSE) IF_NOT_DESKTOP(0)) |
35 |
/* -H or -L */ |
/* -H or -L */ |
36 |
#define BIT_TRAVERSE_TOP (0x20|0x40) |
#define BIT_TRAVERSE_TOP (0x20|0x40) |
37 |
#define OPT_TRAVERSE_TOP (USE_DESKTOP(opt & BIT_TRAVERSE_TOP) SKIP_DESKTOP(0)) |
#define OPT_TRAVERSE_TOP (IF_DESKTOP(opt & BIT_TRAVERSE_TOP) IF_NOT_DESKTOP(0)) |
38 |
|
|
39 |
|
#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS |
40 |
|
static const char chown_longopts[] ALIGN1 = |
41 |
|
"recursive\0" No_argument "R" |
42 |
|
"dereference\0" No_argument "\xff" |
43 |
|
"no-dereference\0" No_argument "h" |
44 |
|
# if ENABLE_DESKTOP |
45 |
|
"changes\0" No_argument "c" |
46 |
|
"silent\0" No_argument "f" |
47 |
|
"quiet\0" No_argument "f" |
48 |
|
"verbose\0" No_argument "v" |
49 |
|
# endif |
50 |
|
; |
51 |
|
#endif |
52 |
|
|
53 |
typedef int (*chown_fptr)(const char *, uid_t, gid_t); |
typedef int (*chown_fptr)(const char *, uid_t, gid_t); |
54 |
|
|
62 |
{ |
{ |
63 |
#define param (*(struct param_t*)vparam) |
#define param (*(struct param_t*)vparam) |
64 |
#define opt option_mask32 |
#define opt option_mask32 |
65 |
uid_t u = (param.ugid.uid == (uid_t)-1) ? statbuf->st_uid : param.ugid.uid; |
uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid; |
66 |
gid_t g = (param.ugid.gid == (gid_t)-1) ? statbuf->st_gid : param.ugid.gid; |
gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid; |
67 |
|
|
68 |
if (param.chown_func(fileName, u, g) == 0) { |
if (param.chown_func(fileName, u, g) == 0) { |
69 |
if (OPT_VERBOSE |
if (OPT_VERBOSE |
75 |
return TRUE; |
return TRUE; |
76 |
} |
} |
77 |
if (!OPT_QUIET) |
if (!OPT_QUIET) |
78 |
bb_simple_perror_msg(fileName); /* A filename can have % in it... */ |
bb_simple_perror_msg(fileName); |
79 |
return FALSE; |
return FALSE; |
80 |
#undef opt |
#undef opt |
81 |
#undef param |
#undef param |
87 |
int opt, flags; |
int opt, flags; |
88 |
struct param_t param; |
struct param_t param; |
89 |
|
|
90 |
param.ugid.uid = -1; |
/* Just -1 might not work: uid_t may be unsigned long */ |
91 |
param.ugid.gid = -1; |
param.ugid.uid = -1L; |
92 |
param.chown_func = chown; |
param.ugid.gid = -1L; |
93 |
|
|
94 |
|
#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS |
95 |
|
applet_long_options = chown_longopts; |
96 |
|
#endif |
97 |
opt_complementary = "-2"; |
opt_complementary = "-2"; |
98 |
opt = getopt32(argv, OPT_STR); |
opt = getopt32(argv, OPT_STR); |
99 |
argv += optind; |
argv += optind; |
100 |
|
|
101 |
/* This matches coreutils behavior (almost - see below) */ |
/* This matches coreutils behavior (almost - see below) */ |
102 |
|
param.chown_func = chown; |
103 |
if (OPT_NODEREF |
if (OPT_NODEREF |
104 |
/* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */ |
/* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */ |
105 |
USE_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE) |
IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE) |
106 |
) { |
) { |
107 |
param.chown_func = lchown; |
param.chown_func = lchown; |
108 |
} |
} |
118 |
parse_chown_usergroup_or_die(¶m.ugid, argv[0]); |
parse_chown_usergroup_or_die(¶m.ugid, argv[0]); |
119 |
|
|
120 |
/* Ok, ready to do the deed now */ |
/* Ok, ready to do the deed now */ |
121 |
argv++; |
while (*++argv) { |
|
do { |
|
122 |
if (!recursive_action(*argv, |
if (!recursive_action(*argv, |
123 |
flags, /* flags */ |
flags, /* flags */ |
124 |
fileAction, /* file action */ |
fileAction, /* file action */ |
128 |
) { |
) { |
129 |
retval = EXIT_FAILURE; |
retval = EXIT_FAILURE; |
130 |
} |
} |
131 |
} while (*++argv); |
} |
132 |
|
|
133 |
return retval; |
return retval; |
134 |
} |
} |