convert commands into strings

This commit is contained in:
chayleaf 2024-08-14 11:28:19 +07:00
parent 847bcd44d9
commit 30e7205ebf
Signed by: chayleaf
GPG key ID: 78171AD46227E68E

View file

@ -4,15 +4,23 @@
non_upper_case_globals,
clippy::missing_safety_doc
)]
use std::{borrow::Cow, env, ffi::CStr, mem, mem::MaybeUninit, os::raw::c_void, process, ptr};
use std::{
borrow::Cow,
env,
ffi::{CStr, CString},
mem,
mem::MaybeUninit,
os::raw::c_void,
process, ptr,
};
use ext_idle_notify_v1_protocol::{
ext_idle_notification_v1_interface, ext_idle_notifier_v1_interface,
};
use libc::{
__errno_location, abort, access, calloc, close, execvp, exit, fclose, fopen, fork, free,
getenv, getline, getopt, getpid, memset, printf, sigemptyset, signal, sigprocmask, sigset_t,
size_t, sprintf, strcmp, strdup, strlen, strncmp, strstr, strtoul, waitpid,
getenv, getline, getopt, getpid, printf, sigemptyset, signal, sigprocmask, sigset_t, size_t,
sprintf, strcmp, strdup, strlen, strncmp, strstr, strtoul, waitpid,
};
use libsystemd_sys::bus::{
sd_bus, sd_bus_call_method, sd_bus_default_system, sd_bus_error, sd_bus_error_free,
@ -134,11 +142,11 @@ struct swayidle_state {
event_loop: *mut wl_event_loop,
timeout_cmds: wl_list,
seats: wl_list,
seat_name: *mut libc::c_char,
before_sleep_cmd: *mut libc::c_char,
after_resume_cmd: *mut libc::c_char,
logind_lock_cmd: *mut libc::c_char,
logind_unlock_cmd: *mut libc::c_char,
seat_name: Option<String>,
before_sleep_cmd: Option<String>,
after_resume_cmd: Option<String>,
logind_lock_cmd: Option<String>,
logind_unlock_cmd: Option<String>,
logind_idlehint: bool,
timeouts_enabled: bool,
wait: bool,
@ -149,8 +157,8 @@ struct swayidle_timeout_cmd {
timeout: libc::c_int,
registered_timeout: libc::c_int,
idle_notification: *mut ext_idle_notification_v1,
idle_cmd: *mut libc::c_char,
resume_cmd: *mut libc::c_char,
idle_cmd: Option<String>,
resume_cmd: Option<String>,
idlehint: bool,
resume_pending: bool,
}
@ -265,11 +273,11 @@ static mut state: swayidle_state = swayidle_state {
prev: ptr::null_mut(),
next: ptr::null_mut(),
},
seat_name: ptr::null_mut(),
before_sleep_cmd: ptr::null_mut(),
after_resume_cmd: ptr::null_mut(),
logind_lock_cmd: ptr::null_mut(),
logind_unlock_cmd: ptr::null_mut(),
seat_name: None,
before_sleep_cmd: None,
after_resume_cmd: None,
logind_lock_cmd: None,
logind_unlock_cmd: None,
logind_idlehint: false,
timeouts_enabled: false,
wait: false,
@ -290,7 +298,6 @@ unsafe extern "C" fn swayidle_log_init(verbosity: log_importance) {
}
impl swayidle_state {
unsafe fn init(&mut self) {
memset(ptr::addr_of_mut!(*self).cast(), 0, mem::size_of::<Self>());
wl_list_init(&mut self.timeout_cmds);
wl_list_init(&mut self.seats);
}
@ -299,22 +306,18 @@ impl swayidle_state {
let mut tmp: *mut swayidle_timeout_cmd = (*cmd).link.next.cast();
while ptr::addr_of_mut!((*cmd).link) != ptr::addr_of_mut!(self.timeout_cmds) {
wl_list_remove(&mut (*cmd).link);
free((*cmd).idle_cmd.cast());
free((*cmd).resume_cmd.cast());
free(cmd.cast());
drop(Box::from_raw(cmd));
cmd = tmp;
tmp = (*cmd).link.next.cast();
}
free(self.after_resume_cmd.cast());
free(self.before_sleep_cmd.cast());
}
unsafe fn sway_terminate(&self, exit_code: libc::c_int) -> ! {
wl_display_disconnect(self.display);
wl_event_loop_destroy(self.event_loop);
exit(exit_code);
}
unsafe fn cmd_exec(&self, param: *mut libc::c_char) {
log::debug!("Cmd exec {}", read_str(param));
unsafe fn cmd_exec(&self, param: &str) {
log::debug!("Cmd exec {param}");
let mut pid = fork();
match pid {
0 => {
@ -330,10 +333,11 @@ impl swayidle_state {
signal(2, 0);
signal(15, 0);
signal(10, 0);
let param = CString::new(param).unwrap();
let cmd: [*const libc::c_char; 4] = [
b"sh\0".as_ptr().cast(),
b"-c\0".as_ptr().cast(),
param,
param.as_ptr(),
ptr::null(),
];
execvp(cmd[0], cmd.as_ptr());
@ -352,7 +356,7 @@ impl swayidle_state {
log::error!("fork failed: {}", strerror(*__errno_location()),);
}
_ => {
log::debug!("Spawned process {}", read_str(param));
log::debug!("Spawned process {param}");
if self.wait {
log::debug!("Blocking until process exits");
}
@ -460,7 +464,7 @@ impl swayidle_state {
self.wait = 1 != 0;
}
83 => {
self.seat_name = strdup(optarg);
self.seat_name = read_str2(optarg);
}
104 | 63 => {
printf(b"Usage: %s [OPTIONS]\n\0".as_ptr().cast(), *argv);
@ -518,16 +522,16 @@ impl swayidle_state {
b"delay\0".as_ptr().cast(),
ptr::addr_of_mut!(sleep_lock_fd),
);
if !self.after_resume_cmd.is_null() {
self.cmd_exec(self.after_resume_cmd);
if let Some(after_resume_cmd) = &self.after_resume_cmd {
self.cmd_exec(after_resume_cmd);
}
if self.logind_idlehint {
set_idle_hint(false);
}
return 0;
}
if !self.before_sleep_cmd.is_null() {
self.cmd_exec(self.before_sleep_cmd);
if let Some(before_sleep_cmd) = &self.before_sleep_cmd {
self.cmd_exec(before_sleep_cmd);
}
log::debug!("Prepare for sleep done");
release_inhibitor_lock(sleep_lock_fd);
@ -535,8 +539,8 @@ impl swayidle_state {
}
unsafe fn handle_lock(&self) -> libc::c_int {
log::debug!("Lock signal received");
if !self.logind_lock_cmd.is_null() {
self.cmd_exec(self.logind_lock_cmd);
if let Some(logind_lock_cmd) = &self.logind_lock_cmd {
self.cmd_exec(logind_lock_cmd);
}
log::debug!("Lock command done");
0
@ -546,8 +550,8 @@ impl swayidle_state {
if self.logind_idlehint {
set_idle_hint(false);
}
if !self.logind_unlock_cmd.is_null() {
self.cmd_exec(self.logind_unlock_cmd);
if let Some(logind_unlock_cmd) = &self.logind_unlock_cmd {
self.cmd_exec(logind_unlock_cmd);
}
log::debug!("Unlock command done");
0
@ -635,8 +639,8 @@ impl swayidle_state {
exit(-1);
}
self.before_sleep_cmd = parse_command(argc - 1, &mut *argv.offset(1));
if !self.before_sleep_cmd.is_null() {
log::debug!("Setup sleep lock: {}", read_str(self.before_sleep_cmd));
if let Some(before_sleep_cmd) = &self.before_sleep_cmd {
log::debug!("Setup sleep lock: {before_sleep_cmd}");
}
2
}
@ -648,8 +652,8 @@ impl swayidle_state {
exit(-1);
}
self.after_resume_cmd = parse_command(argc - 1, &mut *argv.offset(1));
if !self.after_resume_cmd.is_null() {
log::debug!("Setup resume hook: {}", read_str(self.after_resume_cmd));
if let Some(after_resume_cmd) = &self.after_resume_cmd {
log::debug!("Setup resume hook: {after_resume_cmd}");
}
2
}
@ -659,8 +663,8 @@ impl swayidle_state {
exit(-1);
}
self.logind_lock_cmd = parse_command(argc - 1, &mut *argv.offset(1));
if !self.logind_lock_cmd.is_null() {
log::debug!("Setup lock hook: {}", read_str(self.logind_lock_cmd));
if let Some(logind_lock_cmd) = &self.logind_lock_cmd {
log::debug!("Setup lock hook: {logind_lock_cmd}");
}
2
}
@ -670,8 +674,8 @@ impl swayidle_state {
exit(-1);
}
self.logind_unlock_cmd = parse_command(argc - 1, &mut *argv.offset(1));
if !self.logind_unlock_cmd.is_null() {
log::debug!("Setup unlock hook: {}", read_str(self.logind_unlock_cmd));
if let Some(logind_unlock_cmd) = &self.logind_unlock_cmd {
log::debug!("Setup unlock hook: {logind_unlock_cmd}");
}
2
}
@ -752,6 +756,13 @@ impl Drop for swayidle_state {
unsafe { self.finish() }
}
}
unsafe fn read_str2(ptr: *const libc::c_char) -> Option<String> {
if ptr.is_null() {
None
} else {
Some(CStr::from_ptr(ptr).to_string_lossy().into())
}
}
unsafe fn read_str(ptr: *const libc::c_char) -> Cow<'static, str> {
if ptr.is_null() {
"".into()
@ -1227,8 +1238,8 @@ unsafe extern "C" fn handle_idled(data: *mut libc::c_void, _notif: *mut ext_idle
log::debug!("idle state");
if (*cmd).idlehint {
set_idle_hint(true);
} else if !(*cmd).idle_cmd.is_null() {
state.cmd_exec((*cmd).idle_cmd);
} else if let Some(idle_cmd) = &(*cmd).idle_cmd {
state.cmd_exec(idle_cmd);
}
}
unsafe extern "C" fn handle_resumed(
@ -1243,8 +1254,8 @@ unsafe extern "C" fn handle_resumed(
}
if (*cmd).idlehint {
set_idle_hint(false);
} else if !(*cmd).resume_cmd.is_null() {
state.cmd_exec((*cmd).resume_cmd);
} else if let Some(resume_cmd) = &(*cmd).resume_cmd {
state.cmd_exec(resume_cmd);
}
}
static mut idle_notification_listener: ext_idle_notification_v1_listener =
@ -1252,13 +1263,17 @@ static mut idle_notification_listener: ext_idle_notification_v1_listener =
idled: Some(handle_idled),
resumed: Some(handle_resumed),
};
unsafe extern "C" fn parse_command(argc: usize, argv: *mut *mut libc::c_char) -> *mut libc::c_char {
unsafe fn parse_command(argc: usize, argv: *mut *mut libc::c_char) -> Option<String> {
if argc < 1 {
log::error!("Missing command");
return ptr::null_mut();
return None;
}
log::debug!("Command: {}", read_str(*argv));
strdup(*argv)
let Some(ret) = read_str2(*argv) else {
log::error!("Missing command");
return None;
};
log::debug!("Command: {ret}");
Some(ret)
}
unsafe extern "C" fn build_timeout_cmd(argv: *mut *mut libc::c_char) -> *mut swayidle_timeout_cmd {
*__errno_location() = 0;
@ -1272,15 +1287,19 @@ unsafe extern "C" fn build_timeout_cmd(argv: *mut *mut libc::c_char) -> *mut swa
);
exit(-1);
}
let cmd: *mut swayidle_timeout_cmd = calloc(1, mem::size_of::<swayidle_timeout_cmd>()).cast();
(*cmd).idlehint = false;
(*cmd).resume_pending = false;
if seconds > 0 {
(*cmd).timeout = seconds * 1000;
} else {
(*cmd).timeout = -1;
}
cmd
Box::into_raw(Box::new(swayidle_timeout_cmd {
idlehint: false,
resume_pending: false,
timeout: if seconds > 0 { seconds * 1000 } else { -1 },
idle_cmd: None,
idle_notification: ptr::null_mut(),
link: wl_list {
prev: ptr::null_mut(),
next: ptr::null_mut(),
},
registered_timeout: 0,
resume_cmd: None,
}))
}
unsafe extern "C" fn handle_signal(sig: libc::c_int, _data: *mut libc::c_void) -> libc::c_int {
state.handle_signal(sig)
@ -1375,7 +1394,7 @@ unsafe fn main_0(argc: usize, argv: *mut *mut libc::c_char) -> libc::c_int {
let mut seat_i: *mut seat;
seat_i = state.seats.next.cast();
while ptr::addr_of_mut!((*seat_i).link) != ptr::addr_of_mut!(state.seats) {
if (state.seat_name).is_null() || strcmp((*seat_i).name, state.seat_name) == 0 {
if !matches!(&state.seat_name, Some(seat_name) if read_str((*seat_i).name) != *seat_name) {
seat = (*seat_i).proxy;
}
seat_i = (*seat_i).link.next.cast();
@ -1385,25 +1404,25 @@ unsafe fn main_0(argc: usize, argv: *mut *mut libc::c_char) -> libc::c_int {
return -4;
}
if seat.is_null() {
if state.seat_name.is_null() {
log::error!("No seat found");
if let Some(seat_name) = &state.seat_name {
log::error!("Seat {seat_name} not found");
} else {
log::error!("Seat {} not found", read_str(state.seat_name));
log::error!("No seat found");
}
return -5;
}
let mut should_run = wl_list_empty(&state.timeout_cmds) == 0;
state.connect_to_bus();
setup_property_changed_listener();
if !state.before_sleep_cmd.is_null() || !state.after_resume_cmd.is_null() {
if state.before_sleep_cmd.is_some() || state.after_resume_cmd.is_some() {
should_run = true;
setup_sleep_listener();
}
if !state.logind_lock_cmd.is_null() {
if state.logind_lock_cmd.is_some() {
should_run = true;
setup_lock_listener();
}
if !state.logind_unlock_cmd.is_null() {
if state.logind_unlock_cmd.is_some() {
should_run = true;
setup_unlock_listener();
}