Skip to content

Commit 5d54073

Browse files
authored
Merge pull request #29 from nix-community/tempfile
get rid of tempfile crate
2 parents 3fac2a2 + b6470b8 commit 5d54073

File tree

6 files changed

+69
-171
lines changed

6 files changed

+69
-171
lines changed

Cargo.lock

Lines changed: 2 additions & 123 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ edition = "2018"
88

99
[dependencies]
1010
nix = "0.19.*"
11-
tempfile = "3"
11+
libc = "*"

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod mkdtemp;

src/main.rs

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1+
use nix;
12
use nix::mount::{mount, MsFlags};
23
use nix::sched::{unshare, CloneFlags};
34
use nix::sys::signal::{kill, Signal};
45
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
5-
use nix::unistd;
6-
use nix::unistd::{fork, ForkResult};
6+
use nix::unistd::{self, fork, ForkResult};
77
use std::env;
88
use std::fs;
99
use std::io;
1010
use std::io::prelude::*;
1111
use std::os::unix::fs::symlink;
1212
use std::os::unix::process::CommandExt;
13-
use std::path::Path;
14-
use std::path::PathBuf;
13+
use std::path::{Path, PathBuf};
1514
use std::process;
1615
use std::string::String;
17-
use tempfile::TempDir;
16+
17+
mod mkdtemp;
1818

1919
const NONE: Option<&'static [u8]> = None;
2020

