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