diff options
Diffstat (limited to '')
-rw-r--r-- | sys-utils/ipcrm.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/sys-utils/ipcrm.c b/sys-utils/ipcrm.c new file mode 100644 index 0000000..a9f2d1b --- /dev/null +++ b/sys-utils/ipcrm.c @@ -0,0 +1,423 @@ +/* + * krishna balasubramanian 1993 + * + * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + * + * 1999-04-02 frank zago + * - can now remove several id's in the same call + * + */ + +#include <errno.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ipc.h> +#include <sys/msg.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <sys/types.h> +#include "c.h" +#include "nls.h" +#include "strutils.h" +#include "closestream.h" + +#ifndef HAVE_UNION_SEMUN +/* 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, + ALL +} type_id; + +static int verbose = 0; + +/* print the usage */ +static void __attribute__((__noreturn__)) usage(void) +{ + FILE *out = stdout; + fputs(USAGE_HEADER, out); + fprintf(out, _(" %1$s [options]\n" + " %1$s shm|msg|sem <id>...\n"), program_invocation_short_name); + + fputs(USAGE_SEPARATOR, out); + fputs(_("Remove certain IPC resources.\n"), out); + + fputs(USAGE_OPTIONS, out); + fputs(_(" -m, --shmem-id <id> remove shared memory segment by id\n"), out); + fputs(_(" -M, --shmem-key <key> remove shared memory segment by key\n"), out); + fputs(_(" -q, --queue-id <id> remove message queue by id\n"), out); + fputs(_(" -Q, --queue-key <key> remove message queue by key\n"), out); + fputs(_(" -s, --semaphore-id <id> remove semaphore by id\n"), out); + fputs(_(" -S, --semaphore-key <key> remove semaphore by key\n"), out); + fputs(_(" -a, --all[=shm|msg|sem] remove all (in the specified category)\n"), out); + fputs(_(" -v, --verbose explain what is being done\n"), out); + + fputs(USAGE_SEPARATOR, out); + printf(USAGE_HELP_OPTIONS(28)); + printf(USAGE_MAN_TAIL("ipcrm(1)")); + + exit(EXIT_SUCCESS); +} + +static int remove_id(int type, int iskey, int id) +{ + int ret; + char *errmsg; + /* needed to delete semaphores */ + union semun arg; + arg.val = 0; + + /* do the removal */ + switch (type) { + case SHM: + if (verbose) + printf(_("removing shared memory segment id `%d'\n"), id); + ret = shmctl(id, IPC_RMID, NULL); + break; + case MSG: + if (verbose) + printf(_("removing message queue id `%d'\n"), id); + ret = msgctl(id, IPC_RMID, NULL); + break; + case SEM: + if (verbose) + printf(_("removing semaphore id `%d'\n"), id); + ret = semctl(id, 0, IPC_RMID, arg); + break; + default: + errx(EXIT_FAILURE, "impossible occurred"); + } + + /* how did the removal go? */ + if (ret < 0) { + 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: + err(EXIT_FAILURE, "%s", iskey ? _("key failed") : _("id failed")); + } + warnx("%s (%d)", errmsg, id); + return 1; + } + return 0; +} + +static int remove_arg_list(type_id type, int argc, char **argv) +{ + int id; + char *end; + int nb_errors = 0; + + do { + id = strtoul(argv[0], &end, 10); + if (*end != 0) { + warnx(_("invalid id: %s"), argv[0]); + nb_errors++; + } else { + if (remove_id(type, 0, id)) + nb_errors++; + } + argc--; + argv++; + } while (argc); + return (nb_errors); +} + +static int deprecated_main(int argc, char **argv) +{ + type_id type; + + if (!strcmp(argv[1], "shm")) + type = SHM; + else if (!strcmp(argv[1], "msg")) + type = MSG; + else if (!strcmp(argv[1], "sem")) + type = SEM; + else + return 0; + + if (argc < 3) { + warnx(_("not enough arguments")); + errtryhelp(EXIT_FAILURE); + } + + if (remove_arg_list(type, argc - 2, &argv[2])) + exit(EXIT_FAILURE); + + printf(_("resource(s) deleted\n")); + return 1; +} + +static unsigned long strtokey(const char *str, const char *errmesg) +{ + unsigned long num; + char *end = NULL; + + if (str == NULL || *str == '\0') + goto err; + errno = 0; + /* keys are in hex or decimal */ + num = strtoul(str, &end, 0); + + if (errno || str == end || (end && *end)) + goto err; + + return num; + err: + if (errno) + err(EXIT_FAILURE, "%s: '%s'", errmesg, str); + else + errx(EXIT_FAILURE, "%s: '%s'", errmesg, str); + return 0; +} + +static int key_to_id(type_id type, char *s) +{ + int id; + /* keys are in hex or decimal */ + key_t key = strtokey(s, "failed to parse argument"); + if (key == IPC_PRIVATE) { + warnx(_("illegal key (%s)"), s); + return -1; + } + switch (type) { + case SHM: + id = shmget(key, 0, 0); + break; + case MSG: + id = msgget(key, 0); + break; + case SEM: + id = semget(key, 0, 0); + break; + case ALL: + abort(); + default: + errx(EXIT_FAILURE, "impossible occurred"); + } + if (id < 0) { + char *errmsg; + switch (errno) { + case EACCES: + errmsg = _("permission denied for key"); + break; + case EIDRM: + errmsg = _("already removed key"); + break; + case ENOENT: + errmsg = _("invalid key"); + break; + default: + err(EXIT_FAILURE, _("key failed")); + } + warnx("%s (%s)", errmsg, s); + } + return id; +} + +static int remove_all(type_id type) +{ + int ret = 0; + int id, rm_me, maxid; + + struct shmid_ds shmseg; + + struct semid_ds semary; + struct seminfo seminfo; + union semun arg; + + struct msqid_ds msgque; + struct msginfo msginfo; + + if (type == SHM || type == ALL) { + maxid = shmctl(0, SHM_INFO, &shmseg); + if (maxid < 0) + errx(EXIT_FAILURE, + _("kernel not configured for shared memory")); + for (id = 0; id <= maxid; id++) { + rm_me = shmctl(id, SHM_STAT, &shmseg); + if (rm_me < 0) + continue; + ret |= remove_id(SHM, 0, rm_me); + } + } + if (type == SEM || type == ALL) { + arg.array = (ushort *) (void *)&seminfo; + maxid = semctl(0, 0, SEM_INFO, arg); + if (maxid < 0) + errx(EXIT_FAILURE, + _("kernel not configured for semaphores")); + for (id = 0; id <= maxid; id++) { + arg.buf = (struct semid_ds *)&semary; + rm_me = semctl(id, 0, SEM_STAT, arg); + if (rm_me < 0) + continue; + ret |= remove_id(SEM, 0, rm_me); + } + } +/* kFreeBSD hackery -- ah 20140723 */ +#ifndef MSG_STAT +#define MSG_STAT 11 +#endif +#ifndef MSG_INFO +#define MSG_INFO 12 +#endif + if (type == MSG || type == ALL) { + maxid = + msgctl(0, MSG_INFO, (struct msqid_ds *)(void *)&msginfo); + if (maxid < 0) + errx(EXIT_FAILURE, + _("kernel not configured for message queues")); + for (id = 0; id <= maxid; id++) { + rm_me = msgctl(id, MSG_STAT, &msgque); + if (rm_me < 0) + continue; + ret |= remove_id(MSG, 0, rm_me); + } + } + return ret; +} + +int main(int argc, char **argv) +{ + int c; + int ret = 0; + int id = -1; + int iskey; + int rm_all = 0; + type_id what_all = ALL; + + static const struct option longopts[] = { + {"shmem-id", required_argument, NULL, 'm'}, + {"shmem-key", required_argument, NULL, 'M'}, + {"queue-id", required_argument, NULL, 'q'}, + {"queue-key", required_argument, NULL, 'Q'}, + {"semaphore-id", required_argument, NULL, 's'}, + {"semaphore-key", required_argument, NULL, 'S'}, + {"all", optional_argument, NULL, 'a'}, + {"verbose", no_argument, NULL, 'v'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + /* if the command is executed without parameters, do nothing */ + if (argc == 1) + return 0; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); + + /* check to see if the command is being invoked in the old way if so + * then remove argument list */ + if (deprecated_main(argc, argv)) + return EXIT_SUCCESS; + + /* process new syntax to conform with SYSV ipcrm */ + while((c = getopt_long(argc, argv, "q:m:s:Q:M:S:a::vhV", longopts, NULL)) != -1) { + iskey = 0; + switch (c) { + case 'M': + iskey = 1; + id = key_to_id(SHM, optarg); + if (id < 0) { + ret++; + break; + } + /* fallthrough */ + case 'm': + if (!iskey) + id = strtos32_or_err(optarg, _("failed to parse argument")); + if (remove_id(SHM, iskey, id)) + ret++; + break; + case 'Q': + iskey = 1; + id = key_to_id(MSG, optarg); + if (id < 0) { + ret++; + break; + } + /* fallthrough */ + case 'q': + if (!iskey) + id = strtos32_or_err(optarg, _("failed to parse argument")); + if (remove_id(MSG, iskey, id)) + ret++; + break; + case 'S': + iskey = 1; + id = key_to_id(SEM, optarg); + if (id < 0) { + ret++; + break; + } + /* fallthrough */ + case 's': + if (!iskey) + id = strtos32_or_err(optarg, _("failed to parse argument")); + if (remove_id(SEM, iskey, id)) + ret++; + break; + case 'a': + rm_all = 1; + if (optarg) { + if (!strcmp(optarg, "shm")) + what_all = SHM; + else if (!strcmp(optarg, "msg")) + what_all = MSG; + else if (!strcmp(optarg, "sem")) + what_all = SEM; + else + errx(EXIT_FAILURE, + _("unknown argument: %s"), optarg); + } else { + what_all = ALL; + } + break; + case 'v': + verbose = 1; + break; + case 'h': + usage(); + case 'V': + printf(UTIL_LINUX_VERSION); + return EXIT_SUCCESS; + default: + errtryhelp(EXIT_FAILURE); + } + } + + if (rm_all && remove_all(what_all)) + ret++; + + /* print usage if we still have some arguments left over */ + if (optind < argc) { + warnx(_("unknown argument: %s"), argv[optind]); + errtryhelp(EXIT_FAILURE); + } + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} |