util-linux/sys-utils/ipcrm.c

424 lines
9.0 KiB
C

/*
* 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);
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;
}