Bump to version 1.22.1
[platform/upstream/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
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
56 struct 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 */
84 union 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
109 static char format;
110
111 static 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
134 static 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
261 static 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
367 static 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
475 static 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
502 static 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
533 static 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
577 int ipcs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
578 int 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 }