extern crate data_model;
extern crate libc;
extern crate syscall_defines;
#[allow(unused_imports)]
#[macro_use]
extern crate poll_token_derive;
extern crate sync;
#[macro_use]
pub mod handle_eintr;
#[macro_use]
pub mod ioctl;
#[macro_use]
pub mod syslog;
mod clock;
mod errno;
mod eventfd;
mod file_flags;
mod file_traits;
mod fork;
mod guest_address;
pub mod guest_memory;
mod mmap;
pub mod net;
mod passwd;
mod poll;
mod priority;
mod raw_fd;
mod seek_hole;
mod shm;
pub mod signal;
mod signalfd;
mod sock_ctrl_msg;
mod struct_util;
mod tempdir;
mod terminal;
mod timerfd;
mod write_zeroes;
pub use clock::{Clock, FakeClock};
use errno::errno_result;
pub use errno::{Error, Result};
pub use eventfd::*;
pub use file_flags::*;
pub use fork::*;
pub use guest_address::*;
pub use guest_memory::*;
pub use ioctl::*;
pub use mmap::*;
pub use passwd::*;
pub use poll::*;
pub use poll_token_derive::*;
pub use priority::*;
pub use raw_fd::*;
pub use shm::*;
pub use signal::*;
pub use signalfd::*;
pub use sock_ctrl_msg::*;
pub use struct_util::*;
pub use tempdir::*;
pub use terminal::*;
pub use timerfd::*;
pub use file_traits::{FileSetLen, FileSync};
pub use guest_memory::Error as GuestMemoryError;
pub use mmap::Error as MmapError;
pub use seek_hole::SeekHole;
pub use signalfd::Error as SignalFdError;
pub use write_zeroes::{PunchHole, WriteZeroes};
use std::ffi::CStr;
use std::fs::{remove_file, File};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::net::UnixDatagram;
use std::ptr;
use libc::{
c_long, gid_t, kill, pid_t, pipe2, syscall, sysconf, uid_t, waitpid, O_CLOEXEC, SIGKILL,
WNOHANG, _SC_PAGESIZE,
};
use syscall_defines::linux::LinuxSyscall::SYS_getpid;
#[inline(always)]
pub fn pagesize() -> usize {
unsafe { sysconf(_SC_PAGESIZE) as usize }
}
#[inline(always)]
pub fn round_up_to_page_size(v: usize) -> usize {
let page_mask = pagesize() - 1;
(v + page_mask) & !page_mask
}
#[inline(always)]
pub fn getpid() -> pid_t {
unsafe { syscall(SYS_getpid as c_long) as pid_t }
}
#[inline(always)]
pub fn geteuid() -> uid_t {
unsafe { libc::geteuid() }
}
#[inline(always)]
pub fn getegid() -> gid_t {
unsafe { libc::getegid() }
}
#[inline(always)]
pub fn chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()> {
let ret = unsafe { libc::chown(path.as_ptr(), uid, gid) };
if ret < 0 {
errno_result()
} else {
Ok(())
}
}
pub enum FlockOperation {
LockShared,
LockExclusive,
Unlock,
}
#[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;
}
let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
if ret < 0 {
errno_result()
} else {
Ok(())
}
}
pub enum FallocateMode {
PunchHole,
ZeroRange,
}
pub fn fallocate(
file: &AsRawFd,
mode: FallocateMode,
keep_size: bool,
offset: u64,
len: u64,
) -> Result<()> {
let offset = if offset > libc::off64_t::max_value() as u64 {
return Err(Error::new(libc::EINVAL));
} else {
offset as libc::off64_t
};
let len = if len > libc::off64_t::max_value() as u64 {
return Err(Error::new(libc::EINVAL));
} else {
len as libc::off64_t
};
let mut mode = match mode {
FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE,
FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE,
};
if keep_size {
mode |= libc::FALLOC_FL_KEEP_SIZE;
}
let ret = unsafe { libc::fallocate64(file.as_raw_fd(), mode, offset, len) };
if ret < 0 {
errno_result()
} else {
Ok(())
}
}
pub fn reap_child() -> Result<pid_t> {
let ret = unsafe { waitpid(-1, ptr::null_mut(), WNOHANG) };
if ret == -1 {
errno_result()
} else {
Ok(ret)
}
}
pub fn kill_process_group() -> Result<()> {
let ret = unsafe { kill(0, SIGKILL) };
if ret == -1 {
errno_result()
} else {
unreachable!();
}
}
pub fn pipe(close_on_exec: bool) -> Result<(File, File)> {
let flags = if close_on_exec { O_CLOEXEC } else { 0 };
let mut pipe_fds = [-1; 2];
let ret = unsafe { pipe2(&mut pipe_fds[0], flags) };
if ret == -1 {
errno_result()
} else {
Ok(unsafe {
(
File::from_raw_fd(pipe_fds[0]),
File::from_raw_fd(pipe_fds[1]),
)
})
}
}
pub struct UnlinkUnixDatagram(pub UnixDatagram);
impl AsRef<UnixDatagram> for UnlinkUnixDatagram {
fn as_ref(&self) -> &UnixDatagram {
&self.0
}
}
impl Drop for UnlinkUnixDatagram {
fn drop(&mut self) {
if let Ok(addr) = self.0.local_addr() {
if let Some(path) = addr.as_pathname() {
if let Err(e) = remove_file(path) {
warn!("failed to remove control socket file: {:?}", e);
}
}
}
}
}
pub fn validate_raw_fd(raw_fd: RawFd) -> Result<RawFd> {
let flags = unsafe { libc::fcntl(raw_fd, libc::F_GETFD) };
if flags < 0 || (flags & libc::FD_CLOEXEC) != 0 {
return Err(Error::new(libc::EBADF));
}
let dup_fd = unsafe { libc::fcntl(raw_fd, libc::F_DUPFD_CLOEXEC, 0) };
if dup_fd < 0 {
return Err(Error::last());
}
Ok(dup_fd as RawFd)
}