mirror of
https://github.com/coreutils/coreutils.git
synced 2024-11-28 04:24:45 +08:00
new feature: rm accepts new option: --one-file-system
Suggested by Steve McIntyre in <http://bugs.debian.org/392925>. * src/remove.h (struct rm_options) [one_file_system]: New member. * src/rm.c (rm_option_init): Initialize it. (usage): Document the option. * src/mv.c (rm_option_init): Likewise. * src/remove.c (remove_dir): With --one-file-system and --recursive, for each directory command line argument, do not affect a file system different from that of the starting directory. And give a diagnostic. * src/rm.c (ONE_FILE_SYSTEM): New enum. (main): Handle new option. * tests/rm/one-file-system: Test the above. * tests/rm/Makefile.am (TESTS): Add one-file-system. * tests/Makefile.am (check-root): Add the rm/one-file-system test to the list. (EXTRA_DIST): Add other-fs-tmpdir. * tests/mv/setup: Removed. Renamed to... * tests/other-fs-tmpdir: ...this new file. * tests/mv/Makefile.am (EXTRA_DIST): Remove setup. * tests/mv/acl: Reflect renaming: use ../other-fs-tmpdir. * tests/mv/backup-is-src: Likewise. * tests/mv/hard-link-1: Likewise. * tests/mv/leak-fd: Likewise. * tests/mv/mv-special-1: Likewise. * tests/mv/part-fail: Likewise. * tests/mv/part-hardlink: Likewise. * tests/mv/part-rename: Likewise. * tests/mv/part-symlink: Likewise. * tests/mv/partition-perm: Likewise. * tests/mv/to-symlink: Likewise. * tests/mv/into-self-2: Likewise. [doc/ChangeLog] * coreutils.texi (rm invocation): Describe --one-file-system.
This commit is contained in:
parent
ba6b1acefd
commit
5e42576c01
33
ChangeLog
33
ChangeLog
@ -1,5 +1,38 @@
|
||||
2006-10-24 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* NEWS: new feature: rm accepts new option: --one-file-system
|
||||
Suggested by Steve McIntyre in <http://bugs.debian.org/392925>.
|
||||
* src/remove.h (struct rm_options) [one_file_system]: New member.
|
||||
* src/rm.c (rm_option_init): Initialize it.
|
||||
(usage): Document the option.
|
||||
* src/mv.c (rm_option_init): Likewise.
|
||||
* src/remove.c (remove_dir): With --one-file-system and --recursive,
|
||||
for each directory command line argument, do not affect a file system
|
||||
different from that of the starting directory. And give a diagnostic.
|
||||
* src/rm.c (ONE_FILE_SYSTEM): New enum.
|
||||
(main): Handle new option.
|
||||
* tests/rm/one-file-system: Test the above.
|
||||
* tests/rm/Makefile.am (TESTS): Add one-file-system.
|
||||
* tests/Makefile.am (check-root): Add the rm/one-file-system
|
||||
test to the list.
|
||||
(EXTRA_DIST): Add other-fs-tmpdir.
|
||||
|
||||
* tests/mv/setup: Removed. Renamed to...
|
||||
* tests/other-fs-tmpdir: ...this new file.
|
||||
* tests/mv/Makefile.am (EXTRA_DIST): Remove setup.
|
||||
* tests/mv/acl: Reflect renaming: use ../other-fs-tmpdir.
|
||||
* tests/mv/backup-is-src: Likewise.
|
||||
* tests/mv/hard-link-1: Likewise.
|
||||
* tests/mv/leak-fd: Likewise.
|
||||
* tests/mv/mv-special-1: Likewise.
|
||||
* tests/mv/part-fail: Likewise.
|
||||
* tests/mv/part-hardlink: Likewise.
|
||||
* tests/mv/part-rename: Likewise.
|
||||
* tests/mv/part-symlink: Likewise.
|
||||
* tests/mv/partition-perm: Likewise.
|
||||
* tests/mv/to-symlink: Likewise.
|
||||
* tests/mv/into-self-2: Likewise.
|
||||
|
||||
Don't let a failure in one test stop "make -k" from running the others.
|
||||
* tests/Makefile.am (t1 t2 t3 t4 t5): New targets.
|
||||
(check-root): Depend on them, rather than executing the five
|
||||
|
4
NEWS
4
NEWS
@ -2,6 +2,10 @@ GNU coreutils NEWS -*- outline -*-
|
||||
|
||||
* Major changes in release 6.5-cvs (2006-??-??)
|
||||
|
||||
** New features
|
||||
|
||||
rm accepts a new option: --one-file-system
|
||||
|
||||
|
||||
* Major changes in release 6.4 (2006-10-22) [stable]
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
2006-10-23 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* coreutils.texi (rm invocation): Describe --one-file-system.
|
||||
|
||||
2006-09-26 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* coreutils.texi (groups invocation): "groups" no longer prefixes
|
||||
|
@ -7772,6 +7772,24 @@ removal is requested. Equivalent to @option{-I}.
|
||||
Specifying @option{--interactive} and no @var{when} is equivalent to
|
||||
@option{--interactive=always}.
|
||||
|
||||
@itemx --one-file-system
|
||||
@opindex --one-file-system
|
||||
@cindex one file system, restricting @command{rm} to
|
||||
When removing a hierarchy recursively, skip any directory that is on a
|
||||
file system different from that of the corresponding command line argument.
|
||||
|
||||
This option is useful when removing a build ``chroot'' hierarchy,
|
||||
which normally contains no valuable data. However, it is not uncommon
|
||||
to bind-mount @file{/home} into such a hierarchy, to make it easier to
|
||||
use one's start-up file. The catch is that it's easy to forget to
|
||||
unmount @file{/home}. Then, when you use @command{rm -rf} to remove
|
||||
your normally throw-away chroot, that command will remove everything
|
||||
under @file{/home}, too.
|
||||
Use the @option{--one-file-system} option, and it will
|
||||
warn about and skip directories on other file systems.
|
||||
Of course, this will not save your @file{/home} if it and your
|
||||
chroot happen to be on the same file system.
|
||||
|
||||
@itemx --preserve-root
|
||||
@opindex --preserve-root
|
||||
@cindex root directory, disallow recursive destruction
|
||||
|
1
src/mv.c
1
src/mv.c
@ -94,6 +94,7 @@ rm_option_init (struct rm_options *x)
|
||||
x->ignore_missing_files = false;
|
||||
x->root_dev_ino = NULL;
|
||||
x->recursive = true;
|
||||
x->one_file_system = false;
|
||||
|
||||
/* Should we prompt for removal, too? No. Prompting for the `move'
|
||||
part is enough. It implies removal. */
|
||||
|
25
src/remove.c
25
src/remove.c
@ -1298,6 +1298,7 @@ remove_dir (int fd_cwd, Dirstack_state *ds, char const *dir,
|
||||
struct rm_options const *x, int *cwd_errno)
|
||||
{
|
||||
enum RM_status status;
|
||||
dev_t current_dev = dir_st->st_dev;
|
||||
|
||||
/* There is a race condition in that an attacker could replace the nonempty
|
||||
directory, DIR, with a symlink between the preceding call to rmdir
|
||||
@ -1359,15 +1360,31 @@ remove_dir (int fd_cwd, Dirstack_state *ds, char const *dir,
|
||||
}
|
||||
if (subdir)
|
||||
{
|
||||
AD_push (dirfd (dirp), ds, subdir, &subdir_sb);
|
||||
AD_INIT_OTHER_MEMBERS ();
|
||||
if ( ! x->one_file_system
|
||||
|| subdir_sb.st_dev == current_dev)
|
||||
{
|
||||
AD_push (dirfd (dirp), ds, subdir, &subdir_sb);
|
||||
AD_INIT_OTHER_MEMBERS ();
|
||||
free (subdir);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Here, --one-file-system is in effect, and with remove_cwd_entries'
|
||||
traversal into the current directory, (known as SUBDIR, from ..),
|
||||
DIRP's device number is different from CURRENT_DEV. Arrange not
|
||||
to do anything more with this hierarchy. */
|
||||
error (0, errno, _("skipping %s, since it's on a different device"),
|
||||
quote (full_filename (subdir)));
|
||||
free (subdir);
|
||||
continue;
|
||||
AD_mark_current_as_unremovable (ds);
|
||||
tmp_status = RM_ERROR;
|
||||
UPDATE_STATUS (status, tmp_status);
|
||||
}
|
||||
|
||||
/* Execution reaches this point when we've removed the last
|
||||
removable entry from the current directory. */
|
||||
removable entry from the current directory -- or, with
|
||||
--one-file-system, when the current directory is on a
|
||||
different file system. */
|
||||
{
|
||||
/* The name of the directory that we have just processed,
|
||||
nominally removing all of its contents. */
|
||||
|
@ -30,6 +30,14 @@ struct rm_options
|
||||
/* If true, query the user about whether to remove each file. */
|
||||
bool interactive;
|
||||
|
||||
/* If true, do not traverse into (or remove) any directory that is
|
||||
on a file system (i.e., that has a different device number) other
|
||||
than that of the corresponding command line argument. Note that
|
||||
even without this option, rm will fail in the end, due to its
|
||||
probable inability to remove the mount point. But there, the
|
||||
diagnostic comes too late -- after removing all contents. */
|
||||
bool one_file_system;
|
||||
|
||||
/* If true, recursively remove directories. */
|
||||
bool recursive;
|
||||
|
||||
|
12
src/rm.c
12
src/rm.c
@ -72,6 +72,7 @@ char *program_name;
|
||||
enum
|
||||
{
|
||||
INTERACTIVE_OPTION = CHAR_MAX + 1,
|
||||
ONE_FILE_SYSTEM,
|
||||
NO_PRESERVE_ROOT,
|
||||
PRESERVE_ROOT,
|
||||
PRESUME_INPUT_TTY_OPTION
|
||||
@ -90,6 +91,7 @@ static struct option const long_opts[] =
|
||||
{"force", no_argument, NULL, 'f'},
|
||||
{"interactive", optional_argument, NULL, INTERACTIVE_OPTION},
|
||||
|
||||
{"one-file-system", no_argument, NULL, ONE_FILE_SYSTEM},
|
||||
{"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
|
||||
{"preserve-root", no_argument, NULL, PRESERVE_ROOT},
|
||||
|
||||
@ -168,6 +170,11 @@ Remove (unlink) the FILE(s).\n\
|
||||
while still giving protection against most mistakes\n\
|
||||
--interactive[=WHEN] prompt according to WHEN: never, once (-I), or\n\
|
||||
always (-i). Without WHEN, prompt always\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--one-file-system when removing a hierarchy recursively, skip any\n\
|
||||
directory that is on a file system different from\n\
|
||||
that of the corresponding command line argument\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--no-preserve-root do not treat `/' specially\n\
|
||||
@ -207,6 +214,7 @@ rm_option_init (struct rm_options *x)
|
||||
{
|
||||
x->ignore_missing_files = false;
|
||||
x->interactive = false;
|
||||
x->one_file_system = false;
|
||||
x->recursive = false;
|
||||
x->root_dev_ino = NULL;
|
||||
x->stdin_tty = isatty (STDIN_FILENO);
|
||||
@ -299,6 +307,10 @@ main (int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
case ONE_FILE_SYSTEM:
|
||||
x.one_file_system = true;
|
||||
break;
|
||||
|
||||
case NO_PRESERVE_ROOT:
|
||||
preserve_root = false;
|
||||
break;
|
||||
|
@ -15,7 +15,8 @@ TESTS_ENVIRONMENT = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(TESTS) Coreutils.pm Makefile.am.in README acl envvar-check \
|
||||
expensive group-names input-tty lang-default mk-script priv-check \
|
||||
expensive group-names input-tty lang-default mk-script \
|
||||
other-fs-tmpdir priv-check \
|
||||
rwx-to-mode sample-test setgid-check sparse-file \
|
||||
umask-check very-expensive
|
||||
|
||||
@ -28,8 +29,9 @@ SUBDIRS = \
|
||||
tsort unexpand uniq wc
|
||||
## N O T E :: Please do not add new directories.
|
||||
|
||||
.PHONY: check-root t1 t2 t3 t4 t5
|
||||
check-root: t1 t2 t3 t4 t5
|
||||
all_t = t1 t2 t3 t4 t5 t6
|
||||
.PHONY: check-root $(all_t)
|
||||
check-root: $(all_t)
|
||||
|
||||
t1:
|
||||
cd chown && $(MAKE) check TESTS=basic
|
||||
@ -41,6 +43,8 @@ t4:
|
||||
cd rm && $(MAKE) check TESTS=fail-2eperm
|
||||
t5:
|
||||
cd tail-2 && $(MAKE) check TESTS=append-only
|
||||
t6:
|
||||
cd rm && $(MAKE) check TESTS=one-file-system
|
||||
|
||||
check-recursive: root-hint
|
||||
|
||||
|
@ -43,7 +43,7 @@ TESTS = \
|
||||
i-1 hard-link-1 force partition-perm to-symlink dir-file diag \
|
||||
part-symlink part-rename trailing-slash
|
||||
|
||||
EXTRA_DIST = $(TESTS) setup vfat
|
||||
EXTRA_DIST = $(TESTS) vfat
|
||||
TESTS_ENVIRONMENT = \
|
||||
PERL="$(PERL)" \
|
||||
PATH="$(VG_PATH_PREFIX)`pwd`/../../src$(PATH_SEPARATOR)$$PATH" \
|
||||
|
@ -20,7 +20,7 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
. $srcdir/../acl
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
# Make sure we get English translations.
|
||||
. $srcdir/../lang-default
|
||||
|
||||
|
@ -23,7 +23,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
|
||||
if test -z "$other_partition_tmpdir"; then
|
||||
|
@ -24,7 +24,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
# Make sure we get English translations.
|
||||
. $srcdir/../lang-default
|
||||
|
||||
|
@ -25,7 +25,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
|
||||
if test -z "$other_partition_tmpdir"; then
|
||||
|
@ -30,7 +30,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
PRIV_CHECK_ARG=require-non-root . $srcdir/../priv-check
|
||||
|
||||
|
@ -29,7 +29,7 @@ tmp=mv-spec.$$
|
||||
trap 'status=$?; cd "$pwd" && exec 1>&2; rm -rf $tmp $other_partition_tmpdir && exit $status' 0
|
||||
trap '(exit $?); exit' 1 2 13 15
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
# Make sure we get English translations.
|
||||
. $srcdir/../lang-default
|
||||
|
@ -26,7 +26,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
. $srcdir/../lang-default
|
||||
PRIV_CHECK_ARG=require-non-root . $srcdir/../priv-check
|
||||
|
@ -26,7 +26,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
|
||||
pwd=`pwd`
|
||||
|
@ -25,7 +25,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
|
||||
pwd=`pwd`
|
||||
|
@ -32,7 +32,7 @@ trap '(exit $?); exit' 1 2 13 15
|
||||
|
||||
pwd_tmp=$pwd/$tmp
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
# Make sure the programs use C-locale formats/translations.
|
||||
. $srcdir/../lang-default
|
||||
|
@ -23,7 +23,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
. $srcdir/../lang-default
|
||||
|
||||
|
@ -24,7 +24,7 @@ if test "$VERBOSE" = yes; then
|
||||
mv --version
|
||||
fi
|
||||
|
||||
. $srcdir/setup
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
. $srcdir/../envvar-check
|
||||
|
||||
if test -z "$other_partition_tmpdir"; then
|
||||
|
@ -21,6 +21,7 @@
|
||||
AUTOMAKE_OPTIONS = 1.1 gnits
|
||||
|
||||
TESTS = \
|
||||
one-file-system \
|
||||
ignorable \
|
||||
readdir-bug \
|
||||
empty-inacc \
|
||||
|
67
tests/rm/one-file-system
Executable file
67
tests/rm/one-file-system
Executable file
@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
# Demonstrate rm's new --one-file-system option.
|
||||
|
||||
# Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
rm --version
|
||||
fi
|
||||
|
||||
PRIV_CHECK_ARG=require-root . $srcdir/../priv-check
|
||||
. $srcdir/../lang-default
|
||||
. $srcdir/../other-fs-tmpdir
|
||||
|
||||
if test -z "$other_partition_tmpdir"; then
|
||||
(exit 77); exit 77
|
||||
fi
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
t0="$t0 $other_partition_tmpdir"
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
t=$other_partition_tmpdir
|
||||
mkdir -p a/b $t/y
|
||||
mount --bind $t a/b || framework_failure=1
|
||||
|
||||
cat <<\EOF > exp || framework_failure=1
|
||||
rm: skipping `a/b', since it's on a different device
|
||||
EOF
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
rm --one-file-system -rf a 2> out && fail=1
|
||||
test -d $t/y || fail=1
|
||||
umount $t
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
Loading…
Reference in New Issue
Block a user