]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/ipcrm.c
misc: consolidate version printing and close_stdout()
[thirdparty/util-linux.git] / sys-utils / ipcrm.c
CommitLineData
6dbe3af9
KZ
1/*
2 * krishna balasubramanian 1993
7eda085c 3 *
b50945d4 4 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c
KZ
5 * - added Native Language Support
6 *
22853e4a
KZ
7 * 1999-04-02 frank zago
8 * - can now remove several id's in the same call
9 *
6dbe3af9
KZ
10 */
11
79092062 12#include <errno.h>
1b3b3f9f 13#include <getopt.h>
6dbe3af9
KZ
14#include <stdio.h>
15#include <stdlib.h>
fd6b7a7f 16#include <string.h>
5c36a0eb 17#include <sys/ipc.h>
6dbe3af9
KZ
18#include <sys/msg.h>
19#include <sys/sem.h>
79092062 20#include <sys/shm.h>
3d0fc72d 21#include <sys/types.h>
1b3b3f9f 22#include "c.h"
7eda085c 23#include "nls.h"
8b69b6d6 24#include "strutils.h"
efb8854f 25#include "closestream.h"
7eda085c 26
869829e4 27#ifndef HAVE_UNION_SEMUN
5c36a0eb
KZ
28/* according to X/OPEN we have to define it ourselves */
29union semun {
30 int val;
31 struct semid_ds *buf;
32 unsigned short int *array;
33 struct seminfo *__buf;
34};
35#endif
36
22853e4a
KZ
37typedef enum type_id {
38 SHM,
39 SEM,
3d0fc72d
SK
40 MSG,
41 ALL
22853e4a
KZ
42} type_id;
43
99e89ede
SK
44static int verbose = 0;
45
aa06617f 46/* print the usage */
6e1eda6f 47static void __attribute__((__noreturn__)) usage(void)
1b3b3f9f 48{
6e1eda6f 49 FILE *out = stdout;
7009af0e 50 fputs(USAGE_HEADER, out);
17bf9c1c
KZ
51 fprintf(out, _(" %1$s [options]\n"
52 " %1$s shm|msg|sem <id>...\n"), program_invocation_short_name);
451dbcfa
BS
53
54 fputs(USAGE_SEPARATOR, out);
55 fputs(_("Remove certain IPC resources.\n"), out);
56
7009af0e 57 fputs(USAGE_OPTIONS, out);
aa06617f 58 fputs(_(" -m, --shmem-id <id> remove shared memory segment by id\n"), out);
1b3b3f9f
SK
59 fputs(_(" -M, --shmem-key <key> remove shared memory segment by key\n"), out);
60 fputs(_(" -q, --queue-id <id> remove message queue by id\n"), out);
61 fputs(_(" -Q, --queue-key <key> remove message queue by key\n"), out);
f9bd0858
DB
62 fputs(_(" -s, --semaphore-id <id> remove semaphore by id\n"), out);
63 fputs(_(" -S, --semaphore-key <key> remove semaphore by key\n"), out);
aa06617f 64 fputs(_(" -a, --all[=shm|msg|sem] remove all (in the specified category)\n"), out);
99e89ede 65 fputs(_(" -v, --verbose explain what is being done\n"), out);
7009af0e
BS
66
67 fputs(USAGE_SEPARATOR, out);
f45f3ec3
RM
68 printf(USAGE_HELP_OPTIONS(28));
69 printf(USAGE_MAN_TAIL("ipcrm(1)"));
7009af0e 70
6e1eda6f 71 exit(EXIT_SUCCESS);
1b3b3f9f
SK
72}
73
14cbdb85 74static int remove_id(int type, int iskey, int id)
8b69b6d6 75{
7678c735 76 int ret;
8b69b6d6
SK
77 char *errmsg;
78 /* needed to delete semaphores */
6dbe3af9 79 union semun arg;
7eda085c 80 arg.val = 0;
22853e4a 81
8b69b6d6
SK
82 /* do the removal */
83 switch (type) {
84 case SHM:
99e89ede
SK
85 if (verbose)
86 printf(_("removing shared memory segment id `%d'\n"), id);
7678c735 87 ret = shmctl(id, IPC_RMID, NULL);
8b69b6d6
SK
88 break;
89 case MSG:
99e89ede
SK
90 if (verbose)
91 printf(_("removing message queue id `%d'\n"), id);
7678c735 92 ret = msgctl(id, IPC_RMID, NULL);
8b69b6d6
SK
93 break;
94 case SEM:
99e89ede
SK
95 if (verbose)
96 printf(_("removing semaphore id `%d'\n"), id);
7678c735 97 ret = semctl(id, 0, IPC_RMID, arg);
8b69b6d6
SK
98 break;
99 default:
100 errx(EXIT_FAILURE, "impossible occurred");
101 }
22853e4a 102
8b69b6d6 103 /* how did the removal go? */
7678c735
DB
104 if (ret < 0) {
105 switch (errno) {
106 case EACCES:
107 case EPERM:
108 errmsg = iskey ? _("permission denied for key") : _("permission denied for id");
109 break;
110 case EINVAL:
111 errmsg = iskey ? _("invalid key") : _("invalid id");
112 break;
113 case EIDRM:
114 errmsg = iskey ? _("already removed key") : _("already removed id");
115 break;
116 default:
f205c90a 117 err(EXIT_FAILURE, "%s", iskey ? _("key failed") : _("id failed"));
7678c735
DB
118 }
119 warnx("%s (%d)", errmsg, id);
120 return 1;
8b69b6d6 121 }
7678c735 122 return 0;
8b69b6d6 123}
22853e4a 124
8b69b6d6
SK
125static int remove_arg_list(type_id type, int argc, char **argv)
126{
127 int id;
128 char *end;
129 int nb_errors = 0;
130
131 do {
132 id = strtoul(argv[0], &end, 10);
22853e4a 133 if (*end != 0) {
1b3b3f9f 134 warnx(_("invalid id: %s"), argv[0]);
8b69b6d6 135 nb_errors++;
22853e4a 136 } else {
8b69b6d6
SK
137 if (remove_id(type, 0, id))
138 nb_errors++;
22853e4a
KZ
139 }
140 argc--;
141 argv++;
8b69b6d6
SK
142 } while (argc);
143 return (nb_errors);
22853e4a
KZ
144}
145
1d4ad1de 146static int deprecated_main(int argc, char **argv)
22853e4a 147{
8b69b6d6
SK
148 type_id type;
149
150 if (!strcmp(argv[1], "shm"))
151 type = SHM;
152 else if (!strcmp(argv[1], "msg"))
153 type = MSG;
154 else if (!strcmp(argv[1], "sem"))
155 type = SEM;
156 else
157 return 0;
158
159 if (argc < 3) {
160 warnx(_("not enough arguments"));
6e1eda6f 161 errtryhelp(EXIT_FAILURE);
22853e4a
KZ
162 }
163
8b69b6d6
SK
164 if (remove_arg_list(type, argc - 2, &argv[2]))
165 exit(EXIT_FAILURE);
166
167 printf(_("resource(s) deleted\n"));
168 return 1;
169}
170
14cbdb85 171static unsigned long strtokey(const char *str, const char *errmesg)
8b69b6d6
SK
172{
173 unsigned long num;
174 char *end = NULL;
175
176 if (str == NULL || *str == '\0')
177 goto err;
178 errno = 0;
179 /* keys are in hex or decimal */
180 num = strtoul(str, &end, 0);
181
182 if (errno || str == end || (end && *end))
183 goto err;
184
185 return num;
186 err:
187 if (errno)
188 err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
189 else
190 errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
6dbe3af9
KZ
191 return 0;
192}
1d4ad1de 193
eb2306e6 194static int key_to_id(type_id type, char *s)
8b69b6d6
SK
195{
196 int id;
197 /* keys are in hex or decimal */
eb2306e6 198 key_t key = strtokey(s, "failed to parse argument");
8b69b6d6 199 if (key == IPC_PRIVATE) {
eb2306e6 200 warnx(_("illegal key (%s)"), s);
8b69b6d6
SK
201 return -1;
202 }
203 switch (type) {
204 case SHM:
205 id = shmget(key, 0, 0);
206 break;
207 case MSG:
208 id = msgget(key, 0);
209 break;
210 case SEM:
211 id = semget(key, 0, 0);
212 break;
3d0fc72d
SK
213 case ALL:
214 abort();
8b69b6d6
SK
215 default:
216 errx(EXIT_FAILURE, "impossible occurred");
217 }
218 if (id < 0) {
219 char *errmsg;
220 switch (errno) {
221 case EACCES:
222 errmsg = _("permission denied for key");
223 break;
224 case EIDRM:
225 errmsg = _("already removed key");
226 break;
227 case ENOENT:
228 errmsg = _("invalid key");
229 break;
230 default:
231 err(EXIT_FAILURE, _("key failed"));
232 }
eb2306e6 233 warnx("%s (%s)", errmsg, s);
8b69b6d6
SK
234 }
235 return id;
236}
1d4ad1de 237
14cbdb85 238static int remove_all(type_id type)
3d0fc72d
SK
239{
240 int ret = 0;
241 int id, rm_me, maxid;
242
243 struct shmid_ds shmseg;
3d0fc72d
SK
244
245 struct semid_ds semary;
246 struct seminfo seminfo;
247 union semun arg;
248
249 struct msqid_ds msgque;
250 struct msginfo msginfo;
251
252 if (type == SHM || type == ALL) {
929c2575 253 maxid = shmctl(0, SHM_INFO, &shmseg);
3d0fc72d
SK
254 if (maxid < 0)
255 errx(EXIT_FAILURE,
256 _("kernel not configured for shared memory"));
257 for (id = 0; id <= maxid; id++) {
258 rm_me = shmctl(id, SHM_STAT, &shmseg);
259 if (rm_me < 0)
260 continue;
261 ret |= remove_id(SHM, 0, rm_me);
262 }
263 }
264 if (type == SEM || type == ALL) {
265 arg.array = (ushort *) (void *)&seminfo;
266 maxid = semctl(0, 0, SEM_INFO, arg);
267 if (maxid < 0)
268 errx(EXIT_FAILURE,
269 _("kernel not configured for semaphores"));
270 for (id = 0; id <= maxid; id++) {
271 arg.buf = (struct semid_ds *)&semary;
272 rm_me = semctl(id, 0, SEM_STAT, arg);
273 if (rm_me < 0)
274 continue;
275 ret |= remove_id(SEM, 0, rm_me);
276 }
277 }
2eaac548
AH
278/* kFreeBSD hackery -- ah 20140723 */
279#ifndef MSG_STAT
280#define MSG_STAT 11
281#endif
282#ifndef MSG_INFO
283#define MSG_INFO 12
284#endif
3d0fc72d
SK
285 if (type == MSG || type == ALL) {
286 maxid =
287 msgctl(0, MSG_INFO, (struct msqid_ds *)(void *)&msginfo);
288 if (maxid < 0)
289 errx(EXIT_FAILURE,
290 _("kernel not configured for message queues"));
291 for (id = 0; id <= maxid; id++) {
292 rm_me = msgctl(id, MSG_STAT, &msgque);
293 if (rm_me < 0)
294 continue;
295 ret |= remove_id(MSG, 0, rm_me);
296 }
297 }
298 return ret;
299}
300
1d4ad1de
KZ
301int main(int argc, char **argv)
302{
8b69b6d6
SK
303 int c;
304 int ret = 0;
305 int id = -1;
306 int iskey;
3d0fc72d 307 int rm_all = 0;
b83b9b11 308 type_id what_all = ALL;
1b3b3f9f
SK
309
310 static const struct option longopts[] = {
311 {"shmem-id", required_argument, NULL, 'm'},
312 {"shmem-key", required_argument, NULL, 'M'},
313 {"queue-id", required_argument, NULL, 'q'},
314 {"queue-key", required_argument, NULL, 'Q'},
315 {"semaphore-id", required_argument, NULL, 's'},
316 {"semaphore-key", required_argument, NULL, 'S'},
3d0fc72d 317 {"all", optional_argument, NULL, 'a'},
99e89ede 318 {"verbose", no_argument, NULL, 'v'},
1b3b3f9f
SK
319 {"version", no_argument, NULL, 'V'},
320 {"help", no_argument, NULL, 'h'},
321 {NULL, 0, NULL, 0}
322 };
1d4ad1de
KZ
323
324 /* if the command is executed without parameters, do nothing */
325 if (argc == 1)
326 return 0;
327
328 setlocale(LC_ALL, "");
329 bindtextdomain(PACKAGE, LOCALEDIR);
330 textdomain(PACKAGE);
2c308875 331 close_stdout_atexit();
1d4ad1de
KZ
332
333 /* check to see if the command is being invoked in the old way if so
8b69b6d6
SK
334 * then remove argument list */
335 if (deprecated_main(argc, argv))
336 return EXIT_SUCCESS;
1d4ad1de
KZ
337
338 /* process new syntax to conform with SYSV ipcrm */
d916761f
FC
339 while((c = getopt_long(argc, argv, "q:m:s:Q:M:S:a::vhV", longopts, NULL)) != -1) {
340 iskey = 0;
8b69b6d6
SK
341 switch (c) {
342 case 'M':
d916761f 343 iskey = 1;
8b69b6d6
SK
344 id = key_to_id(SHM, optarg);
345 if (id < 0) {
346 ret++;
347 break;
1d4ad1de 348 }
b1557fe9 349 /* fallthrough */
8b69b6d6 350 case 'm':
d916761f 351 if (!iskey)
20a39982 352 id = strtos32_or_err(optarg, _("failed to parse argument"));
8b69b6d6
SK
353 if (remove_id(SHM, iskey, id))
354 ret++;
355 break;
356 case 'Q':
d916761f 357 iskey = 1;
8b69b6d6
SK
358 id = key_to_id(MSG, optarg);
359 if (id < 0) {
360 ret++;
1d4ad1de 361 break;
8b69b6d6 362 }
b1557fe9 363 /* fallthrough */
8b69b6d6 364 case 'q':
d916761f 365 if (!iskey)
20a39982 366 id = strtos32_or_err(optarg, _("failed to parse argument"));
8b69b6d6
SK
367 if (remove_id(MSG, iskey, id))
368 ret++;
369 break;
370 case 'S':
d916761f 371 iskey = 1;
8b69b6d6
SK
372 id = key_to_id(SEM, optarg);
373 if (id < 0) {
374 ret++;
1d4ad1de 375 break;
1d4ad1de 376 }
b1557fe9 377 /* fallthrough */
8b69b6d6 378 case 's':
d916761f 379 if (!iskey)
20a39982 380 id = strtos32_or_err(optarg, _("failed to parse argument"));
8b69b6d6
SK
381 if (remove_id(SEM, iskey, id))
382 ret++;
383 break;
3d0fc72d
SK
384 case 'a':
385 rm_all = 1;
386 if (optarg) {
387 if (!strcmp(optarg, "shm"))
388 what_all = SHM;
389 else if (!strcmp(optarg, "msg"))
390 what_all = MSG;
391 else if (!strcmp(optarg, "sem"))
392 what_all = SEM;
393 else
394 errx(EXIT_FAILURE,
395 _("unknown argument: %s"), optarg);
396 } else {
397 what_all = ALL;
398 }
399 break;
99e89ede
SK
400 case 'v':
401 verbose = 1;
402 break;
2c308875 403
8b69b6d6 404 case 'h':
6e1eda6f 405 usage();
8b69b6d6 406 case 'V':
2c308875 407 print_version(EXIT_SUCCESS);
8b69b6d6 408 default:
677ec86c 409 errtryhelp(EXIT_FAILURE);
1d4ad1de
KZ
410 }
411 }
412
74ce680a
SK
413 if (rm_all && remove_all(what_all))
414 ret++;
3d0fc72d 415
1d4ad1de 416 /* print usage if we still have some arguments left over */
3d0fc72d 417 if (optind < argc) {
1b3b3f9f 418 warnx(_("unknown argument: %s"), argv[optind]);
677ec86c 419 errtryhelp(EXIT_FAILURE);
1d4ad1de
KZ
420 }
421
8b69b6d6 422 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1d4ad1de 423}