source: branches/3.2/mindi-busybox/util-linux/ipcs.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
File size: 17.0 KB
Line 
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 %ld\n"
170                "pages resident  %ld\n"
171                "pages swapped   %ld\n"
172                "Swap performance: %ld attempts\t%ld 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("%-10d %-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}
Note: See TracBrowser for help on using the repository browser.