]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/ipcrm.c
libmount: don't use sscanf() for swaps parsing
[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 printf(USAGE_HELP_OPTIONS(28));
69 printf(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;
129 int nb_errors = 0;
130
131 do {
132 id = strtoul(argv[0], &end, 10);
133 if (*end != 0) {
134 warnx(_("invalid id: %s"), argv[0]);
135 nb_errors++;
136 } else {
137 if (remove_id(type, 0, id))
138 nb_errors++;
139 }
140 argc--;
141 argv++;
142 } while (argc);
143 return (nb_errors);
144 }
145
146 static int deprecated_main(int argc, char **argv)
147 {
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"));
161 errtryhelp(EXIT_FAILURE);
162 }
163
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
171 static unsigned long strtokey(const char *str, const char *errmesg)
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);
191 return 0;
192 }
193
194 static int key_to_id(type_id type, char *s)
195 {
196 int id;
197 /* keys are in hex or decimal */
198 key_t key = strtokey(s, "failed to parse argument");
199 if (key == IPC_PRIVATE) {
200 warnx(_("illegal key (%s)"), s);
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;
213 case ALL:
214 abort();
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 }
233 warnx("%s (%s)", errmsg, s);
234 }
235 return id;
236 }
237
238 static int remove_all(type_id type)
239 {
240 int ret = 0;
241 int id, rm_me, maxid;
242
243 struct shmid_ds shmseg;
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) {
253 maxid = shmctl(0, SHM_INFO, &shmseg);
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 }
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
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
301 int main(int argc, char **argv)
302 {
303 int c;
304 int ret = 0;
305 int id = -1;
306 int iskey;
307 int rm_all = 0;
308 type_id what_all = ALL;
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'},
317 {"all", optional_argument, NULL, 'a'},
318 {"verbose", no_argument, NULL, 'v'},
319 {"version", no_argument, NULL, 'V'},
320 {"help", no_argument, NULL, 'h'},
321 {NULL, 0, NULL, 0}
322 };
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);
331 atexit(close_stdout);
332
333 /* check to see if the command is being invoked in the old way if so
334 * then remove argument list */
335 if (deprecated_main(argc, argv))
336 return EXIT_SUCCESS;
337
338 /* process new syntax to conform with SYSV ipcrm */
339 while((c = getopt_long(argc, argv, "q:m:s:Q:M:S:a::vhV", longopts, NULL)) != -1) {
340 iskey = 0;
341 switch (c) {
342 case 'M':
343 iskey = 1;
344 id = key_to_id(SHM, optarg);
345 if (id < 0) {
346 ret++;
347 break;
348 }
349 /* fallthrough */
350 case 'm':
351 if (!iskey)
352 id = strtos32_or_err(optarg, _("failed to parse argument"));
353 if (remove_id(SHM, iskey, id))
354 ret++;
355 break;
356 case 'Q':
357 iskey = 1;
358 id = key_to_id(MSG, optarg);
359 if (id < 0) {
360 ret++;
361 break;
362 }
363 /* fallthrough */
364 case 'q':
365 if (!iskey)
366 id = strtos32_or_err(optarg, _("failed to parse argument"));
367 if (remove_id(MSG, iskey, id))
368 ret++;
369 break;
370 case 'S':
371 iskey = 1;
372 id = key_to_id(SEM, optarg);
373 if (id < 0) {
374 ret++;
375 break;
376 }
377 /* fallthrough */
378 case 's':
379 if (!iskey)
380 id = strtos32_or_err(optarg, _("failed to parse argument"));
381 if (remove_id(SEM, iskey, id))
382 ret++;
383 break;
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;
400 case 'v':
401 verbose = 1;
402 break;
403 case 'h':
404 usage();
405 case 'V':
406 printf(UTIL_LINUX_VERSION);
407 return EXIT_SUCCESS;
408 default:
409 errtryhelp(EXIT_FAILURE);
410 }
411 }
412
413 if (rm_all && remove_all(what_all))
414 ret++;
415
416 /* print usage if we still have some arguments left over */
417 if (optind < argc) {
418 warnx(_("unknown argument: %s"), argv[optind]);
419 errtryhelp(EXIT_FAILURE);
420 }
421
422 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
423 }