@@ -48,8 +48,7 @@ impl<'a> RunChroot<'a> {
4848
let mountpoint = self.rootdir.join(entry.file_name());
4949
if let Err(e) = fs::create_dir(&mountpoint) {
5050
if e.kind() != io::ErrorKind::AlreadyExists {
51-
let e2: io::Result<()> = Err(e);
52-
e2.unwrap_or_else(|_| panic!("failed to create {}", &mountpoint.display()));
51+
panic!("failed to create {}: {}", &mountpoint.display(), e);
5352
}
5453
}
5554

@@ -59,15 +58,15 @@ impl<'a> RunChroot<'a> {
5958
fn bind_mount_file(&self, entry: &fs::DirEntry) {
6059
let mountpoint = self.rootdir.join(entry.file_name());
6160
fs::File::create(&mountpoint)
62-
.unwrap_or_else(|_| panic!("failed to create {}", &mountpoint.display()));
61+
.unwrap_or_else(|err| panic!("failed to create {}: {}", &mountpoint.display(), err));
6362

6463
bind_mount(&entry.path(), &mountpoint)
6564
}
6665

6766
fn mirror_symlink(&self, entry: &fs::DirEntry) {
6867
let path = entry.path();
6968
let target = fs::read_link(&path)
70-
.unwrap_or_else(|_| panic!("failed to resolve symlink {}", &path.display()));
69+
.unwrap_or_else(|err| panic!("failed to resolve symlink {}: {}", &path.display(), err));
7170
let link_path = self.rootdir.join(entry.file_name());
7271
symlink(&target, &link_path).unwrap_or_else(|_| {
7372
panic!(
@@ -87,7 +86,7 @@ impl<'a> RunChroot<'a> {
8786
let path = entry.path();
8887
let stat = entry
8988
.metadata()
90-
.unwrap_or_else(|_| panic!("cannot get stat of {}", path.display()));
89+
.unwrap_or_else(|err| panic!("cannot get stat of {}: {}", path.display(), err));
9190
if stat.is_dir() {
9291
self.bind_mount_directory(&entry);
9392
} else if stat.is_file() {
@@ -115,19 +114,19 @@ impl<'a> RunChroot<'a> {
115114
// mount the store
116115
let nix_mount = self.rootdir.join("nix");
117116
fs::create_dir(&nix_mount)
118-
.unwrap_or_else(|_| panic!("failed to create {}", &nix_mount.display()));
117+
.unwrap_or_else(|err| panic!("failed to create {}: {}", &nix_mount.display(), err));
119118
mount(
120119
Some(nixdir),
121120
&nix_mount,
122121
Some("none"),
123122
MsFlags::MS_BIND | MsFlags::MS_REC,
124123
NONE,
125124
)
126-
.unwrap_or_else(|_| panic!("failed to bind mount {} to /nix", nixdir.display()));
125+
.unwrap_or_else(|err| panic!("failed to bind mount {} to /nix: {}", nixdir.display(), err));
127126

128127
// chroot
129128
unistd::chroot(self.rootdir)
130-
.unwrap_or_else(|_| panic!("chroot({})", self.rootdir.display(),));
129+
.unwrap_or_else(|err| panic!("chroot({}): {}", self.rootdir.display(), err));
131130

132131
env::set_current_dir("/").expect("cannot change directory to /");
133132

@@ -163,48 +162,38 @@ impl<'a> RunChroot<'a> {
163162
}
164163
}
165164

166-
fn wait_for_child(child_pid: unistd::Pid, tempdir: TempDir, rootdir: &Path) {
165+
fn wait_for_child(rootdir: &Path, child_pid: unistd::Pid) -> ! {
166+
let mut exit_status = 1;
167167
loop {
168168
match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) {
169169
Ok(WaitStatus::Signaled(child, Signal::SIGSTOP, _)) => {
170170
let _ = kill(unistd::getpid(), Signal::SIGSTOP);
171171
let _ = kill(child, Signal::SIGCONT);
172172
}
173173
Ok(WaitStatus::Signaled(_, signal, _)) => {
174-
kill(unistd::getpid(), signal)
175-
.unwrap_or_else(|_| panic!("failed to send {} signal to our self", signal));
174+
kill(unistd::getpid(), signal).unwrap_or_else(|err| {
175+
panic!("failed to send {} signal to our self: {}", signal, err)
176+
});
176177
}
177178
Ok(WaitStatus::Exited(_, status)) => {
178-
tempdir.close().unwrap_or_else(|_| {
179-
panic!(
180-
"failed to remove temporary directory: {}",
181-
rootdir.display()
182-
)
183-
});
184-
process::exit(status);
179+
exit_status = status;
180+
break;
185181
}
186182
Ok(what) => {
187-
tempdir.close().unwrap_or_else(|_| {
188-
panic!(
189-
"failed to remove temporary directory: {}",
190-
rootdir.display()
191-
)
192-
});
193183
eprintln!("unexpected wait event happend: {:?}", what);
194-
process::exit(1);
184+
break;
195185
}
196186
Err(e) => {
197-
tempdir.close().unwrap_or_else(|_| {
198-
panic!(
199-
"failed to remove temporary directory: {}",
200-
rootdir.display()
201-
)
202-
});
203187
eprintln!("waitpid failed: {}", e);
204-
process::exit(1);
188+
break;
205189
}
206190
};
207191
}
192+
193+
fs::remove_dir_all(rootdir)
194+
.unwrap_or_else(|err| panic!("cannot remove tempdir {}: {}", rootdir.display(), err));
195+
196+
process::exit(exit_status);
208197
}
209198

210199
fn main() {
@@ -213,14 +202,15 @@ fn main() {
213202
eprintln!("Usage: {} <nixpath> <command>\n", args[0]);
214203
process::exit(1);
215204
}
216-
let tempdir = TempDir::new().expect("failed to create temporary directory for mount point");
217-
let rootdir = PathBuf::from(tempdir.path());
205+
206+
let rootdir = mkdtemp::mkdtemp("nix-chroot.XXXXXX")
207+
.unwrap_or_else(|err| panic!("failed to create temporary directory: {}", err));
218208

219209
let nixdir = fs::canonicalize(&args[1])
220-
.unwrap_or_else(|_| panic!("failed to resolve nix directory {}", &args[1]));
210+
.unwrap_or_else(|err| panic!("failed to resolve nix directory {}: {}", &args[1], err));
221211

222212
match unsafe { fork() } {
223-
Ok(ForkResult::Parent { child, .. }) => wait_for_child(child, tempdir, &rootdir),
213+
Ok(ForkResult::Parent { child, .. }) => wait_for_child(&rootdir, child),
224214
Ok(ForkResult::Child) => RunChroot::new(&rootdir).run_chroot(&nixdir, &args[2], &args[3..]),
225215
Err(e) => {
226216
eprintln!("fork failed: {}", e);

src/mkdtemp.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use nix::errno::Errno;
2+
use std::env;
3+
use std::ffi::OsString;
4+
use std::os::unix::ffi::OsStringExt;
5+
use std::path::PathBuf;
6+
use std::ptr;
7+
8+
mod ffi {
9+
extern "C" {
10+
pub fn mkdtemp(template: *mut libc::c_char) -> *mut libc::c_char;
11+
}
12+
}
13+
14+
pub fn mkdtemp(template: &str) -> nix::Result<PathBuf> {
15+
let mut tmpdir = env::temp_dir();
16+
tmpdir.push(template);
17+
let mut buf = tmpdir.into_os_string().into_vec();
18+
buf.push(b'\0'); // make a c string
19+
20+
let res = unsafe { ffi::mkdtemp(buf.as_mut_ptr() as *mut libc::c_char) };
21+
if res == ptr::null_mut() {
22+
Err(nix::Error::Sys(Errno::last()))
23+
} else {
24+
buf.pop(); // strip null byte
25+
Ok(PathBuf::from(OsString::from_vec(buf)))
26+
}
27+
}

tests/integration.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
1+
use nix_user_chroot::mkdtemp;
12
use std::env;
3+
use std::fs;
24
use std::process::Command;
3-
use tempfile::TempDir;
45

56
const TARGET: &str = env!("TARGET");
67

78
#[test]
89
fn run_nix_install() {
9-
let tempdir = TempDir::new().unwrap();
10+
let tempdir = mkdtemp::mkdtemp("/tmp/nix.XXXXXX").unwrap();
1011

1112
let result = Command::new("cargo")
1213
.args(&[
1314
"run",
1415
"--target",
1516
TARGET,
16-
tempdir.path().to_str().unwrap(),
17+
tempdir.to_str().unwrap(),
1718
"bash",
1819
"-c",
1920
"curl https://nixos.org/nix/install | bash",
2021
])
21-
.status()
22-
.unwrap();
23-
assert!(result.success());
22+
.status();
23+
fs::remove_dir_all(tempdir).unwrap();
24+
assert!(result.unwrap().success());
2425
}

0 commit comments

Comments
 (0)