1 /* ipcs.c - provide information on ipc facilities
2 *
3 * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
4 *
5 * see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ipcs.html
6
7 #ifdef TOYBOX_OH_ADAPT
8 //delete 'ipcs -s' fail problem: kernel is not configured for semaphores
9 USE_IPCS(NEWTOY(ipcs, "acptulqmi#", TOYFLAG_USR|TOYFLAG_BIN))
10 #else
11 USE_IPCS(NEWTOY(ipcs, "acptulsqmi#", TOYFLAG_USR|TOYFLAG_BIN))
12 #endif
13
14 config IPCS
15 bool "ipcs"
16 default n
17 help
18 usage: ipcs [[-smq] -i shmid] | [[-asmq] [-tcplu]]
19
20 -i Show specific resource
21 Resource specification:
22 -a All (default)
23 -m Shared memory segments
24 -q Message queues
25 -s Semaphore arrays
26 Output format:
27 -c Creator
28 -l Limits
29 -p Pid
30 -t Time
31 -u Summary
32 */
33
34 #define FOR_ipcs
35 #include "toys.h"
36 #include <sys/ipc.h>
37 #include <sys/shm.h>
38 #include <sys/sem.h>
39 #include <sys/msg.h>
40
41 GLOBALS(
42 int id;
43 )
44
45 //used many times, so good to paste it
46 #define flag(x) (toys.optflags & FLAG_ ## x)
47
48 union semun { //man says declare it yourself
49 int val;
50 struct semid_ds *buf;
51 unsigned short *array;
52 struct seminfo *__buf;
53 };
54
show_msg_id(void)55 static void show_msg_id(void)
56 {
57 struct msqid_ds buf;
58 int ret;
59
60 if ((ret = msgctl(TT.id, IPC_STAT, &buf)) < 0) {
61 perror_msg("msgctl");
62 return;
63 }
64
65 #define ipcperm buf.msg_perm
66
67 printf("\nMessage Queue msqid=%d\n"
68 "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\tmode=%#o\n",
69 TT.id, ipcperm.uid, ipcperm.gid, ipcperm.cuid, ipcperm.cgid,ipcperm.mode);
70 printf ("cbytes=%ld\tqbytes=%ld\tqnum=%ld\tlspid=%d\tlrpid=%d\n",
71 (long) buf.msg_cbytes, (long) buf.msg_qbytes,
72 (long) buf.msg_qnum, buf.msg_lspid, buf.msg_lrpid);
73
74 printf("send_time=%-26.24s\nrcv_time=%-26.24s\nchange_time=%-26.24s\n\n",
75 buf.msg_stime ? ctime(&buf.msg_stime) : "Not set",
76 buf.msg_rtime ? ctime(&buf.msg_rtime) : "Not set",
77 buf.msg_ctime ? ctime(&buf.msg_ctime) : "Not set");
78 #undef ipcperm
79 }
80
show_sem_id(void)81 static void show_sem_id(void)
82 {
83 struct semid_ds buf;
84 union semun n;
85 int ret, i;
86
87 n.buf = &buf;
88 if ((ret = semctl(TT.id, 0, IPC_STAT, n)) < 0) {
89 perror_msg("semctl");
90 return;
91 }
92
93 #define ipcperm buf.sem_perm
94 printf("\nSemaphore Array semid=%d\n"
95 "uid=%d\t gid=%d\t cuid=%d\t cgid=%d\n"
96 "mode=%#o, access_perms=%#o\n"
97 "nsems = %ld\n"
98 "otime = %-26.24s\n",
99 TT.id,
100 ipcperm.uid, ipcperm.gid, ipcperm.cuid, ipcperm.cgid,
101 ipcperm.mode, ipcperm.mode & 0777,
102 (long) buf.sem_nsems,
103 buf.sem_otime ? ctime(&buf.sem_otime) : "Not set");
104 printf("ctime = %-26.24s\n"
105 "%-10s %-10s %-10s %-10s %-10s\n",
106 ctime(&buf.sem_ctime),
107 "semnum", "value", "ncount", "zcount", "pid");
108 #undef ipcperm
109
110 for (i = 0; i < buf.sem_nsems; i++) {
111 int val, nc, zc, pid;
112 val = semctl(TT.id, i, GETVAL, n);
113 nc = semctl(TT.id, i, GETNCNT, n);
114 zc = semctl(TT.id, i, GETZCNT, n);
115 pid = semctl(TT.id, i, GETPID, n);
116 if (val < 0 || nc < 0 || zc < 0 || pid < 0)
117 perror_exit("semctl");
118 printf("%-10d %-10d %-10d %-10d %-10d\n", i, val, nc, zc, pid);
119 }
120 xputc('\n');
121 }
122
show_shm_id(void)123 static void show_shm_id(void)
124 {
125 struct shmid_ds buf;
126 int ret;
127
128 if ((ret = shmctl(TT.id, IPC_STAT, &buf)) < 0) {
129 perror_msg("shmctl");
130 return;
131 }
132
133 #define ipcperm buf.shm_perm
134
135 printf("\nShared memory Segment shmid=%d\n"
136 "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\n"
137 "mode=%#o\taccess_perms=%#o\n"
138 "bytes=%ld\tlpid=%d\tcpid=%d\tnattch=%ld\n",
139 TT.id,
140 ipcperm.uid, ipcperm.gid, ipcperm.cuid, ipcperm.cgid,
141 ipcperm.mode, (ipcperm.mode & 0777),
142 (long) buf.shm_segsz, buf.shm_lpid, buf.shm_cpid,
143 (long) buf.shm_nattch);
144 printf("att_time=%-26.24s\n",
145 buf.shm_atime ? ctime(&buf.shm_atime) : "Not set");
146 printf("det_time=%-26.24s\n",
147 buf.shm_dtime ? ctime(&buf.shm_dtime) : "Not set");
148 printf("change_time=%-26.24s\n\n", ctime(&buf.shm_ctime));
149 #undef ipcperm
150 }
151
shm_array(void)152 static void shm_array(void)
153 {
154 struct shm_info shm_buf;
155 struct shminfo ipc_buf;
156 struct shmid_ds buf;
157 int max_nr, i, shmid;
158 struct passwd *pw;
159 struct group *gr;
160
161 if ((max_nr = shmctl(0, SHM_INFO, (struct shmid_ds*)&shm_buf)) < 0) {
162 perror_msg("kernel not configured for shared memory");
163 return;
164 }
165
166 if (flag(u)) {
167 printf("------ Shared Memory Status --------\n");
168 printf("segments allocated %d\n"
169 "pages allocated %ld\n"
170 "pages resident %ld\n"
171 "pages swapped %ld\n"
172 "Swap performance: %ld attempts\t%ld successes\n",
173 shm_buf.used_ids,
174 shm_buf.shm_tot,
175 shm_buf.shm_rss,
176 shm_buf.shm_swp,
177 shm_buf.swap_attempts, shm_buf.swap_successes);
178 return;
179 }
180 if (flag(l)) {
181 if ((shmctl(0, 3, (struct shmid_ds*)&ipc_buf)) < 0) return; //IPC_INFO
182 printf("------ Shared Memory Limits --------\n");
183 printf("max number of segments = %lu\n"
184 "max seg size (kbytes) = %lu\n"
185 "max total shared memory (pages) = %lu\n"
186 "min seg size (bytes) = %lu\n",
187 (unsigned long) ipc_buf.shmmni,
188 (unsigned long) (ipc_buf.shmmax >> 10),
189 (unsigned long) ipc_buf.shmall,
190 (unsigned long) ipc_buf.shmmin);
191 return;
192 }
193
194 if (flag(t)) {
195 printf("------ Shared Memory Attach/Detach/Change Times --------\n");
196 printf("%-10s %-10s %-20s %-20s %-20s\n",
197 "shmid", "owner", "attached", "detached", "changed");
198 } else if (flag(p)) {
199 printf("------ Shared Memory Creator/Last-op --------\n");
200 printf("%-10s %-10s %-10s %-10s\n",
201 "shmid", "owner", "cpid", "lpid");
202 } else if (flag(c)) {
203 printf("------ Shared Memory Segment Creators/Owners --------\n");
204 printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
205 "shmid", "perms", "cuid", "cgid", "uid", "gid");
206 } else {
207 printf("------ Shared Memory Segments --------\n");
208 printf("%-10s %-10s %-10s %-10s %-10s %-10s %-12s\n",
209 "key", "shmid", "owner", "perms", "bytes", "nattch",
210 "status");
211 }
212
213 for (i = 0; i <= max_nr; i++) {
214 if ((shmid = shmctl(i, SHM_STAT, &buf)) < 0 ) continue;
215 if (flag(t)) {
216 if ((pw = getpwuid(buf.shm_perm.uid)))
217 printf("%-10d %-10.10s", shmid, pw->pw_name);
218 else printf("%-10d %-10.10d", shmid, buf.shm_perm.uid);
219 printf(" %-20.16s", buf.shm_atime
220 ? ctime(&buf.shm_atime) + 4 : "Not set");
221 printf(" %-20.16s", buf.shm_dtime
222 ? ctime(&buf.shm_dtime) + 4 : "Not set");
223 printf(" %-20.16s\n", buf.shm_ctime
224 ? ctime(&buf.shm_ctime) + 4 : "Not set");
225 } else if (flag(p)) {
226 if ((pw = getpwuid(buf.shm_perm.uid)))
227 printf("%-10d %-10.10s", shmid, pw->pw_name);
228 else printf("%-10d %-10.10d", shmid, buf.shm_perm.uid);
229 printf(" %-10d %-10d\n", buf.shm_cpid, buf.shm_lpid);
230 } else if (flag(c)) {
231 printf("%-10d %-10o", shmid, buf.shm_perm.mode & 0777);
232 if ((pw = getpwuid(buf.shm_perm.cuid))) printf(" %-10s", pw->pw_name);
233 else printf(" %-10d", buf.shm_perm.cuid);
234 if ((gr = getgrgid(buf.shm_perm.cgid))) printf(" %-10s", gr->gr_name);
235 else printf(" %-10d", buf.shm_perm.cgid);
236 if ((pw = getpwuid(buf.shm_perm.uid))) printf(" %-10s", pw->pw_name);
237 else printf(" %-10d", buf.shm_perm.uid);
238 if ((gr = getgrgid(buf.shm_perm.gid))) printf(" %-10s\n", gr->gr_name);
239 else printf(" %-10d\n", buf.shm_perm.gid);
240 } else {
241 printf("0x%08x ", buf.shm_perm.__key);
242 if ((pw = getpwuid(buf.shm_perm.uid)))
243 printf("%-10d %-10.10s", shmid, pw->pw_name);
244 else printf("%-10d %-10.10d", shmid, buf.shm_perm.uid);
245 printf(" %-10o %-10lu %-10ld %-6s %-6s\n", buf.shm_perm.mode & 0777,
246 (unsigned long) buf.shm_segsz,
247 (long) buf.shm_nattch,
248 buf.shm_perm.mode & SHM_DEST ? "dest" : " ",
249 buf.shm_perm.mode & SHM_LOCKED ? "locked" : " ");
250 }
251 }
252 }
253
254 #ifdef TOYBOX_OH_ADAPT
255 //delete 'ipcs -s' fail problem: kernel is not configured for semaphores
256 #else
sem_array(void)257 static void sem_array(void)
258 {
259 struct seminfo info_buf;
260 struct semid_ds buf;
261 union semun u;
262 int max_nr, i,semid;
263 struct passwd *pw;
264 struct group *gr;
265
266 u.array = (unsigned short *)&info_buf;
267 if ((max_nr = semctl(0, 0, SEM_INFO, u)) < 0) {
268 perror_msg("kernel is not configured for semaphores");
269 return;
270 }
271
272
273 if (flag(u)) {
274 printf("------ Semaphore Status --------\n");
275 printf("used arrays = %d\n"
276 "allocated semaphores = %d\n",
277 info_buf.semusz, info_buf.semaem);
278 return;
279 }
280 if (flag(l)) {
281 printf("------ Semaphore Limits --------\n");
282 u.array = (unsigned short *)&info_buf;
283 if ((semctl(0, 0, 3, u)) < 0) //IPC_INFO
284 return;
285 printf("max number of arrays = %d\n"
286 "max semaphores per array = %d\n"
287 "max semaphores system wide = %d\n"
288 "max ops per semop call = %d\n"
289 "semaphore max value = %d\n",
290 info_buf.semmni,
291 info_buf.semmsl,
292 info_buf.semmns, info_buf.semopm, info_buf.semvmx);
293 return;
294 }
295
296 if (flag(t)) {
297 printf("------ Semaphore Operation/Change Times --------\n");
298 printf("%-8s %-10s %-26.24s %-26.24s\n",
299 "shmid", "owner", "last-op", "last-changed");
300 } else if (flag(c)) {
301 printf("------ Semaphore %s --------\n", "Arrays Creators/Owners");
302 printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
303 "semid", "perms", "cuid", "cgid", "uid", "gid");
304
305 } else if (flag(p)){
306 return;
307 } else {
308 printf("------ Semaphore %s --------\n", "Arrays");
309 printf("%-10s %-10s %-10s %-10s %-10s\n",
310 "key", "semid", "owner", "perms", "nsems");
311 }
312
313 for (i = 0; i <= max_nr; i++) {
314 u.buf = &buf;
315 if ((semid = semctl(i, 0, SEM_STAT, u)) < 0) continue;
316 pw = getpwuid(buf.sem_perm.uid);
317 if (flag(t)) {
318 if (pw) printf("%-8d %-10.10s", semid, pw->pw_name);
319 else printf("%-8d %-10d", semid, buf.sem_perm.uid);
320
321 printf(" %-26.24s", buf.sem_otime
322 ? ctime(&buf.sem_otime) : "Not set");
323 printf(" %-26.24s\n", buf.sem_ctime
324 ? ctime(&buf.sem_ctime) : "Not set");
325 } else if (flag(c)) {
326 printf("%-10d %-10o", semid, buf.sem_perm.mode & 0777);
327 if ((pw = getpwuid(buf.sem_perm.cuid))) printf(" %-10s", pw->pw_name);
328 else printf(" %-10d", buf.sem_perm.cuid);
329 if ((gr = getgrgid(buf.sem_perm.cgid))) printf(" %-10s", gr->gr_name);
330 else printf(" %-10d", buf.sem_perm.cgid);
331 if ((pw = getpwuid(buf.sem_perm.uid))) printf(" %-10s", pw->pw_name);
332 else printf(" %-10d", buf.sem_perm.uid);
333 if ((gr = getgrgid(buf.sem_perm.gid))) printf(" %-10s\n", gr->gr_name);
334 else printf(" %-10d\n", buf.sem_perm.gid);
335 } else {
336 printf("0x%08x ", buf.sem_perm.__key);
337 if (pw) printf("%-10d %-10.9s", semid, pw->pw_name);
338 else printf("%-10d %-9d", semid, buf.sem_perm.uid);
339 printf(" %-10o %-10ld\n", buf.sem_perm.mode & 0777,
340 (long) buf.sem_nsems);
341 }
342 }
343 }
344 #endif
345
msg_array(void)346 static void msg_array(void)
347 {
348 struct msginfo info_buf;
349 struct msqid_ds buf;
350 int max_nr, i, msqid;
351 struct passwd *pw;
352 struct group *gr;
353
354 if ((max_nr = msgctl(0, MSG_INFO, (struct msqid_ds*)&info_buf)) < 0) {
355 perror_msg("kernel not configured for message queue");
356 return;
357 }
358
359 if (flag(u)) {
360 printf("------ Message%s --------\n", "s: Status");
361 printf("allocated queues = %d\n"
362 "used headers = %d\n"
363 "used space = %d bytes\n",
364 info_buf.msgpool, info_buf.msgmap, info_buf.msgtql);
365 return;
366 }
367 if (flag(l)) {
368 if ((msgctl(0, 3, (struct msqid_ds*)&info_buf)) < 0) return; //IPC_INFO
369 printf("------ Messages: Limits --------\n");
370 printf("max queues system wide = %d\n"
371 "max size of message (bytes) = %d\n"
372 "default max size of queue (bytes) = %d\n",
373 info_buf.msgmni, info_buf.msgmax, info_buf.msgmnb);
374 return;
375 }
376
377 if (flag(t)) {
378 printf("------ Message%s --------\n", " Queues Send/Recv/Change Times");
379 printf("%-8s %-10s %-20s %-20s %-20s\n",
380 "msqid", "owner", "send", "recv", "change");
381 } else if (flag(p)) {
382 printf("------ Message%s --------\n", " Queues PIDs");
383 printf("%-10s %-10s %-10s %-10s\n",
384 "msqid", "owner", "lspid", "lrpid");
385 } else if (flag(c)) {
386 printf("------ Message%s --------\n", " Queues: Creators/Owners");
387 printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
388 "msqid", "perms", "cuid", "cgid", "uid", "gid");
389 } else {
390 printf("------ Message%s --------\n", " Queues");
391 printf("%-10s %-10s %-10s %-10s %-12s %-12s\n",
392 "key", "msqid", "owner", "perms", "used-bytes", "messages");
393 }
394
395 for (i = 0; i <= max_nr; i++) {
396 if ((msqid = msgctl(i, MSG_STAT, &buf)) < 0 ) continue;
397 pw = getpwuid(buf.msg_perm.uid);
398 if (flag(t)) {
399 if (pw) printf("%-8d %-10.10s", msqid, pw->pw_name);
400 else printf("%-8d %-10d", msqid, buf.msg_perm.uid);
401 printf(" %-20.16s", buf.msg_stime
402 ? ctime(&buf.msg_stime) + 4 : "Not set");
403 printf(" %-20.16s", buf.msg_rtime
404 ? ctime(&buf.msg_rtime) + 4 : "Not set");
405 printf(" %-20.16s\n", buf.msg_ctime
406 ? ctime(&buf.msg_ctime) + 4 : "Not set");
407 } else if (flag(p)) {
408 if (pw) printf("%-8d %-10.10s", msqid, pw->pw_name);
409 else printf("%-8d %-10d", msqid, buf.msg_perm.uid);
410 printf(" %5d %5d\n", buf.msg_lspid, buf.msg_lrpid);
411 } else if (flag(c)) {
412 printf("%-10d %-10o", msqid, buf.msg_perm.mode & 0777);
413 if ((pw = getpwuid(buf.msg_perm.cuid))) printf(" %-10s", pw->pw_name);
414 else printf(" %-10d", buf.msg_perm.cuid);
415 if ((gr = getgrgid(buf.msg_perm.cgid))) printf(" %-10s", gr->gr_name);
416 else printf(" %-10d", buf.msg_perm.cgid);
417 if ((pw = getpwuid(buf.msg_perm.uid))) printf(" %-10s", pw->pw_name);
418 else printf(" %-10d", buf.msg_perm.uid);
419 if ((gr = getgrgid(buf.msg_perm.gid))) printf(" %-10s\n", gr->gr_name);
420 else printf(" %-10d\n", buf.msg_perm.gid);
421 } else {
422 printf("0x%08x ", buf.msg_perm.__key);
423 if (pw) printf("%-10d %-10.10s", msqid, pw->pw_name);
424 else printf("%-10d %-10d", msqid, buf.msg_perm.uid);
425 printf(" %-10o %-12ld %-12ld\n", buf.msg_perm.mode & 0777,
426 (long) buf.msg_cbytes, (long) buf.msg_qnum);
427 }
428 }
429 }
430
ipcs_main(void)431 void ipcs_main(void)
432 {
433 #ifdef TOYBOX_OH_ADAPT
434 //delete 'ipcs -s' fail problem: kernel is not configured for semaphores
435 if (flag(i)) {
436 if (flag(m)) show_shm_id();
437 else if (flag(q)) show_msg_id();
438 else help_exit(0);
439 return;
440 }
441 #else
442 if (flag(i)) {
443 if (flag(m)) show_shm_id();
444 else if (flag(s)) show_sem_id();
445 else if (flag(q)) show_msg_id();
446 else help_exit(0);
447 return;
448 }
449 #endif
450
451 #ifdef TOYBOX_OH_ADAPT
452 //delete 'ipcs -s' fail problem: kernel is not configured for semaphores
453 if (!(flag(m) || flag(q)) || flag(a)) toys.optflags |= (FLAG_m|FLAG_q);
454 #else
455 if (!(flag(m) || flag(s) || flag(q)) || flag(a)) toys.optflags |= (FLAG_m|FLAG_s|FLAG_q);
456 #endif
457
458 xputc('\n');
459 if (flag(m)) {
460 shm_array();
461 xputc('\n');
462 }
463 #ifdef TOYBOX_OH_ADAPT
464 //delete 'ipcs -s' fail problem: kernel is not configured for semaphores
465 #else
466 if (flag(s)) {
467 sem_array();
468 xputc('\n');
469 }
470 #endif
471 if (flag(q)) {
472 msg_array();
473 xputc('\n');
474 }
475 }
476