diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index b38671a9a..1ce64bb78 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -521,10 +521,17 @@ impl OutputTrait for Output { let mut dst = open_dst(Path::new(&fname), &cflags, &oflags) .map_err_context(|| format!("failed to open {}", fname.quote()))?; + // Seek to the index in the output file, truncating if requested. + // + // Calling `set_len()` may result in an error (for + // example, when calling it on `/dev/null`), but we don't + // want to terminate the process when that happens. + // Instead, we suppress the error by calling + // `Result::ok()`. This matches the behavior of GNU `dd` + // when given the command-line argument `of=/dev/null`. let i = seek.unwrap_or(0).try_into().unwrap(); if !cflags.notrunc { - dst.set_len(i) - .map_err_context(|| "failed to truncate output file".to_string())?; + dst.set_len(i).ok(); } dst.seek(io::SeekFrom::Start(i)) .map_err_context(|| "failed to seek in output file".to_string())?; diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 7a52488eb..04f5490ec 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -1095,3 +1095,10 @@ fn test_truncated_record() { .stdout_is("ac") .stderr_is("0+1 records in\n0+1 records out\n2 truncated records\n"); } + +/// Test that the output file can be `/dev/null`. +#[cfg(unix)] +#[test] +fn test_outfile_dev_null() { + new_ucmd!().arg("of=/dev/null").succeeds().no_stdout(); +}