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