/* * krishna balasubramanian 1993 * * 1999-02-22 Arkadiusz Miƛkiewicz * - added Native Language Support * * 1999-04-02 frank zago * - can now remove several id's in the same call * */ #include #include #include #include #include #include #include #include #include #include #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 ...\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, out); fputs(_("Remove certain IPC resources.\n"), out); fputs(USAGE_OPTIONS, out); fputs(_(" -m, --shmem-id remove shared memory segment by id\n"), out); fputs(_(" -M, --shmem-key remove shared memory segment by key\n"), out); fputs(_(" -q, --queue-id remove message queue by id\n"), out); fputs(_(" -Q, --queue-key remove message queue by key\n"), out); fputs(_(" -s, --semaphore-id remove semaphore by id\n"), out); fputs(_(" -S, --semaphore-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); close_stdout_atexit(); /* 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': print_version(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; }