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