From c9ee7d6447834084534a5842c1506d0ec6f00a86 Mon Sep 17 00:00:00 2001 From: sisungo Date: Sun, 12 May 2024 19:37:17 +0800 Subject: [PATCH] Implement `ctrlaltdel` (#31) * Implement ctrlaltdel * Add tests for `ctrlaltdel` * Bless the unit tests on unsupported platforms --- Cargo.lock | 9 ++ Cargo.toml | 2 + src/uu/ctrlaltdel/Cargo.toml | 15 +++ src/uu/ctrlaltdel/ctrlaltdel.md | 7 ++ src/uu/ctrlaltdel/src/ctrlaltdel.rs | 139 ++++++++++++++++++++++++++++ src/uu/ctrlaltdel/src/main.rs | 1 + tests/by-util/test_ctrlaltdel.rs | 14 +++ tests/tests.rs | 4 + 8 files changed, 191 insertions(+) create mode 100644 src/uu/ctrlaltdel/Cargo.toml create mode 100644 src/uu/ctrlaltdel/ctrlaltdel.md create mode 100644 src/uu/ctrlaltdel/src/ctrlaltdel.rs create mode 100644 src/uu/ctrlaltdel/src/main.rs create mode 100644 tests/by-util/test_ctrlaltdel.rs diff --git a/Cargo.lock b/Cargo.lock index 66234b4..c747f6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -641,12 +641,21 @@ dependencies = [ "rlimit", "tempfile", "textwrap", + "uu_ctrlaltdel", "uu_lscpu", "uu_mountpoint", "uucore", "xattr", ] +[[package]] +name = "uu_ctrlaltdel" +version = "0.0.1" +dependencies = [ + "clap", + "uucore", +] + [[package]] name = "uu_lscpu" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index c406220..ddc6390 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ default = ["feat_common_core"] feat_common_core = [ "mountpoint", "lscpu", + "ctrlaltdel", ] [workspace.dependencies] @@ -56,6 +57,7 @@ textwrap = { workspace = true } # lscpu = { optional = true, version = "0.0.1", package = "uu_lscpu", path = "src/uu/lscpu" } mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", path = "src/uu/mountpoint" } +ctrlaltdel = { optional = true, version = "0.0.1", package = "uu_ctrlaltdel", path = "src/uu/ctrlaltdel" } [dev-dependencies] pretty_assertions = "1" diff --git a/src/uu/ctrlaltdel/Cargo.toml b/src/uu/ctrlaltdel/Cargo.toml new file mode 100644 index 0000000..8641dc1 --- /dev/null +++ b/src/uu/ctrlaltdel/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "uu_ctrlaltdel" +version = "0.0.1" +edition = "2021" + +[lib] +path = "src/ctrlaltdel.rs" + +[[bin]] +name = "ctrlaltdel" +path = "src/main.rs" + +[dependencies] +uucore = { workspace = true } +clap = { workspace = true } diff --git a/src/uu/ctrlaltdel/ctrlaltdel.md b/src/uu/ctrlaltdel/ctrlaltdel.md new file mode 100644 index 0000000..1da16d6 --- /dev/null +++ b/src/uu/ctrlaltdel/ctrlaltdel.md @@ -0,0 +1,7 @@ +# ctrlaltdel + +``` +ctrlaltdel hard|soft +``` + +set the function of the ctrl-alt-del combination \ No newline at end of file diff --git a/src/uu/ctrlaltdel/src/ctrlaltdel.rs b/src/uu/ctrlaltdel/src/ctrlaltdel.rs new file mode 100644 index 0000000..6794ed6 --- /dev/null +++ b/src/uu/ctrlaltdel/src/ctrlaltdel.rs @@ -0,0 +1,139 @@ +// This file is part of the uutils util-linux package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use clap::{crate_version, Arg, ArgAction, Command}; +use uucore::{error::UResult, format_usage, help_about, help_usage}; + +const ABOUT: &str = help_about!("ctrlaltdel.md"); +const USAGE: &str = help_usage!("ctrlaltdel.md"); + +#[cfg(target_os = "linux")] +const CTRL_ALT_DEL_PATH: &str = "/proc/sys/kernel/ctrl-alt-del"; + +#[cfg(target_os = "linux")] +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?; + let pattern = matches.get_one::("pattern"); + match pattern { + Some(x) if x == "hard" => { + set_ctrlaltdel(CtrlAltDel::Hard)?; + } + Some(x) if x == "soft" => { + set_ctrlaltdel(CtrlAltDel::Soft)?; + } + Some(x) => { + Err(Error::UnknownArgument(x.clone()))?; + } + None => { + println!("{}", get_ctrlaltdel()?); + } + } + + Ok(()) +} + +#[cfg(not(target_os = "linux"))] +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let _matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?; + + Err(uucore::error::USimpleError::new( + 1, + "`ctrlaltdel` is unavailable on current platform.", + )) +} + +#[cfg(target_os = "linux")] +fn get_ctrlaltdel() -> UResult { + let value: i32 = std::fs::read_to_string(CTRL_ALT_DEL_PATH)? + .trim() + .parse() + .map_err(|_| Error::UnknownData)?; + + Ok(CtrlAltDel::from_sysctl(value)) +} + +#[cfg(target_os = "linux")] +fn set_ctrlaltdel(ctrlaltdel: CtrlAltDel) -> UResult<()> { + std::fs::write(CTRL_ALT_DEL_PATH, format!("{}\n", ctrlaltdel.to_sysctl())) + .map_err(|_| Error::NotRoot)?; + + Ok(()) +} + +#[cfg(target_os = "linux")] +#[derive(Clone, Copy)] +enum CtrlAltDel { + Soft, + Hard, +} +#[cfg(target_os = "linux")] +impl CtrlAltDel { + /// # Panics + /// Panics if value of the parameter `value` is neither `0` nor `1`. + fn from_sysctl(value: i32) -> Self { + match value { + 0 => Self::Soft, + 1 => Self::Hard, + _ => unreachable!(), + } + } + + fn to_sysctl(self) -> i32 { + match self { + Self::Soft => 0, + Self::Hard => 1, + } + } +} +#[cfg(target_os = "linux")] +impl std::fmt::Display for CtrlAltDel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Soft => write!(f, "soft"), + Self::Hard => write!(f, "hard"), + } + } +} + +#[cfg(target_os = "linux")] +#[derive(Debug)] +enum Error { + NotRoot, + UnknownArgument(String), + UnknownData, +} +#[cfg(target_os = "linux")] +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::NotRoot => write!(f, "You must be root to set the Ctrl-Alt-Del behavior"), + Self::UnknownArgument(x) => write!(f, "unknown argument: {x}"), + Self::UnknownData => write!(f, "unknown data"), + } + } +} +#[cfg(target_os = "linux")] +impl std::error::Error for Error {} +#[cfg(target_os = "linux")] +impl uucore::error::UError for Error { + fn code(&self) -> i32 { + 1 + } + + fn usage(&self) -> bool { + false + } +} + +pub fn uu_app() -> Command { + Command::new(uucore::util_name()) + .version(crate_version!()) + .about(ABOUT) + .override_usage(format_usage(USAGE)) + .infer_long_args(true) + .arg(Arg::new("pattern").action(ArgAction::Set)) +} diff --git a/src/uu/ctrlaltdel/src/main.rs b/src/uu/ctrlaltdel/src/main.rs new file mode 100644 index 0000000..22520ce --- /dev/null +++ b/src/uu/ctrlaltdel/src/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_ctrlaltdel); diff --git a/tests/by-util/test_ctrlaltdel.rs b/tests/by-util/test_ctrlaltdel.rs new file mode 100644 index 0000000..e657dab --- /dev/null +++ b/tests/by-util/test_ctrlaltdel.rs @@ -0,0 +1,14 @@ +// This file is part of the uutils util-linux package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. +// spell-checker:ignore (words) symdir somefakedir + +#[cfg(target_os = "linux")] +use crate::common::util::TestScenario; + +#[test] +#[cfg(target_os = "linux")] +fn test_invalid_arg() { + new_ucmd!().arg("--definitely-invalid").fails().code_is(1); +} diff --git a/tests/tests.rs b/tests/tests.rs index fa8e1a5..a1574f5 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -12,3 +12,7 @@ mod test_lscpu; #[cfg(feature = "mountpoint")] #[path = "by-util/test_mountpoint.rs"] mod test_mountpoint; + +#[cfg(feature = "ctrlaltdel")] +#[path = "by-util/test_ctrlaltdel.rs"] +mod test_ctrlaltdel;