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
108
109
110
use super::CurrentUser;
use crate::cmd::KillFailedError;
use failure::Error;
use nix::{
sys::signal::{kill, Signal},
unistd::{Gid, Pid, Uid},
};
use std::convert::AsRef;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path;
const EXECUTABLE_BITS: u32 = 0o5;
pub(crate) fn kill_process(id: u32) -> Result<(), KillFailedError> {
match kill(Pid::from_raw(id as i32), Signal::SIGKILL) {
Ok(()) => Ok(()),
Err(err) => Err(KillFailedError {
pid: id,
errno: if let nix::Error::Sys(errno) = err {
Some(errno)
} else {
None
},
}),
}
}
pub(crate) fn current_user() -> Option<CurrentUser> {
Some(CurrentUser {
user_id: Uid::effective().into(),
group_id: Gid::effective().into(),
})
}
fn executable_mode_for(path: &Path) -> Result<u32, Error> {
let metadata = path.metadata()?;
let user = current_user().unwrap();
if metadata.uid() == user.user_id {
Ok(EXECUTABLE_BITS << 6)
} else if metadata.gid() == user.group_id {
Ok(EXECUTABLE_BITS << 3)
} else {
Ok(EXECUTABLE_BITS)
}
}
pub(crate) fn is_executable<P: AsRef<Path>>(path: P) -> Result<bool, Error> {
let path = path.as_ref();
let expected_mode = executable_mode_for(&path)?;
Ok(path.metadata()?.mode() & expected_mode == expected_mode)
}
pub(crate) fn make_executable<P: AsRef<Path>>(path: P) -> Result<(), Error> {
let path = path.as_ref();
let mut perms = path.metadata()?.permissions();
let new_mode = perms.mode() | executable_mode_for(&path)?;
perms.set_mode(new_mode);
::std::fs::set_permissions(path, perms)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::CurrentUser;
use nix::unistd::{Gid, Uid};
use std::fs::File;
use std::os::unix::process::ExitStatusExt;
use std::process::Command;
#[test]
fn test_kill_process() {
let mut cmd = Command::new("sleep").args(&["2"]).spawn().unwrap();
super::kill_process(cmd.id()).unwrap();
assert_eq!(cmd.wait().unwrap().signal(), Some(9));
}
#[test]
fn test_current_user() {
assert_eq!(
super::current_user(),
Some(CurrentUser {
user_id: u32::from(Uid::effective()),
group_id: u32::from(Gid::effective()),
})
);
}
#[test]
fn test_executables() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("test");
File::create(&path).unwrap();
assert!(!super::is_executable(&path).unwrap());
super::make_executable(&path).unwrap();
assert!(super::is_executable(&path).unwrap());
}
}