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