|
|
// Copyright 2018 Yuya Nishihara <yuya@tcha.org>
|
|
|
//
|
|
|
// 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<u32>,
|
|
|
) -> 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(())
|
|
|
}
|
|
|
|