use std::os::fd::RawFd;
use btoi::btoi;
use libc::pid_t;
use memchr::{
arch::all::{is_equal, is_prefix},
memchr,
};
use nix::{errno::Errno, unistd::Pid};
use crate::{
err::btoi2err,
path::{XPath, XPathBuf},
};
const FD: &[u8] = b"/fd/";
const PROC: &[u8] = b"/proc/";
const TASK: &[u8] = b"/task/";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProcMagic {
Pid {
pid: Pid,
},
Tid {
pid: Pid,
tgid: Pid,
},
Fd {
pid: Pid,
fd: RawFd,
},
Cwd {
pid: Pid,
},
Root {
pid: Pid,
},
Exe {
pid: Pid,
},
Ns {
pid: Pid,
kind: NsKind,
},
}
impl ProcMagic {
pub fn check_link(
expected_pid: Pid,
path: &XPath,
restrict_magiclinks: bool,
) -> Result<Option<Self>, Errno> {
if !path.is_proc() {
return Ok(None); }
let after_proc = &path.as_bytes()[PROC.len()..];
let pid_sep_index = memchr(b'/', after_proc).unwrap_or(after_proc.len());
let pid_component = &after_proc[..pid_sep_index];
if pid_component.is_empty() || pid_component.iter().any(|c| !c.is_ascii_digit()) {
return Ok(None); }
let mut current_pid = if restrict_magiclinks {
let parsed = bytes_to_pid(pid_component)?;
if parsed != expected_pid {
return Err(Errno::EACCES);
}
parsed
} else {
bytes_to_pid(pid_component)?
};
let mut remainder = &after_proc[pid_sep_index..];
if is_prefix(remainder, TASK) {
let after_task = &remainder[TASK.len()..]; let tid_end = memchr(b'/', after_task).unwrap_or(after_task.len());
if tid_end == 0 {
return Ok(None); }
current_pid = bytes_to_pid(&after_task[..tid_end])?;
remainder = &after_task[tid_end..]; }
if is_prefix(remainder, FD) {
let fd_digits = &remainder[FD.len()..];
if fd_digits.is_empty() || fd_digits.iter().any(|c| !c.is_ascii_digit()) {
return Ok(None);
}
let fd_value = bytes_to_fd(fd_digits)?;
return Ok(Some(Self::Fd {
pid: current_pid,
fd: fd_value,
}));
}
if is_equal(remainder, b"/cwd") {
return Ok(Some(Self::Cwd { pid: current_pid }));
}
if is_equal(remainder, b"/root") {
return Ok(Some(Self::Root { pid: current_pid }));
}
if is_equal(remainder, b"/exe") {
return Ok(Some(Self::Exe { pid: current_pid }));
}
if remainder.starts_with(b"/ns/") {
let name = &remainder[b"/ns/".len()..];
if !name.is_empty() && memchr::memchr(b'/', name).is_none() {
if let Ok(kind) = NsKind::try_from(name) {
return Ok(Some(ProcMagic::Ns {
pid: current_pid,
kind,
}));
}
}
}
Ok(None)
}
pub fn link_path(self) -> Result<XPathBuf, Errno> {
match self {
Self::Pid { .. } => {
let mut pfd = XPathBuf::empty();
pfd.try_append_bytes(b"self")?;
Ok(pfd)
}
Self::Tid { .. } => {
let mut pfd = XPathBuf::empty();
pfd.try_append_bytes(b"thread-self")?;
Ok(pfd)
}
Self::Fd { pid, fd } => XPathBuf::from_pid_fd(pid, fd),
Self::Cwd { pid } => XPathBuf::from_cwd(pid),
Self::Root { pid } => XPathBuf::from_root(pid),
Self::Exe { pid } => XPathBuf::from_exe(pid),
Self::Ns { pid, kind } => {
let mut sym = XPathBuf::from_pid(pid)?;
sym.try_push(b"ns")?;
sym.try_push(match kind {
NsKind::Cgroup => b"cgroup",
NsKind::Ipc => b"ipc",
NsKind::Mnt => b"mnt",
NsKind::Net => b"net",
NsKind::Pid => b"pid",
NsKind::PidForChildren => b"pid_for_children",
NsKind::Time => b"time",
NsKind::TimeForChildren => b"time_for_children",
NsKind::User => b"user",
NsKind::Uts => b"uts",
})?;
Ok(sym)
}
}
}
pub fn rlink_path(self) -> Result<XPathBuf, Errno> {
let link = self.link_path()?;
let mut pfd = XPathBuf::empty();
pfd.try_append_bytes(b"proc/")?;
pfd.try_append_bytes(link.as_bytes())?;
Ok(pfd)
}
pub fn link_fd(self) -> Result<RawFd, Errno> {
match self {
Self::Fd { fd, .. } => Ok(fd),
Self::Cwd { .. } => Ok(libc::AT_FDCWD),
Self::Root { .. } => Ok(-1),
Self::Exe { .. } => Ok(-2),
_ => Err(Errno::EINVAL),
}
}
pub fn want_dir(self) -> bool {
matches!(self, Self::Cwd { .. } | Self::Root { .. })
}
pub fn base(self) -> Result<Option<XPathBuf>, Errno> {
match self {
Self::Pid { pid } => Ok(Some(XPathBuf::from_pid(pid)?)),
Self::Tid { tgid, pid } => Ok(Some(XPathBuf::from_task(tgid, pid)?)),
Self::Fd { fd, .. } => Ok(Some(XPathBuf::from_fd(fd)?)),
Self::Ns { kind, .. } => Ok(Some(XPathBuf::try_from(kind)?)),
_ => Ok(None),
}
}
pub fn pid(self) -> Pid {
match self {
Self::Pid { pid, .. } => pid,
Self::Tid { pid, .. } => pid,
Self::Fd { pid, .. } => pid,
Self::Cwd { pid } => pid,
Self::Root { pid } => pid,
Self::Exe { pid } => pid,
Self::Ns { pid, .. } => pid,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NsKind {
Cgroup,
Ipc,
Mnt,
Net,
Pid,
PidForChildren,
Time,
TimeForChildren,
User,
Uts,
}
impl TryFrom<NsKind> for XPathBuf {
type Error = Errno;
fn try_from(kind: NsKind) -> Result<Self, Self::Error> {
let kind = match kind {
NsKind::Cgroup => "cgroup",
NsKind::Ipc => "ipc",
NsKind::Mnt => "mnt",
NsKind::Net => "net",
NsKind::Pid => "pid",
NsKind::PidForChildren => "pid_for_children",
NsKind::Time => "time",
NsKind::TimeForChildren => "time_for_children",
NsKind::User => "user",
NsKind::Uts => "uts",
};
XPathBuf::try_from(kind)
}
}
impl TryFrom<&[u8]> for NsKind {
type Error = Errno;
fn try_from(name: &[u8]) -> Result<Self, Self::Error> {
match name {
b"net" => Ok(Self::Net),
b"mnt" => Ok(Self::Mnt),
b"pid" => Ok(Self::Pid),
b"user" => Ok(Self::User),
b"uts" => Ok(Self::Uts),
b"ipc" => Ok(Self::Ipc),
b"cgroup" => Ok(Self::Cgroup),
b"time" => Ok(Self::Time),
b"pid_for_children" => Ok(Self::PidForChildren),
b"time_for_children" => Ok(Self::TimeForChildren),
_ => Err(Errno::EOPNOTSUPP),
}
}
}
fn bytes_to_pid(bytes: &[u8]) -> Result<Pid, Errno> {
btoi::<pid_t>(bytes)
.map(Pid::from_raw)
.map_err(|err| btoi2err(&err))
}
fn bytes_to_fd(bytes: &[u8]) -> Result<RawFd, Errno> {
btoi::<RawFd>(bytes).map_err(|err| btoi2err(&err))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
path::{XPath, XPathBuf},
xpath,
};
fn assert_ok_some(result: Result<Option<ProcMagic>, Errno>, expected: ProcMagic) {
assert_eq!(result, Ok(Some(expected)));
}
fn assert_ok_none(result: Result<Option<ProcMagic>, Errno>) {
assert_eq!(result, Ok(None));
}
fn assert_err(result: Result<Option<ProcMagic>, Errno>, e: Errno) {
assert_eq!(result, Err(e));
}
#[test]
fn test_check_link_1() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/cwd").unwrap(), true),
ProcMagic::Cwd { pid: this },
);
}
#[test]
fn test_check_link_2() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/exe").unwrap(), true),
ProcMagic::Exe { pid: this },
);
}
#[test]
fn test_check_link_3() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/root").unwrap(), true),
ProcMagic::Root { pid: this },
);
}
#[test]
fn test_check_link_4() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_err(
ProcMagic::check_link(this, &xpath!("/proc/{that}/fd").unwrap(), true),
Errno::EACCES,
);
}
#[test]
fn test_check_link_5() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{that}/fd").unwrap(),
false,
));
}
#[test]
fn test_check_link_6() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/fd").unwrap(),
true,
));
}
#[test]
fn test_check_link_7() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/0").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 0 },
);
}
#[test]
fn test_check_link_8() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/42").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 42 },
);
}
#[test]
fn test_check_link_9() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/1984").unwrap(), true),
ProcMagic::Fd {
pid: this,
fd: 1984,
},
);
}
#[test]
fn test_check_link_10() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_ok_some(
ProcMagic::check_link(
this,
&xpath!("/proc/{this}/task/{that}/fd/7").unwrap(),
true,
),
ProcMagic::Fd { pid: that, fd: 7 },
);
}
#[test]
fn test_check_link_11() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_err(
ProcMagic::check_link(this, &xpath!("/proc/{that}/cwd").unwrap(), true),
Errno::EACCES,
);
}
#[test]
fn test_check_link_12() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_err(
ProcMagic::check_link(this, &xpath!("/proc/{that}/exe").unwrap(), true),
Errno::EACCES,
);
}
#[test]
fn test_check_link_13() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_err(
ProcMagic::check_link(this, &xpath!("/proc/{that}/root").unwrap(), true),
Errno::EACCES,
);
}
#[test]
fn test_check_link_14() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_err(
ProcMagic::check_link(this, &xpath!("/proc/{that}/fd/0").unwrap(), true),
Errno::EACCES,
);
}
#[test]
fn test_check_link_15() {
let this = Pid::this();
let that = Pid::from_raw(this.as_raw() + 123);
assert_err(
ProcMagic::check_link(
this,
&xpath!("/proc/{that}/task/{this}/fd/7").unwrap(),
true,
),
Errno::EACCES,
);
}
#[test]
fn test_check_link_16() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{that}/cwd").unwrap(), false),
ProcMagic::Cwd { pid: that },
);
}
#[test]
fn test_check_link_17() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{that}/exe").unwrap(), false),
ProcMagic::Exe { pid: that },
);
}
#[test]
fn test_check_link_18() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{that}/root").unwrap(), false),
ProcMagic::Root { pid: that },
);
}
#[test]
fn test_check_link_19() {
let this = Pid::this();
let that = Pid::from_raw(1);
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{that}/fd/0").unwrap(), false),
ProcMagic::Fd { pid: that, fd: 0 },
);
}
#[test]
fn test_check_link_20() {
let this = Pid::this();
let that = Pid::from_raw(this.as_raw() + 77);
assert_ok_some(
ProcMagic::check_link(
this,
&xpath!("/proc/{that}/task/{this}/fd/7").unwrap(),
false,
),
ProcMagic::Fd { pid: this, fd: 7 },
);
}
#[test]
fn test_check_link_21() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/dev/null").unwrap(),
true,
));
}
#[test]
fn test_check_link_22() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(this, &xpath!("/").unwrap(), true));
}
#[test]
fn test_check_link_23() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/abc/cwd").unwrap(),
true,
));
}
#[test]
fn test_check_link_24() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc//cwd").unwrap(),
true,
));
}
#[test]
fn test_check_link_25() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/12a/fd/1").unwrap(),
true,
));
}
#[test]
fn test_check_link_26() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/task/").unwrap(),
true,
));
}
#[test]
fn test_check_link_27() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/task//fd/3").unwrap(),
true,
));
}
#[test]
fn test_check_link_28() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/fd/").unwrap(),
true,
));
}
#[test]
fn test_check_link_29() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/fd/+1").unwrap(),
true,
));
}
#[test]
fn test_check_link_30() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/fd/a7").unwrap(),
true,
));
}
#[test]
fn test_check_link_31() {
let this = Pid::this();
let huge = format!("/proc/{}/fd/{}", this.as_raw(), "999999999999999999999999");
let buf = XPathBuf::try_from(huge.as_str()).unwrap();
let x: &XPath = buf.as_ref();
assert_err(ProcMagic::check_link(this, x, true), Errno::EOVERFLOW);
}
#[test]
fn test_check_link_32() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/cwd/extra").unwrap(),
true,
));
}
#[test]
fn test_check_link_33() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/exe/also").unwrap(),
true,
));
}
#[test]
fn test_check_link_34() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/root/too").unwrap(),
true,
));
}
#[test]
fn test_check_link_35() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/0").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 0 },
);
}
#[test]
fn test_check_link_36() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/5").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 5 },
);
}
#[test]
fn test_check_link_37() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/9").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 9 },
);
}
#[test]
fn test_check_link_38() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/63").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 63 },
);
}
#[test]
fn test_check_link_39() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/100").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 100 },
);
}
#[test]
fn test_check_link_40() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/fd/255").unwrap(), true),
ProcMagic::Fd { pid: this, fd: 255 },
);
}
#[test]
fn test_check_link_41() {
let this = Pid::this();
let tid = Pid::from_raw(this.as_raw() + 2000);
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/task/{tid}/fd/3").unwrap(), true),
ProcMagic::Fd { pid: tid, fd: 3 },
);
}
#[test]
fn test_check_link_42() {
let this = Pid::this();
let tid = Pid::from_raw(this.as_raw() + 2001);
assert_ok_some(
ProcMagic::check_link(
this,
&xpath!("/proc/{this}/task/{tid}/fd/11").unwrap(),
true,
),
ProcMagic::Fd { pid: tid, fd: 11 },
);
}
#[test]
fn test_check_link_43() {
let this = Pid::this();
let tid = Pid::from_raw(this.as_raw() + 2002);
assert_ok_some(
ProcMagic::check_link(
this,
&xpath!("/proc/{this}/task/{tid}/fd/90").unwrap(),
true,
),
ProcMagic::Fd { pid: tid, fd: 90 },
);
}
#[test]
fn test_check_link_44() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/ns/net").unwrap(), true),
ProcMagic::Ns {
pid: this,
kind: NsKind::Net,
},
);
}
#[test]
fn test_check_link_45() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/ns/mnt").unwrap(), true),
ProcMagic::Ns {
pid: this,
kind: NsKind::Mnt,
},
);
}
#[test]
fn test_check_link_46() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/ns/pid").unwrap(), true),
ProcMagic::Ns {
pid: this,
kind: NsKind::Pid,
},
);
}
#[test]
fn test_check_link_47() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(this, &xpath!("/proc/{this}/ns/user").unwrap(), true),
ProcMagic::Ns {
pid: this,
kind: NsKind::User,
},
);
}
#[test]
fn test_check_link_48() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(
this,
&xpath!("/proc/{this}/ns/time_for_children").unwrap(),
true,
),
ProcMagic::Ns {
pid: this,
kind: NsKind::TimeForChildren,
},
);
}
#[test]
fn test_check_link_49() {
let this = Pid::this();
assert_ok_some(
ProcMagic::check_link(
this,
&xpath!("/proc/{this}/ns/pid_for_children").unwrap(),
true,
),
ProcMagic::Ns {
pid: this,
kind: NsKind::PidForChildren,
},
);
}
#[test]
fn test_check_link_50() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/ns/foobar").unwrap(),
true,
));
}
#[test]
fn test_check_link_51() {
let this = Pid::this();
assert_ok_none(ProcMagic::check_link(
this,
&xpath!("/proc/{this}/ns/net/extra").unwrap(),
true,
));
}
#[test]
fn test_link_path_1() {
let this = Pid::this();
let m = ProcMagic::Fd { pid: this, fd: 7 };
assert_eq!(m.link_path().unwrap(), xpath!("{this}/fd/7").unwrap());
}
#[test]
fn test_link_path_2() {
let this = Pid::this();
assert_eq!(
ProcMagic::Cwd { pid: this }.link_path().unwrap(),
xpath!("{this}/cwd").unwrap()
);
}
#[test]
fn test_link_path_3() {
let this = Pid::this();
assert_eq!(
ProcMagic::Root { pid: this }.link_path().unwrap(),
xpath!("{this}/root").unwrap()
);
}
#[test]
fn test_link_path_4() {
let this = Pid::this();
assert_eq!(
ProcMagic::Exe { pid: this }.link_path().unwrap(),
xpath!("{this}/exe").unwrap()
);
}
#[test]
fn test_link_path_5() {
let this = Pid::this();
let m = ProcMagic::Ns {
pid: this,
kind: NsKind::Net,
};
assert_eq!(m.link_path().unwrap(), xpath!("{this}/ns/net").unwrap());
}
#[test]
fn test_link_path_6() {
let this = Pid::this();
let m = ProcMagic::Ns {
pid: this,
kind: NsKind::Uts,
};
assert_eq!(m.link_path().unwrap(), xpath!("{this}/ns/uts").unwrap());
}
#[test]
fn test_link_fd_1() {
let this = Pid::this();
assert_eq!(ProcMagic::Fd { pid: this, fd: 3 }.link_fd(), Ok(3));
}
#[test]
fn test_link_fd_2() {
let this = Pid::this();
assert_eq!(ProcMagic::Cwd { pid: this }.link_fd(), Ok(libc::AT_FDCWD));
}
#[test]
fn test_link_fd_3() {
let this = Pid::this();
assert_eq!(ProcMagic::Root { pid: this }.link_fd(), Ok(-1));
}
#[test]
fn test_link_fd_4() {
let this = Pid::this();
assert_eq!(
ProcMagic::Ns {
pid: this,
kind: NsKind::Net
}
.link_fd(),
Err(Errno::EINVAL)
);
}
#[test]
fn test_want_dir_1() {
let this = Pid::this();
assert!(ProcMagic::Cwd { pid: this }.want_dir());
assert!(ProcMagic::Root { pid: this }.want_dir());
}
#[test]
fn test_want_dir_2() {
let this = Pid::this();
assert!(!ProcMagic::Fd { pid: this, fd: 5 }.want_dir());
assert!(!ProcMagic::Exe { pid: this }.want_dir());
assert!(!ProcMagic::Ns {
pid: this,
kind: NsKind::Net
}
.want_dir());
}
#[test]
fn test_base_1() {
let this = Pid::this();
assert_eq!(
ProcMagic::Fd { pid: this, fd: 42 }.base().unwrap(),
Some(XPathBuf::try_from("42").unwrap())
);
}
#[test]
fn test_base_2() {
let this = Pid::this();
assert_eq!(
ProcMagic::Ns {
pid: this,
kind: NsKind::Mnt
}
.base()
.unwrap(),
Some(XPathBuf::try_from("mnt").unwrap())
);
}
#[test]
fn test_base_3() {
let this = Pid::this();
assert_eq!(ProcMagic::Cwd { pid: this }.base().unwrap(), None);
assert_eq!(ProcMagic::Root { pid: this }.base().unwrap(), None);
assert_eq!(ProcMagic::Exe { pid: this }.base().unwrap(), None);
}
#[test]
fn test_pid_1() {
let this = Pid::from_raw(4242);
assert_eq!(ProcMagic::Fd { pid: this, fd: 1 }.pid(), this);
}
#[test]
fn test_pid_2() {
let p = Pid::from_raw(2025);
assert_eq!(ProcMagic::Cwd { pid: p }.pid(), p);
assert_eq!(ProcMagic::Root { pid: p }.pid(), p);
assert_eq!(ProcMagic::Exe { pid: p }.pid(), p);
}
#[test]
fn test_pid_3() {
let p = Pid::from_raw(77);
assert_eq!(
ProcMagic::Ns {
pid: p,
kind: NsKind::User
}
.pid(),
p
);
}
#[test]
fn test_try_from_bytes_1() {
assert_eq!(NsKind::try_from(b"net".as_slice()), Ok(NsKind::Net));
assert_eq!(NsKind::try_from(b"mnt".as_slice()), Ok(NsKind::Mnt));
assert_eq!(NsKind::try_from(b"pid".as_slice()), Ok(NsKind::Pid));
assert_eq!(NsKind::try_from(b"user".as_slice()), Ok(NsKind::User));
assert_eq!(NsKind::try_from(b"uts".as_slice()), Ok(NsKind::Uts));
assert_eq!(
NsKind::try_from(b"time_for_children".as_slice()),
Ok(NsKind::TimeForChildren)
);
}
#[test]
fn test_try_from_bytes_2() {
assert_eq!(
NsKind::try_from(b"other".as_slice()),
Err(Errno::EOPNOTSUPP)
);
}
#[test]
fn test_from_ns_kind_1() {
let xb_net: XPathBuf = XPathBuf::try_from(NsKind::Net).unwrap();
let xb_ipc: XPathBuf = XPathBuf::try_from(NsKind::Ipc).unwrap();
let xb_cg: XPathBuf = XPathBuf::try_from(NsKind::Cgroup).unwrap();
assert_eq!(xb_net, XPathBuf::try_from("net").unwrap());
assert_eq!(xb_ipc, XPathBuf::try_from("ipc").unwrap());
assert_eq!(xb_cg, XPathBuf::try_from("cgroup").unwrap());
}
#[test]
fn test_bytes_1() {
assert_eq!(bytes_to_pid(b"0"), Ok(Pid::from_raw(0)));
assert_eq!(bytes_to_pid(b"12345"), Ok(Pid::from_raw(12345)));
}
#[test]
fn test_bytes_2() {
assert_eq!(bytes_to_pid(b"-7"), Ok(Pid::from_raw(-7)));
}
#[test]
fn test_bytes_3() {
assert_eq!(bytes_to_pid(b""), Err(Errno::EINVAL));
}
#[test]
fn test_bytes_4() {
assert_eq!(
bytes_to_pid(b"9999999999999999999999999"),
Err(Errno::EOVERFLOW)
);
}
#[test]
fn test_bytes_5() {
assert_eq!(bytes_to_fd(b"0"), Ok(0));
assert_eq!(bytes_to_fd(b"42"), Ok(42));
assert_eq!(bytes_to_fd(b"1984"), Ok(1984));
}
#[test]
fn test_bytes_6() {
assert_eq!(bytes_to_fd(b""), Err(Errno::EINVAL));
assert_eq!(bytes_to_fd(b"1a"), Err(Errno::EINVAL));
assert_eq!(
bytes_to_fd(b"999999999999999999999999"),
Err(Errno::EOVERFLOW)
);
}
}