diff --git a/Cargo.lock b/Cargo.lock index e469f7a..2866d9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,12 +8,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - [[package]] name = "bitflags" version = "1.3.2" @@ -22,13 +16,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "caffeinate2" -version = "0.4.2" +version = "0.4.3" dependencies = [ "clap", "core-foundation", "libloading", "nix", - "plist", "regex", "signal-hook", "time", @@ -59,6 +52,7 @@ dependencies = [ "once_cell", "strsim", "termcolor", + "terminal_size", ] [[package]] @@ -76,9 +70,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" dependencies = [ "os_str_bytes", ] @@ -120,12 +114,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "heck" version = "0.4.1" @@ -134,19 +122,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" - -[[package]] -name = "indexmap" -version = "1.9.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown", -] +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "io-lifetimes" @@ -160,9 +138,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ "hermit-abi", "io-lifetimes", @@ -192,27 +170,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - [[package]] name = "linux-raw-sys" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - [[package]] name = "memoffset" version = "0.7.1" @@ -263,20 +226,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "plist" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9469799ca90293a376f68f6fcb8f11990d9cff55602cfba0ba83893c973a7f46" -dependencies = [ - "base64", - "indexmap", - "line-wrap", - "quick-xml", - "serde", - "time", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -310,15 +259,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-xml" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.23" @@ -357,12 +297,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - [[package]] name = "serde" version = "1.0.152" @@ -402,9 +336,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -420,6 +354,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" +dependencies = [ + "rustix", + "windows-sys", +] + [[package]] name = "time" version = "0.3.20" diff --git a/Cargo.toml b/Cargo.toml index 53f739c..dbc8514 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "caffeinate2" -version = "0.4.2" +version = "0.4.3" edition = "2021" authors = ["Randomblock1 "] description = "Caffeinate MacOS utility with more options. Temporarily prevent your system from sleeping." @@ -14,11 +14,10 @@ categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "4.1.6", features = ["derive"] } +clap = { version = "4.1.6", features = ["derive", "wrap_help"] } core-foundation = "0.9.3" libloading = "0.7.4" nix = "0.26.2" -plist = "1.4.1" regex = { version = "1.7.1", default-features = false, features = ["std", "unicode-perl"] } signal-hook = "0.3.15" -time = { version = "0.3.20", features = ["macros", "local-offset"] } +time = { version = "0.3.20", features = ["macros", "formatting", "local-offset"] } diff --git a/README.md b/README.md index e5c5f95..f7acde3 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ This project is licensed under the MIT License - see [the license file](LICENSE. ## TODO - [ ] Treat timeout like a timeout, and not a timer. -- [ ] Figure out if I can get commands to support color (for example, `caffeinate2 brew` is uncolored) +- [ ] Figure out how to fake a tty (for example, `caffeinate2 brew list` is uncolored) - [ ] Print sleep types better -- [ ] Get system sleep status without reading a plist -- [ ] Get PID info by using Grand Central Dispatch instead of a weird `lsof` hack +- [x] Get system sleep status without reading a plist +- [x] Get PID info by using Grand Central Dispatch instead of a weird `lsof` hack - POSTPONED because it's a mess and it currently Just Works™️ diff --git a/src/main.rs b/src/main.rs index 243be2b..77aad47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,7 +58,7 @@ fn release_assertions(iokit: &power_management::IOKit, assertions: &Vec) { for assertion in assertions { iokit.release_assertion(*assertion); } - if power_management::IOKit::get_sleep_disabled() { + if power_management::IOKit::get_sleep_disabled(iokit) { iokit.set_sleep_disabled(false).unwrap_or_else(|_| { eprintln!("Error: Insufficient privileges to disable sleep. Try running with sudo."); process::exit(1); diff --git a/src/power_management.rs b/src/power_management.rs index 8b3eeae..15433be 100644 --- a/src/power_management.rs +++ b/src/power_management.rs @@ -1,5 +1,7 @@ -use core_foundation::base::TCFType; +use core_foundation::base::{TCFType, TCFTypeRef}; use core_foundation::boolean::CFBoolean; +use core_foundation::dictionary::{CFDictionaryGetValueIfPresent, CFDictionaryRef}; +use core_foundation::number::CFBooleanRef; use core_foundation::string::{CFString, CFStringRef}; use libloading::{Library, Symbol}; use std::mem::MaybeUninit; @@ -28,6 +30,13 @@ impl IOKit { } } + fn iopm_copy_power_settings(&self) -> CFDictionaryRef { + let iokit = &self.library; + let iopm_copy_power_settings: Symbol CFDictionaryRef> = + unsafe { iokit.get(b"IOPMCopySystemPowerSettings") }.unwrap(); + unsafe { iopm_copy_power_settings() } + } + pub fn create_assertion(&self, assertion_type: &str, state: bool) -> u32 { let iokit = &self.library; let iopmassertion_create_with_name: Symbol< @@ -182,43 +191,21 @@ impl IOKit { } } - pub fn get_sleep_disabled() -> bool { - const PATH: &str = "/Library/Preferences/com.apple.PowerManagement.plist"; + pub fn get_sleep_disabled(&self) -> bool { + let mut ptr: *const std::os::raw::c_void = std::ptr::null(); - // Open the file - let value: plist::Value = match plist::from_file(PATH) { - Ok(v) => v, - Err(e) => { - panic!("Failed to open {}: {}", PATH, e); - } + let result = unsafe { + CFDictionaryGetValueIfPresent( + self.iopm_copy_power_settings(), + CFString::new("SleepDisabled").as_CFTypeRef().as_void_ptr(), + &mut ptr, + ) }; - // Get the "SystemPowerSettings" dictionary from the root dictionary - let system_power_settings = value - .as_dictionary() - .and_then(|dict| dict.get("SystemPowerSettings")) - .and_then(|dict| dict.as_dictionary()) - .unwrap_or_else(|| { - panic!("Failed to get SystemPowerSettings dictionary from {}", PATH); - }); - - // Get the "SleepDisabled" key from the "SystemPowerSettings" dictionary - let sleep_disabled = system_power_settings - .get("SleepDisabled") - .and_then(|val| val.as_boolean()) - .unwrap_or_else(|| { - panic!("Failed to get SleepDisabled value from {}", PATH); - }); + if result == 0 { + panic!("Failed to get SleepDisabled value!"); + } - #[cfg(debug_assertions)] - println!( - "System sleep is currently {}", - if sleep_disabled { - "disabled" - } else { - "enabled" - } - ); - sleep_disabled + ptr as CFBooleanRef == unsafe { core_foundation::number::kCFBooleanTrue } } }