2017-05-03 21:06:12 +00:00
|
|
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
//! Small system utility modules for usage by other modules.
|
|
|
|
|
2017-06-20 17:15:51 +00:00
|
|
|
extern crate data_model;
|
2017-05-03 21:06:12 +00:00
|
|
|
extern crate libc;
|
2017-06-28 17:33:13 +00:00
|
|
|
extern crate syscall_defines;
|
2018-02-28 06:22:35 +00:00
|
|
|
#[allow(unused_imports)]
|
|
|
|
#[macro_use]
|
|
|
|
extern crate poll_token_derive;
|
2017-05-03 21:06:12 +00:00
|
|
|
|
2017-06-29 18:35:17 +00:00
|
|
|
#[macro_use]
|
|
|
|
pub mod handle_eintr;
|
2017-07-11 01:33:19 +00:00
|
|
|
#[macro_use]
|
|
|
|
pub mod ioctl;
|
|
|
|
#[macro_use]
|
|
|
|
pub mod syslog;
|
2017-05-03 21:06:12 +00:00
|
|
|
mod mmap;
|
2017-07-07 00:02:26 +00:00
|
|
|
mod shm;
|
2017-05-03 21:29:14 +00:00
|
|
|
mod eventfd;
|
2017-05-03 21:06:12 +00:00
|
|
|
mod errno;
|
2017-05-16 00:37:47 +00:00
|
|
|
mod guest_address;
|
|
|
|
mod guest_memory;
|
2017-05-25 03:09:22 +00:00
|
|
|
mod poll;
|
2017-05-04 02:37:03 +00:00
|
|
|
mod struct_util;
|
2017-05-31 23:10:25 +00:00
|
|
|
mod tempdir;
|
2017-05-25 03:11:50 +00:00
|
|
|
mod terminal;
|
2018-02-22 19:35:05 +00:00
|
|
|
pub mod signal;
|
2017-05-31 01:49:48 +00:00
|
|
|
mod fork;
|
2017-06-29 23:10:21 +00:00
|
|
|
mod signalfd;
|
2017-07-07 00:59:49 +00:00
|
|
|
mod sock_ctrl_msg;
|
2017-10-20 18:02:26 +00:00
|
|
|
mod passwd;
|
2017-05-03 21:06:12 +00:00
|
|
|
|
|
|
|
pub use mmap::*;
|
2017-07-07 00:02:26 +00:00
|
|
|
pub use shm::*;
|
2017-05-03 21:29:14 +00:00
|
|
|
pub use eventfd::*;
|
2017-05-03 21:06:12 +00:00
|
|
|
pub use errno::{Error, Result};
|
|
|
|
use errno::errno_result;
|
2017-05-16 00:37:47 +00:00
|
|
|
pub use guest_address::*;
|
|
|
|
pub use guest_memory::*;
|
2017-05-25 03:09:22 +00:00
|
|
|
pub use poll::*;
|
2017-05-04 02:37:03 +00:00
|
|
|
pub use struct_util::*;
|
2017-05-31 23:10:25 +00:00
|
|
|
pub use tempdir::*;
|
2017-05-25 03:11:50 +00:00
|
|
|
pub use terminal::*;
|
2017-05-23 18:16:24 +00:00
|
|
|
pub use signal::*;
|
2017-05-31 01:49:48 +00:00
|
|
|
pub use fork::*;
|
2017-06-29 23:10:21 +00:00
|
|
|
pub use signalfd::*;
|
2017-07-11 01:33:19 +00:00
|
|
|
pub use ioctl::*;
|
2017-07-07 00:59:49 +00:00
|
|
|
pub use sock_ctrl_msg::*;
|
2017-10-20 18:02:26 +00:00
|
|
|
pub use passwd::*;
|
2018-02-28 06:22:35 +00:00
|
|
|
pub use poll_token_derive::*;
|
2017-05-04 21:58:06 +00:00
|
|
|
|
2017-08-04 22:12:58 +00:00
|
|
|
pub use mmap::Error as MmapError;
|
2017-05-04 21:58:06 +00:00
|
|
|
pub use guest_memory::Error as GuestMemoryError;
|
2017-06-29 23:10:21 +00:00
|
|
|
pub use signalfd::Error as SignalFdError;
|
2017-08-24 20:50:14 +00:00
|
|
|
|
2017-10-24 00:01:16 +00:00
|
|
|
use std::ffi::CStr;
|
2018-02-21 22:17:27 +00:00
|
|
|
use std::os::unix::io::AsRawFd;
|
2017-08-24 20:50:14 +00:00
|
|
|
use std::ptr;
|
|
|
|
|
2018-01-09 23:49:04 +00:00
|
|
|
use libc::{kill, syscall, sysconf, waitpid, c_long, pid_t, uid_t, gid_t, _SC_PAGESIZE,
|
|
|
|
SIGKILL, WNOHANG};
|
2017-08-24 20:50:14 +00:00
|
|
|
|
|
|
|
use syscall_defines::linux::LinuxSyscall::SYS_getpid;
|
|
|
|
|
2018-01-09 23:49:04 +00:00
|
|
|
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn pagesize() -> usize {
|
|
|
|
// Trivially safe
|
|
|
|
unsafe { sysconf(_SC_PAGESIZE) as usize }
|
|
|
|
}
|
|
|
|
|
2017-08-24 20:50:14 +00:00
|
|
|
/// This bypasses `libc`'s caching `getpid(2)` wrapper which can be invalid if a raw clone was used
|
|
|
|
/// elsewhere.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn getpid() -> pid_t {
|
|
|
|
// Safe because this syscall can never fail and we give it a valid syscall number.
|
2017-08-31 00:07:01 +00:00
|
|
|
unsafe { syscall(SYS_getpid as c_long) as pid_t }
|
2017-08-24 20:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Safe wrapper for `geteuid(2)`.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn geteuid() -> uid_t {
|
|
|
|
// trivially safe
|
|
|
|
unsafe { libc::geteuid() }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Safe wrapper for `getegid(2)`.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn getegid() -> gid_t {
|
|
|
|
// trivially safe
|
|
|
|
unsafe { libc::getegid() }
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:01:16 +00:00
|
|
|
/// Safe wrapper for chown(2).
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()> {
|
|
|
|
// Safe since we pass in a valid string pointer and check the return value.
|
|
|
|
let ret = unsafe { libc::chown(path.as_ptr(), uid, gid) };
|
|
|
|
|
|
|
|
if ret < 0 {
|
|
|
|
errno_result()
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-21 22:17:27 +00:00
|
|
|
/// The operation to perform with `flock`.
|
|
|
|
pub enum FlockOperation {
|
|
|
|
LockShared,
|
|
|
|
LockExclusive,
|
|
|
|
Unlock,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Safe wrapper for flock(2) with the operation `op` and optionally `nonblocking`. The lock will be
|
|
|
|
/// dropped automatically when `file` is dropped.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn flock(file: &AsRawFd, op: FlockOperation, nonblocking: bool) -> Result<()> {
|
|
|
|
let mut operation = match op {
|
|
|
|
FlockOperation::LockShared => libc::LOCK_SH,
|
|
|
|
FlockOperation::LockExclusive => libc::LOCK_EX,
|
|
|
|
FlockOperation::Unlock => libc::LOCK_UN,
|
|
|
|
};
|
|
|
|
|
|
|
|
if nonblocking {
|
|
|
|
operation |= libc::LOCK_NB;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Safe since we pass in a valid fd and flock operation, and check the return value.
|
|
|
|
let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
|
|
|
|
|
|
|
|
if ret < 0 {
|
|
|
|
errno_result()
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-24 20:50:14 +00:00
|
|
|
/// Reaps a child process that has terminated.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(pid)` where `pid` is the process that was reaped or `Ok(0)` if none of the children
|
|
|
|
/// have terminated. An `Error` is with `errno == ECHILD` if there are no children left to reap.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// Reaps all child processes until there are no terminated children to reap.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # extern crate libc;
|
|
|
|
/// # extern crate sys_util;
|
|
|
|
/// fn reap_children() {
|
|
|
|
/// loop {
|
|
|
|
/// match sys_util::reap_child() {
|
|
|
|
/// Ok(0) => println!("no children ready to reap"),
|
|
|
|
/// Ok(pid) => {
|
|
|
|
/// println!("reaped {}", pid);
|
|
|
|
/// continue
|
|
|
|
/// },
|
|
|
|
/// Err(e) if e.errno() == libc::ECHILD => println!("no children left"),
|
|
|
|
/// Err(e) => println!("error reaping children: {:?}", e),
|
|
|
|
/// }
|
|
|
|
/// break
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
pub fn reap_child() -> Result<pid_t> {
|
|
|
|
// Safe because we pass in no memory, prevent blocking with WNOHANG, and check for error.
|
|
|
|
let ret = unsafe { waitpid(-1, ptr::null_mut(), WNOHANG) };
|
|
|
|
if ret == -1 {
|
|
|
|
errno_result()
|
|
|
|
} else {
|
|
|
|
Ok(ret)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Kill all processes in the current process group.
|
|
|
|
///
|
|
|
|
/// On success, this kills all processes in the current process group, including the current
|
|
|
|
/// process, meaning this will not return. This is equivalent to a call to `kill(0, SIGKILL)`.
|
|
|
|
pub fn kill_process_group() -> Result<()> {
|
|
|
|
let ret = unsafe { kill(0, SIGKILL) };
|
|
|
|
if ret == -1 {
|
|
|
|
errno_result()
|
|
|
|
} else {
|
|
|
|
// Kill succeeded, so this process never reaches here.
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|