Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/make.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: make
# spell-checker:ignore (jargon) deps softprops toolchain
# spell-checker:ignore (people) dawidd
# spell-checker:ignore (shell/tools) nextest sccache zstd
# spell-checker:ignore (misc) bindir busytest defconfig DESTDIR manpages multisize runtest testsuite toybox uutils
# spell-checker:ignore (misc) bindir busytest defconfig DESTDIR manpages multisize runtest testsuite toybox userns uutils

env:
PROJECT_NAME: coreutils
Expand Down Expand Up @@ -80,7 +80,11 @@ jobs:
mv -t target/ target.cache/release 2>/dev/null || true
- name: "`make nextest`"
shell: bash
run: make nextest PROFILE=ci CARGOFLAGS="--hide-progress-bar"
run: |
# some test needs unshare
sudo sysctl -w kernel.unprivileged_userns_clone=1 || true
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true
make nextest PROFILE=ci CARGOFLAGS="--hide-progress-bar"
env:
RUST_BACKTRACE: "1"
- name: Upload test results to Codecov
Expand Down
45 changes: 5 additions & 40 deletions src/uu/id/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,54 +641,26 @@ fn id_print(state: &State, groups: &[u32]) -> io::Result<()> {
write!(
lock,
"uid={uid}({})",
entries::uid2usr(uid).unwrap_or_else(|_| {
show_error!(
"{}",
translate!("id-error-cannot-find-user-name", "uid" => uid)
);
set_exit_code(1);
uid.to_string()
})
entries::uid2usr(uid).unwrap_or_else(|_| { uid.to_string() })
)?;
write!(
lock,
" gid={gid}({})",
entries::gid2grp(gid).unwrap_or_else(|_| {
show_error!(
"{}",
translate!("id-error-cannot-find-group-name", "gid" => gid)
);
set_exit_code(1);
gid.to_string()
})
entries::gid2grp(gid).unwrap_or_else(|_| { gid.to_string() })
)?;
if !state.user_specified && (euid != uid) {
write!(
lock,
" euid={euid}({})",
entries::uid2usr(euid).unwrap_or_else(|_| {
show_error!(
"{}",
translate!("id-error-cannot-find-user-name", "uid" => euid)
);
set_exit_code(1);
euid.to_string()
})
entries::uid2usr(euid).unwrap_or_else(|_| { euid.to_string() })
)?;
}
if !state.user_specified && (egid != gid) {
// BUG? printing egid={euid} ?
write!(
lock,
" egid={egid}({})",
entries::gid2grp(egid).unwrap_or_else(|_| {
show_error!(
"{}",
translate!("id-error-cannot-find-group-name", "gid" => egid)
);
set_exit_code(1);
egid.to_string()
})
entries::gid2grp(egid).unwrap_or_else(|_| { egid.to_string() })
)?;
}
write!(
Expand All @@ -698,14 +670,7 @@ fn id_print(state: &State, groups: &[u32]) -> io::Result<()> {
.iter()
.map(|&gr| format!(
"{gr}({})",
entries::gid2grp(gr).unwrap_or_else(|_| {
show_error!(
"{}",
translate!("id-error-cannot-find-group-name", "gid" => gr)
);
set_exit_code(1);
gr.to_string()
})
entries::gid2grp(gr).unwrap_or_else(|_| { gr.to_string() })
))
.collect::<Vec<_>>()
.join(",")
Expand Down
29 changes: 29 additions & 0 deletions tests/by-util/test_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,35 @@ fn test_id_no_specified_user() {
.code_is(exp_result.code());
}

#[test]
#[cfg(target_os = "linux")]
fn test_id_nonexisting_ids() {
use uutests::{get_tests_binary, util::unshare_bin};

let unshare = unwrap_or_return!(unshare_bin());

let unshare_args = ["-U", "--map-user=10101", "--"];

let exp_result = Command::new(&unshare)
.args(unshare_args)
.arg(util_name!())
.output()
.unwrap();

let result = Command::new(unshare)
.args(unshare_args)
.arg(get_tests_binary!())
.arg(util_name!())
.output()
.unwrap();

assert_eq!(result.status.code(), exp_result.status.code());

let exp_stderr = String::from_utf8_lossy(&exp_result.stderr);
let act_stderr = String::from_utf8_lossy(&result.stderr);
assert_eq!(act_stderr, exp_stderr);
}

#[test]
fn test_id_single_user() {
let test_users = [&whoami()[..]];
Expand Down
32 changes: 32 additions & 0 deletions tests/uutests/src/lib/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3235,6 +3235,38 @@ pub fn run_ucmd_as_root_with_stdin_stdout(
}
}

/// Determines whether `unshare` can be used in the current setup, and returns the path to its binary.
///
/// # Errors
/// If `unshare` is not available on the system, or cannot be run (e.g. in CI), this function
/// returns a String describing the reason.
pub fn unshare_bin() -> Result<String> {
// Determine whether 'unshare' is available
let which_result = Command::new("which").arg("unshare").output()?;
if !which_result.status.success() {
return Err(io::Error::other("'unshare' not found on system"));
}
let unshare = String::from_utf8_lossy(&which_result.stdout)
.trim()
.to_string();

// Determine whether 'unshare' works as expected
let test_result = Command::new(&unshare)
.args(["-U", "--map-user=0", "--map-group=0", "--", "whoami"])
.output()?;
if !test_result.status.success() {
let err = String::from_utf8_lossy(&test_result.stderr)
.trim()
.to_string();
return Err(io::Error::other(format!("failed to run 'unshare': {err}")));
}
if String::from_utf8_lossy(&test_result.stdout).trim() != "root" {
return Err(io::Error::other("'unshare' does not work as expected"));
}

Ok(unshare)
}

/// Sanity checks for test utils
#[cfg(test)]
mod tests {
Expand Down
Loading