rfelker writes in Bug 736: stty.c includes unneeded, obsolete header memory.h
[oweals/busybox.git] / util-linux / ipcrm.c
1 /*
2  * ipcrm.c -- utility to allow removal of IPC objects and data structures.
3  *
4  * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com>
5  * Adapted for busybox from util-linux-2.12a.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  * --- Pre-busybox history from util-linux-2.12a ------------------------
22  *
23  * 1999-04-02 frank zago
24  * - can now remove several id's in the same call
25  *
26  * 1999-02-22 Arkadiusz Miÿkiewicz <misiek@pld.ORG.PL>
27  * - added Native Language Support
28  *
29  * Original author - krishna balasubramanian 1993
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #include <sys/types.h>
38 #include <sys/ipc.h>
39 #include <sys/shm.h>
40 #include <sys/msg.h>
41 #include <sys/sem.h>
42
43 /* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
44 /* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
45 /* for getopt */
46 #include <unistd.h>
47
48 /* for tolower and isupper */
49 #include <ctype.h>
50
51 #include "busybox.h"
52
53 #if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
54 /* union semun is defined by including <sys/sem.h> */
55 #else
56 /* according to X/OPEN we have to define it ourselves */
57 union semun {
58         int val;
59         struct semid_ds *buf;
60         unsigned short int *array;
61         struct seminfo *__buf;
62 };
63 #endif
64
65 typedef enum type_id {
66         SHM,
67         SEM,
68         MSG
69 } type_id;
70
71 static int
72 remove_ids(type_id type, int argc, char **argv) {
73         int id;
74         int ret = 0;            /* for gcc */
75         char *end;
76         int nb_errors = 0;
77         union semun arg;
78
79         arg.val = 0;
80
81         while(argc) {
82
83                 id = strtoul(argv[0], &end, 10);
84
85                 if (*end != 0) {
86                         bb_printf ("invalid id: %s\n", argv[0]);
87                         nb_errors ++;
88                 } else {
89                         switch(type) {
90                         case SEM:
91                                 ret = semctl (id, 0, IPC_RMID, arg);
92                                 break;
93
94                         case MSG:
95                                 ret = msgctl (id, IPC_RMID, NULL);
96                                 break;
97
98                         case SHM:
99                                 ret = shmctl (id, IPC_RMID, NULL);
100                                 break;
101                         }
102
103                         if (ret) {
104                                 bb_printf ("cannot remove id %s (%s)\n",
105                                         argv[0], strerror(errno));
106                                 nb_errors ++;
107                         }
108                 }
109                 argc--;
110                 argv++;
111         }
112
113         return(nb_errors);
114 }
115
116 static int deprecated_main(int argc, char **argv)
117 {
118         if (argc < 3) {
119                 bb_show_usage();
120                 bb_fflush_stdout_and_exit(1);
121         }
122
123         if (!strcmp(argv[1], "shm")) {
124                 if (remove_ids(SHM, argc-2, &argv[2]))
125                         bb_fflush_stdout_and_exit(1);
126         }
127         else if (!strcmp(argv[1], "msg")) {
128                 if (remove_ids(MSG, argc-2, &argv[2]))
129                         bb_fflush_stdout_and_exit(1);
130         }
131         else if (!strcmp(argv[1], "sem")) {
132                 if (remove_ids(SEM, argc-2, &argv[2]))
133                         bb_fflush_stdout_and_exit(1);
134         }
135         else {
136                 bb_printf ("unknown resource type: %s\n", argv[1]);
137                 bb_show_usage();
138                 bb_fflush_stdout_and_exit(1);
139         }
140
141         bb_printf ("resource(s) deleted\n");
142         return 0;
143 }
144
145
146 int ipcrm_main(int argc, char **argv)
147 {
148         int   c;
149         int   error = 0;
150         char *prog = argv[0];
151
152         /* if the command is executed without parameters, do nothing */
153         if (argc == 1)
154                 return 0;
155
156         /* check to see if the command is being invoked in the old way if so
157            then run the old code */
158         if (strcmp(argv[1], "shm") == 0 ||
159                 strcmp(argv[1], "msg") == 0 ||
160                 strcmp(argv[1], "sem") == 0)
161                 return deprecated_main(argc, argv);
162
163         /* process new syntax to conform with SYSV ipcrm */
164         while ((c = getopt(argc, argv, "q:m:s:Q:M:S:h?")) != -1) {
165                 int result;
166                 int id = 0;
167                 int iskey = isupper(c);
168
169                 /* needed to delete semaphores */
170                 union semun arg;
171                 arg.val = 0;
172
173                 if ((c == '?') || (c == 'h'))
174                 {
175                         bb_show_usage();
176                         return 0;
177                 }
178
179                 /* we don't need case information any more */
180                 c = tolower(c);
181
182                 /* make sure the option is in range */
183                 if (c != 'q' && c != 'm' && c != 's') {
184                         bb_show_usage();
185                         error++;
186                         return error;
187                 }
188
189                 if (iskey) {
190                         /* keys are in hex or decimal */
191                         key_t key = strtoul(optarg, NULL, 0);
192                         if (key == IPC_PRIVATE) {
193                                 error++;
194                                 bb_fprintf(stderr, "%s: illegal key (%s)\n",
195                                         prog, optarg);
196                                 continue;
197                         }
198
199                         /* convert key to id */
200                         id = ((c == 'q') ? msgget(key, 0) :
201                                   (c == 'm') ? shmget(key, 0, 0) :
202                                   semget(key, 0, 0));
203
204                         if (id < 0) {
205                                 char *errmsg;
206                                 error++;
207                                 switch(errno) {
208                                 case EACCES:
209                                         errmsg = "permission denied for key";
210                                         break;
211                                 case EIDRM:
212                                         errmsg = "already removed key";
213                                         break;
214                                 case ENOENT:
215                                         errmsg = "invalid key";
216                                         break;
217                                 default:
218                                         errmsg = "unknown error in key";
219                                         break;
220                                 }
221                                 bb_fprintf(stderr, "%s: %s (%s)\n",
222                                         prog, errmsg, optarg);
223                                 continue;
224                         }
225                 } else {
226                         /* ids are in decimal */
227                         id = strtoul(optarg, NULL, 10);
228                 }
229
230                 result = ((c == 'q') ? msgctl(id, IPC_RMID, NULL) :
231                           (c == 'm') ? shmctl(id, IPC_RMID, NULL) :
232                           semctl(id, 0, IPC_RMID, arg));
233
234                 if (result < 0) {
235                         char *errmsg;
236                         error++;
237                         switch(errno) {
238                         case EACCES:
239                         case EPERM:
240                                 errmsg = iskey
241                                         ? "permission denied for key"
242                                         : "permission denied for id";
243                                 break;
244                         case EINVAL:
245                                 errmsg = iskey
246                                         ? "invalid key"
247                                         : "invalid id";
248                                 break;
249                         case EIDRM:
250                                 errmsg = iskey
251                                         ? "already removed key"
252                                         : "already removed id";
253                                 break;
254                         default:
255                                 errmsg = iskey
256                                         ? "unknown error in key"
257                                         : "unknown error in id";
258                                 break;
259                         }
260                         bb_fprintf(stderr, "%s: %s (%s)\n",
261                                 prog, errmsg, optarg);
262                         continue;
263                 }
264         }
265
266         /* print usage if we still have some arguments left over */
267         if (optind != argc) {
268                 bb_show_usage();
269         }
270
271         /* exit value reflects the number of errors encountered */
272         return error;
273 }