Without a version field, `cargo publish` fails for all crates that
depend on shadow-core:
all dependencies must have a version requirement specified when publishing.
dependency `shadow-core` does not specify a version
Add version = "0.2.0" to all three shadow-core dependency declarations
in Cargo.toml (workspace.dependencies, [dependencies], and dev-dependencies)
to allow `cargo publish` to work correctly.
Renovate's single-package update (#198) could not land this: clap_derive
4.6.4 requires syn >=3.0.2 while the lockfile pinned syn 3.0.0 (via
thiserror-impl), so the conservative 'cargo update -p clap --precise'
had no solvable resolution. Update both together (clap 4.6.3 -> 4.6.4,
syn 3.0.0 -> 3.0.3). cargo deny check passes with the syn skip added in
#194.
Per review on #171, inline the one caller: permission_denied() now calls
uucore::error::strip_errno directly. Also disambiguate the module doc now
that the local strerror fn is gone (it refers to libc's strerror).
Replace the local " (os error N)" suffix stripping with uucore's existing
strip_errno helper, per review on #171. Adds uucore (already in the
dependency tree via the tool crates) to shadow-core.
io::Error::from_raw_os_error(e).to_string() renders as
"Permission denied (os error 13)" — Rust appends its own suffix to the
libc text. Strip it so the message is the bare OS string (matching
GNU/coreutils output), and add a regression test that the suffix is
absent. Addresses review feedback on #171.
The manual root-privilege guards across the account tools printed a
hardcoded "Permission denied." string. Route that text through libc's
strerror instead (via std::io::Error::from_raw_os_error), so the wording
comes from the host OS and is translated by glibc on localized systems —
the same way GNU coreutils renders system errors (e.g. cat: Is a
directory). This also keeps the string out of our source tree, shrinking
the residual clean-room surface that motivated #159.
Add shadow_core::os_error with strerror(errno) and permission_denied(),
and convert the 13 caller_is_root() guards in chage, chpasswd, groupadd,
groupdel, groupmod, passwd, useradd, userdel, usermod to use it.
Scope: this covers the errno-mappable class only. True I/O errors already
render the OS strerror via ShadowError::Io/IoPath. Domain errors (e.g.
"group already exists") have no OS equivalent and stay in-tree. The
gettext-catalog idea was evaluated and declined in #159 (the English
msgid must remain in source as the lookup key, so it does not remove the
exposure).
Note: output changes from "Permission denied." to the OS text
"Permission denied" (no trailing period; translated off-English). No
tests asserted the old literal.
Every tool's uumain carried the same 10-line clap-error match plus a
per-enum AlreadyPrinted(i32) sentinel variant with identical Display and
code() arms. Hoist all of it into shadow-core:
- shadow_core::cli::AlreadyPrinted(i32): shared UError whose Display is
empty (the message was already printed), carrying only the exit code.
- shadow_core::cli::parse_args(cmd, args, code): parses argv, prints the
clap error, returns Ok(None) for --help/--version, and maps real parse
failures through the tool's code function.
Each of the 12 tools now opens with a single let-else line; the
AlreadyPrinted variant and its Display/code() arms are deleted from all
12 error enums, and non-clap uses of the sentinel switch to the shared
type. grpck/pwck (which use plain '?') are unchanged.
Behavior is preserved and verified: --help/--version exit 0 with
identical output; bad flags exit 1 (chfn/chpasswd/chsh/newgrp),
2 (chage/group*/user*), and passwd keeps its kind-dependent 2/6 mapping.
useradd's clap-error match had two arms both returning 2; it collapses
to the constant.
userdel's remaining variants all share the Cant prefix, tripping
clippy::enum_variant_names; allowed with a comment since the names
mirror userdel(8)'s documented exit-code names.
Closes#181.
Zero API drift: the surface we use (show_error!/show_warning!,
uucore::error, #[uucore::main], uucore::bin!, util_name) is unchanged
between 0.8 and 0.9. uucore 0.9's MSRV is 1.88, below our 1.94 gate.
Renovate's bump PR (#166) was closed during dependency-update cleanup,
which makes Renovate ignore the 0.9 line permanently — hence the manual
bump.
Closes#179.