-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathbind.rs
More file actions
108 lines (98 loc) · 2.93 KB
/
bind.rs
File metadata and controls
108 lines (98 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::fmt;
use std::ffi::{CStr, CString, OsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use nix::mount::{MsFlags, mount};
use crate::{OSError, Error};
use crate::util::{path_to_cstring, as_path};
use crate::explain::{Explainable, exists, user};
use crate::remount::Remount;
/// A mount bind definition
///
/// By default bind mount is recursive (it's what you want most of the time).
///
/// Also recursive mounts can be used in user namespaces.
#[derive(Debug, Clone)]
pub struct BindMount {
source: CString,
target: CString,
recursive: bool,
readonly: bool,
}
impl BindMount {
/// Create a new, recursive bind mount
///
/// You can disable recursion with a `non_recursive()` method
pub fn new<A: AsRef<Path>, B: AsRef<Path>>(source: A, target: B)
-> BindMount
{
BindMount {
source: path_to_cstring(source.as_ref()),
target: path_to_cstring(target.as_ref()),
recursive: true,
readonly: false,
}
}
/// Toggle recursion
pub fn recursive(mut self, flag: bool) -> BindMount {
self.recursive = flag;
self
}
/// If set to `true` makes bind-mount readonly
///
/// Few notes:
///
/// 1. This makes additional `mount` call (`Remount().readonly()`)
/// 2. If remount fails mount bind is left on the filesystem, no cleanup
/// is done
/// 3. If set to `false` is option is no-op (does **not** remount `rw`)
pub fn readonly(mut self, flag: bool) -> BindMount {
self.readonly = flag;
self
}
/// Execute a bind mount
pub fn bare_mount(self) -> Result<(), OSError> {
let mut flags = MsFlags::MS_BIND;
if self.recursive {
flags |= MsFlags::MS_REC;
}
if let Err(err) = mount(
Some(&*self.source),
&*self.target,
None::<&CStr>,
flags,
None::<&CStr>,
) {
return Err(OSError::from_nix(err, Box::new(self)));
}
if self.readonly {
Remount::new(OsStr::from_bytes(self.target.as_bytes()))
.bind(true)
.readonly(true)
.bare_remount()?;
}
Ok(())
}
/// Execute a bind mount and explain the error immediately
pub fn mount(self) -> Result<(), Error> {
self.bare_mount().map_err(OSError::explain)
}
}
impl fmt::Display for BindMount {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.recursive {
write!(fmt, "recursive ")?;
}
write!(fmt, "bind mount {:?} -> {:?}",
as_path(&self.source), as_path(&self.target))
}
}
impl Explainable for BindMount {
fn explain(&self) -> String {
[
format!("source: {}", exists(as_path(&self.source))),
format!("target: {}", exists(as_path(&self.target))),
user().to_string(),
].join(", ")
}
}