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