]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/ipcrm.c
ipcrm: refactor new and old main to share code
[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 <getopt.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17
18 #include <sys/types.h>
19 #include <sys/ipc.h>
20 #include <sys/shm.h>
21 #include <sys/msg.h>
22 #include <sys/sem.h>
23 #include "c.h"
24 #include "nls.h"
25 #include "strutils.h"
26
27 /* for getopt */
28 #include <unistd.h>
29 /* for tolower and isupper */
30 #include <ctype.h>
31
32 #ifndef HAVE_UNION_SEMUN
33 /* according to X/OPEN we have to define it ourselves */
34 union semun {
35 int val;
36 struct semid_ds *buf;
37 unsigned short int *array;
38 struct seminfo *__buf;
39 };
40 #endif
41
42 typedef enum type_id {
43 SHM,
44 SEM,
45 MSG
46 } type_id;
47
48 /* print the new usage */
49 static void __attribute__ ((__noreturn__)) usage(FILE * out)
50 {
51 fprintf(out, USAGE_HEADER);
52 fprintf(out, " %s [options]\n", program_invocation_short_name);
53 fprintf(out, " %s <shm|msg|sem> <id> [...]\n", program_invocation_short_name);
54 fprintf(out, USAGE_OPTIONS);
55 fputs(_(" -m, --shmem-id <id> remove shared memory segment by shmid\n"), out);
56 fputs(_(" -M, --shmem-key <key> remove shared memory segment by key\n"), out);
57 fputs(_(" -q, --queue-id <id> remove message queue by id\n"), out);
58 fputs(_(" -Q, --queue-key <key> remove message queue by key\n"), out);
59 fputs(_(" -s, --semaphore-id <id> remove semaprhore by id\n"), out);
60 fputs(_(" -S, --semaphore-key <key> remove semaprhore by key\n"), out);
61 fprintf(out, USAGE_HELP);
62 fprintf(out, USAGE_VERSION);
63 fprintf(out, USAGE_BEGIN_TAIL);
64 fprintf(out, USAGE_MAN_TAIL, "ipcrm(1)");
65 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
66 }
67
68 int remove_id(int type, int iskey, int id)
69 {
70 char *errmsg;
71 /* needed to delete semaphores */
72 union semun arg;
73 arg.val = 0;
74
75 /* do the removal */
76 switch (type) {
77 case SHM:
78 shmctl(id, IPC_RMID, NULL);
79 break;
80 case MSG:
81 msgctl(id, IPC_RMID, NULL);
82 break;
83 case SEM:
84 semctl(id, 0, IPC_RMID, arg);
85 break;
86 default:
87 errx(EXIT_FAILURE, "impossible occurred");
88 }
89
90 /* how did the removal go? */
91 switch (errno) {
92 case 0:
93 return 0;
94 case EACCES:
95 case EPERM:
96 errmsg = iskey ? _("permission denied for key") : _("permission denied for id");
97 break;
98 case EINVAL:
99 errmsg = iskey ? _("invalid key") : _("invalid id");
100 break;
101 case EIDRM:
102 errmsg = iskey ? _("already removed key") : _("already removed id");
103 break;
104 default:
105 if (iskey)
106 err(EXIT_FAILURE, _("key failed"));
107 err(EXIT_FAILURE, _("id failed"));
108 }
109 warnx("%s (%d)", errmsg, id);
110 return 1;
111 }
112
113 static int remove_arg_list(type_id type, int argc, char **argv)
114 {
115 int id;
116 char *end;
117 int nb_errors = 0;
118
119 do {
120 id = strtoul(argv[0], &end, 10);
121 if (*end != 0) {
122 warnx(_("invalid id: %s"), argv[0]);
123 nb_errors++;
124 } else {
125 if (remove_id(type, 0, id))
126 nb_errors++;
127 }
128 argc--;
129 argv++;
130 } while (argc);
131 return (nb_errors);
132 }
133
134 static int deprecated_main(int argc, char **argv)
135 {
136 type_id type;
137
138 if (!strcmp(argv[1], "shm"))
139 type = SHM;
140 else if (!strcmp(argv[1], "msg"))
141 type = MSG;
142 else if (!strcmp(argv[1], "sem"))
143 type = SEM;
144 else
145 return 0;
146
147 if (argc < 3) {
148 warnx(_("not enough arguments"));
149 usage(stderr);
150 }
151
152 if (remove_arg_list(type, argc - 2, &argv[2]))
153 exit(EXIT_FAILURE);
154
155 printf(_("resource(s) deleted\n"));
156 return 1;
157 }
158
159 unsigned long strtokey(const char *str, const char *errmesg)
160 {
161 unsigned long num;
162 char *end = NULL;
163
164 if (str == NULL || *str == '\0')
165 goto err;
166 errno = 0;
167 /* keys are in hex or decimal */
168 num = strtoul(str, &end, 0);
169
170 if (errno || str == end || (end && *end))
171 goto err;
172
173 return num;
174 err:
175 if (errno)
176 err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
177 else
178 errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
179 return 0;
180 }
181
182 static int key_to_id(type_id type, char *optarg)
183 {
184 int id;
185 /* keys are in hex or decimal */
186 key_t key = strtokey(optarg, "failed to parse argument");
187 if (key == IPC_PRIVATE) {
188 warnx(_("illegal key (%s)"), optarg);
189 return -1;
190 }
191 switch (type) {
192 case SHM:
193 id = shmget(key, 0, 0);
194 break;
195 case MSG:
196 id = msgget(key, 0);
197 break;
198 case SEM:
199 id = semget(key, 0, 0);
200 break;
201 default:
202 errx(EXIT_FAILURE, "impossible occurred");
203 }
204 if (id < 0) {
205 char *errmsg;
206 switch (errno) {
207 case EACCES:
208 errmsg = _("permission denied for key");
209 break;
210 case EIDRM:
211 errmsg = _("already removed key");
212 break;
213 case ENOENT:
214 errmsg = _("invalid key");
215 break;
216 default:
217 err(EXIT_FAILURE, _("key failed"));
218 }
219 warnx("%s (%s)", errmsg, optarg);
220 }
221 return id;
222 }
223
224 int main(int argc, char **argv)
225 {
226 int c;
227 int ret = 0;
228 int id = -1;
229 int iskey;
230
231 static const struct option longopts[] = {
232 {"shmem-id", required_argument, NULL, 'm'},
233 {"shmem-key", required_argument, NULL, 'M'},
234 {"queue-id", required_argument, NULL, 'q'},
235 {"queue-key", required_argument, NULL, 'Q'},
236 {"semaphore-id", required_argument, NULL, 's'},
237 {"semaphore-key", required_argument, NULL, 'S'},
238 {"version", no_argument, NULL, 'V'},
239 {"help", no_argument, NULL, 'h'},
240 {NULL, 0, NULL, 0}
241 };
242
243 /* if the command is executed without parameters, do nothing */
244 if (argc == 1)
245 return 0;
246
247 setlocale(LC_ALL, "");
248 bindtextdomain(PACKAGE, LOCALEDIR);
249 textdomain(PACKAGE);
250
251 /* check to see if the command is being invoked in the old way if so
252 * then remove argument list */
253 if (deprecated_main(argc, argv))
254 return EXIT_SUCCESS;
255
256 /* process new syntax to conform with SYSV ipcrm */
257 for (id = -1;
258 (c = getopt_long(argc, argv, "q:m:s:Q:M:S:hV", longopts, NULL)) != -1;
259 id = -1) {
260 switch (c) {
261 case 'M':
262 iskey = 0;
263 id = key_to_id(SHM, optarg);
264 if (id < 0) {
265 ret++;
266 break;
267 }
268 case 'm':
269 if (id < 0) {
270 iskey = 1;
271 id = strtoll_or_err(optarg, _("failed to parse argument"));
272 }
273 if (remove_id(SHM, iskey, id))
274 ret++;
275 break;
276 case 'Q':
277 iskey = 0;
278 id = key_to_id(MSG, optarg);
279 if (id < 0) {
280 ret++;
281 break;
282 }
283 case 'q':
284 if (id < 0) {
285 iskey = 1;
286 id = strtoll_or_err(optarg, _("failed to parse argument"));
287 }
288 if (remove_id(MSG, iskey, id))
289 ret++;
290 break;
291 case 'S':
292 iskey = 0;
293 id = key_to_id(SEM, optarg);
294 if (id < 0) {
295 ret++;
296 break;
297 }
298 case 's':
299 if (id < 0) {
300 iskey = 1;
301 id = strtoll_or_err(optarg, _("failed to parse argument"));
302 }
303 if (remove_id(SEM, iskey, id))
304 ret++;
305 break;
306 case 'h':
307 usage(stdout);
308 case 'V':
309 printf(UTIL_LINUX_VERSION);
310 return EXIT_SUCCESS;
311 default:
312 usage(stderr);
313 }
314 }
315
316 /* print usage if we still have some arguments left over */
317 if (optind != argc) {
318 warnx(_("unknown argument: %s"), argv[optind]);
319 usage(stderr);
320 }
321
322 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
323 }