source: MondoRescue/branches/3.3/mindi-busybox/util-linux/ipcs.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 17.0 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * ipcs.c -- provides information on allocated ipc resources.
4 *
5 * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com>
6 * Adapted for busybox from util-linux-2.12a.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
10
11//usage:#define ipcs_trivial_usage
12//usage: "[[-smq] -i shmid] | [[-asmq] [-tcplu]]"
13//usage:#define ipcs_full_usage "\n\n"
14//usage: " -i Show specific resource"
15//usage: "\nResource specification:"
16//usage: "\n -m Shared memory segments"
17//usage: "\n -q Message queues"
18//usage: "\n -s Semaphore arrays"
19//usage: "\n -a All (default)"
20//usage: "\nOutput format:"
21//usage: "\n -t Time"
22//usage: "\n -c Creator"
23//usage: "\n -p Pid"
24//usage: "\n -l Limits"
25//usage: "\n -u Summary"
26
27/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
28/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
29/* X/OPEN tells us to use <sys/{types,ipc,shm}.h> for shmctl() */
30#include <sys/types.h>
31#include <sys/ipc.h>
32#include <sys/sem.h>
33#include <sys/msg.h>
34#include <sys/shm.h>
35
36#include "libbb.h"
37
38/*-------------------------------------------------------------------*/
39/* SHM_DEST and SHM_LOCKED are defined in kernel headers,
40 but inside #ifdef __KERNEL__ ... #endif */
41#ifndef SHM_DEST
42/* shm_mode upper byte flags */
43#define SHM_DEST 01000 /* segment will be destroyed on last detach */
44#define SHM_LOCKED 02000 /* segment will not be swapped */
45#endif
46
47/* For older kernels the same holds for the defines below */
48#ifndef MSG_STAT
49#define MSG_STAT 11
50#define MSG_INFO 12
51#endif
52
53#ifndef SHM_STAT
54#define SHM_STAT 13
55#define SHM_INFO 14
56struct shm_info {
57 int used_ids;
58 unsigned long shm_tot; /* total allocated shm */
59 unsigned long shm_rss; /* total resident shm */
60 unsigned long shm_swp; /* total swapped shm */
61 unsigned long swap_attempts;
62 unsigned long swap_successes;
63};
64#endif
65
66#ifndef SEM_STAT
67#define SEM_STAT 18
68#define SEM_INFO 19
69#endif
70
71/* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */
72#ifndef IPC_INFO
73#define IPC_INFO 3
74#endif
75/*-------------------------------------------------------------------*/
76
77/* The last arg of semctl is a union semun, but where is it defined?
78 X/OPEN tells us to define it ourselves, but until recently
79 Linux include files would also define it. */
80#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
81/* union semun is defined by including <sys/sem.h> */
82#else
83/* according to X/OPEN we have to define it ourselves */
84union semun {
85 int val;
86 struct semid_ds *buf;
87 unsigned short *array;
88 struct seminfo *__buf;
89};
90#endif
91
92/* X/OPEN (Jan 1987) does not define fields key, seq in struct ipc_perm;
93 libc 4/5 does not mention struct ipc_term at all, but includes
94 <linux/ipc.h>, which defines a struct ipc_perm with such fields.
95 glibc-1.09 has no support for sysv ipc.
96 glibc 2 uses __key, __seq */
97#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
98#define KEY __key
99#else
100#define KEY key
101#endif
102
103#define LIMITS 1
104#define STATUS 2
105#define CREATOR 3
106#define TIME 4
107#define PID 5
108
109static char format;
110
111static void print_perms(int id, struct ipc_perm *ipcp)
112{
113 struct passwd *pw;
114 struct group *gr;
115
116 printf("%-10d %-10o", id, ipcp->mode & 0777);
117
118 pw = getpwuid(ipcp->cuid);
119 if (pw) printf(" %-10s", pw->pw_name);
120 else printf(" %-10d", ipcp->cuid);
121 gr = getgrgid(ipcp->cgid);
122 if (gr) printf(" %-10s", gr->gr_name);
123 else printf(" %-10d", ipcp->cgid);
124
125 pw = getpwuid(ipcp->uid);
126 if (pw) printf(" %-10s", pw->pw_name);
127 else printf(" %-10d", ipcp->uid);
128 gr = getgrgid(ipcp->gid);
129 if (gr) printf(" %-10s\n", gr->gr_name);
130 else printf(" %-10d\n", ipcp->gid);
131}
132
133
134static NOINLINE void do_shm(void)
135{
136 int maxid, shmid, id;
137 struct shmid_ds shmseg;
138 struct shm_info shm_info;
139 struct shminfo shminfo;
140 struct ipc_perm *ipcp = &shmseg.shm_perm;
141 struct passwd *pw;
142
143 maxid = shmctl(0, SHM_INFO, (struct shmid_ds *) (void *) &shm_info);
144 if (maxid < 0) {
145 printf("kernel not configured for %s\n", "shared memory");
146 return;
147 }
148
149 switch (format) {
150 case LIMITS:
151 printf("------ Shared Memory %s --------\n", "Limits");
152 if ((shmctl(0, IPC_INFO, (struct shmid_ds *) (void *) &shminfo)) < 0)
153 return;
154 /* glibc 2.1.3 and all earlier libc's have ints as fields
155 * of struct shminfo; glibc 2.1.91 has unsigned long; ach */
156 printf("max number of segments = %lu\n"
157 "max seg size (kbytes) = %lu\n"
158 "max total shared memory (pages) = %lu\n"
159 "min seg size (bytes) = %lu\n",
160 (unsigned long) shminfo.shmmni,
161 (unsigned long) (shminfo.shmmax >> 10),
162 (unsigned long) shminfo.shmall,
163 (unsigned long) shminfo.shmmin);
164 return;
165
166 case STATUS:
167 printf("------ Shared Memory %s --------\n", "Status");
168 printf("segments allocated %d\n"
169 "pages allocated %lu\n"
170 "pages resident %lu\n"
171 "pages swapped %lu\n"
172 "Swap performance: %lu attempts\t%lu successes\n",
173 shm_info.used_ids,
174 shm_info.shm_tot,
175 shm_info.shm_rss,
176 shm_info.shm_swp,
177 shm_info.swap_attempts, shm_info.swap_successes);
178 return;
179
180 case CREATOR:
181 printf("------ Shared Memory %s --------\n", "Segment Creators/Owners");
182 printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
183 "shmid", "perms", "cuid", "cgid", "uid", "gid");
184 break;
185
186 case TIME:
187 printf("------ Shared Memory %s --------\n", "Attach/Detach/Change Times");
188 printf("%-10s %-10s %-20s %-20s %-20s\n",
189 "shmid", "owner", "attached", "detached", "changed");
190 break;
191
192 case PID:
193 printf("------ Shared Memory %s --------\n", "Creator/Last-op");
194 printf("%-10s %-10s %-10s %-10s\n",
195 "shmid", "owner", "cpid", "lpid");
196 break;
197
198 default:
199 printf("------ Shared Memory %s --------\n", "Segments");
200 printf("%-10s %-10s %-10s %-10s %-10s %-10s %-12s\n",
201 "key", "shmid", "owner", "perms", "bytes", "nattch",
202 "status");
203 break;
204 }
205
206 for (id = 0; id <= maxid; id++) {
207 shmid = shmctl(id, SHM_STAT, &shmseg);
208 if (shmid < 0)
209 continue;
210 if (format == CREATOR) {
211 print_perms(shmid, ipcp);
212 continue;
213 }
214 pw = getpwuid(ipcp->uid);
215 switch (format) {
216 case TIME:
217 if (pw)
218 printf("%-10d %-10.10s", shmid, pw->pw_name);
219 else
220 printf("%-10d %-10d", shmid, ipcp->uid);
221 /* ctime uses static buffer: use separate calls */
222 printf(" %-20.16s", shmseg.shm_atime
223 ? ctime(&shmseg.shm_atime) + 4 : "Not set");
224 printf(" %-20.16s", shmseg.shm_dtime
225 ? ctime(&shmseg.shm_dtime) + 4 : "Not set");
226 printf(" %-20.16s\n", shmseg.shm_ctime
227 ? ctime(&shmseg.shm_ctime) + 4 : "Not set");
228 break;
229 case PID:
230 if (pw)
231 printf("%-10d %-10.10s", shmid, pw->pw_name);
232 else
233 printf("%-10d %-10d", shmid, ipcp->uid);
234 printf(" %-10d %-10d\n", shmseg.shm_cpid, shmseg.shm_lpid);
235 break;
236
237 default:
238 printf("0x%08x ", ipcp->KEY);
239 if (pw)
240 printf("%-10d %-10.10s", shmid, pw->pw_name);
241 else
242 printf("%-10d %-10d", shmid, ipcp->uid);
243 printf(" %-10o %-10lu %-10ld %-6s %-6s\n", ipcp->mode & 0777,
244 /*
245 * earlier: int, Austin has size_t
246 */
247 (unsigned long) shmseg.shm_segsz,
248 /*
249 * glibc-2.1.3 and earlier has unsigned short;
250 * Austin has shmatt_t
251 */
252 (long) shmseg.shm_nattch,
253 ipcp->mode & SHM_DEST ? "dest" : " ",
254 ipcp->mode & SHM_LOCKED ? "locked" : " ");
255 break;
256 }
257 }
258}
259
260
261static NOINLINE void do_sem(void)
262{
263 int maxid, semid, id;
264 struct semid_ds semary;
265 struct seminfo seminfo;
266 struct ipc_perm *ipcp = &semary.sem_perm;
267 struct passwd *pw;
268 union semun arg;
269
270 arg.array = (unsigned short *) (void *) &seminfo;
271 maxid = semctl(0, 0, SEM_INFO, arg);
272 if (maxid < 0) {
273 printf("kernel not configured for %s\n", "semaphores");
274 return;
275 }
276
277 switch (format) {
278 case LIMITS:
279 printf("------ Semaphore %s --------\n", "Limits");
280 arg.array = (unsigned short *) (void *) &seminfo; /* damn union */
281 if ((semctl(0, 0, IPC_INFO, arg)) < 0)
282 return;
283 printf("max number of arrays = %d\n"
284 "max semaphores per array = %d\n"
285 "max semaphores system wide = %d\n"
286 "max ops per semop call = %d\n"
287 "semaphore max value = %d\n",
288 seminfo.semmni,
289 seminfo.semmsl,
290 seminfo.semmns, seminfo.semopm, seminfo.semvmx);
291 return;
292
293 case STATUS:
294 printf("------ Semaphore %s --------\n", "Status");
295 printf("used arrays = %d\n"
296 "allocated semaphores = %d\n",
297 seminfo.semusz, seminfo.semaem);
298 return;
299
300 case CREATOR:
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 break;
305
306 case TIME:
307 printf("------ Shared Memory %s --------\n", "Operation/Change Times");
308 printf("%-8s %-10s %-26.24s %-26.24s\n",
309 "shmid", "owner", "last-op", "last-changed");
310 break;
311
312 case PID:
313 break;
314
315 default:
316 printf("------ Semaphore %s --------\n", "Arrays");
317 printf("%-10s %-10s %-10s %-10s %-10s\n",
318 "key", "semid", "owner", "perms", "nsems");
319 break;
320 }
321
322 for (id = 0; id <= maxid; id++) {
323 arg.buf = (struct semid_ds *) &semary;
324 semid = semctl(id, 0, SEM_STAT, arg);
325 if (semid < 0)
326 continue;
327 if (format == CREATOR) {
328 print_perms(semid, ipcp);
329 continue;
330 }
331 pw = getpwuid(ipcp->uid);
332 switch (format) {
333 case TIME:
334 if (pw)
335 printf("%-8d %-10.10s", semid, pw->pw_name);
336 else
337 printf("%-8d %-10d", semid, ipcp->uid);
338 /* ctime uses static buffer: use separate calls */
339 printf(" %-26.24s", semary.sem_otime
340 ? ctime(&semary.sem_otime) : "Not set");
341 printf(" %-26.24s\n", semary.sem_ctime
342 ? ctime(&semary.sem_ctime) : "Not set");
343 break;
344 case PID:
345 break;
346
347 default:
348 printf("0x%08x ", ipcp->KEY);
349 if (pw)
350 printf("%-10d %-10.9s", semid, pw->pw_name);
351 else
352 printf("%-10d %-9d", semid, ipcp->uid);
353 printf(" %-10o %-10ld\n", ipcp->mode & 0777,
354 /*
355 * glibc-2.1.3 and earlier has unsigned short;
356 * glibc-2.1.91 has variation between
357 * unsigned short and unsigned long
358 * Austin prescribes unsigned short.
359 */
360 (long) semary.sem_nsems);
361 break;
362 }
363 }
364}
365
366
367static NOINLINE void do_msg(void)
368{
369 int maxid, msqid, id;
370 struct msqid_ds msgque;
371 struct msginfo msginfo;
372 struct ipc_perm *ipcp = &msgque.msg_perm;
373 struct passwd *pw;
374
375 maxid = msgctl(0, MSG_INFO, (struct msqid_ds *) (void *) &msginfo);
376 if (maxid < 0) {
377 printf("kernel not configured for %s\n", "message queues");
378 return;
379 }
380
381 switch (format) {
382 case LIMITS:
383 if ((msgctl(0, IPC_INFO, (struct msqid_ds *) (void *) &msginfo)) < 0)
384 return;
385 printf("------ Message%s --------\n", "s: Limits");
386 printf("max queues system wide = %d\n"
387 "max size of message (bytes) = %d\n"
388 "default max size of queue (bytes) = %d\n",
389 msginfo.msgmni, msginfo.msgmax, msginfo.msgmnb);
390 return;
391
392 case STATUS:
393 printf("------ Message%s --------\n", "s: Status");
394 printf("allocated queues = %d\n"
395 "used headers = %d\n"
396 "used space = %d bytes\n",
397 msginfo.msgpool, msginfo.msgmap, msginfo.msgtql);
398 return;
399
400 case CREATOR:
401 printf("------ Message%s --------\n", " Queues: Creators/Owners");
402 printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
403 "msqid", "perms", "cuid", "cgid", "uid", "gid");
404 break;
405
406 case TIME:
407 printf("------ Message%s --------\n", " Queues Send/Recv/Change Times");
408 printf("%-8s %-10s %-20s %-20s %-20s\n",
409 "msqid", "owner", "send", "recv", "change");
410 break;
411
412 case PID:
413 printf("------ Message%s --------\n", " Queues PIDs");
414 printf("%-10s %-10s %-10s %-10s\n",
415 "msqid", "owner", "lspid", "lrpid");
416 break;
417
418 default:
419 printf("------ Message%s --------\n", " Queues");
420 printf("%-10s %-10s %-10s %-10s %-12s %-12s\n",
421 "key", "msqid", "owner", "perms", "used-bytes", "messages");
422 break;
423 }
424
425 for (id = 0; id <= maxid; id++) {
426 msqid = msgctl(id, MSG_STAT, &msgque);
427 if (msqid < 0)
428 continue;
429 if (format == CREATOR) {
430 print_perms(msqid, ipcp);
431 continue;
432 }
433 pw = getpwuid(ipcp->uid);
434 switch (format) {
435 case TIME:
436 if (pw)
437 printf("%-8d %-10.10s", msqid, pw->pw_name);
438 else
439 printf("%-8d %-10d", msqid, ipcp->uid);
440 printf(" %-20.16s", msgque.msg_stime
441 ? ctime(&msgque.msg_stime) + 4 : "Not set");
442 printf(" %-20.16s", msgque.msg_rtime
443 ? ctime(&msgque.msg_rtime) + 4 : "Not set");
444 printf(" %-20.16s\n", msgque.msg_ctime
445 ? ctime(&msgque.msg_ctime) + 4 : "Not set");
446 break;
447 case PID:
448 if (pw)
449 printf("%-8d %-10.10s", msqid, pw->pw_name);
450 else
451 printf("%-8d %-10d", msqid, ipcp->uid);
452 printf(" %5d %5d\n", msgque.msg_lspid, msgque.msg_lrpid);
453 break;
454
455 default:
456 printf("0x%08x ", ipcp->KEY);
457 if (pw)
458 printf("%-10d %-10.10s", msqid, pw->pw_name);
459 else
460 printf("%-10d %-10d", msqid, ipcp->uid);
461 printf(" %-10o %-12ld %-12ld\n", ipcp->mode & 0777,
462 /*
463 * glibc-2.1.3 and earlier has unsigned short;
464 * glibc-2.1.91 has variation between
465 * unsigned short, unsigned long
466 * Austin has msgqnum_t
467 */
468 (long) msgque.msg_cbytes, (long) msgque.msg_qnum);
469 break;
470 }
471 }
472}
473
474
475static void print_shm(int shmid)
476{
477 struct shmid_ds shmds;
478 struct ipc_perm *ipcp = &shmds.shm_perm;
479
480 if (shmctl(shmid, IPC_STAT, &shmds) == -1) {
481 bb_perror_msg("shmctl");
482 return;
483 }
484
485 printf("\nShared memory Segment shmid=%d\n"
486 "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\n"
487 "mode=%#o\taccess_perms=%#o\n"
488 "bytes=%ld\tlpid=%d\tcpid=%d\tnattch=%ld\n",
489 shmid,
490 ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid,
491 ipcp->mode, ipcp->mode & 0777,
492 (long) shmds.shm_segsz, shmds.shm_lpid, shmds.shm_cpid,
493 (long) shmds.shm_nattch);
494 printf("att_time=%-26.24s\n",
495 shmds.shm_atime ? ctime(&shmds.shm_atime) : "Not set");
496 printf("det_time=%-26.24s\n",
497 shmds.shm_dtime ? ctime(&shmds.shm_dtime) : "Not set");
498 printf("change_time=%-26.24s\n\n", ctime(&shmds.shm_ctime));
499}
500
501
502static void print_msg(int msqid)
503{
504 struct msqid_ds buf;
505 struct ipc_perm *ipcp = &buf.msg_perm;
506
507 if (msgctl(msqid, IPC_STAT, &buf) == -1) {
508 bb_perror_msg("msgctl");
509 return;
510 }
511
512 printf("\nMessage Queue msqid=%d\n"
513 "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\tmode=%#o\n"
514 "cbytes=%ld\tqbytes=%ld\tqnum=%ld\tlspid=%d\tlrpid=%d\n",
515 msqid, ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid, ipcp->mode,
516 /*
517 * glibc-2.1.3 and earlier has unsigned short;
518 * glibc-2.1.91 has variation between
519 * unsigned short, unsigned long
520 * Austin has msgqnum_t (for msg_qbytes)
521 */
522 (long) buf.msg_cbytes, (long) buf.msg_qbytes,
523 (long) buf.msg_qnum, buf.msg_lspid, buf.msg_lrpid);
524
525 printf("send_time=%-26.24s\n",
526 buf.msg_stime ? ctime(&buf.msg_stime) : "Not set");
527 printf("rcv_time=%-26.24s\n",
528 buf.msg_rtime ? ctime(&buf.msg_rtime) : "Not set");
529 printf("change_time=%-26.24s\n\n",
530 buf.msg_ctime ? ctime(&buf.msg_ctime) : "Not set");
531}
532
533static void print_sem(int semid)
534{
535 struct semid_ds semds;
536 struct ipc_perm *ipcp = &semds.sem_perm;
537 union semun arg;
538 unsigned int i;
539
540 arg.buf = &semds;
541 if (semctl(semid, 0, IPC_STAT, arg)) {
542 bb_perror_msg("semctl");
543 return;
544 }
545
546 printf("\nSemaphore Array semid=%d\n"
547 "uid=%d\t gid=%d\t cuid=%d\t cgid=%d\n"
548 "mode=%#o, access_perms=%#o\n"
549 "nsems = %ld\n"
550 "otime = %-26.24s\n",
551 semid,
552 ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid,
553 ipcp->mode, ipcp->mode & 0777,
554 (long) semds.sem_nsems,
555 semds.sem_otime ? ctime(&semds.sem_otime) : "Not set");
556 printf("ctime = %-26.24s\n"
557 "%-10s %-10s %-10s %-10s %-10s\n",
558 ctime(&semds.sem_ctime),
559 "semnum", "value", "ncount", "zcount", "pid");
560
561 arg.val = 0;
562 for (i = 0; i < semds.sem_nsems; i++) {
563 int val, ncnt, zcnt, pid;
564
565 val = semctl(semid, i, GETVAL, arg);
566 ncnt = semctl(semid, i, GETNCNT, arg);
567 zcnt = semctl(semid, i, GETZCNT, arg);
568 pid = semctl(semid, i, GETPID, arg);
569 if (val < 0 || ncnt < 0 || zcnt < 0 || pid < 0) {
570 bb_perror_msg_and_die("semctl");
571 }
572 printf("%-10u %-10d %-10d %-10d %-10d\n", i, val, ncnt, zcnt, pid);
573 }
574 bb_putchar('\n');
575}
576
577int ipcs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
578int ipcs_main(int argc UNUSED_PARAM, char **argv)
579{
580 int id = 0;
581 unsigned flags = 0;
582 unsigned opt;
583 char *opt_i;
584#define flag_print (1<<0)
585#define flag_msg (1<<1)
586#define flag_sem (1<<2)
587#define flag_shm (1<<3)
588
589 opt = getopt32(argv, "i:aqsmtcplu", &opt_i);
590 if (opt & 0x1) { // -i
591 id = xatoi(opt_i);
592 flags |= flag_print;
593 }
594 if (opt & 0x2) flags |= flag_msg | flag_sem | flag_shm; // -a
595 if (opt & 0x4) flags |= flag_msg; // -q
596 if (opt & 0x8) flags |= flag_sem; // -s
597 if (opt & 0x10) flags |= flag_shm; // -m
598 if (opt & 0x20) format = TIME; // -t
599 if (opt & 0x40) format = CREATOR; // -c
600 if (opt & 0x80) format = PID; // -p
601 if (opt & 0x100) format = LIMITS; // -l
602 if (opt & 0x200) format = STATUS; // -u
603
604 if (flags & flag_print) {
605 if (flags & flag_shm) {
606 print_shm(id);
607 fflush_stdout_and_exit(EXIT_SUCCESS);
608 }
609 if (flags & flag_sem) {
610 print_sem(id);
611 fflush_stdout_and_exit(EXIT_SUCCESS);
612 }
613 if (flags & flag_msg) {
614 print_msg(id);
615 fflush_stdout_and_exit(EXIT_SUCCESS);
616 }
617 bb_show_usage();
618 }
619
620 if (!(flags & (flag_shm | flag_msg | flag_sem)))
621 flags |= flag_msg | flag_shm | flag_sem;
622 bb_putchar('\n');
623
624 if (flags & flag_shm) {
625 do_shm();
626 bb_putchar('\n');
627 }
628 if (flags & flag_sem) {
629 do_sem();
630 bb_putchar('\n');
631 }
632 if (flags & flag_msg) {
633 do_msg();
634 bb_putchar('\n');
635 }
636 fflush_stdout_and_exit(EXIT_SUCCESS);
637}
Note: See TracBrowser for help on using the repository browser.