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