sys_util/
lib.rs

1// Copyright 2017 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Small system utility modules for usage by other modules.
6
7extern 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/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
91#[inline(always)]
92pub fn pagesize() -> usize {
93    // Trivially safe
94    unsafe { sysconf(_SC_PAGESIZE) as usize }
95}
96
97/// Uses the system's page size in bytes to round the given value up to the nearest page boundary.
98#[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/// This bypasses `libc`'s caching `getpid(2)` wrapper which can be invalid if a raw clone was used
105/// elsewhere.
106#[inline(always)]
107pub fn getpid() -> pid_t {
108    // Safe because this syscall can never fail and we give it a valid syscall number.
109    unsafe { syscall(SYS_getpid as c_long) as pid_t }
110}
111
112/// Safe wrapper for `geteuid(2)`.
113#[inline(always)]
114pub fn geteuid() -> uid_t {
115    // trivially safe
116    unsafe { libc::geteuid() }
117}
118
119/// Safe wrapper for `getegid(2)`.
120#[inline(always)]
121pub fn getegid() -> gid_t {
122    // trivially safe
123    unsafe { libc::getegid() }
124}
125
126/// Safe wrapper for chown(2).
127#[inline(always)]
128pub fn chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()> {
129    // Safe since we pass in a valid string pointer and check the return value.
130    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
139/// The operation to perform with `flock`.
140pub enum FlockOperation {
141    LockShared,
142    LockExclusive,
143    Unlock,
144}
145
146/// Safe wrapper for flock(2) with the operation `op` and optionally `nonblocking`. The lock will be
147/// dropped automatically when `file` is dropped.
148#[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    // Safe since we pass in a valid fd and flock operation, and check the return value.
161    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
170/// The operation to perform with `fallocate`.
171pub enum FallocateMode {
172    PunchHole,
173    ZeroRange,
174}
175
176/// Safe wrapper for `fallocate()`.
177pub 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    // Safe since we pass in a valid fd and fallocate mode, validate offset and len,
206    // and check the return value.
207    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
215/// Reaps a child process that has terminated.
216///
217/// Returns `Ok(pid)` where `pid` is the process that was reaped or `Ok(0)` if none of the children
218/// have terminated. An `Error` is with `errno == ECHILD` if there are no children left to reap.
219///
220/// # Examples
221///
222/// Reaps all child processes until there are no terminated children to reap.
223///
224/// ```
225/// # extern crate libc;
226/// # extern crate sys_util;
227/// fn reap_children() {
228///     loop {
229///         match sys_util::reap_child() {
230///             Ok(0) => println!("no children ready to reap"),
231///             Ok(pid) => {
232///                 println!("reaped {}", pid);
233///                 continue
234///             },
235///             Err(e) if e.errno() == libc::ECHILD => println!("no children left"),
236///             Err(e) => println!("error reaping children: {:?}", e),
237///         }
238///         break
239///     }
240/// }
241/// ```
242pub fn reap_child() -> Result<pid_t> {
243    // Safe because we pass in no memory, prevent blocking with WNOHANG, and check for error.
244    let ret = unsafe { waitpid(-1, ptr::null_mut(), WNOHANG) };
245    if ret == -1 {
246        errno_result()
247    } else {
248        Ok(ret)
249    }
250}
251
252/// Kill all processes in the current process group.
253///
254/// On success, this kills all processes in the current process group, including the current
255/// process, meaning this will not return. This is equivalent to a call to `kill(0, SIGKILL)`.
256pub fn kill_process_group() -> Result<()> {
257    let ret = unsafe { kill(0, SIGKILL) };
258    if ret == -1 {
259        errno_result()
260    } else {
261        // Kill succeeded, so this process never reaches here.
262        unreachable!();
263    }
264}
265
266/// Spawns a pipe pair where the first pipe is the read end and the second pipe is the write end.
267///
268/// If `close_on_exec` is true, the `O_CLOEXEC` flag will be set during pipe creation.
269pub 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    // Safe because pipe2 will only write 2 element array of i32 to the given pointer, and we check
273    // for error.
274    let ret = unsafe { pipe2(&mut pipe_fds[0], flags) };
275    if ret == -1 {
276        errno_result()
277    } else {
278        // Safe because both fds must be valid for pipe2 to have returned sucessfully and we have
279        // exclusive ownership of them.
280        Ok(unsafe {
281            (
282                File::from_raw_fd(pipe_fds[0]),
283                File::from_raw_fd(pipe_fds[1]),
284            )
285        })
286    }
287}
288
289/// Used to attempt to clean up a named pipe after it is no longer used.
290pub 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
308/// Verifies that |raw_fd| is actually owned by this process and duplicates it to ensure that
309/// we have a unique handle to it.
310pub fn validate_raw_fd(raw_fd: RawFd) -> Result<RawFd> {
311    // Checking that close-on-exec isn't set helps filter out FDs that were opened by
312    // crosvm as all crosvm FDs are close on exec.
313    // Safe because this doesn't modify any memory and we check the return value.
314    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    // Duplicate the fd to ensure that we don't accidentally close an fd previously
320    // opened by another subsystem.  Safe because this doesn't modify any memory and
321    // we check the return value.
322    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}