1use anyhow;
2use regex;
3#[derive(Debug, Clone)]
4pub enum NsType {
5 CGROUP,
6 PID,
7 USER,
8 UTS,
9 IPC,
10 MNT,
11 NET,
12 UNK,
13}
14#[derive(Debug, Clone)]
15pub struct Namespace {
16 genre: NsType,
17 procs: Vec<String>,
18}
19impl Namespace {
20 pub fn new(genre: String, proc: String) -> Self {
21 let genre = match genre.as_str() {
22 "cgroup" => NsType::CGROUP,
23 "pid" => NsType::PID,
24 "user" => NsType::USER,
25 "uts" => NsType::UTS,
26 "ipc" => NsType::IPC,
27 "mnt" => NsType::MNT,
28 "net" => NsType::NET,
29 _ => NsType::UNK,
30 };
31 let procs: Vec<String> = vec![proc];
32 Namespace { genre, procs }
33 }
34 pub fn get_fd(&self) -> Option<i32> {
35 for i in &self.procs {
36 unsafe {
37 let fd = libc::open(
38 std::ffi::CString::new(i.as_str()).unwrap().as_ptr() as *const libc::c_char,
39 libc::O_RDONLY,
40 );
41 if fd != -1 {
42 return Some(fd);
43 }
44 }
45 }
46 None
47 }
48}
49pub type Namespaces = std::collections::HashMap<String, Namespace>;
50
51pub fn get_namespaces() -> anyhow::Result<Namespaces> {
52 let usize_pattern = regex::Regex::new(r"[1-9]\d*").unwrap();
53 let mut namespaces = Namespaces::new();
54 for proc_dir in std::fs::read_dir("/proc")?.filter_map(|f| match f {
55 Ok(f) => match f.file_name().to_str().unwrap_or_default().parse::<u64>() {
56 Ok(_) => Some(f),
57 Err(_) => None,
58 },
59 Err(_) => None,
60 }) {
61 let ns_dir = match std::fs::read_dir(proc_dir.path().to_str().unwrap().to_string() + "/ns")
62 {
63 Ok(dir) => dir,
64 Err(_) => continue,
65 };
66 for ns_file in ns_dir.filter_map(|f| match f {
67 Ok(f) => Some(f),
68 Err(_) => None,
69 }) {
70 let index = match std::fs::read_link(ns_file.path()) {
71 Ok(link) => usize_pattern
72 .find(link.to_str().unwrap_or_default())
73 .unwrap()
74 .as_str()
75 .to_owned(),
76 Err(_) => continue,
77 };
78 if namespaces.contains_key(&index) {
79 namespaces
80 .get_mut(&index)
81 .unwrap()
82 .procs
83 .push(ns_file.path().to_str().unwrap_or_default().to_string());
84 } else {
85 namespaces.insert(
86 index,
87 Namespace::new(
88 ns_file.file_name().to_str().unwrap_or_default().to_string(),
89 ns_file.path().to_str().unwrap_or_default().to_string(),
90 ),
91 );
92 }
93 }
94 }
95 Ok(namespaces)
96}
97
98pub fn get_specific_namespaces(genre: NsType) -> anyhow::Result<Namespaces> {
99 let usize_pattern = regex::Regex::new(r"[1-9]\d*").unwrap();
100 let mut namespaces = Namespaces::new();
101 let ns_type = format!("{:?}", genre).to_lowercase();
102 for proc_dir in std::fs::read_dir("/proc")?.filter_map(|f| match f {
103 Ok(f) => match f.file_name().to_str().unwrap_or_default().parse::<u64>() {
104 Ok(_) => Some(f),
105 Err(_) => None,
106 },
107 Err(_) => None,
108 }) {
109 let index;
110 if proc_dir.file_name().to_str().unwrap() == "1" {
111 index = "origin".to_owned()
112 } else {
113 index = match std::fs::read_link(
114 proc_dir.path().to_str().unwrap().to_string() + "/ns/" + ns_type.as_str(),
115 ) {
116 Ok(link) => usize_pattern
117 .find(link.to_str().unwrap_or_default())
118 .unwrap()
119 .as_str()
120 .to_owned(),
121 Err(_) => continue,
122 };
123 }
124 if namespaces.contains_key(&index) {
125 namespaces
126 .get_mut(&index)
127 .unwrap()
128 .procs
129 .push(proc_dir.path().to_str().unwrap().to_string() + "/ns/" + ns_type.as_str());
130 } else {
131 namespaces.insert(
132 index,
133 Namespace::new(
134 ns_type.clone(),
135 proc_dir.path().to_str().unwrap().to_string() + "/ns/" + ns_type.as_str(),
136 ),
137 );
138 }
139 }
140 Ok(namespaces)
141}
142#[cfg(test)]
143mod tests {
144 use super::*;
145 #[test]
146 fn get_namespaces_test() {
147 println!("{:?}", get_namespaces().unwrap());
148 }
149 #[test]
150 fn get_specific_namespaces_test() {
151 println!("{:?}", get_specific_namespaces(NsType::MNT).unwrap());
152 }
153}