summaryrefslogtreecommitdiffstats
path: root/src/util/unix.rs
blob: ee0507c76c1400964e4b80ecccb0dc3fd49a768a (plain)
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
use std::{fs::File, io::Result, os::unix::prelude::AsRawFd, path::Path};

use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode, unistd};

use super::ToIOResult;

pub struct SetEUID(unistd::Uid);

impl Drop for SetEUID {
	fn drop(&mut self) {
		unistd::seteuid(self.0).expect("failed to reset effective UID");
	}
}

pub fn seteuid(uid: unistd::Uid) -> Result<SetEUID> {
	let old_uid = unistd::geteuid();
	unistd::seteuid(uid).to_io_result()?;
	Ok(SetEUID(old_uid))
}

pub struct SetEGID(unistd::Gid);

impl Drop for SetEGID {
	fn drop(&mut self) {
		unistd::setegid(self.0).expect("failed to reset effective GID");
	}
}

pub fn setegid(gid: unistd::Gid) -> Result<SetEGID> {
	let old_gid = unistd::getegid();
	unistd::setegid(gid).to_io_result()?;
	Ok(SetEGID(old_gid))
}

pub fn create_as<P: AsRef<Path>>(
	path: P,
	uid: Option<unistd::Uid>,
	gid: Option<unistd::Gid>,
) -> Result<File> {
	let _setegid = gid.map(setegid).transpose()?;
	let _seteuid = uid.map(seteuid).transpose()?;

	File::create(path)
}

pub struct Chdir(Dir);

impl Drop for Chdir {
	fn drop(&mut self) {
		unistd::fchdir(self.0.as_raw_fd()).expect("failed to revert directory change");
	}
}

pub fn chdir<P: AsRef<Path>>(path: P) -> Result<Chdir> {
	let dir = Dir::open(
		".",
		OFlag::O_PATH | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW,
		Mode::empty(),
	)
	.to_io_result()?;

	unistd::chdir(path.as_ref()).to_io_result()?;

	Ok(Chdir(dir))
}