-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
cp -rL returns exit code 0 when encountering circular symbolic links error
Component
cp -rL
Description
When cp -rL encounters circular symbolic links during directory traversal, it prints error messages but returns exit code 0 instead of a non-zero exit code.
This happens because show_error! macro is used instead of show! macro, which doesn't set the exit code.
In copydir.rs, when WalkDir encounters an error (such as "Too many levels of symbolic links"), the error is handled with show_error! which only prints the message without setting the exit code.
pub(crate) fn copy_directory(
// [...]
// Traverse the contents of the directory, copying each one.
for direntry_result in WalkDir::new(root)
.same_file_system(options.one_file_system)
.follow_links(options.dereference)
{
match direntry_result {
// [...]
// Print an error message, but continue traversing the directory.
! Err(e) => show_error!("{e}"),
}
}
The show_error! macro only prints to stderr.
macro_rules! show_error(
($($args:tt)+) => ({
eprint!("{}: ", $crate::util_name());
eprintln!($($args)+);
})
);
However, show! macro sets the exit code.
macro_rules! show(
($err:expr) => ({
#[allow(unused_imports)]
use $crate::error::UError;
let e = $err;
! $crate::error::set_exit_code(e.code());
eprintln!("{}: {e}", $crate::util_name());
})
);
Test / Reproduction Steps
# Create circular symbolic links
$ mkdir -p /tmp/test_circular_symlinks/src_cycle
$ cd /tmp/test_circular_symlinks/src_cycle
$ ln -s a b
$ ln -s b a
# Run cp -rL
$ coreutils cp -rL /tmp/test_circular_symlinks/src_cycle /tmp/test_circular_symlinks/dest_cycle
cp: IO error for operation on /tmp/test_circular_symlinks/src_cycle/a:
Too many levels of symbolic links (os error 40)
cp: IO error for operation on /tmp/test_circular_symlinks/src_cycle/b:
Too many levels of symbolic links (os error 40)
# Check exit code (should be non-zero but returns 0)
$ echo $?
0Impact
Scripts that rely on exit codes to detect copy failures will not properly detect errors when circular symbolic links are encountered. This breaks compatibility with GNU cp behavior, which returns a non-zero exit code in such cases.
Recommendations
Change show_error! to show! in copy_directory function, converting walkdir::Error to CpError::WalkDirErr:
-Err(e) => show_error!("{e}"),
+Err(e) => show!(CpError::WalkDirErr(e)),
This ensures that the exit code is properly set when errors occur during directory traversal.