diff --git a/Cargo.lock b/Cargo.lock index 8fc0e9b..40bceb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -260,6 +260,7 @@ dependencies = [ "bscreensaver-command", "bscreensaver-util", "clap", + "libc", "log", "nix", "xcb", diff --git a/Makefile b/Makefile index abaabf1..6eb7310 100644 --- a/Makefile +++ b/Makefile @@ -17,15 +17,22 @@ HELPERS = \ INSTALL ?= install +RUST_RELEASE_CHANNEL = nightly +ifeq ($(RUST_RELEASE_CHANNEL),nightly) + RUST_RELEASE_CHANNEL_ARG = +nightly +else + FEATURES_ARGS = --no-default-features +endif + DEV_LOG_LEVEL = debug all: release release: - HELPER_DIR=$(HELPER_DIR) cargo build --release + HELPER_DIR=$(HELPER_DIR) cargo $(RUST_RELEASE_CHANNEL_ARG) build $(FEATURES_ARGS) --release dev: - HELPER_DIR=target/debug cargo build + HELPER_DIR=target/debug cargo $(RUST_RELEASE_CHANNEL_ARG) build $(FEATURES_ARGS) install: release $(INSTALL) -m 0755 -d $(BINDIR) $(HELPER_DIR) $(CONFIG_DIR) $(APPLICATIONS_DIR) @@ -35,7 +42,7 @@ install: release $(INSTALL) -m 0644 settings/bscreensaver-settings.desktop $(APPLICATIONS_DIR) clean: - cargo clean + cargo $(RUST_RELEASE_CHANNEL_ARG) clean uninstall: rm -f $(BINDIR)/bscreensaver $(BINDIR)/bscreensaver-command $(BINDIR)/bscreensaver-settings $(addprefix $(HELPER_DIR)/,$(HELPERS)) || true @@ -50,10 +57,10 @@ run: dev BSCREENSAVER_SYSTEMD_LOG=$(DEV_LOG_LEVEL) \ BSCREENSAVER_DIALOG_GTK3_LOG=$(DEV_LOG_LEVEL) \ HELPER_DIR=target/debug \ - cargo run --bin bscreensaver + cargo $(RUST_RELEASE_CHANNEL_ARG) run $(FEATURES_ARGS) --bin bscreensaver run-dialog: RUST_BACKTRACE=1 \ BSCREENSAVER_DIALOG_GTK3_LOG=$(DEV_LOG_LEVEL) \ BSCREENSAVER_DIALOG_STANDALONE=1 \ - cargo run --bin bscreensaver-dialog-gtk3 + cargo $(RUST_RELEASE_CHANNEL_ARG) run $(FEATURES_ARGS) --bin bscreensaver-dialog-gtk3 diff --git a/dbus-service/src/main.rs b/dbus-service/src/main.rs index e6fd3c3..d93b1af 100644 --- a/dbus-service/src/main.rs +++ b/dbus-service/src/main.rs @@ -1,6 +1,3 @@ -#![feature(option_result_contains)] -#![feature(is_some_with)] - use async_std::{fs::File, prelude::*, sync::{Arc, Mutex}, task}; use bscreensaver_util::init_logging; use futures::{future::FutureExt, pin_mut, select}; @@ -160,7 +157,7 @@ async fn dbus_task(state: Arc>) -> anyhow::Result<()> { let args = name_owner_changed.args()?; match args.name() { BusName::WellKnown(name) if name == OUR_DBUS_NAME => { - if args.new_owner().is_none() || args.new_owner().is_some_and(|no| no != our_unique_name) { + if args.new_owner().is_none() || args.new_owner().as_ref().filter(|no| no != &our_unique_name).is_some() { info!("Lost bus name {}; quitting", OUR_DBUS_NAME); exit(0); } @@ -168,7 +165,7 @@ async fn dbus_task(state: Arc>) -> anyhow::Result<()> { BusName::Unique(name) => { if args.new_owner().is_none() { state.lock().await.inhibitors.retain(|inhibitor| { - if inhibitor.peer.contains(name) { + if inhibitor.peer.as_ref().filter(|n| n == &name).is_some() { info!("Canceling inhibit from {}, as the client has disappeared", inhibitor.app_name); false } else { diff --git a/locker/Cargo.toml b/locker/Cargo.toml index 3d75898..53c0ebd 100644 --- a/locker/Cargo.toml +++ b/locker/Cargo.toml @@ -12,11 +12,16 @@ readme = "README.md" keywords = ["gui", "screensaver", "screen-locker"] categories = ["gui"] +[features] +default = ["use-nightly"] +use-nightly = [] + [dependencies] anyhow = "1" clap = "3" bscreensaver-command = { path = "../command" } bscreensaver-util = { path = "../util" } +libc = "0.2" log = "0.4" nix = "0.23" # git source needed until extension event error resolution fix is released diff --git a/locker/src/main.rs b/locker/src/main.rs index 5ae1beb..2378581 100644 --- a/locker/src/main.rs +++ b/locker/src/main.rs @@ -1,5 +1,8 @@ -#![feature(linux_pidfd)] -#![feature(option_result_contains)] +#![cfg_attr(feature = "use-nightly", feature(linux_pidfd))] +#![cfg_attr(feature = "use-nightly", feature(option_result_contains))] + +#[cfg(not(feature = "use-nightly"))] +mod pidfd; use clap::{Arg, Command as ClapCommand}; use log::{debug, error, info, trace, warn}; @@ -17,7 +20,6 @@ use std::{ fs::read_link, io::{self, Read}, os::{ - linux::process::{ChildExt, CommandExt, PidFd}, unix::io::AsRawFd, unix::process::ExitStatusExt, }, @@ -30,6 +32,11 @@ use xcb_xembed::embedder::Embedder; use bscreensaver_command::{BCommand, create_command_window}; use bscreensaver_util::{*, settings::Configuration}; +#[cfg(feature = "use-nightly")] +use std::os::linux::process::{ChildExt, CommandExt, PidFd}; +#[cfg(not(feature = "use-nightly"))] +use pidfd::{CreatePidFd, PidFd}; + const BLANKED_ARG: &str = "blanked"; const LOCKED_ARG: &str = "locked"; @@ -202,9 +209,9 @@ fn main() -> anyhow::Result<()> { let result = match pfd.as_raw_fd() { fd if fd == signal_fd.as_raw_fd() => handle_signals(&mut state, &mut signal_fd), fd if fd == conn.as_raw_fd() => handle_xcb_events(&conn, &mut state, &command_atoms), - fd if dbus_service_fd.contains(&fd) => handle_subservice_quit(state.dbus_service.take(), "DBus", || start_dbus_service(&mut state)), - fd if systemd_service_fd.contains(&fd) => handle_subservice_quit(state.systemd_service.take(), "systemd", || start_systemd_service(&mut state)), - fd if dialog_fd.contains(&fd) => handle_unlock_dialog_quit(&conn, &mut state), + fd if opt_contains(&dbus_service_fd, &fd) => handle_subservice_quit(state.dbus_service.take(), "DBus", || start_dbus_service(&mut state)), + fd if opt_contains(&systemd_service_fd, &fd) => handle_subservice_quit(state.systemd_service.take(), "systemd", || start_systemd_service(&mut state)), + fd if opt_contains(&dialog_fd, &fd) => handle_unlock_dialog_quit(&conn, &mut state), _ => Ok(()), }; @@ -425,10 +432,16 @@ fn create_blanker_windows(conn: &xcb::Connection) -> xcb::Result> { } fn start_subservice(binary_name: &str) -> anyhow::Result<(Child, PidFd)> { - let mut child = Command::new(format!("{}/{}", env!("HELPER_DIR"), binary_name)) - .create_pidfd(true) - .spawn()?; + let mut command = Command::new(format!("{}/{}", env!("HELPER_DIR"), binary_name)); + #[cfg(feature = "use-nightly")] + command.create_pidfd(true); + let mut child = command.spawn()?; + + #[cfg(feature = "use-nightly")] let pidfd = child.take_pidfd()?; + #[cfg(not(feature = "use-nightly"))] + let pidfd = child.create_pidfd()?; + Ok((child, pidfd)) } @@ -670,13 +683,18 @@ fn start_unlock_dialog<'a>(conn: &'a xcb::Connection, state: &State<'a>, trigger state.monitors.iter().nth(0).unwrap() }); - let mut child = Command::new(format!("{}/{}", env!("HELPER_DIR"), state.config.dialog_backend.binary_name())) - .create_pidfd(true) + let mut command = Command::new(format!("{}/{}", env!("HELPER_DIR"), state.config.dialog_backend.binary_name())); + #[cfg(feature = "use-nightly")] + command.create_pidfd(true); + let mut child = command .stdout(Stdio::piped()) .spawn()?; let mut child_out = child.stdout.take().unwrap(); + #[cfg(feature = "use-nightly")] let child_pidfd = child.take_pidfd()?; + #[cfg(not(feature = "use-nightly"))] + let child_pidfd = child.create_pidfd()?; let mut xid_buf: [u8; 4] = [0; 4]; child_out.read_exact(&mut xid_buf)?; @@ -913,3 +931,12 @@ fn kill_child_processes(state: &mut State) -> anyhow::Result<()> { Ok(()) } + +fn opt_contains(o: &Option, v: &T) -> bool { + #[cfg(feature = "use-nightly")] + let res = o.contains(v); + #[cfg(not(feature = "use-nightly"))] + let res = o.as_ref().filter(|ov| ov == &v).is_some(); + + res +} diff --git a/locker/src/pidfd.rs b/locker/src/pidfd.rs new file mode 100644 index 0000000..ef46166 --- /dev/null +++ b/locker/src/pidfd.rs @@ -0,0 +1,45 @@ +use std::{os::unix::io::{AsRawFd, RawFd}, process::Child}; + +fn pidfd_open(pid: RawFd) -> nix::Result { + // SAFETY: passing arguments as specified for pidfd_open() + match unsafe { libc::syscall(libc::SYS_pidfd_open, pid as libc::pid_t, 0 as libc::c_uint) } { + fd if fd >= 0 => Ok(PidFd(fd as RawFd)), + _ => { + // SAFETY: libc must be sane + let errno_location = unsafe { libc::__errno_location() }; + if errno_location.is_null() { + Err(nix::errno::Errno::UnknownErrno) + } else { + // SAFETY: pointer is checked for null; libc must be sane + let errno = unsafe { *errno_location }; + Err(nix::errno::Errno::from_i32(errno)) + } + } + } +} + +pub struct PidFd(RawFd); + +pub trait CreatePidFd { + // mut isn't necessary here, but it is for the nightly PidFd stuff, + // so keep it like this to avoid a warning when compiling using stable. + fn create_pidfd(&mut self) -> nix::Result; +} + +impl CreatePidFd for Child { + fn create_pidfd(&mut self) -> nix::Result { + pidfd_open(self.id() as RawFd) + } +} + +impl AsRawFd for PidFd { + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +impl Drop for PidFd { + fn drop(&mut self) { + let _ = nix::unistd::close(self.0); + } +} diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index bf867e0..0000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly