diff options
author | Rob Landley <rob@landley.net> | 2005-06-20 04:30:36 +0000 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2005-06-20 04:30:36 +0000 |
commit | 6eb1e416743c597f8ecd3b595ddb00d3aa42c1f4 (patch) | |
tree | b88e5e3d34a2edea9bd2a9c59fd1cf84a62ddf4d | |
parent | df1eda82b90d1c179b34d27f2825264efed10045 (diff) | |
download | busybox-6eb1e416743c597f8ecd3b595ddb00d3aa42c1f4.tar.gz |
Rodney Radford submitted ipcs and ipcrm (system V IPC stuff). They could use
some more work to shrink them down.
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | docs/busybox_header.pod | 18 | ||||
-rw-r--r-- | include/applets.h | 6 | ||||
-rw-r--r-- | include/usage.h | 42 | ||||
-rw-r--r-- | sysdeps/linux/defconfig | 2 | ||||
-rw-r--r-- | util-linux/Config.in | 45 | ||||
-rw-r--r-- | util-linux/Makefile.in | 2 | ||||
-rw-r--r-- | util-linux/ipcrm.c | 273 | ||||
-rw-r--r-- | util-linux/ipcs.c | 686 |
9 files changed, 1049 insertions, 28 deletions
@@ -113,6 +113,9 @@ Bruce Perens <bruce@pixar.com> Original author of BusyBox in 1995, 1996. Some of his code can still be found hiding here and there... +Rodney Radford <rradford@mindspring.com> + ipcs, ipcrm + Tim Riker <Tim@Rikers.org> bug fixes, member of fan club diff --git a/docs/busybox_header.pod b/docs/busybox_header.pod index 35631b84e..5af92401c 100644 --- a/docs/busybox_header.pod +++ b/docs/busybox_header.pod @@ -89,15 +89,15 @@ Currently defined functions include: fgrep, find, fold, free, freeramdisk, fsck.minix, ftpget, ftpput, getopt, getty, grep, gunzip, gzip, halt, hdparm, head, hexdump, hostid, hostname, httpd, hush, hwclock, id, ifconfig, ifdown, ifup, inetd, init, insmod, - install, ip, ipaddr, ipcalc, iplink, iproute, iptunnel, kill, killall, - klogd, lash, last, length, linuxrc, ln, loadfont, loadkmap, logger, login, - logname, logread, losetup, ls, lsmod, makedevs, md5sum, mesg, mkdir, - mkfifo, mkfs.minix, mknod, mkswap, mktemp, modprobe, more, mount, msh, mt, - mv, nameif, nc, netstat, nslookup, od, openvt, passwd, patch, pidof, ping, - ping6, pipe_progress, pivot_root, poweroff, printf, ps, pwd, rdate, - readlink, realpath, reboot, renice, reset, rm, rmdir, rmmod, route, rpm, - rpm2cpio, run-parts, rx, sed, seq, setkeycodes, sha1sum, sleep, sort, - start-stop-daemon, strings, stty, su, sulogin, swapoff, swapon, sync, + install, ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, iproute, iptunnel, kill, + killall, klogd, lash, last, length, linuxrc, ln, loadfont, loadkmap, + logger, login, logname, logread, losetup, ls, lsmod, makedevs, md5sum, + mesg, mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, modprobe, more, + mount, msh, mt, mv, nameif, nc, netstat, nslookup, od, openvt, passwd, + patch, pidof, ping, ping6, pipe_progress, pivot_root, poweroff, printf, ps, + pwd, rdate, readlink, realpath, reboot, renice, reset, rm, rmdir, rmmod, + route, rpm, rpm2cpio, run-parts, rx, sed, seq, setkeycodes, sha1sum, sleep, + sort, start-stop-daemon, strings, stty, su, sulogin, swapoff, swapon, sync, sysctl, syslogd, tail, tar, tee, telnet, telnetd, test, tftp, time, top, touch, tr, traceroute, true, tty, udhcpc, udhcpd, umount, uname, uncompress, uniq, unix2dos, unzip, uptime, usleep, uudecode, uuencode, diff --git a/include/applets.h b/include/applets.h index e0b18085a..a7578ba1a 100644 --- a/include/applets.h +++ b/include/applets.h @@ -320,6 +320,12 @@ #ifdef CONFIG_IPCALC APPLET(ipcalc, ipcalc_main, _BB_DIR_BIN, _BB_SUID_NEVER) #endif +#ifdef CONFIG_IPCRM + APPLET(ipcrm, ipcrm_main, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS) +#endif +#ifdef CONFIG_IPCS + APPLET(ipcs, ipcs_main, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS) +#endif #ifdef CONFIG_IPLINK APPLET(iplink, iplink_main, _BB_DIR_BIN, _BB_SUID_NEVER) #endif diff --git a/include/usage.h b/include/usage.h index 5fb9858bc..017cb9c3e 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1395,6 +1395,32 @@ "\t-h\t--hostname\tDisplay first resolved host name\n" \ "\t-s\t--silent\tDon't ever display error messages.") +#define ipcrm_trivial_usage \ + "[-[MQS] key] [-[mqs] id]" +#define ipcrm_full_usage \ + "The upper-case options MQS are used to remove a shared memory\n" \ + "segment by an shmkey value. The lower-case options mqs are used\n" \ + "to remove a segment by shmid value.\n" \ + "\t-m | -M\tRemove the memory segment after the last detatch\n" \ + "\t-q | -Q\tRemove the message queue\n" \ + "\t-s | -S\tRemove the semaphore\n" + +#define ipcs_trivial_usage \ + "[[-smq] -i shmid] | [[-asmq] [-tclup]]" +#define ipcs_full_usage \ + "\t-i\tspecify a specific resource id\n" \ + "Resource specification:\n" \ + "\t-m\tshared memory segments\n" \ + "\t-q\tmessage queues\n" \ + "\t-s\tsempahore arrays\n" \ + "\t-a\tall (default)\n" \ + "Output format:\n" \ + "\t-t\ttime\n" \ + "\t-p\tpid\n" \ + "\t-s\tcreator\n" \ + "\t-a\tlimits\n" \ + "\t-i\tsummary\n" + #define iplink_trivial_usage \ "{ set DEVICE { up | down | arp { on | off } | show [ DEVICE ] }" #define iplink_full_usage \ @@ -2080,18 +2106,30 @@ "$ printf \"Val=%d\\n\" 5\n" \ "Val=5\n" +#if !defined(CONFIG_SELINUX) && !defined(CONFIG_PS_FEATURE_WIDE) +#define USAGE_PS "\n\tThis version of ps accepts no options." +#else +#define USAGE_PS "\nOptions:" +#endif #ifdef CONFIG_SELINUX #define USAGE_NONSELINUX(a) #else #define USAGE_NONSELINUX(a) a #endif +#ifdef CONFIG_PS_FEATURE_WIDE +#define USAGE_PS_WIDE(a) a +#else +#define USAGE_PS_WIDE(a) +#endif #define ps_trivial_usage \ "" #define ps_full_usage \ "Report process status\n" \ - USAGE_NONSELINUX("\n\tThis version of ps accepts no options.") \ - USAGE_SELINUX("\nOptions:\n\t-c\tshow SE Linux context") + USAGE_PS \ + USAGE_SELINUX("\n\t-c\tshow SE Linux context") \ + USAGE_PS_WIDE("\n\tw\twide output") + #define ps_example_usage \ "$ ps\n" \ diff --git a/sysdeps/linux/defconfig b/sysdeps/linux/defconfig index fd2b118e3..8848a6c37 100644 --- a/sysdeps/linux/defconfig +++ b/sysdeps/linux/defconfig @@ -397,6 +397,8 @@ CONFIG_DMESG=y # CONFIG_GETOPT is not set CONFIG_HEXDUMP=y # CONFIG_HWCLOCK is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set # CONFIG_LOSETUP is not set # CONFIG_MKSWAP is not set CONFIG_MORE=y diff --git a/util-linux/Config.in b/util-linux/Config.in index 3c990b936..a1e0b0848 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in @@ -216,6 +216,21 @@ config CONFIG_LOSETUP file or block device, and to query the status of a loop device. This version does not currently support enabling data encryption. +config CONFIG_IPCRM + bool "ipcrm" + default n + help + The ipcrm utility allows the removal of System V interprocess + communication (IPC) objects and the associated data structures + from the system. + +config CONFIG_IPCS + bool "ipcs" + default n + help + The ipcs utility is used to provide information on the currently + allocated System V interprocess (IPC) objects in the system. + config CONFIG_MKSWAP bool "mkswap" default n @@ -322,14 +337,18 @@ config CONFIG_FEATURE_MOUNT_LOOP default n depends on CONFIG_MOUNT || CONFIG_UMOUNT help - Enabling this feature allows mount to use the '-o' loop options, - which lets you loop mount files. Mount will automagically setup and - free the necessary loop devices so you do not need to mess with the - 'losetup' utility unless you really want to. This is really - only useful if you plan to loop mount files. + Enabling this feature allows automatic loopback mounts, meaning you can mount + filesystems contained in normal files as well as in block devices. The mount + and umount commands will detect you are trying to mount a file instead of a + block device, and transparently associate it with a loopback device (and free + the loopback device on unmount) for you. + + You can still use the 'losetup' utility and mount the loopback device yourself + if you need to do something advanced, such as specify an offset or cryptographic + options to the loopback device. config CONFIG_FEATURE_MTAB_SUPPORT - bool " Support for a real /etc/mtab (instead of /proc/mounts)" + bool " Support for a /etc/mtab file (instead of symlink to /proc/mounts)" default n depends on CONFIG_MOUNT || CONFIG_UMOUNT help @@ -339,17 +358,9 @@ config CONFIG_FEATURE_MTAB_SUPPORT BusyBox have a read-only root filesystem, so they will leave this option disabled and BusyBox will use the /proc/mounts file. -config CONFIG_FEATURE_MTAB_FILENAME - string " mtab file location" - default "/etc/mtab" - depends on CONFIG_FEATURE_MTAB_SUPPORT - help - Some people have a read only root filesystem, but they also wish to - have the 'mount' utility create an mtab file listing the filesystems - which have been mounted. This option allows you to specify an alternative - location for the mtab file, such as /var/mtab, or /tmp/mtab. The default - value is /etc/mtab, which is where this file is located on most desktop - Linux systems. + Note that even non-embedded developers probably want to have /etc/mtab + be a symlink to /proc/mounts, since otherwise mtab can get out of sync + with the real kernel mount state in numerous ways. config CONFIG_READPROFILE bool "readprofile" diff --git a/util-linux/Makefile.in b/util-linux/Makefile.in index 9aaaf9f8f..504560c27 100644 --- a/util-linux/Makefile.in +++ b/util-linux/Makefile.in @@ -34,6 +34,8 @@ UTILLINUX-$(CONFIG_FSCK_MINIX) +=fsck_minix.o UTILLINUX-$(CONFIG_GETOPT) +=getopt.o UTILLINUX-$(CONFIG_HEXDUMP) +=hexdump.o UTILLINUX-$(CONFIG_HWCLOCK) +=hwclock.o +UTILLINUX-$(CONFIG_IPCRM) +=ipcrm.o +UTILLINUX-$(CONFIG_IPCS) +=ipcs.o UTILLINUX-$(CONFIG_LOSETUP) +=losetup.o UTILLINUX-$(CONFIG_MKFS_MINIX) +=mkfs_minix.o UTILLINUX-$(CONFIG_MKSWAP) +=mkswap.o diff --git a/util-linux/ipcrm.c b/util-linux/ipcrm.c new file mode 100644 index 000000000..9e18752a3 --- /dev/null +++ b/util-linux/ipcrm.c @@ -0,0 +1,273 @@ +/* + * ipcrm.c -- utility to allow removal of IPC objects and data structures. + * + * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com> + * Adapted for busybox from util-linux-2.12a. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- Pre-busybox history from util-linux-2.12a ------------------------ + * + * 1999-04-02 frank zago + * - can now remove several id's in the same call + * + * 1999-02-22 Arkadiusz Mi˙kiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + * + * Original author - krishna balasubramanian 1993 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/msg.h> +#include <sys/sem.h> + +/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */ +/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */ +/* for getopt */ +#include <unistd.h> + +/* for tolower and isupper */ +#include <ctype.h> + +#include "busybox.h" + +#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +/* union semun is defined by including <sys/sem.h> */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; + struct semid_ds *buf; + unsigned short int *array; + struct seminfo *__buf; +}; +#endif + +typedef enum type_id { + SHM, + SEM, + MSG +} type_id; + +static int +remove_ids(type_id type, int argc, char **argv) { + int id; + int ret = 0; /* for gcc */ + char *end; + int nb_errors = 0; + union semun arg; + + arg.val = 0; + + while(argc) { + + id = strtoul(argv[0], &end, 10); + + if (*end != 0) { + bb_printf ("invalid id: %s\n", argv[0]); + nb_errors ++; + } else { + switch(type) { + case SEM: + ret = semctl (id, 0, IPC_RMID, arg); + break; + + case MSG: + ret = msgctl (id, IPC_RMID, NULL); + break; + + case SHM: + ret = shmctl (id, IPC_RMID, NULL); + break; + } + + if (ret) { + bb_printf ("cannot remove id %s (%s)\n", + argv[0], strerror(errno)); + nb_errors ++; + } + } + argc--; + argv++; + } + + return(nb_errors); +} + +static int deprecated_main(int argc, char **argv) +{ + if (argc < 3) { + bb_show_usage(); + bb_fflush_stdout_and_exit(1); + } + + if (!strcmp(argv[1], "shm")) { + if (remove_ids(SHM, argc-2, &argv[2])) + bb_fflush_stdout_and_exit(1); + } + else if (!strcmp(argv[1], "msg")) { + if (remove_ids(MSG, argc-2, &argv[2])) + bb_fflush_stdout_and_exit(1); + } + else if (!strcmp(argv[1], "sem")) { + if (remove_ids(SEM, argc-2, &argv[2])) + bb_fflush_stdout_and_exit(1); + } + else { + bb_printf ("unknown resource type: %s\n", argv[1]); + bb_show_usage(); + bb_fflush_stdout_and_exit(1); + } + + bb_printf ("resource(s) deleted\n"); + return 0; +} + + +int ipcrm_main(int argc, char **argv) +{ + int c; + int error = 0; + char *prog = argv[0]; + + /* if the command is executed without parameters, do nothing */ + if (argc == 1) + return 0; + + /* check to see if the command is being invoked in the old way if so + then run the old code */ + if (strcmp(argv[1], "shm") == 0 || + strcmp(argv[1], "msg") == 0 || + strcmp(argv[1], "sem") == 0) + return deprecated_main(argc, argv); + + /* process new syntax to conform with SYSV ipcrm */ + while ((c = getopt(argc, argv, "q:m:s:Q:M:S:h?")) != -1) { + int result; + int id = 0; + int iskey = isupper(c); + + /* needed to delete semaphores */ + union semun arg; + arg.val = 0; + + if ((c == '?') || (c == 'h')) + { + bb_show_usage(); + return 0; + } + + /* we don't need case information any more */ + c = tolower(c); + + /* make sure the option is in range */ + if (c != 'q' && c != 'm' && c != 's') { + bb_show_usage(); + error++; + return error; + } + + if (iskey) { + /* keys are in hex or decimal */ + key_t key = strtoul(optarg, NULL, 0); + if (key == IPC_PRIVATE) { + error++; + bb_fprintf(stderr, "%s: illegal key (%s)\n", + prog, optarg); + continue; + } + + /* convert key to id */ + id = ((c == 'q') ? msgget(key, 0) : + (c == 'm') ? shmget(key, 0, 0) : + semget(key, 0, 0)); + + if (id < 0) { + char *errmsg; + error++; + switch(errno) { + case EACCES: + errmsg = "permission denied for key"; + break; + case EIDRM: + errmsg = "already removed key"; + break; + case ENOENT: + errmsg = "invalid key"; + break; + default: + errmsg = "unknown error in key"; + break; + } + bb_fprintf(stderr, "%s: %s (%s)\n", + prog, errmsg, optarg); + continue; + } + } else { + /* ids are in decimal */ + id = strtoul(optarg, NULL, 10); + } + + result = ((c == 'q') ? msgctl(id, IPC_RMID, NULL) : + (c == 'm') ? shmctl(id, IPC_RMID, NULL) : + semctl(id, 0, IPC_RMID, arg)); + + if (result < 0) { + char *errmsg; + error++; + switch(errno) { + case EACCES: + case EPERM: + errmsg = iskey + ? "permission denied for key" + : "permission denied for id"; + break; + case EINVAL: + errmsg = iskey + ? "invalid key" + : "invalid id"; + break; + case EIDRM: + errmsg = iskey + ? "already removed key" + : "already removed id"; + break; + default: + errmsg = iskey + ? "unknown error in key" + : "unknown error in id"; + break; + } + bb_fprintf(stderr, "%s: %s (%s)\n", + prog, errmsg, optarg); + continue; + } + } + + /* print usage if we still have some arguments left over */ + if (optind != argc) { + bb_show_usage(); + } + + /* exit value reflects the number of errors encountered */ + return error; +} diff --git a/util-linux/ipcs.c b/util-linux/ipcs.c new file mode 100644 index 000000000..23759eeda --- /dev/null +++ b/util-linux/ipcs.c @@ -0,0 +1,686 @@ +/* + * ipcs.c -- provides information on allocated ipc resources. + * + * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com> + * Adapted for busybox from util-linux-2.12a. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- Pre-busybox history from util-linux-2.12a ------------------------ + * + * 1999-02-22 Arkadiusz Mi˙kiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + * + * Patched to display the key field -- hy@picksys.com 12/18/96 + * + * Patch from arnolds@ifns.de (Heinz-Ado Arnolds) applied Mon Jul 1 + * 19:30:41 1996 by janl@math.uio.no to add code missing in case PID: + * clauses. + * + * Patches from Mike Jagdis (jaggy@purplet.demon.co.uk) applied + * Wed Feb 8 12:12:21 1995 by faith@cs.unc.edu to print numeric uids + * if no passwd file entry. + * + * Modified Sat Oct 9 10:55:28 1993 for 0.99.13 + * Original author unknown, may be "krishna balasub@cis.ohio-state.edu" + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <errno.h> +#include <time.h> +#include <pwd.h> +#include <grp.h> + +/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */ +/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */ +/* X/OPEN tells us to use <sys/{types,ipc,shm}.h> for shmctl() */ +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <sys/msg.h> +#include <sys/shm.h> + +#include "busybox.h" + +/*-------------------------------------------------------------------*/ +/* SHM_DEST and SHM_LOCKED are defined in kernel headers, + but inside #ifdef __KERNEL__ ... #endif */ +#ifndef SHM_DEST +/* shm_mode upper byte flags */ +#define SHM_DEST 01000 /* segment will be destroyed on last detach */ +#define SHM_LOCKED 02000 /* segment will not be swapped */ +#endif + +/* For older kernels the same holds for the defines below */ +#ifndef MSG_STAT +#define MSG_STAT 11 +#define MSG_INFO 12 +#endif + +#ifndef SHM_STAT +#define SHM_STAT 13 +#define SHM_INFO 14 +struct shm_info { + int used_ids; + ulong shm_tot; /* total allocated shm */ + ulong shm_rss; /* total resident shm */ + ulong shm_swp; /* total swapped shm */ + ulong swap_attempts; + ulong swap_successes; +}; +#endif + +#ifndef SEM_STAT +#define SEM_STAT 18 +#define SEM_INFO 19 +#endif + +/* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */ +#ifndef IPC_INFO +#define IPC_INFO 3 +#endif +/*-------------------------------------------------------------------*/ + +/* The last arg of semctl is a union semun, but where is it defined? + X/OPEN tells us to define it ourselves, but until recently + Linux include files would also define it. */ +#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +/* union semun is defined by including <sys/sem.h> */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; + struct semid_ds *buf; + unsigned short int *array; + struct seminfo *__buf; +}; +#endif + +/* X/OPEN (Jan 1987) does not define fields key, seq in struct ipc_perm; + libc 4/5 does not mention struct ipc_term at all, but includes + <linux/ipc.h>, which defines a struct ipc_perm with such fields. + glibc-1.09 has no support for sysv ipc. + glibc 2 uses __key, __seq */ +#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 +#define KEY __key +#else +#define KEY key +#endif + +#define LIMITS 1 +#define STATUS 2 +#define CREATOR 3 +#define TIME 4 +#define PID 5 + +void do_shm (char format); +void do_sem (char format); +void do_msg (char format); +void print_shm (int id); +void print_msg (int id); +void print_sem (int id); + +int ipcs_main (int argc, char **argv) { + int opt, msg = 0, sem = 0, shm = 0, id=0, print=0; + char format = 0; + char options[] = "atclupsmqi:ih?"; + + while ((opt = getopt (argc, argv, options)) != -1) { + switch (opt) { + case 'i': + id = atoi (optarg); + print = 1; + break; + case 'a': + msg = shm = sem = 1; + break; + case 'q': + msg = 1; + break; + case 's': + sem = 1; + break; + case 'm': + shm = 1; + break; + case 't': + format = TIME; + break; + case 'c': + format = CREATOR; + break; + case 'p': + format = PID; + break; + case 'l': + format = LIMITS; + break; + case 'u': + format = STATUS; + break; + case 'h': + case '?': + bb_show_usage(); + bb_fflush_stdout_and_exit (0); + } + } + + if (print) { + if (shm) { + print_shm (id); + bb_fflush_stdout_and_exit (0); + } + if (sem) { + print_sem (id); + bb_fflush_stdout_and_exit (0); + } + if (msg) { + print_msg (id); + bb_fflush_stdout_and_exit (0); + } + bb_show_usage(); + bb_fflush_stdout_and_exit (0); + } + + if ( !shm && !msg && !sem) + msg = sem = shm = 1; + bb_printf ("\n"); + + if (shm) { + do_shm (format); + bb_printf ("\n"); + } + if (sem) { + do_sem (format); + bb_printf ("\n"); + } + if (msg) { + do_msg (format); + bb_printf ("\n"); + } + return 0; +} + + +static void +print_perms (int id, struct ipc_perm *ipcp) { + struct passwd *pw; + struct group *gr; + + bb_printf ("%-10d %-10o", id, ipcp->mode & 0777); + + if ((pw = getpwuid(ipcp->cuid))) + bb_printf(" %-10s", pw->pw_name); + else + bb_printf(" %-10d", ipcp->cuid); + if ((gr = getgrgid(ipcp->cgid))) + bb_printf(" %-10s", gr->gr_name); + else + bb_printf(" %-10d", ipcp->cgid); + + if ((pw = getpwuid(ipcp->uid))) + bb_printf(" %-10s", pw->pw_name); + else + bb_printf(" %-10d", ipcp->uid); + if ((gr = getgrgid(ipcp->gid))) + bb_printf(" %-10s\n", gr->gr_name); + else + bb_printf(" %-10d\n", ipcp->gid); +} + + +void do_shm (char format) +{ + int maxid, shmid, id; + struct shmid_ds shmseg; + struct shm_info shm_info; + struct shminfo shminfo; + struct ipc_perm *ipcp = &shmseg.shm_perm; + struct passwd *pw; + + maxid = shmctl (0, SHM_INFO, (struct shmid_ds *) (void *) &shm_info); + if (maxid < 0) { + bb_printf ("kernel not configured for shared memory\n"); + return; + } + + switch (format) { + case LIMITS: + bb_printf ("------ Shared Memory Limits --------\n"); + if ((shmctl (0, IPC_INFO, (struct shmid_ds *) (void *) &shminfo)) < 0 ) + return; + /* glibc 2.1.3 and all earlier libc's have ints as fields + of struct shminfo; glibc 2.1.91 has unsigned long; ach */ + bb_printf ("max number of segments = %lu\n", + (unsigned long) shminfo.shmmni); + bb_printf ("max seg size (kbytes) = %lu\n", + (unsigned long) (shminfo.shmmax >> 10)); + bb_printf ("max total shared memory (pages) = %lu\n", + (unsigned long) shminfo.shmall); + bb_printf ("min seg size (bytes) = %lu\n", + (unsigned long) shminfo.shmmin); + return; + + case STATUS: + bb_printf ("------ Shared Memory Status --------\n"); + bb_printf ("segments allocated %d\n", shm_info.used_ids); + bb_printf ("pages allocated %ld\n", shm_info.shm_tot); + bb_printf ("pages resident %ld\n", shm_info.shm_rss); + bb_printf ("pages swapped %ld\n", shm_info.shm_swp); + bb_printf ("Swap performance: %ld attempts\t %ld successes\n", + shm_info.swap_attempts, shm_info.swap_successes); + return; + + case CREATOR: + bb_printf ("------ Shared Memory Segment Creators/Owners --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s %-10s %-10s\n", + "shmid","perms","cuid","cgid","uid","gid"); + break; + + case TIME: + bb_printf ("------ Shared Memory Attach/Detach/Change Times --------\n"); + bb_printf ("%-10s %-10s %-20s %-20s %-20s\n", + "shmid","owner","attached","detached","changed"); + break; + + case PID: + bb_printf ("------ Shared Memory Creator/Last-op --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s\n", + "shmid","owner","cpid","lpid"); + break; + + default: + bb_printf ("------ Shared Memory Segments --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s %-10s %-10s %-12s\n", + "key","shmid","owner","perms","bytes","nattch","status"); + break; + } + + for (id = 0; id <= maxid; id++) { + shmid = shmctl (id, SHM_STAT, &shmseg); + if (shmid < 0) + continue; + if (format == CREATOR) { + print_perms (shmid, ipcp); + continue; + } + pw = getpwuid(ipcp->uid); + switch (format) { + case TIME: + if (pw) + bb_printf ("%-10d %-10.10s", shmid, pw->pw_name); + else + bb_printf ("%-10d %-10d", shmid, ipcp->uid); + /* ctime uses static buffer: use separate calls */ + bb_printf(" %-20.16s", shmseg.shm_atime + ? ctime(&shmseg.shm_atime) + 4 : "Not set"); + bb_printf(" %-20.16s", shmseg.shm_dtime + ? ctime(&shmseg.shm_dtime) + 4 : "Not set"); + bb_printf(" %-20.16s\n", shmseg.shm_ctime + ? ctime(&shmseg.shm_ctime) + 4 : "Not set"); + break; + case PID: + if (pw) + bb_printf ("%-10d %-10.10s", shmid, pw->pw_name); + else + bb_printf ("%-10d %-10d", shmid, ipcp->uid); + bb_printf (" %-10d %-10d\n", + shmseg.shm_cpid, shmseg.shm_lpid); + break; + + default: + bb_printf("0x%08x ",ipcp->KEY ); + if (pw) + bb_printf ("%-10d %-10.10s", shmid, pw->pw_name); + else + bb_printf ("%-10d %-10d", shmid, ipcp->uid); + bb_printf ("%-10o %-10lu %-10ld %-6s %-6s\n", + ipcp->mode & 0777, + /* + * earlier: int, Austin has size_t + */ + (unsigned long) shmseg.shm_segsz, + /* + * glibc-2.1.3 and earlier has unsigned short; + * Austin has shmatt_t + */ + (long) shmseg.shm_nattch, + ipcp->mode & SHM_DEST ? "dest" : " ", + ipcp->mode & SHM_LOCKED ? "locked" : " "); + break; + } + } + return; +} + + +void do_sem (char format) +{ + int maxid, semid, id; + struct semid_ds semary; + struct seminfo seminfo; + struct ipc_perm *ipcp = &semary.sem_perm; + struct passwd *pw; + union semun arg; + + arg.array = (ushort *) (void *) &seminfo; + maxid = semctl (0, 0, SEM_INFO, arg); + if (maxid < 0) { + bb_printf ("kernel not configured for semaphores\n"); + return; + } + + switch (format) { + case LIMITS: + bb_printf ("------ Semaphore Limits --------\n"); + arg.array = (ushort *) (void *) &seminfo; /* damn union */ + if ((semctl (0, 0, IPC_INFO, arg)) < 0 ) + return; + bb_printf ("max number of arrays = %d\n", seminfo.semmni); + bb_printf ("max semaphores per array = %d\n", seminfo.semmsl); + bb_printf ("max semaphores system wide = %d\n", seminfo.semmns); + bb_printf ("max ops per semop call = %d\n", seminfo.semopm); + bb_printf ("semaphore max value = %d\n", seminfo.semvmx); + return; + + case STATUS: + bb_printf ("------ Semaphore Status --------\n"); + bb_printf ("used arrays = %d\n", seminfo.semusz); + bb_printf ("allocated semaphores = %d\n", seminfo.semaem); + return; + + case CREATOR: + bb_printf ("------ Semaphore Arrays Creators/Owners --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s %-10s %-10s\n", + "semid","perms","cuid","cgid","uid","gid"); + break; + + case TIME: + bb_printf ("------ Shared Memory Operation/Change Times --------\n"); + bb_printf ("%-8s %-10s %-26.24s %-26.24s\n", + "shmid","owner","last-op","last-changed"); + break; + + case PID: + break; + + default: + bb_printf ("------ Semaphore Arrays --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s %-10s\n", + "key","semid","owner","perms","nsems"); + break; + } + + for (id = 0; id <= maxid; id++) { + arg.buf = (struct semid_ds *) &semary; + semid = semctl (id, 0, SEM_STAT, arg); + if (semid < 0) + continue; + if (format == CREATOR) { + print_perms (semid, ipcp); + continue; + } + pw = getpwuid(ipcp->uid); + switch (format) { + case TIME: + if (pw) + bb_printf ("%-8d %-10.10s", semid, pw->pw_name); + else + bb_printf ("%-8d %-10d", semid, ipcp->uid); + bb_printf (" %-26.24s", semary.sem_otime + ? ctime(&semary.sem_otime) : "Not set"); + bb_printf (" %-26.24s\n", semary.sem_ctime + ? ctime(&semary.sem_ctime) : "Not set"); + break; + case PID: + break; + + default: + bb_printf("0x%08x ", ipcp->KEY); + if (pw) + bb_printf ("%-10d %-10.9s", semid, pw->pw_name); + else + bb_printf ("%-10d %-9d", semid, ipcp->uid); + bb_printf ("%-10o %-10ld\n", + ipcp->mode & 0777, + /* + * glibc-2.1.3 and earlier has unsigned short; + * glibc-2.1.91 has variation between + * unsigned short and unsigned long + * Austin prescribes unsigned short. + */ + (long) semary.sem_nsems); + break; + } + } +} + + +void do_msg (char format) +{ + int maxid, msqid, id; + struct msqid_ds msgque; + struct msginfo msginfo; + struct ipc_perm *ipcp = &msgque.msg_perm; + struct passwd *pw; + + maxid = msgctl (0, MSG_INFO, (struct msqid_ds *) (void *) &msginfo); + if (maxid < 0) { + bb_printf ("kernel not configured for message queues\n"); + return; + } + + switch (format) { + case LIMITS: + if ((msgctl (0, IPC_INFO, (struct msqid_ds *) (void *) &msginfo)) < 0 ) + return; + bb_printf ("------ Messages: Limits --------\n"); + bb_printf ("max queues system wide = %d\n", msginfo.msgmni); + bb_printf ("max size of message (bytes) = %d\n", msginfo.msgmax); + bb_printf ("default max size of queue (bytes) = %d\n", msginfo.msgmnb); + return; + + case STATUS: + bb_printf ("------ Messages: Status --------\n"); + bb_printf ("allocated queues = %d\n", msginfo.msgpool); + bb_printf ("used headers = %d\n", msginfo.msgmap); + bb_printf ("used space = %d bytes\n", msginfo.msgtql); + return; + + case CREATOR: + bb_printf ("------ Message Queues: Creators/Owners --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s %-10s %-10s\n", + "msqid","perms","cuid","cgid","uid","gid"); + break; + + case TIME: + bb_printf ("------ Message Queues Send/Recv/Change Times --------\n"); + bb_printf ("%-8s %-10s %-20s %-20s %-20s\n", + "msqid","owner","send","recv","change"); + break; + + case PID: + bb_printf ("------ Message Queues PIDs --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s\n", + "msqid","owner","lspid","lrpid"); + break; + + default: + bb_printf ("------ Message Queues --------\n"); + bb_printf ("%-10s %-10s %-10s %-10s %-12s %-12s\n", + "key", "msqid", "owner", "perms","used-bytes", "messages"); + break; + } + + for (id = 0; id <= maxid; id++) { + msqid = msgctl (id, MSG_STAT, &msgque); + if (msqid < 0) + continue; + if (format == CREATOR) { + print_perms (msqid, ipcp); + continue; + } + pw = getpwuid(ipcp->uid); + switch (format) { + case TIME: + if (pw) + bb_printf ("%-8d %-10.10s", msqid, pw->pw_name); + else + bb_printf ("%-8d %-10d", msqid, ipcp->uid); + bb_printf (" %-20.16s", msgque.msg_stime + ? ctime(&msgque.msg_stime) + 4 : "Not set"); + bb_printf (" %-20.16s", msgque.msg_rtime + ? ctime(&msgque.msg_rtime) + 4 : "Not set"); + bb_printf (" %-20.16s\n", msgque.msg_ctime + ? ctime(&msgque.msg_ctime) + 4 : "Not set"); + break; + case PID: + if (pw) + bb_printf ("%-8d %-10.10s", msqid, pw->pw_name); + else + bb_printf ("%-8d %-10d", msqid, ipcp->uid); + bb_printf (" %5d %5d\n", + msgque.msg_lspid, msgque.msg_lrpid); + break; + + default: + bb_printf( "0x%08x ",ipcp->KEY ); + if (pw) + bb_printf ("%-10d %-10.10s", msqid, pw->pw_name); + else + bb_printf ("%-10d %-10d", msqid, ipcp->uid); + bb_printf (" %-10o %-12ld %-12ld\n", + ipcp->mode & 0777, + /* + * glibc-2.1.3 and earlier has unsigned short; + * glibc-2.1.91 has variation between + * unsigned short, unsigned long + * Austin has msgqnum_t + */ + (long) msgque.msg_cbytes, + (long) msgque.msg_qnum); + break; + } + } + return; +} + + +void print_shm (int shmid) +{ + struct shmid_ds shmds; + struct ipc_perm *ipcp = &shmds.shm_perm; + + if (shmctl (shmid, IPC_STAT, &shmds) == -1) { + perror ("shmctl "); + return; + } + + bb_printf ("\nShared memory Segment shmid=%d\n", shmid); + bb_printf ("uid=%d\tgid=%d\tcuid=%d\tcgid=%d\n", + ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid); + bb_printf ("mode=%#o\taccess_perms=%#o\n", + ipcp->mode, ipcp->mode & 0777); + bb_printf ("bytes=%ld\tlpid=%d\tcpid=%d\tnattch=%ld\n", + (long) shmds.shm_segsz, shmds.shm_lpid, shmds.shm_cpid, + (long) shmds.shm_nattch); + bb_printf ("att_time=%-26.24s\n", + shmds.shm_atime ? ctime (&shmds.shm_atime) : "Not set"); + bb_printf ("det_time=%-26.24s\n", + shmds.shm_dtime ? ctime (&shmds.shm_dtime) : "Not set"); + bb_printf ("change_time=%-26.24s\n", ctime (&shmds.shm_ctime)); + bb_printf ("\n"); + return; +} + + +void print_msg (int msqid) +{ + struct msqid_ds buf; + struct ipc_perm *ipcp = &buf.msg_perm; + + if (msgctl (msqid, IPC_STAT, &buf) == -1) { + perror ("msgctl "); + return; + } + + bb_printf ("\nMessage Queue msqid=%d\n", msqid); + bb_printf ("uid=%d\tgid=%d\tcuid=%d\tcgid=%d\tmode=%#o\n", + ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid, ipcp->mode); + bb_printf ("cbytes=%ld\tqbytes=%ld\tqnum=%ld\tlspid=%d\tlrpid=%d\n", + /* + * glibc-2.1.3 and earlier has unsigned short; + * glibc-2.1.91 has variation between + * unsigned short, unsigned long + * Austin has msgqnum_t (for msg_qbytes) + */ + (long) buf.msg_cbytes, (long) buf.msg_qbytes, + (long) buf.msg_qnum, buf.msg_lspid, buf.msg_lrpid); + bb_printf ("send_time=%-26.24s\n", + buf.msg_stime ? ctime (&buf.msg_stime) : "Not set"); + bb_printf ("rcv_time=%-26.24s\n", + buf.msg_rtime ? ctime (&buf.msg_rtime) : "Not set"); + bb_printf ("change_time=%-26.24s\n", + buf.msg_ctime ? ctime (&buf.msg_ctime) : "Not set"); + bb_printf ("\n"); + return; +} + +void print_sem (int semid) +{ + struct semid_ds semds; + struct ipc_perm *ipcp = &semds.sem_perm; + union semun arg; + int i; + + arg.buf = &semds; + if (semctl (semid, 0, IPC_STAT, arg) < 0) { + perror ("semctl "); + return; + } + + bb_printf ("\nSemaphore Array semid=%d\n", semid); + bb_printf ("uid=%d\t gid=%d\t cuid=%d\t cgid=%d\n", + ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid); + bb_printf ("mode=%#o, access_perms=%#o\n", + ipcp->mode, ipcp->mode & 0777); + bb_printf ("nsems = %ld\n", (long) semds.sem_nsems); + bb_printf ("otime = %-26.24s\n", + semds.sem_otime ? ctime (&semds.sem_otime) : "Not set"); + bb_printf ("ctime = %-26.24s\n", ctime (&semds.sem_ctime)); + + bb_printf ("%-10s %-10s %-10s %-10s %-10s\n", + "semnum","value","ncount","zcount","pid"); + + arg.val = 0; + for (i=0; i< semds.sem_nsems; i++) { + int val, ncnt, zcnt, pid; + val = semctl (semid, i, GETVAL, arg); + ncnt = semctl (semid, i, GETNCNT, arg); + zcnt = semctl (semid, i, GETZCNT, arg); + pid = semctl (semid, i, GETPID, arg); + if (val < 0 || ncnt < 0 || zcnt < 0 || pid < 0) { + perror ("semctl "); + bb_fflush_stdout_and_exit (1); + } + bb_printf ("%-10d %-10d %-10d %-10d %-10d\n", + i, val, ncnt, zcnt, pid); + } + bb_printf ("\n"); + return; +} |