]>
Commit | Line | Data |
---|---|---|
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 */ |
29 | union semun { | |
30 | int val; | |
31 | struct semid_ds *buf; | |
32 | unsigned short int *array; | |
33 | struct seminfo *__buf; | |
34 | }; | |
35 | #endif | |
36 | ||
22853e4a KZ |
37 | typedef enum type_id { |
38 | SHM, | |
39 | SEM, | |
3d0fc72d SK |
40 | MSG, |
41 | ALL | |
22853e4a KZ |
42 | } type_id; |
43 | ||
99e89ede SK |
44 | static int verbose = 0; |
45 | ||
aa06617f | 46 | /* print the usage */ |
6e1eda6f | 47 | static 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 | 74 | static 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 |
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); | |
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 | 146 | static 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 | 171 | static 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 | 194 | static 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 | 238 | static 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 |
301 | int 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); | |
efb8854f | 331 | atexit(close_stdout); |
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; | |
8b69b6d6 | 403 | case 'h': |
6e1eda6f | 404 | usage(); |
8b69b6d6 SK |
405 | case 'V': |
406 | printf(UTIL_LINUX_VERSION); | |
407 | return EXIT_SUCCESS; | |
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 | } |