1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 29 30 /* 31 * ipcrm - IPC remove 32 * 33 * Remove specified message queues, 34 * semaphore sets and shared memory ids. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/ipc.h> 39 #include <sys/msg.h> 40 #include <sys/sem.h> 41 #include <sys/shm.h> 42 #include <errno.h> 43 #include <sys/ipc_impl.h> 44 #include <zone.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <signal.h> 48 #include <locale.h> 49 50 #define NULL_MSG ((struct msqid_ds *)NULL) 51 #define NULL_SEM ((struct semid_ds *)NULL) 52 #define NULL_SHM ((struct shmid_ds *)NULL) 53 54 #define USAGE "usage: ipcrm [-z zone] [ [-q msqid] [-m shmid] " \ 55 "[-s semid]\n\t [-Q msgkey] [-M shmkey] [-S semkey] ... ]\n" 56 57 #define IPC_KEYMATCH(perm, zoneid, key) \ 58 ((perm).ipcx_key == (key) && (perm).ipcx_zoneid == (zoneid)) 59 60 static char opts[] = "z:q:m:s:Q:M:S:"; /* allowable options for getopt */ 61 extern char *optarg; /* arg pointer for getopt */ 62 extern int optind; /* option index for getopt */ 63 64 static zoneid_t zoneid; 65 static int zflg; 66 67 static int *idlist, nids; 68 69 static void 70 oops(char *thing, char *arg) 71 { 72 char *e; 73 74 switch (errno) { 75 case ENOENT: /* key not found */ 76 case EINVAL: /* id not found */ 77 e = "not found"; 78 break; 79 80 case EPERM: 81 e = "permission denied"; 82 break; 83 default: 84 e = "unknown error"; 85 } 86 87 (void) fprintf(stderr, gettext("ipcrm: %s(%s): %s\n"), thing, arg, e); 88 } 89 90 /* convert string to numeric key */ 91 static key_t 92 getkey(char *kp) 93 { 94 key_t k; 95 char *tp; /* will point to char that terminates strtol scan */ 96 97 if ((k = (key_t)strtoul(kp, &tp, 0)) == IPC_PRIVATE || *tp != '\0') { 98 (void) fprintf(stderr, gettext("ipcrm: illegal key: %s\n"), 99 kp); 100 return (0); 101 } 102 return (k); 103 } 104 105 /* 106 * Gets list of all IPC ids (of a particular type) visible in the 107 * caller's zone. Returns number of ids retrieved. On return, idlist 108 * is set to point to an array of ids at least as large as the number 109 * retrieved. 110 */ 111 static uint_t 112 getids(int (*idsfunc)(int *, uint_t, uint_t *)) 113 { 114 uint_t n; 115 116 for (;;) { 117 if (idsfunc(idlist, nids, &n) != 0) 118 goto err; /* should never happen */ 119 if (n <= nids) 120 break; 121 idlist = realloc(idlist, (nids = n) * sizeof (int)); 122 if (idlist == NULL) 123 goto err; 124 } 125 return (n); 126 127 err: 128 perror("ipcrm"); 129 exit(1); 130 /* NOTREACHED */ 131 } 132 133 static int 134 msggetid(char *arg) 135 { 136 int id = atol(arg); 137 struct msqid_ds64 qds; 138 139 if (!zflg) 140 return (id); 141 142 if (msgctl64(id, IPC_STAT64, &qds) < 0) { 143 oops("msgctl", arg); 144 return (-1); 145 } 146 if (qds.msgx_perm.ipcx_zoneid != zoneid) { 147 /* 148 * Not in right zone, pretend the call failed. 149 * Message should be the same as that returned if 150 * msggetid succeeds but the subsequent IPC_RMID fails 151 * with EINVAL. 152 */ 153 errno = EINVAL; 154 oops("msgctl", arg); 155 return (-1); 156 } 157 return (id); 158 } 159 160 static int 161 msggetkey(char *kp) 162 { 163 key_t k; 164 int id, i; 165 uint_t n; 166 struct msqid_ds64 qds; 167 168 if ((k = getkey(kp)) == 0) 169 return (-1); 170 171 if (!zflg) { 172 /* lookup in local zone is simple */ 173 if ((id = msgget(k, 0)) == -1) 174 oops("msgget", kp); 175 return (id); 176 } 177 178 n = getids(msgids); 179 180 /* search for right key and zone combination */ 181 for (i = 0; i < n; i++) { 182 id = idlist[i]; 183 if (msgctl64(id, IPC_STAT64, &qds) < 0) 184 continue; 185 if (IPC_KEYMATCH(qds.msgx_perm, zoneid, k)) 186 return (id); /* found it, no need to look further */ 187 } 188 (void) fprintf(stderr, gettext("ipcrm: unknown key: %s\n"), kp); 189 return (-1); 190 } 191 192 static int 193 semgetid(char *arg) 194 { 195 int id = atol(arg); 196 struct semid_ds64 sds; 197 union semun { 198 int val; 199 struct semid_ds64 *buf; 200 ushort_t *array; 201 } semarg; 202 203 if (!zflg) 204 return (id); 205 206 semarg.buf = &sds; 207 if (semctl64(id, 0, IPC_STAT64, semarg) < 0) { 208 oops("semctl", arg); 209 return (-1); 210 } 211 if (sds.semx_perm.ipcx_zoneid != zoneid) { 212 /* 213 * Not in right zone, pretend the call failed. 214 * Message should be the same as that returned if 215 * semgetid succeeds but the subsequent IPC_RMID fails 216 * with EINVAL. 217 */ 218 errno = EINVAL; 219 oops("semctl", arg); 220 return (-1); 221 } 222 return (id); 223 } 224 225 static int 226 semgetkey(char *kp) 227 { 228 key_t k; 229 int id, i; 230 uint_t n; 231 struct semid_ds64 sds; 232 union semun { 233 int val; 234 struct semid_ds64 *buf; 235 ushort_t *array; 236 } semarg; 237 238 if ((k = getkey(kp)) == 0) 239 return (-1); 240 241 if (!zflg) { 242 /* lookup in local zone is simple */ 243 if ((id = semget(k, 0, 0)) == -1) 244 oops("semget", kp); 245 return (id); 246 } 247 248 n = getids(semids); 249 250 semarg.buf = &sds; 251 /* search for right key and zone combination */ 252 for (i = 0; i < n; i++) { 253 int id; 254 id = idlist[i]; 255 if (semctl64(id, 0, IPC_STAT64, semarg) < 0) 256 continue; 257 if (IPC_KEYMATCH(sds.semx_perm, zoneid, k)) 258 return (id); /* found it, no need to look further */ 259 } 260 261 (void) fprintf(stderr, gettext("ipcrm: unknown key: %s\n"), kp); 262 return (-1); 263 } 264 265 static int 266 shmgetid(char *arg) 267 { 268 int id = atol(arg); 269 struct shmid_ds64 mds; 270 271 if (!zflg) 272 return (id); 273 274 if (shmctl64(id, IPC_STAT64, &mds) < 0) { 275 oops("shmctl", arg); 276 return (-1); 277 } 278 if (mds.shmx_perm.ipcx_zoneid != zoneid) { 279 /* 280 * Not in right zone, pretend the call failed. 281 * Message should be the same as that returned if 282 * shmgetid succeeds but the subsequent IPC_RMID fails 283 * with EINVAL. 284 */ 285 errno = EINVAL; 286 oops("shmctl", arg); 287 return (-1); 288 } 289 return (id); 290 } 291 292 static int 293 shmgetkey(char *kp) 294 { 295 key_t k; 296 int id, i; 297 uint_t n; 298 struct shmid_ds64 mds; 299 300 if ((k = getkey(kp)) == 0) 301 return (-1); 302 303 if (!zflg) { 304 /* lookup in local zone is simple */ 305 if ((id = shmget(k, 0, 0)) == -1) 306 oops("shmget", kp); 307 return (id); 308 } 309 310 n = getids(shmids); 311 312 /* search for right key and zone combination */ 313 for (i = 0; i < n; i++) { 314 int id; 315 id = idlist[i]; 316 if (shmctl64(id, IPC_STAT64, &mds) < 0) 317 continue; 318 if (IPC_KEYMATCH(mds.shmx_perm, zoneid, k)) 319 return (id); /* found it, no need to look further */ 320 } 321 (void) fprintf(stderr, gettext("ipcrm: unknown key: %s\n"), kp); 322 return (-1); 323 } 324 325 326 /* convert string containing zone name or id to a numeric id */ 327 static zoneid_t 328 getzone(char *arg) 329 { 330 zoneid_t zoneid; 331 332 if (zone_get_id(arg, &zoneid) != 0) { 333 (void) fprintf(stderr, gettext("ipcrm: unknown zone: %s\n"), 334 arg); 335 exit(1); 336 } 337 return (zoneid); 338 } 339 340 int 341 main(int argc, char **argv) 342 { 343 int o; /* option flag */ 344 int err; /* error count */ 345 int ipc_id; /* id to remove */ 346 347 (void) setlocale(LC_ALL, ""); 348 (void) textdomain(TEXT_DOMAIN); 349 /* 350 * If one or more of the IPC modules is not 351 * included in the kernel, the corresponding 352 * system calls will incur SIGSYS. Ignoring 353 * that signal makes the system call appear 354 * to fail with errno == EINVAL, which can be 355 * interpreted appropriately in oops(). 356 */ 357 358 (void) signal(SIGSYS, SIG_IGN); 359 360 /* 361 * If no -z argument is specified, only objects in the current 362 * zone can be removed with keys. 363 */ 364 zoneid = getzoneid(); 365 366 /* 367 * Go through the options. The first pass looks only for -z 368 * since this option can affect the processing of keys. The 369 * second pass looks for the other options and ignores -z. 370 */ 371 err = 0; 372 while ((o = getopt(argc, argv, opts)) != EOF) { 373 switch (o) { 374 case 'z': 375 zflg++; 376 zoneid = getzone(optarg); 377 break; 378 379 case 'q': /* skip the rest of the flags */ 380 case 'm': 381 case 's': 382 case 'Q': 383 case 'M': 384 case 'S': 385 break; 386 387 case '?': /* anything else is an error */ 388 default: 389 err++; 390 break; 391 } 392 } 393 394 if (err || (optind < argc)) { 395 (void) fprintf(stderr, gettext(USAGE)); 396 return (err); 397 } 398 399 if (zflg > 1) { 400 (void) fprintf(stderr, 401 gettext("multiple -z options not allowed\n")); 402 (void) fprintf(stderr, gettext(USAGE)); 403 return (1); 404 } 405 406 optind = 1; /* rewind for pass 2 */ 407 while ((o = getopt(argc, argv, opts)) != EOF) { 408 switch (o) { 409 case 'z': /* zone identifier */ 410 break; 411 412 case 'q': /* message queue */ 413 if ((ipc_id = msggetid(optarg)) < 0) { 414 err++; 415 } else if (msgctl(ipc_id, IPC_RMID, NULL_MSG) == -1) { 416 oops("msgctl", optarg); 417 err++; 418 } 419 break; 420 421 case 'm': /* shared memory */ 422 if ((ipc_id = shmgetid(optarg)) < 0) { 423 err++; 424 } else if (shmctl(ipc_id, IPC_RMID, NULL_SHM) == -1) { 425 oops("shmctl", optarg); 426 err++; 427 } 428 break; 429 430 case 's': /* semaphores */ 431 if ((ipc_id = semgetid(optarg)) < 0) { 432 err++; 433 } else if (semctl(ipc_id, 0, IPC_RMID, NULL_SEM) == 434 -1) { 435 oops("semctl", optarg); 436 err++; 437 } 438 break; 439 440 case 'Q': /* message queue (by key) */ 441 if ((ipc_id = msggetkey(optarg)) == -1) { 442 err++; 443 break; 444 } 445 if (msgctl(ipc_id, IPC_RMID, NULL_MSG) == -1) { 446 oops("msgctl", optarg); 447 err++; 448 } 449 break; 450 451 case 'M': /* shared memory (by key) */ 452 if ((ipc_id = shmgetkey(optarg)) == -1) { 453 err++; 454 break; 455 } 456 if (shmctl(ipc_id, IPC_RMID, NULL_SHM) == -1) { 457 oops("shmctl", optarg); 458 err++; 459 } 460 break; 461 462 case 'S': /* semaphores (by key) */ 463 if ((ipc_id = semgetkey(optarg)) == -1) { 464 err++; 465 break; 466 } 467 if (semctl(ipc_id, 0, IPC_RMID, NULL_SEM) == -1) { 468 oops("semctl", optarg); 469 err++; 470 } 471 break; 472 } 473 } 474 return (err); 475 } 476