1 // Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved.
2 //
3 // StratoVirt is licensed under Mulan PSL v2.
4 // You can use this software according to the terms and conditions of the Mulan
5 // PSL v2.
6 // You may obtain a copy of Mulan PSL v2 at:
7 //         http://license.coscl.org.cn/MulanPSL2
8 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
9 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
10 // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 // See the Mulan PSL v2 for more details.
12 
13 pub mod logger;
14 pub mod prctl;
15 
16 mod channel;
17 mod clone;
18 mod error;
19 
20 pub use channel::{Channel, Message};
21 pub use clone::Clone3;
22 pub use error::OzonecErr;
23 
24 use std::{
25     fs::create_dir_all,
26     mem,
27     os::unix::io::{AsRawFd, RawFd},
28     path::{Path, PathBuf},
29 };
30 
31 use anyhow::{bail, Context, Result};
32 use nix::{
33     errno::errno,
34     fcntl::{open, OFlag},
35     sys::stat::Mode,
36     NixPath,
37 };
38 
39 struct OpenHow(libc::open_how);
40 
41 bitflags::bitflags! {
42     struct ResolveFlag: libc::c_ulonglong {
43         const RESOLVE_BENEATH = libc::RESOLVE_BENEATH;
44         const RESOLVE_IN_ROOT = libc::RESOLVE_IN_ROOT;
45         const RESOLVE_NO_MAGICLINKS = libc::RESOLVE_NO_MAGICLINKS;
46         const RESOLVE_NO_SYMLINKS = libc::RESOLVE_NO_SYMLINKS;
47         const RESOLVE_NO_XDEV = libc::RESOLVE_NO_XDEV;
48     }
49 }
50 
51 impl OpenHow {
new() -> Self52     fn new() -> Self {
53         // SAFETY: FFI call with valid arguments.
54         unsafe { mem::zeroed() }
55     }
56 
flags(mut self, flags: OFlag) -> Self57     fn flags(mut self, flags: OFlag) -> Self {
58         let flags = flags.bits() as libc::c_ulonglong;
59         self.0.flags = flags;
60         self
61     }
62 
mode(mut self, mode: Mode) -> Self63     fn mode(mut self, mode: Mode) -> Self {
64         let mode = mode.bits() as libc::c_ulonglong;
65         self.0.mode = mode;
66         self
67     }
68 
resolve(mut self, resolve: ResolveFlag) -> Self69     fn resolve(mut self, resolve: ResolveFlag) -> Self {
70         let resolve = resolve.bits() as libc::c_ulonglong;
71         self.0.resolve = resolve;
72         self
73     }
74 }
75 
76 /// Get a file descriptor by openat2 with `root` path, relative `target` path in `root`
77 /// and whether is director or not. If the target directory or file doesn't exist, create
78 /// automatically.
openat2_in_root(root: &Path, target: &Path, is_dir: bool) -> Result<RawFd>79 pub fn openat2_in_root(root: &Path, target: &Path, is_dir: bool) -> Result<RawFd> {
80     let mut flags = OFlag::O_CLOEXEC;
81     let mode;
82     if is_dir {
83         flags |= OFlag::O_DIRECTORY | OFlag::O_PATH;
84         mode = Mode::empty();
85         create_dir_all(root.join(target))
86             .with_context(|| OzonecErr::CreateDir(target.to_string_lossy().to_string()))?;
87     } else {
88         flags |= OFlag::O_CREAT;
89         mode = Mode::S_IRWXU;
90     };
91 
92     let mut open_how = OpenHow::new()
93         .flags(flags)
94         .mode(mode)
95         .resolve(ResolveFlag::RESOLVE_IN_ROOT);
96     let dirfd = open(root, flags & !OFlag::O_CREAT, Mode::empty())
97         .with_context(|| OzonecErr::OpenFile(root.to_string_lossy().to_string()))?;
98     let fd = target
99         // SAFETY: FFI call with valid arguments.
100         .with_nix_path(|p| unsafe {
101             libc::syscall(
102                 libc::SYS_openat2,
103                 dirfd.as_raw_fd(),
104                 p.as_ptr(),
105                 &mut open_how as *mut OpenHow,
106                 mem::size_of::<libc::open_how>(),
107             )
108         })
109         .with_context(|| "with_nix_path error")?;
110     if fd < 0 {
111         bail!(
112             "openat2 {} error with RESOLVE_IN_ROOT: {}",
113             target.display(),
114             errno()
115         );
116     }
117     Ok(RawFd::try_from(fd)?)
118 }
119 
120 /// Build path "/proc/self/fd/{}" with an opened file descriptor.
proc_fd_path(dirfd: RawFd) -> PathBuf121 pub fn proc_fd_path(dirfd: RawFd) -> PathBuf {
122     PathBuf::from(format!("/proc/self/fd/{}", dirfd))
123 }
124