1extern crate data_model;
8extern crate libc;
9extern crate syscall_defines;
10#[allow(unused_imports)]
11#[macro_use]
12extern crate poll_token_derive;
13extern crate sync;
14
15#[macro_use]
16pub mod handle_eintr;
17#[macro_use]
18pub mod ioctl;
19#[macro_use]
20pub mod syslog;
21mod clock;
22mod errno;
23mod eventfd;
24mod file_flags;
25mod file_traits;
26mod fork;
27mod guest_address;
28pub mod guest_memory;
29mod mmap;
30pub mod net;
31mod passwd;
32mod poll;
33mod priority;
34mod raw_fd;
35mod seek_hole;
36mod shm;
37pub mod signal;
38mod signalfd;
39mod sock_ctrl_msg;
40mod struct_util;
41mod tempdir;
42mod terminal;
43mod timerfd;
44mod write_zeroes;
45
46pub use clock::{Clock, FakeClock};
47use errno::errno_result;
48pub use errno::{Error, Result};
49pub use eventfd::*;
50pub use file_flags::*;
51pub use fork::*;
52pub use guest_address::*;
53pub use guest_memory::*;
54pub use ioctl::*;
55pub use mmap::*;
56pub use passwd::*;
57pub use poll::*;
58pub use poll_token_derive::*;
59pub use priority::*;
60pub use raw_fd::*;
61pub use shm::*;
62pub use signal::*;
63pub use signalfd::*;
64pub use sock_ctrl_msg::*;
65pub use struct_util::*;
66pub use tempdir::*;
67pub use terminal::*;
68pub use timerfd::*;
69
70pub use file_traits::{FileSetLen, FileSync};
71pub use guest_memory::Error as GuestMemoryError;
72pub use mmap::Error as MmapError;
73pub use seek_hole::SeekHole;
74pub use signalfd::Error as SignalFdError;
75pub use write_zeroes::{PunchHole, WriteZeroes};
76
77use std::ffi::CStr;
78use std::fs::{remove_file, File};
79use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
80use std::os::unix::net::UnixDatagram;
81use std::ptr;
82
83use libc::{
84 c_long, gid_t, kill, pid_t, pipe2, syscall, sysconf, uid_t, waitpid, O_CLOEXEC, SIGKILL,
85 WNOHANG, _SC_PAGESIZE,
86};
87
88use syscall_defines::linux::LinuxSyscall::SYS_getpid;
89
90#[inline(always)]
92pub fn pagesize() -> usize {
93 unsafe { sysconf(_SC_PAGESIZE) as usize }
95}
96
97#[inline(always)]
99pub fn round_up_to_page_size(v: usize) -> usize {
100 let page_mask = pagesize() - 1;
101 (v + page_mask) & !page_mask
102}
103
104#[inline(always)]
107pub fn getpid() -> pid_t {
108 unsafe { syscall(SYS_getpid as c_long) as pid_t }
110}
111
112#[inline(always)]
114pub fn geteuid() -> uid_t {
115 unsafe { libc::geteuid() }
117}
118
119#[inline(always)]
121pub fn getegid() -> gid_t {
122 unsafe { libc::getegid() }
124}
125
126#[inline(always)]
128pub fn chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()> {
129 let ret = unsafe { libc::chown(path.as_ptr(), uid, gid) };
131
132 if ret < 0 {
133 errno_result()
134 } else {
135 Ok(())
136 }
137}
138
139pub enum FlockOperation {
141 LockShared,
142 LockExclusive,
143 Unlock,
144}
145
146#[inline(always)]
149pub fn flock(file: &AsRawFd, op: FlockOperation, nonblocking: bool) -> Result<()> {
150 let mut operation = match op {
151 FlockOperation::LockShared => libc::LOCK_SH,
152 FlockOperation::LockExclusive => libc::LOCK_EX,
153 FlockOperation::Unlock => libc::LOCK_UN,
154 };
155
156 if nonblocking {
157 operation |= libc::LOCK_NB;
158 }
159
160 let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
162
163 if ret < 0 {
164 errno_result()
165 } else {
166 Ok(())
167 }
168}
169
170pub enum FallocateMode {
172 PunchHole,
173 ZeroRange,
174}
175
176pub fn fallocate(
178 file: &AsRawFd,
179 mode: FallocateMode,
180 keep_size: bool,
181 offset: u64,
182 len: u64,
183) -> Result<()> {
184 let offset = if offset > libc::off64_t::max_value() as u64 {
185 return Err(Error::new(libc::EINVAL));
186 } else {
187 offset as libc::off64_t
188 };
189
190 let len = if len > libc::off64_t::max_value() as u64 {
191 return Err(Error::new(libc::EINVAL));
192 } else {
193 len as libc::off64_t
194 };
195
196 let mut mode = match mode {
197 FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE,
198 FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE,
199 };
200
201 if keep_size {
202 mode |= libc::FALLOC_FL_KEEP_SIZE;
203 }
204
205 let ret = unsafe { libc::fallocate64(file.as_raw_fd(), mode, offset, len) };
208 if ret < 0 {
209 errno_result()
210 } else {
211 Ok(())
212 }
213}
214
215pub fn reap_child() -> Result<pid_t> {
243 let ret = unsafe { waitpid(-1, ptr::null_mut(), WNOHANG) };
245 if ret == -1 {
246 errno_result()
247 } else {
248 Ok(ret)
249 }
250}
251
252pub fn kill_process_group() -> Result<()> {
257 let ret = unsafe { kill(0, SIGKILL) };
258 if ret == -1 {
259 errno_result()
260 } else {
261 unreachable!();
263 }
264}
265
266pub fn pipe(close_on_exec: bool) -> Result<(File, File)> {
270 let flags = if close_on_exec { O_CLOEXEC } else { 0 };
271 let mut pipe_fds = [-1; 2];
272 let ret = unsafe { pipe2(&mut pipe_fds[0], flags) };
275 if ret == -1 {
276 errno_result()
277 } else {
278 Ok(unsafe {
281 (
282 File::from_raw_fd(pipe_fds[0]),
283 File::from_raw_fd(pipe_fds[1]),
284 )
285 })
286 }
287}
288
289pub struct UnlinkUnixDatagram(pub UnixDatagram);
291impl AsRef<UnixDatagram> for UnlinkUnixDatagram {
292 fn as_ref(&self) -> &UnixDatagram {
293 &self.0
294 }
295}
296impl Drop for UnlinkUnixDatagram {
297 fn drop(&mut self) {
298 if let Ok(addr) = self.0.local_addr() {
299 if let Some(path) = addr.as_pathname() {
300 if let Err(e) = remove_file(path) {
301 warn!("failed to remove control socket file: {:?}", e);
302 }
303 }
304 }
305 }
306}
307
308pub fn validate_raw_fd(raw_fd: RawFd) -> Result<RawFd> {
311 let flags = unsafe { libc::fcntl(raw_fd, libc::F_GETFD) };
315 if flags < 0 || (flags & libc::FD_CLOEXEC) != 0 {
316 return Err(Error::new(libc::EBADF));
317 }
318
319 let dup_fd = unsafe { libc::fcntl(raw_fd, libc::F_DUPFD_CLOEXEC, 0) };
323 if dup_fd < 0 {
324 return Err(Error::last());
325 }
326 Ok(dup_fd as RawFd)
327}