hush: do not assign to readonly VAR in "VAR=VAL CMD" syntax too
[oweals/busybox.git] / util-linux / ipcrm.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * ipcrm.c - utility to allow removal of IPC objects and data structures.
4  *
5  * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com>
6  * Adapted for busybox from util-linux-2.12a.
7  *
8  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9  */
10 //config:config IPCRM
11 //config:       bool "ipcrm"
12 //config:       default y
13 //config:       help
14 //config:         The ipcrm utility allows the removal of System V interprocess
15 //config:         communication (IPC) objects and the associated data structures
16 //config:         from the system.
17
18 //applet:IF_IPCRM(APPLET(ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP))
19
20 //kbuild:lib-$(CONFIG_IPCRM) += ipcrm.o
21
22 //usage:#define ipcrm_trivial_usage
23 //usage:       "[-MQS key] [-mqs id]"
24 //usage:#define ipcrm_full_usage "\n\n"
25 //usage:       "Upper-case options MQS remove an object by shmkey value.\n"
26 //usage:       "Lower-case options remove an object by shmid value.\n"
27 //usage:     "\n        -mM     Remove memory segment after last detach"
28 //usage:     "\n        -qQ     Remove message queue"
29 //usage:     "\n        -sS     Remove semaphore"
30
31 #include "libbb.h"
32
33 /* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
34 /* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
35 #include <sys/ipc.h>
36 #include <sys/shm.h>
37 #include <sys/msg.h>
38 #include <sys/sem.h>
39
40 #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
41 /* union semun is defined by including <sys/sem.h> */
42 #else
43 /* according to X/OPEN we have to define it ourselves */
44 union semun {
45         int val;
46         struct semid_ds *buf;
47         unsigned short *array;
48         struct seminfo *__buf;
49 };
50 #endif
51
52 #define IPCRM_LEGACY 1
53
54
55 #if IPCRM_LEGACY
56
57 typedef enum type_id {
58         SHM,
59         SEM,
60         MSG
61 } type_id;
62
63 static int remove_ids(type_id type, char **argv)
64 {
65         unsigned long id;
66         int nb_errors = 0;
67         union semun arg;
68
69         arg.val = 0;
70
71         while (argv[0]) {
72                 id = bb_strtoul(argv[0], NULL, 10);
73                 if (errno || id > INT_MAX) {
74                         bb_error_msg("invalid id: %s", argv[0]);
75                         nb_errors++;
76                 } else {
77                         int ret = 0;
78                         if (type == SEM)
79                                 ret = semctl(id, 0, IPC_RMID, arg);
80                         else if (type == MSG)
81                                 ret = msgctl(id, IPC_RMID, NULL);
82                         else if (type ==  SHM)
83                                 ret = shmctl(id, IPC_RMID, NULL);
84
85                         if (ret) {
86                                 bb_perror_msg("can't remove id %s", argv[0]);
87                                 nb_errors++;
88                         }
89                 }
90                 argv++;
91         }
92
93         return nb_errors;
94 }
95 #endif /* IPCRM_LEGACY */
96
97
98 int ipcrm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
99 int ipcrm_main(int argc, char **argv)
100 {
101         int c;
102         int error = 0;
103
104         /* if the command is executed without parameters, do nothing */
105         if (argc == 1)
106                 return 0;
107 #if IPCRM_LEGACY
108         /* check to see if the command is being invoked in the old way if so
109            then run the old code. Valid commands are msg, shm, sem. */
110         {
111                 type_id what = 0; /* silence gcc */
112                 char w;
113
114                 w = argv[1][0];
115                 if ( ((w == 'm' && argv[1][1] == 's' && argv[1][2] == 'g')
116                        || (argv[1][0] == 's'
117                            && ((w = argv[1][1]) == 'h' || w == 'e')
118                            && argv[1][2] == 'm')
119                      ) && argv[1][3] == '\0'
120                 ) {
121                         if (argc < 3)
122                                 bb_show_usage();
123
124                         if (w == 'h')
125                                 what = SHM;
126                         else if (w == 'm')
127                                 what = MSG;
128                         else if (w == 'e')
129                                 what = SEM;
130
131                         if (remove_ids(what, &argv[2]))
132                                 fflush_stdout_and_exit(EXIT_FAILURE);
133                         puts("resource(s) deleted");
134                         return 0;
135                 }
136         }
137 #endif /* IPCRM_LEGACY */
138
139         /* process new syntax to conform with SYSV ipcrm */
140         while ((c = getopt(argc, argv, "q:m:s:Q:M:S:h?")) != -1) {
141                 int result;
142                 int id = 0;
143                 int iskey = isupper(c);
144
145                 /* needed to delete semaphores */
146                 union semun arg;
147
148                 arg.val = 0;
149
150                 if ((c == '?') || (c == 'h')) {
151                         bb_show_usage();
152                 }
153
154                 /* we don't need case information any more */
155                 c = tolower(c);
156
157                 /* make sure the option is in range: allowed are q, m, s */
158                 if (c != 'q' && c != 'm' && c != 's') {
159                         bb_show_usage();
160                 }
161
162                 if (iskey) {
163                         /* keys are in hex or decimal */
164                         key_t key = xstrtoul(optarg, 0);
165
166                         if (key == IPC_PRIVATE) {
167                                 error++;
168                                 bb_error_msg("illegal key (%s)", optarg);
169                                 continue;
170                         }
171
172                         /* convert key to id */
173                         id = ((c == 'q') ? msgget(key, 0) :
174                                 (c == 'm') ? shmget(key, 0, 0) : semget(key, 0, 0));
175
176                         if (id < 0) {
177                                 const char *errmsg;
178
179                                 error++;
180                                 switch (errno) {
181                                 case EACCES:
182                                         errmsg = "permission denied for";
183                                         break;
184                                 case EIDRM:
185                                         errmsg = "already removed";
186                                         break;
187                                 case ENOENT:
188                                         errmsg = "invalid";
189                                         break;
190                                 default:
191                                         errmsg = "unknown error in";
192                                         break;
193                                 }
194                                 bb_error_msg("%s %s (%s)", errmsg, "key", optarg);
195                                 continue;
196                         }
197                 } else {
198                         /* ids are in decimal */
199                         id = xatoul(optarg);
200                 }
201
202                 result = ((c == 'q') ? msgctl(id, IPC_RMID, NULL) :
203                                 (c == 'm') ? shmctl(id, IPC_RMID, NULL) :
204                                 semctl(id, 0, IPC_RMID, arg));
205
206                 if (result) {
207                         const char *errmsg;
208                         const char *const what = iskey ? "key" : "id";
209
210                         error++;
211                         switch (errno) {
212                         case EACCES:
213                         case EPERM:
214                                 errmsg = "permission denied for";
215                                 break;
216                         case EINVAL:
217                                 errmsg = "invalid";
218                                 break;
219                         case EIDRM:
220                                 errmsg = "already removed";
221                                 break;
222                         default:
223                                 errmsg = "unknown error in";
224                                 break;
225                         }
226                         bb_error_msg("%s %s (%s)", errmsg, what, optarg);
227                         continue;
228                 }
229         }
230
231         /* print usage if we still have some arguments left over */
232         if (optind != argc) {
233                 bb_show_usage();
234         }
235
236         /* exit value reflects the number of errors encountered */
237         return error;
238 }