chown: support -H -L -P if ENABLE_DESKTOP

chmod: cosmetic fixes
expr: smallish help for dumb compilers
This commit is contained in:
Denis Vlasenko 2007-03-08 13:37:43 +00:00
parent 6c939e0cb4
commit cd27c42552
3 changed files with 109 additions and 28 deletions

View File

@ -118,10 +118,12 @@ int chmod_main(int argc, char **argv)
/* /*
Security: chmod is too important and too subtle. Security: chmod is too important and too subtle.
This is a test script (busybox chmod versus coreutils). This is a test script (busybox chmod versus coreutils).
Run it in empty dir. Probably requires bash. Run it in empty directory.
#!/bin/sh #!/bin/sh
function create() { t1="/tmp/busybox chmod"
t2="/usr/bin/chmod"
create() {
rm -rf $1; mkdir $1 rm -rf $1; mkdir $1
( (
cd $1 || exit 1 cd $1 || exit 1
@ -134,17 +136,16 @@ function create() {
ln -s ../up dir/up ln -s ../up dir/up
) )
} }
function tst() { tst() {
(cd test1; $t1 $1) (cd test1; $t1 $1)
(cd test2; $t2 $1) (cd test2; $t2 $1)
(cd test1; ls -lR) >out1 (cd test1; ls -lR) >out1
(cd test2; ls -lR) >out2 (cd test2; ls -lR) >out2
echo "chmod $1" >out.diff echo "chmod $1" >out.diff
if ! diff -u out1 out2 >>out.diff; then exit 1; fi if ! diff -u out1 out2 >>out.diff; then exit 1; fi
mv out.diff out1.diff rm out.diff
} }
t1="/tmp/busybox chmod" echo "If script produced 'out.diff' file, then at least one testcase failed"
t2="/usr/bin/chmod"
create test1; create test2 create test1; create test2
tst "a+w file" tst "a+w file"
tst "a-w dir" tst "a-w dir"

View File

@ -17,25 +17,31 @@ static struct bb_uidgid_t ugid = { -1, -1 };
static int (*chown_func)(const char *, uid_t, gid_t) = chown; static int (*chown_func)(const char *, uid_t, gid_t) = chown;
#define OPT_STR ("Rh" USE_DESKTOP("vcfLHP"))
#define BIT_RECURSE 1
#define BIT_NODEREF 2
#define BIT_TRAVERSE 0x20
#define BIT_TRAVERSETOP (0x20|0x40)
#define OPT_RECURSE (option_mask32 & 1) #define OPT_RECURSE (option_mask32 & 1)
#define OPT_NODEREF (option_mask32 & 2) #define OPT_NODEREF (option_mask32 & 2)
#define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0)) #define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 0x04) SKIP_DESKTOP(0))
#define OPT_CHANGED (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0)) #define OPT_CHANGED (USE_DESKTOP(option_mask32 & 0x08) SKIP_DESKTOP(0))
#define OPT_QUIET (USE_DESKTOP(option_mask32 & 0x10) SKIP_DESKTOP(0)) #define OPT_QUIET (USE_DESKTOP(option_mask32 & 0x10) SKIP_DESKTOP(0))
#define OPT_STR ("Rh" USE_DESKTOP("vcf")) /* POSIX options
/* TODO:
* -H if a command line argument is a symbolic link to a directory, traverse it
* -L traverse every symbolic link to a directory encountered * -L traverse every symbolic link to a directory encountered
* -H if a command line argument is a symbolic link to a directory, traverse it
* -P do not traverse any symbolic links (default) * -P do not traverse any symbolic links (default)
*/ * We do not conform to the following:
* "Specifying more than one of -H, -L, and -P is not an error.
* The last option specified shall determine the behavior of the utility." */
/* -L */
#define OPT_TRAVERSE (USE_DESKTOP(option_mask32 & BIT_TRAVERSE) SKIP_DESKTOP(0))
/* -H or -L */
#define OPT_TRAVERSETOP (USE_DESKTOP(option_mask32 & BIT_TRAVERSETOP) SKIP_DESKTOP(0))
static int fileAction(const char *fileName, struct stat *statbuf, static int fileAction(const char *fileName, struct stat *statbuf,
void ATTRIBUTE_UNUSED *junk, int depth) void ATTRIBUTE_UNUSED *junk, int depth)
{ {
// TODO: -H/-L/-P
// if (depth ... && S_ISLNK(statbuf->st_mode)) ....
if (!chown_func(fileName, if (!chown_func(fileName,
(ugid.uid == (uid_t)-1) ? statbuf->st_uid : ugid.uid, (ugid.uid == (uid_t)-1) ? statbuf->st_uid : ugid.uid,
(ugid.gid == (gid_t)-1) ? statbuf->st_gid : ugid.gid) (ugid.gid == (gid_t)-1) ? statbuf->st_gid : ugid.gid)
@ -62,16 +68,31 @@ int chown_main(int argc, char **argv)
getopt32(argc, argv, OPT_STR); getopt32(argc, argv, OPT_STR);
argv += optind; argv += optind;
if (OPT_NODEREF) chown_func = lchown; /* This matches coreutils behavior (almost - see below) */
if (OPT_NODEREF
/* || (OPT_RECURSE && !OPT_TRAVERSETOP): */
USE_DESKTOP( || (option_mask32 & (BIT_RECURSE|BIT_TRAVERSETOP)) == BIT_RECURSE)
) {
chown_func = lchown;
}
parse_chown_usergroup_or_die(&ugid, argv[0]); parse_chown_usergroup_or_die(&ugid, argv[0]);
/* Ok, ready to do the deed now */ /* Ok, ready to do the deed now */
argv++; argv++;
do { do {
if (!recursive_action(*argv, char *arg = *argv;
OPT_RECURSE, // recurse
FALSE, // follow links: TODO: -H/-L/-P if (OPT_TRAVERSETOP) {
/* resolves symlink (even recursive) */
arg = xmalloc_realpath(arg);
if (!arg)
continue;
}
if (!recursive_action(arg,
OPT_RECURSE, // recurse
OPT_TRAVERSE, // follow links if -L
FALSE, // depth first FALSE, // depth first
fileAction, // file action fileAction, // file action
fileAction, // dir action fileAction, // dir action
@ -80,7 +101,66 @@ int chown_main(int argc, char **argv)
) { ) {
retval = EXIT_FAILURE; retval = EXIT_FAILURE;
} }
if (OPT_TRAVERSETOP)
free(arg);
} while (*++argv); } while (*++argv);
return retval; return retval;
} }
/*
Testcase. Run in empty directory.
#!/bin/sh
t1="/tmp/busybox chown"
t2="/usr/bin/chown"
create() {
rm -rf $1; mkdir $1
(
cd $1 || exit 1
mkdir dir dir2
>up
>file
>dir/file
>dir2/file
ln -s dir linkdir
ln -s file linkfile
ln -s ../up dir/linkup
ln -s ../dir2 dir/linkupdir2
)
chown -R 0:0 $1
}
tst() {
create test1
create test2
(cd test1; $t1 $1)
(cd test2; $t2 $1)
(cd test1; ls -lnR) >out1
(cd test2; ls -lnR) >out2
echo "chown $1" >out.diff
if ! diff -u out1 out2 >>out.diff; then exit 1; fi
rm out.diff
}
tst_for_each() {
tst "$1 1:1 file"
tst "$1 1:1 dir"
tst "$1 1:1 linkdir"
tst "$1 1:1 linkfile"
}
echo "If script produced 'out.diff' file, then at least one testcase failed"
# These match coreutils 6.8:
tst_for_each ""
tst_for_each "-R"
tst_for_each "-RP"
tst_for_each "-RL"
tst_for_each "-RH"
tst_for_each "-h"
tst_for_each "-hR"
tst_for_each "-hRP"
# Below: with "chown linkdir" coreutils 6.8 will chown linkdir _target_,
# we lchown _the link_. I believe we are "more correct".
#tst_for_each "-hRL"
#tst_for_each "-hRH"
*/

View File

@ -136,8 +136,8 @@ static int null(VALUE * v)
{ {
if (v->type == integer) if (v->type == integer)
return v->u.i == 0; return v->u.i == 0;
else /* string: */ /* string: */
return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0'); return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0');
} }
/* Coerce V to a string value (can't fail). */ /* Coerce V to a string value (can't fail). */
@ -194,16 +194,16 @@ static int cmp_common(VALUE * l, VALUE * r, int op)
cmpval = l->u.i - r->u.i; cmpval = l->u.i - r->u.i;
if (op == '<') if (op == '<')
return cmpval < 0; return cmpval < 0;
else if (op == ('L' + 'E')) if (op == ('L' + 'E'))
return cmpval <= 0; return cmpval <= 0;
else if (op == '=') if (op == '=')
return cmpval == 0; return cmpval == 0;
else if (op == '!') if (op == '!')
return cmpval != 0; return cmpval != 0;
else if (op == '>') if (op == '>')
return cmpval > 0; return cmpval > 0;
else /* >= */ /* >= */
return cmpval >= 0; return cmpval >= 0;
} }
/* The arithmetic operator handling functions. */ /* The arithmetic operator handling functions. */