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