Skip to content

Conversation

@shskwmt
Copy link
Contributor

@shskwmt shskwmt commented Mar 25, 2025

Fixes #7011

Implement --one-file-system and --preserve-root=all options for the rm command.

Comment on lines 565 to 580
match validate_single_filesystem(path) {
Ok(()) => true,
Err(additional_reason) => {
if !additional_reason.is_empty() {
show_error!("{}", additional_reason);
}
show_error!(
"skipping {}, since it's on a different device",
path.quote()
);
if options.preserve_root == PreserveRoot::YesAll {
show_error!("and --preserve-root=all is in effect");
}
false
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can probably be simplified with something like:

Suggested change
match validate_single_filesystem(path) {
Ok(()) => true,
Err(additional_reason) => {
if !additional_reason.is_empty() {
show_error!("{}", additional_reason);
}
show_error!(
"skipping {}, since it's on a different device",
path.quote()
);
if options.preserve_root == PreserveRoot::YesAll {
show_error!("and --preserve-root=all is in effect");
}
false
}
}
let result = validate_single_filesystem(path);
if result.is_ok() {
return true;
}
if let Err(additional_reason) = result {
if !additional_reason.is_empty() {
show_error!("{}", additional_reason);
}
}
show_error!(
"skipping {}, since it's on a different device",
path.quote()
);
if options.preserve_root == PreserveRoot::YesAll {
show_error!("and --preserve-root=all is in effect");
}
false

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing that out! I've implemented the suggested simplification.

c091369

@github-actions
Copy link

GNU testsuite comparison:

Skip an intermittent issue tests/misc/stdbuf (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/timeout/timeout (passes in this run but fails in the 'main' branch)

@sylvestre
Copy link
Contributor

some jobs are failing :)

@github-actions
Copy link

GNU testsuite comparison:

Skip an intermittent issue tests/timeout/timeout (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/misc/stdbuf (passes in this run but fails in the 'main' branch)

@github-actions
Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/misc/stdbuf (passes in this run but fails in the 'main' branch)

@sylvestre
Copy link
Contributor

does
bash -v util/run-gnu-test.sh tests/rm/one-file-system.sh
passes on your system ?

@github-actions
Copy link

GNU testsuite comparison:

Skip an intermittent issue tests/misc/stdbuf (fails in this run but passes in the 'main' branch)

@shskwmt
Copy link
Contributor Author

shskwmt commented Mar 29, 2025

The following is the test result. It has passed.

PASS: tests/rm/one-file-system.sh
============================================================================
Testsuite summary for GNU coreutils 9.6-dirty
============================================================================
# TOTAL: 1
# PASS:  1
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================

@shskwmt
Copy link
Contributor Author

shskwmt commented Mar 30, 2025

I tried again and it failed, so I will fix it.

FAIL: tests/rm/one-file-system
==============================

--- exp 2025-03-31 00:11:32.336030079 +0900
+++ out 2025-03-31 00:11:32.336030079 +0900
@@ -1 +1 @@
-rm: skipping 'a', since it's on a different device
+rm: cannot remove 'a/b': Device or resource busy
FAIL tests/rm/one-file-system.sh (exit status: 1)

============================================================================
Testsuite summary for GNU coreutils 9.6-dirty
============================================================================
# TOTAL: 1
# PASS:  0
# SKIP:  0
# XFAIL: 0
# FAIL:  1
# XPASS: 0
# ERROR: 0
============================================================================
See ./tests/test-suite.log for debugging.
Some test(s) failed.  Please report this to [email protected],
together with the test-suite.log file (gzipped) and your system
information.  Thanks.
============================================================================

@github-actions
Copy link

github-actions bot commented Apr 3, 2025

GNU testsuite comparison:

GNU test failed: tests/chgrp/default-no-deref. tests/chgrp/default-no-deref is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/chgrp/recurse. tests/chgrp/recurse is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/chmod/thru-dangling. tests/chmod/thru-dangling is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/chown/deref. tests/chown/deref is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/chown/preserve-root. tests/chown/preserve-root is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/abuse. tests/cp/abuse is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/attr-existing. tests/cp/attr-existing is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/cp-HL. tests/cp/cp-HL is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/cross-dev-symlink. tests/cp/cross-dev-symlink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/keep-directory-symlink. tests/cp/keep-directory-symlink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/link-deref. tests/cp/link-deref is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/link-no-deref. tests/cp/link-no-deref is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/link-preserve. tests/cp/link-preserve is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/link-symlink. tests/cp/link-symlink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/no-deref-link1. tests/cp/no-deref-link1 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/no-deref-link2. tests/cp/no-deref-link2 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/no-deref-link3. tests/cp/no-deref-link3 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/preserve-slink-time. tests/cp/preserve-slink-time is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/r-vs-symlink. tests/cp/r-vs-symlink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/same-file. tests/cp/same-file is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/slink-2-slink. tests/cp/slink-2-slink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/thru-dangling. tests/cp/thru-dangling is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/dd/misc. tests/dd/misc is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/du/deref. tests/du/deref is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/du/deref-args. tests/du/deref-args is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/du/long-sloop. tests/du/long-sloop is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/du/no-deref. tests/du/no-deref is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/du/one-file-system. tests/du/one-file-system is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/du/trailing-slash. tests/du/trailing-slash is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/env/env. tests/env/env is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ln/hard-to-sym. tests/ln/hard-to-sym is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ln/relative. tests/ln/relative is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ln/sf-1. tests/ln/sf-1 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ln/target-1. tests/ln/target-1 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/classify. tests/ls/classify is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/dangle. tests/ls/dangle is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/dired. tests/ls/dired is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/file-type. tests/ls/file-type is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/follow-slink. tests/ls/follow-slink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/group-dirs. tests/ls/group-dirs is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/hyperlink. tests/ls/hyperlink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/no-arg. tests/ls/no-arg is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/selinux-segfault. tests/ls/selinux-segfault is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/slink-acl. tests/ls/slink-acl is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/stat-dtype. tests/ls/stat-dtype is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/stat-failed. tests/ls/stat-failed is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/stat-free-color. tests/ls/stat-free-color is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/symlink-loop. tests/ls/symlink-loop is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/ls/symlink-quote. tests/ls/symlink-quote is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/misc/realpath. tests/misc/realpath is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/mv/atomic. tests/mv/atomic is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/mv/part-symlink. tests/mv/part-symlink is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/mv/symlink-onto-hardlink-to-self. tests/mv/symlink-onto-hardlink-to-self is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/pwd/pwd-option. tests/pwd/pwd-option is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/readlink/can-e. tests/readlink/can-e is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/readlink/can-f. tests/readlink/can-f is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/readlink/can-m. tests/readlink/can-m is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/readlink/multi. tests/readlink/multi is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/readlink/readlink-fp-loop. tests/readlink/readlink-fp-loop is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/readlink/readlink-root. tests/readlink/readlink-root is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/readlink/rl-1. tests/readlink/rl-1 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/rm/ext3-perf. tests/rm/ext3-perf is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/rm/fail-eacces. tests/rm/fail-eacces is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/rm/rm2. tests/rm/rm2 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/rm/rm3. tests/rm/rm3 is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/rmdir/symlink-errors. tests/rmdir/symlink-errors is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/stat/stat-slash. tests/stat/stat-slash is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/no-dereference. tests/touch/no-dereference is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/trailing-slash. tests/touch/trailing-slash is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/truncate/truncate-dangling-symlink. tests/truncate/truncate-dangling-symlink is passing on 'main'. Maybe you have to rebase?
Skipping an intermittent issue tests/timeout/timeout (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/rm/one-file-system is no longer failing!

@github-actions
Copy link

github-actions bot commented Apr 3, 2025

GNU testsuite comparison:

Skipping an intermittent issue tests/timeout/timeout (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/rm/one-file-system is no longer failing!

@sylvestre sylvestre force-pushed the rm-one-file-system branch from 2b9e697 to 3882f38 Compare April 4, 2025 16:49
@github-actions
Copy link

github-actions bot commented Apr 4, 2025

GNU testsuite comparison:

Skipping an intermittent issue tests/misc/stdbuf (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/timeout/timeout (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/rm/one-file-system is no longer failing!

@sylvestre
Copy link
Contributor

Sorry, i think i made a mistake with the conflict resolution :( could you please fix it? thanks

@shskwmt
Copy link
Contributor Author

shskwmt commented May 4, 2025

No warries, I'll fix it.
Thanks for reaching out!

@shskwmt shskwmt force-pushed the rm-one-file-system branch from 5e09b83 to 42a24fb Compare May 7, 2025 14:43
@github-actions
Copy link

github-actions bot commented May 7, 2025

GNU testsuite comparison:

Skip an intermittent issue tests/timeout/timeout (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/misc/tee (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/rm/one-file-system is no longer failing!

@sylvestre
Copy link
Contributor

sorry, i missed it :(
it needs to be rebased, could you please do this? sorry :(

@shskwmt shskwmt force-pushed the rm-one-file-system branch from 42a24fb to f4adf86 Compare December 6, 2025 09:54
@github-actions
Copy link

github-actions bot commented Dec 6, 2025

GNU testsuite comparison:

Congrats! The gnu test tests/du/files0-from is no longer failing!

@shskwmt shskwmt force-pushed the rm-one-file-system branch from f4adf86 to 5dd9c19 Compare December 6, 2025 10:25
This comment enhances the safety of recursive deletion in `rm` by introducing two key features to
prevent accidental data loss.

`--one-file-system`: When specified, `rm` will not traverse into directories that are on a
different file system from the one on which the traversal began, this prevents `rm -r` from
accidentally deleting data on mounted volumes.

`--preserve-root=all`: The `--preserve-root` option is enhanced to accept an optional argument,
`all`. When set to `all`, `rm` will refuse to remove any directory that is a mount point. The
default behavior (`--preserve-root` without an argument) remains, protecting only the root
directory (`/`).
@shskwmt shskwmt force-pushed the rm-one-file-system branch from 5dd9c19 to 8d0a839 Compare December 6, 2025 10:36
@github-actions
Copy link

github-actions bot commented Dec 6, 2025

GNU testsuite comparison:

Skipping an intermittent issue tests/tail/overlay-headers (passes in this run but fails in the 'main' branch)

@shskwmt
Copy link
Contributor Author

shskwmt commented Dec 6, 2025

I've finished rebasing the branch.
Could you please review it?

} else {
match matches
.get_one::<String>(OPT_PRESERVE_ROOT)
.unwrap()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove the unwrap()

.map_err(|err| format!("cannot canonicalize {}: {err}", path.quote()))?;

// Get parent path, handling root case
let parent_canon = child_canon.parent().ok_or("")?.to_path_buf();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we avoid the empty strings in ok_or(") ?

fn handle_dir(path: &Path, options: &Options, progress_bar: Option<&ProgressBar>) -> bool {
let mut had_err = false;

if let Err(additional_reason) = check_one_fs(path, options) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same code as in line 621, please dedup

@ChrisDryden
Copy link
Collaborator

I see the Smack tests are failing in the CI here and it appears that its due to no space left on device. I'm guessing its caused when downloading the arch linux img

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rm --one-file-system should fail wih rm: skipping 'a/b', since it's on a different device

3 participants