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