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