From d98f11e96f78d4249212656994d4c48cd6ea31ad Mon Sep 17 00:00:00 2001 From: Jared Baur Date: Sat, 19 Oct 2024 11:08:34 -0700 Subject: [PATCH] switch-to-configuration-ng: improve user experience When calling switch-to-configuration (ng) as a non-root user, the user calling the program should be guided to calling the program in the correct way, not given a confusing error message. --- .../src/src/main.rs | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs b/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs index 802b5e64f101..d93fe834b778 100644 --- a/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs +++ b/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs @@ -937,8 +937,21 @@ fn do_user_switch(parent_exe: String) -> anyhow::Result<()> { Ok(()) } +fn usage(argv0: &str) -> ! { + eprintln!( + r#"Usage: {} [switch|boot|test|dry-activate] +switch: make the configuration the boot default and activate now +boot: make the configuration the boot default +test: activate the configuration, but don't make it the boot default +dry-activate: show what would be done if this configuration were activated +"#, + argv0 + ); + std::process::exit(1); +} + /// Performs switch-to-configuration functionality for the entire system -fn do_system_switch() -> anyhow::Result<()> { +fn do_system_switch(action: Action) -> anyhow::Result<()> { let out = PathBuf::from(required_env("OUT")?); let toplevel = PathBuf::from(required_env("TOPLEVEL")?); let distro_id = required_env("DISTRO_ID")?; @@ -946,25 +959,6 @@ fn do_system_switch() -> anyhow::Result<()> { let locale_archive = required_env("LOCALE_ARCHIVE")?; let new_systemd = PathBuf::from(required_env("SYSTEMD")?); - let mut args = std::env::args(); - let argv0 = args.next().ok_or(anyhow!("no argv[0]"))?; - - let Some(Ok(action)) = args.next().map(|a| Action::from_str(&a)) else { - eprintln!( - r#"Usage: {} [switch|boot|test|dry-activate] -switch: make the configuration the boot default and activate now -boot: make the configuration the boot default -test: activate the configuration, but don't make it the boot default -dry-activate: show what would be done if this configuration were activated -"#, - argv0 - .split(std::path::MAIN_SEPARATOR_STR) - .last() - .unwrap_or("switch-to-configuration") - ); - std::process::exit(1); - }; - let action = ACTION.get_or_init(|| action); // The action that is to be performed (like switch, boot, test, dry-activate) Also exposed via @@ -1939,13 +1933,26 @@ won't take effect until you reboot the system. } fn main() -> anyhow::Result<()> { - match ( - unsafe { nix::libc::geteuid() }, - std::env::var("__NIXOS_SWITCH_TO_CONFIGURATION_PARENT_EXE").ok(), - ) { - (0, None) => do_system_switch(), - (1..=u32::MAX, None) => bail!("This program does not support being ran outside of the switch-to-configuration environment"), - (_, Some(parent_exe)) => do_user_switch(parent_exe), + match std::env::var("__NIXOS_SWITCH_TO_CONFIGURATION_PARENT_EXE").ok() { + Some(parent_exe) => do_user_switch(parent_exe), + None => { + let mut args = std::env::args(); + let argv0 = args.next().ok_or(anyhow!("no argv[0]"))?; + let argv0 = argv0 + .split(std::path::MAIN_SEPARATOR_STR) + .last() + .unwrap_or("switch-to-configuration"); + + let Some(Ok(action)) = args.next().map(|a| Action::from_str(&a)) else { + usage(&argv0); + }; + + if unsafe { nix::libc::geteuid() } == 0 { + do_system_switch(action) + } else { + bail!("{} must be run as the root user", argv0); + } + } } }