linuxutils_system/
ipcs.rs1use linuxutils_common::man::ManContent;
2
3pub const MAN: ManContent = ManContent::empty();
4
5use clap::Parser;
6use std::{
7 fs::{self, File},
8 io::{self, BufRead},
9 process::ExitCode,
10};
11
12#[derive(Parser)]
17#[command(name = "ipcs", about = "Show information on System V IPC facilities")]
18pub struct Args {
19 #[arg(short = 'm', long)]
21 shmems: bool,
22
23 #[arg(short = 'q', long)]
25 queues: bool,
26
27 #[arg(short = 's', long)]
29 semaphores: bool,
30
31 #[arg(short = 'a', long)]
33 all: bool,
34
35 #[arg(short = 'l', long)]
37 limits: bool,
38
39 #[arg(short = 'u', long)]
41 summary: bool,
42
43 #[arg(short = 'b', long)]
45 bytes: bool,
46}
47
48fn read_proc_val(path: &str) -> String {
49 fs::read_to_string(path)
50 .unwrap_or_default()
51 .trim()
52 .to_string()
53}
54
55fn show_shm_limits() {
56 let shmmax = read_proc_val("/proc/sys/kernel/shmmax");
57 let shmall = read_proc_val("/proc/sys/kernel/shmall");
58 let shmmni = read_proc_val("/proc/sys/kernel/shmmni");
59
60 println!();
61 println!("------ Shared Memory Limits --------");
62 println!("max number of segments = {shmmni}");
63 println!(
64 "max seg size (kbytes) = {}",
65 shmmax.parse::<u64>().unwrap_or(0) / 1024
66 );
67 println!(
68 "max total shared memory (kbytes) = {}",
69 shmall.parse::<u64>().unwrap_or(0) * 4096 / 1024
70 );
71 println!("min seg size (bytes) = 1");
72}
73
74fn show_msg_limits() {
75 let msgmni = read_proc_val("/proc/sys/kernel/msgmni");
76 let msgmax = read_proc_val("/proc/sys/kernel/msgmax");
77 let msgmnb = read_proc_val("/proc/sys/kernel/msgmnb");
78
79 println!();
80 println!("------ Messages Limits --------");
81 println!("max queues system wide = {msgmni}");
82 println!("max size of message (bytes) = {msgmax}");
83 println!("default max size of queue (bytes) = {msgmnb}");
84}
85
86fn show_sem_limits() {
87 let sem = read_proc_val("/proc/sys/kernel/sem");
88 let parts: Vec<&str> = sem.split_whitespace().collect();
89 let semmsl = parts.first().unwrap_or(&"0");
90 let semmns = parts.get(1).unwrap_or(&"0");
91 let semopm = parts.get(2).unwrap_or(&"0");
92 let semmni = parts.get(3).unwrap_or(&"0");
93
94 println!();
95 println!("------ Semaphore Limits --------");
96 println!("max number of arrays = {semmni}");
97 println!("max semaphores per array = {semmsl}");
98 println!("max semaphores system wide = {semmns}");
99 println!("max ops per semop call = {semopm}");
100 println!("semaphore max value = 32767");
101}
102
103fn show_shm_summary() {
104 let count = count_proc_entries("/proc/sysvipc/shm");
105 println!();
106 println!("------ Shared Memory Status --------");
107 println!("segments allocated {count}");
108}
109
110fn show_msg_summary() {
111 let count = count_proc_entries("/proc/sysvipc/msg");
112 println!();
113 println!("------ Messages Status --------");
114 println!("allocated queues = {count}");
115}
116
117fn show_sem_summary() {
118 let count = count_proc_entries("/proc/sysvipc/sem");
119 println!();
120 println!("------ Semaphore Status --------");
121 println!("used arrays = {count}");
122}
123
124fn count_proc_entries(path: &str) -> usize {
125 let Ok(file) = File::open(path) else {
126 return 0;
127 };
128 io::BufReader::new(file)
129 .lines()
130 .map_while(Result::ok)
131 .skip(1)
132 .count()
133}
134
135fn show_shm_list() {
136 println!();
137 println!("------ Shared Memory Segments --------");
138 println!(
139 "{:<10} {:<10} {:<10} {:<10} {:>10} {:>6} status",
140 "key", "shmid", "owner", "perms", "bytes", "nattch"
141 );
142
143 let Ok(file) = File::open("/proc/sysvipc/shm") else {
144 return;
145 };
146 for line in io::BufReader::new(file)
147 .lines()
148 .map_while(Result::ok)
149 .skip(1)
150 {
151 let f: Vec<&str> = line.split_whitespace().collect();
152 if f.len() >= 14 {
153 let key = format!("0x{:08x}", f[0].parse::<i64>().unwrap_or(0));
154 let uid: u32 = f[7].parse().unwrap_or(0);
155 let owner = uid_to_name(uid);
156 println!(
157 "{:<10} {:<10} {:<10} {:<10} {:>10} {:>6} ",
158 key, f[1], owner, f[2], f[3], f[5]
159 );
160 }
161 }
162}
163
164fn show_msg_list() {
165 println!();
166 println!("------ Message Queues --------");
167 println!(
168 "{:<10} {:<10} {:<10} {:<10} {:>10} {:>8}",
169 "key", "msqid", "owner", "perms", "used-bytes", "messages"
170 );
171
172 let Ok(file) = File::open("/proc/sysvipc/msg") else {
173 return;
174 };
175 for line in io::BufReader::new(file)
176 .lines()
177 .map_while(Result::ok)
178 .skip(1)
179 {
180 let f: Vec<&str> = line.split_whitespace().collect();
181 if f.len() >= 13 {
182 let key = format!("0x{:08x}", f[0].parse::<i64>().unwrap_or(0));
183 let uid: u32 = f[7].parse().unwrap_or(0);
184 let owner = uid_to_name(uid);
185 println!(
186 "{:<10} {:<10} {:<10} {:<10} {:>10} {:>8}",
187 key, f[1], owner, f[2], f[3], f[4]
188 );
189 }
190 }
191}
192
193fn show_sem_list() {
194 println!();
195 println!("------ Semaphore Arrays --------");
196 println!(
197 "{:<10} {:<10} {:<10} {:<10} {:>5}",
198 "key", "semid", "owner", "perms", "nsems"
199 );
200
201 let Ok(file) = File::open("/proc/sysvipc/sem") else {
202 return;
203 };
204 for line in io::BufReader::new(file)
205 .lines()
206 .map_while(Result::ok)
207 .skip(1)
208 {
209 let f: Vec<&str> = line.split_whitespace().collect();
210 if f.len() >= 9 {
211 let key = format!("0x{:08x}", f[0].parse::<i64>().unwrap_or(0));
212 let uid: u32 = f[4].parse().unwrap_or(0);
213 let owner = uid_to_name(uid);
214 println!(
215 "{:<10} {:<10} {:<10} {:<10} {:>5}",
216 key, f[1], owner, f[2], f[3]
217 );
218 }
219 }
220}
221
222fn uid_to_name(uid: u32) -> String {
223 fs::read_to_string("/etc/passwd")
224 .ok()
225 .and_then(|content| {
226 content.lines().find_map(|line| {
227 let parts: Vec<&str> = line.split(':').collect();
228 if parts.len() >= 3 && parts[2].parse::<u32>().ok() == Some(uid)
229 {
230 Some(parts[0].to_string())
231 } else {
232 None
233 }
234 })
235 })
236 .unwrap_or_else(|| uid.to_string())
237}
238
239pub fn run(args: Args) -> ExitCode {
240 let none_specified = !args.shmems && !args.queues && !args.semaphores;
241 let show_shm = args.shmems || args.all || none_specified;
242 let show_msg = args.queues || args.all || none_specified;
243 let show_sem = args.semaphores || args.all || none_specified;
244
245 if args.limits {
246 if show_shm {
247 show_shm_limits();
248 }
249 if show_msg {
250 show_msg_limits();
251 }
252 if show_sem {
253 show_sem_limits();
254 }
255 } else if args.summary {
256 if show_shm {
257 show_shm_summary();
258 }
259 if show_msg {
260 show_msg_summary();
261 }
262 if show_sem {
263 show_sem_summary();
264 }
265 } else {
266 if show_shm {
267 show_shm_list();
268 }
269 if show_msg {
270 show_msg_list();
271 }
272 if show_sem {
273 show_sem_list();
274 }
275 }
276
277 ExitCode::SUCCESS
278}