summaryrefslogtreecommitdiffstats
path: root/sys-utils/ipcrm.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sys-utils/ipcrm.c423
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;
+}