busybox/util-linux/ipcrm.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * ipcrm.c - utility to allow removal of IPC objects and data structures.
   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 IPCRM
  11//config:       bool "ipcrm (3.2 kb)"
  12//config:       default y
  13//config:       help
  14//config:       The ipcrm utility allows the removal of System V interprocess
  15//config:       communication (IPC) objects and the associated data structures
  16//config:       from the system.
  17
  18//applet:IF_IPCRM(APPLET_NOEXEC(ipcrm, ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP, ipcrm))
  19
  20//kbuild:lib-$(CONFIG_IPCRM) += ipcrm.o
  21
  22#include "libbb.h"
  23
  24/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
  25/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
  26#include <sys/ipc.h>
  27#include <sys/shm.h>
  28#include <sys/msg.h>
  29#include <sys/sem.h>
  30
  31#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
  32/* union semun is defined by including <sys/sem.h> */
  33#else
  34/* according to X/OPEN we have to define it ourselves */
  35union semun {
  36        int val;
  37        struct semid_ds *buf;
  38        unsigned short *array;
  39        struct seminfo *__buf;
  40};
  41#endif
  42
  43#define IPCRM_LEGACY 1
  44
  45
  46#if IPCRM_LEGACY
  47
  48typedef enum type_id {
  49        SHM,
  50        SEM,
  51        MSG
  52} type_id;
  53
  54static int remove_ids(type_id type, char **argv)
  55{
  56        unsigned long id;
  57        int nb_errors = 0;
  58        union semun arg;
  59
  60        arg.val = 0;
  61
  62        while (argv[0]) {
  63                id = bb_strtoul(argv[0], NULL, 10);
  64                if (errno || id > INT_MAX) {
  65                        bb_error_msg("invalid id: %s", argv[0]);
  66                        nb_errors++;
  67                } else {
  68                        int ret = 0;
  69                        if (type == SEM)
  70                                ret = semctl(id, 0, IPC_RMID, arg);
  71                        else if (type == MSG)
  72                                ret = msgctl(id, IPC_RMID, NULL);
  73                        else if (type ==  SHM)
  74                                ret = shmctl(id, IPC_RMID, NULL);
  75
  76                        if (ret) {
  77                                bb_perror_msg("can't remove id %s", argv[0]);
  78                                nb_errors++;
  79                        }
  80                }
  81                argv++;
  82        }
  83
  84        return nb_errors;
  85}
  86#endif /* IPCRM_LEGACY */
  87
  88//usage:#define ipcrm_trivial_usage
  89//usage:       "[-MQS key] [-mqs id]"
  90//usage:#define ipcrm_full_usage "\n\n"
  91//usage:       "Upper-case options MQS remove an object by shmkey value.\n"
  92//usage:       "Lower-case options remove an object by shmid value.\n"
  93//usage:     "\n        -mM     Remove memory segment after last detach"
  94//usage:     "\n        -qQ     Remove message queue"
  95//usage:     "\n        -sS     Remove semaphore"
  96
  97int ipcrm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  98int ipcrm_main(int argc, char **argv)
  99{
 100        int c;
 101        int error = 0;
 102
 103        /* if the command is executed without parameters, do nothing */
 104        if (argc == 1)
 105                return 0;
 106#if IPCRM_LEGACY
 107        /* check to see if the command is being invoked in the old way if so
 108           then run the old code. Valid commands are msg, shm, sem. */
 109        {
 110                type_id what = 0; /* silence gcc */
 111                char w;
 112
 113                w = argv[1][0];
 114                if ( ((w == 'm' && argv[1][1] == 's' && argv[1][2] == 'g')
 115                       || (argv[1][0] == 's'
 116                           && ((w = argv[1][1]) == 'h' || w == 'e')
 117                           && argv[1][2] == 'm')
 118                     ) && argv[1][3] == '\0'
 119                ) {
 120                        if (argc < 3)
 121                                bb_show_usage();
 122
 123                        if (w == 'h')
 124                                what = SHM;
 125                        else if (w == 'm')
 126                                what = MSG;
 127                        else if (w == 'e')
 128                                what = SEM;
 129
 130                        if (remove_ids(what, &argv[2]))
 131                                fflush_stdout_and_exit(EXIT_FAILURE);
 132                        puts("resource(s) deleted");
 133                        return 0;
 134                }
 135        }
 136#endif /* IPCRM_LEGACY */
 137
 138        /* process new syntax to conform with SYSV ipcrm */
 139        while ((c = getopt(argc, argv, "q:m:s:Q:M:S:")) != -1) {
 140                int result;
 141                int id;
 142                int iskey;
 143                /* needed to delete semaphores */
 144                union semun arg;
 145
 146                if (c == '?') /* option not in the string */
 147                        bb_show_usage();
 148
 149                id = 0;
 150                arg.val = 0;
 151
 152                iskey = !(c & 0x20); /* uppercase? */
 153                if (iskey) {
 154                        /* keys are in hex or decimal */
 155                        key_t key = xstrtoul(optarg, 0);
 156
 157                        if (key == IPC_PRIVATE) {
 158                                error++;
 159                                bb_error_msg("illegal key (%s)", optarg);
 160                                continue;
 161                        }
 162
 163                        c |= 0x20; /* lowercase. c is 'q', 'm' or 's' now */
 164                        /* convert key to id */
 165                        id = ((c == 'q') ? msgget(key, 0) :
 166                                (c == 'm') ? shmget(key, 0, 0) : semget(key, 0, 0));
 167
 168                        if (id < 0) {
 169                                const char *errmsg;
 170
 171                                error++;
 172                                switch (errno) {
 173                                case EACCES:
 174                                        errmsg = "permission denied for";
 175                                        break;
 176                                case EIDRM:
 177                                        errmsg = "already removed";
 178                                        break;
 179                                case ENOENT:
 180                                        errmsg = "invalid";
 181                                        break;
 182                                default:
 183                                        errmsg = "unknown error in";
 184                                        break;
 185                                }
 186                                bb_error_msg("%s %s (%s)", errmsg, "key", optarg);
 187                                continue;
 188                        }
 189                } else {
 190                        /* ids are in decimal */
 191                        id = xatoul(optarg);
 192                }
 193
 194                result = ((c == 'q') ? msgctl(id, IPC_RMID, NULL) :
 195                                (c == 'm') ? shmctl(id, IPC_RMID, NULL) :
 196                                semctl(id, 0, IPC_RMID, arg));
 197
 198                if (result) {
 199                        const char *errmsg;
 200                        const char *const what = iskey ? "key" : "id";
 201
 202                        error++;
 203                        switch (errno) {
 204                        case EACCES:
 205                        case EPERM:
 206                                errmsg = "permission denied for";
 207                                break;
 208                        case EINVAL:
 209                                errmsg = "invalid";
 210                                break;
 211                        case EIDRM:
 212                                errmsg = "already removed";
 213                                break;
 214                        default:
 215                                errmsg = "unknown error in";
 216                                break;
 217                        }
 218                        bb_error_msg("%s %s (%s)", errmsg, what, optarg);
 219                        continue;
 220                }
 221        }
 222
 223        /* print usage if we still have some arguments left over */
 224        if (optind != argc) {
 225                bb_show_usage();
 226        }
 227
 228        /* exit value reflects the number of errors encountered */
 229        return error;
 230}
 231