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