// Copyright 2018 Yuya Nishihara // // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. //! Low-level utility for signal and process handling. use libc::{self, c_int, pid_t, size_t, ssize_t}; use std::io; use std::os::unix::io::RawFd; use std::sync; #[link(name = "procutil", kind = "static")] extern "C" { // sendfds.c fn sendfds(sockfd: c_int, fds: *const c_int, fdlen: size_t) -> ssize_t; // sighandlers.c fn setupsignalhandler(pid: pid_t, pgid: pid_t) -> c_int; fn restoresignalhandler() -> c_int; } /// Returns the effective uid of the current process. pub fn get_effective_uid() -> u32 { unsafe { libc::geteuid() } } /// Returns the umask of the current process. /// /// # Safety /// /// This is unsafe because the umask value is temporarily changed, and /// the change can be observed from the other threads. Don't call this in /// multi-threaded context. pub unsafe fn get_umask() -> u32 { let mask = libc::umask(0); libc::umask(mask); mask } /// Changes the given fd to blocking mode. pub fn set_blocking_fd(fd: RawFd) -> io::Result<()> { let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) }; if flags < 0 { return Err(io::Error::last_os_error()); } let r = unsafe { libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK) }; if r < 0 { return Err(io::Error::last_os_error()); } Ok(()) } /// Sends file descriptors via the given socket. pub fn send_raw_fds(sock_fd: RawFd, fds: &[RawFd]) -> io::Result<()> { let r = unsafe { sendfds(sock_fd, fds.as_ptr(), fds.len() as size_t) }; if r < 0 { return Err(io::Error::last_os_error()); } Ok(()) } static SETUP_SIGNAL_HANDLER: sync::Once = sync::Once::new(); static RESTORE_SIGNAL_HANDLER: sync::Once = sync::Once::new(); /// Installs signal handlers to forward signals to the server. /// /// # Safety /// /// This touches global states, and thus synchronized as a one-time /// initialization function. pub fn setup_signal_handler_once( pid: u32, pgid: Option, ) -> io::Result<()> { let pid_signed = pid as i32; let pgid_signed = pgid.map(|n| n as i32).unwrap_or(0); let mut r = 0; SETUP_SIGNAL_HANDLER.call_once(|| { r = unsafe { setupsignalhandler(pid_signed, pgid_signed) }; }); if r < 0 { return Err(io::Error::last_os_error()); } Ok(()) } /// Restores the original signal handlers. /// /// # Safety /// /// This touches global states, and thus synchronized as a one-time /// initialization function. pub fn restore_signal_handler_once() -> io::Result<()> { let mut r = 0; RESTORE_SIGNAL_HANDLER.call_once(|| { r = unsafe { restoresignalhandler() }; }); if r < 0 { return Err(io::Error::last_os_error()); } Ok(()) }