Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit64d1f40

Browse files
committed
feat(pivot_root): add pivot_root utility
Implement the pivot_root(2) syscall wrapper for changing the rootfilesystem. This utility is commonly used during container initializationand system boot.Features:- Linux/Android support via direct syscall- Graceful error on unsupported platforms- Detailed error messages with errno-specific hints- Non-UTF-8 path support via OsStringThe implementation delegates all path validation to the kernel,only checking for embedded null bytes which are invalid for C strings.
1 parente9b21aa commit64d1f40

File tree

9 files changed

+758
-0
lines changed

9 files changed

+758
-0
lines changed

‎Cargo.lock‎

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ feat_common_core = [
4242
"mesg",
4343
"mountpoint",
4444
"nologin",
45+
"pivot_root",
4546
"renice",
4647
"rev",
4748
"setpgid",
@@ -110,6 +111,7 @@ mcookie = { optional = true, version = "0.0.1", package = "uu_mcookie", path = "
110111
mesg = {optional =true,version ="0.0.1",package ="uu_mesg",path ="src/uu/mesg" }
111112
mountpoint = {optional =true,version ="0.0.1",package ="uu_mountpoint",path ="src/uu/mountpoint" }
112113
nologin = {optional =true,version ="0.0.1",package ="uu_nologin",path ="src/uu/nologin" }
114+
pivot_root = {optional =true,version ="0.0.1",package ="uu_pivot_root",path ="src/uu/pivot_root" }
113115
renice = {optional =true,version ="0.0.1",package ="uu_renice",path ="src/uu/renice" }
114116
rev = {optional =true,version ="0.0.1",package ="uu_rev",path ="src/uu/rev" }
115117
setpgid = {optional =true,version ="0.0.1",package ="uu_setpgid",path ="src/uu/setpgid" }

‎src/uu/pivot_root/Cargo.toml‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name ="uu_pivot_root"
3+
version ="0.0.1"
4+
edition ="2021"
5+
description ="change the root filesystem"
6+
7+
[lib]
8+
path ="src/pivot_root.rs"
9+
10+
[[bin]]
11+
name ="pivot_root"
12+
path ="src/main.rs"
13+
14+
[dependencies]
15+
clap = {workspace =true }
16+
libc = {workspace =true }
17+
uucore = {workspace =true }
18+
thiserror = {workspace =true }

‎src/uu/pivot_root/pivot_root.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pivot_root
2+
3+
```
4+
pivot_root NEW_ROOT PUT_OLD
5+
```
6+
7+
Change the root filesystem.
8+
9+
Moves the root filesystem of the calling process to the directory PUT_OLD and
10+
makes NEW_ROOT the new root filesystem.
11+
12+
This command requires the CAP_SYS_ADMIN capability and is typically used during
13+
container initialization or system boot.
14+
15+
- NEW_ROOT must be a mount point
16+
- PUT_OLD must be at or underneath NEW_ROOT

‎src/uu/pivot_root/src/errors.rs‎

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
// This file is part of the uutils util-linux package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
use std::ffi::{NulError,OsString};
7+
8+
#[derive(Debug)]
9+
#[allow(dead_code)]// Never constructed on non-Linux platforms
10+
pub(crate)enumPathWhich{
11+
NewRoot,
12+
PutOld,
13+
}
14+
15+
impl std::fmt::DisplayforPathWhich{
16+
fnfmt(&self,f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result{
17+
matchself{
18+
PathWhich::NewRoot =>write!(f,"new_root"),
19+
PathWhich::PutOld =>write!(f,"put_old"),
20+
}
21+
}
22+
}
23+
24+
#[derive(Debug, thiserror::Error)]
25+
pubenumPivotRootError{
26+
#[error("{which} path contains null byte at position {pos} (in '{path:?}')")]
27+
NulError{
28+
which:PathWhich,
29+
pos:usize,
30+
source:NulError,
31+
path:OsString,
32+
},
33+
34+
#[error("{message}")]
35+
SyscallFailed{
36+
message:String,
37+
source: std::io::Error,
38+
},
39+
40+
#[allow(dead_code)]// Only used on non-Linux platforms
41+
#[error("pivot_root is only supported on Linux")]
42+
UnsupportedPlatform,
43+
}
44+
45+
impl uucore::error::UErrorforPivotRootError{
46+
fncode(&self) ->i32{
47+
1
48+
}
49+
50+
fnusage(&self) ->bool{
51+
false
52+
}
53+
}
54+
55+
/// Convert a `std::io::Error` into a `PivotRootError` immediately after a
56+
/// failed `pivot_root(2)` syscall.
57+
///
58+
/// Important: this conversion is intended to be used right at the call site of
59+
/// `pivot_root`, with the error value obtained from `std::io::Error::last_os_error()`.
60+
/// Doing so preserves the correct `errno` from the kernel and lets us attach
61+
/// helpful hints to well-known error codes (e.g., `EPERM`, `EINVAL`). Using an
62+
/// arbitrary `std::io::Error` captured earlier or created in another context
63+
/// may carry a stale or unrelated `raw_os_error`, which would yield misleading
64+
/// diagnostics. The error codes can be obtained from the `pivot_root(2)` man page,
65+
/// which acknowledges that errors from the `stat(2)` system call may also occur.
66+
implFrom<std::io::Error>forPivotRootError{
67+
fnfrom(err: std::io::Error) ->Self{
68+
letmut msg =format!("failed to change root: {}", err);
69+
ifletSome(code) = err.raw_os_error(){
70+
msg.push_str(&format!(" (errno {code})"));
71+
msg.push_str(match code{
72+
libc::EPERM =>"; the calling process does not have the CAP_SYS_ADMIN capability",
73+
libc::EBUSY =>"; new_root or put_old is on the current root mount",
74+
libc::EINVAL =>{
75+
"; new_root is not a mount point, put_old is not at or underneath new_root,\
76+
the current root is not a mount point, the current root is on the rootfs,\
77+
or a mount point has propagation type MS_SHARED"
78+
}
79+
libc::ENOTDIR =>"; new_root or put_old is not a directory",
80+
libc::EACCES =>"; search permission denied for a directory in the path prefix",
81+
libc::EBADF =>"; bad file descriptor",
82+
libc::EFAULT =>"; new_root or put_old points outside the accessible address space",
83+
libc::ELOOP =>"; too many symbolic links encountered while resolving the path",
84+
libc::ENAMETOOLONG =>"; new_root or put_old path is too long",
85+
libc::ENOENT =>{
86+
"; a component of new_root or put_old does not exist,\
87+
or is a dangling symbolic link"
88+
}
89+
libc::ENOMEM =>"; out of kernel memory",
90+
libc::EOVERFLOW =>{
91+
"; path refers to a file whose size, inode number, or number of blocks\
92+
cannot be represented"
93+
}
94+
_ =>"",
95+
});
96+
}
97+
98+
PivotRootError::SyscallFailed{
99+
message: msg,
100+
source: err,
101+
}
102+
}
103+
}
104+
105+
#[cfg(test)]
106+
mod tests{
107+
usesuper::*;
108+
109+
#[test]
110+
fntest_nul_error_display(){
111+
// Create a NulError via CString::new
112+
let bytes =b"/tmp\0/dir";
113+
let err = std::ffi::CString::new(&bytes[..]).unwrap_err();
114+
let e =PivotRootError::NulError{
115+
which:PathWhich::NewRoot,
116+
pos: err.nul_position(),
117+
source: err,
118+
path:OsString::from("/tmp\u{0}/dir"),
119+
};
120+
let s = e.to_string();
121+
assert!(s.contains("new_root"),"{s}");
122+
assert!(s.contains("null byte"),"{s}");
123+
}
124+
125+
fnmsg_for(code:i32) ->String{
126+
let err = std::io::Error::from_raw_os_error(code);
127+
let e =PivotRootError::from(err);
128+
e.to_string()
129+
}
130+
131+
#[test]
132+
fntest_syscall_failed_eperm_hint(){
133+
let s =msg_for(libc::EPERM);
134+
assert!(s.contains("failed to change root"),"{s}");
135+
assert!(s.contains("errno"),"{s}");
136+
assert!(s.contains("CAP_SYS_ADMIN"),"{s}");
137+
}
138+
139+
#[test]
140+
fntest_syscall_failed_ebusy_hint(){
141+
let s =msg_for(libc::EBUSY);
142+
assert!(s.contains("failed to change root"),"{s}");
143+
assert!(s.contains("on the current root mount"),"{s}");
144+
}
145+
146+
#[test]
147+
fntest_syscall_failed_einval_hint(){
148+
let s =msg_for(libc::EINVAL);
149+
assert!(s.contains("failed to change root"),"{s}");
150+
assert!(s.contains("not a mount point"),"{s}");
151+
assert!(s.contains("MS_SHARED"),"{s}");
152+
}
153+
154+
#[test]
155+
fntest_syscall_failed_enotdir_hint(){
156+
let s =msg_for(libc::ENOTDIR);
157+
assert!(s.contains("failed to change root"),"{s}");
158+
assert!(s.contains("not a directory"),"{s}");
159+
}
160+
161+
#[test]
162+
fntest_syscall_failed_eacces_hint(){
163+
let s =msg_for(libc::EACCES);
164+
assert!(s.contains("failed to change root"),"{s}");
165+
assert!(s.contains("permission denied"),"{s}");
166+
}
167+
168+
#[test]
169+
fntest_syscall_failed_ebadf_hint(){
170+
let s =msg_for(libc::EBADF);
171+
assert!(s.contains("failed to change root"),"{s}");
172+
assert!(s.contains("bad file descriptor"),"{s}");
173+
}
174+
175+
#[test]
176+
fntest_syscall_failed_efault_hint(){
177+
let s =msg_for(libc::EFAULT);
178+
assert!(s.contains("failed to change root"),"{s}");
179+
assert!(s.contains("accessible address space"),"{s}");
180+
}
181+
182+
#[test]
183+
fntest_syscall_failed_eloop_hint(){
184+
let s =msg_for(libc::ELOOP);
185+
assert!(s.contains("failed to change root"),"{s}");
186+
assert!(s.contains("symbolic links"),"{s}");
187+
}
188+
189+
#[test]
190+
fntest_syscall_failed_enametoolong_hint(){
191+
let s =msg_for(libc::ENAMETOOLONG);
192+
assert!(s.contains("failed to change root"),"{s}");
193+
assert!(s.contains("path is too long"),"{s}");
194+
}
195+
196+
#[test]
197+
fntest_syscall_failed_enoent_hint(){
198+
let s =msg_for(libc::ENOENT);
199+
assert!(s.contains("failed to change root"),"{s}");
200+
assert!(s.contains("does not exist"),"{s}");
201+
assert!(s.contains("dangling symbolic link"),"{s}");
202+
}
203+
204+
#[test]
205+
fntest_syscall_failed_enomem_hint(){
206+
let s =msg_for(libc::ENOMEM);
207+
assert!(s.contains("failed to change root"),"{s}");
208+
assert!(s.contains("out of kernel memory"),"{s}");
209+
}
210+
211+
#[test]
212+
fntest_syscall_failed_eoverflow_hint(){
213+
let s =msg_for(libc::EOVERFLOW);
214+
assert!(s.contains("failed to change root"),"{s}");
215+
assert!(s.contains("cannot be represented"),"{s}");
216+
}
217+
218+
#[test]
219+
fntest_unsupported_platform_display(){
220+
let s =PivotRootError::UnsupportedPlatform.to_string();
221+
assert!(s.contains("only supported on Linux"),"{s}");
222+
}
223+
}

‎src/uu/pivot_root/src/main.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uucore::bin!(uu_pivot_root);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp