1 /* $NetBSD: linux_ipc.c,v 1.9 1995/10/08 22:49:29 fvdl Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Frank van der Linden 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Frank van der Linden 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/shm.h> 38 #include <sys/sem.h> 39 #include <sys/msg.h> 40 #include <sys/proc.h> 41 #include <sys/uio.h> 42 #include <sys/time.h> 43 #include <sys/malloc.h> 44 #include <sys/mman.h> 45 #include <sys/systm.h> 46 #include <sys/stat.h> 47 48 #include <sys/mount.h> 49 #include <sys/syscallargs.h> 50 51 #include <compat/linux/linux_types.h> 52 #include <compat/linux/linux_signal.h> 53 #include <compat/linux/linux_syscallargs.h> 54 #include <compat/linux/linux_util.h> 55 #include <compat/linux/linux_ipc.h> 56 #include <compat/linux/linux_msg.h> 57 #include <compat/linux/linux_shm.h> 58 #include <compat/linux/linux_sem.h> 59 #include <compat/linux/linux_ipccall.h> 60 61 /* 62 * Stuff to deal with the SysV ipc/shm/semaphore interface in Linux. 63 * The main difference is, that Linux handles it all via one 64 * system call, which has the usual maximum amount of 5 arguments. 65 * This results in a kludge for calls that take 6 of them. 66 * 67 * The SYSVXXXX options have to be enabled to get the appropriate 68 * functions to work. 69 */ 70 71 #ifdef SYSVSEM 72 static int linux_semop __P((struct proc *, struct linux_sys_ipc_args *, 73 register_t *)); 74 static int linux_semget __P((struct proc *, struct linux_sys_ipc_args *, 75 register_t *)); 76 static int linux_semctl __P((struct proc *, struct linux_sys_ipc_args *, 77 register_t *)); 78 #endif 79 80 #ifdef SYSVMSG 81 static int linux_msgsnd __P((struct proc *, struct linux_sys_ipc_args *, 82 register_t *)); 83 static int linux_msgrcv __P((struct proc *, struct linux_sys_ipc_args *, 84 register_t *)); 85 static int linux_msgop __P((struct proc *, struct linux_sys_ipc_args *, 86 register_t *)); 87 static int linux_msgctl __P((struct proc *, struct linux_sys_ipc_args *, 88 register_t *)); 89 #endif 90 91 #ifdef SYSVSHM 92 static int linux_shmat __P((struct proc *, struct linux_sys_ipc_args *, 93 register_t *)); 94 static int linux_shmdt __P((struct proc *, struct linux_sys_ipc_args *, 95 register_t *)); 96 static int linux_shmget __P((struct proc *, struct linux_sys_ipc_args *, 97 register_t *)); 98 static int linux_shmctl __P((struct proc *, struct linux_sys_ipc_args *, 99 register_t *)); 100 #endif 101 102 103 int 104 linux_sys_ipc(p, v, retval) 105 struct proc *p; 106 void *v; 107 register_t *retval; 108 { 109 struct linux_sys_ipc_args /* { 110 syscallarg(int) what; 111 syscallarg(int) a1; 112 syscallarg(int) a2; 113 syscallarg(int) a3; 114 syscallarg(caddr_t) ptr; 115 } */ *uap = v; 116 int what, error; 117 118 switch (SCARG(uap, what)) { 119 #ifdef SYSVSEM 120 case LINUX_SYS_semop: 121 return linux_semop(p, uap, retval); 122 case LINUX_SYS_semget: 123 return linux_semget(p, uap, retval); 124 case LINUX_SYS_semctl: 125 return linux_semctl(p, uap, retval); 126 #endif 127 #ifdef SYSVMSG 128 case LINUX_SYS_msgsnd: 129 return linux_msgsnd(p, uap, retval); 130 case LINUX_SYS_msgrcv: 131 return linux_msgrcv(p, uap, retval); 132 case LINUX_SYS_msgget: 133 return linux_msgget(p, uap, retval); 134 case LINUX_SYS_msgctl: 135 return linux_msgctl(p, uap, retval); 136 #endif 137 #ifdef SYSVSHM 138 case LINUX_SYS_shmat: 139 return linux_shmat(p, uap, retval); 140 case LINUX_SYS_shmdt: 141 return linux_shmdt(p, uap, retval); 142 case LINUX_SYS_shmget: 143 return linux_shmget(p, uap, retval); 144 case LINUX_SYS_shmctl: 145 return linux_shmctl(p, uap, retval); 146 #endif 147 default: 148 return ENOSYS; 149 } 150 } 151 152 /* 153 * Convert between Linux and NetBSD ipc_perm structures. Only the 154 * order of the fields is different. 155 */ 156 static void 157 linux_to_bsd_ipc_perm(lpp, bpp) 158 struct linux_ipc_perm *lpp; 159 struct ipc_perm *bpp; 160 { 161 162 bpp->key = lpp->l_key; 163 bpp->uid = lpp->l_uid; 164 bpp->gid = lpp->l_gid; 165 bpp->cuid = lpp->l_cuid; 166 bpp->cgid = lpp->l_cgid; 167 bpp->mode = lpp->l_mode; 168 bpp->seq = lpp->l_seq; 169 } 170 171 static void 172 bsd_to_linux_ipc_perm(bpp, lpp) 173 struct ipc_perm *bpp; 174 struct linux_ipc_perm *lpp; 175 { 176 177 lpp->l_key = bpp->key; 178 lpp->l_uid = bpp->uid; 179 lpp->l_gid = bpp->gid; 180 lpp->l_cuid = bpp->cuid; 181 lpp->l_cgid = bpp->cgid; 182 lpp->l_mode = bpp->mode; 183 lpp->l_seq = bpp->seq; 184 } 185 186 #ifdef SYSVSEM 187 /* 188 * Semaphore operations. Most constants and structures are the same on 189 * both systems. Only semctl() needs some extra work. 190 */ 191 192 /* 193 * Convert between Linux and NetBSD semid_ds structures. 194 */ 195 static void 196 bsd_to_linux_semid_ds(bs, ls) 197 struct semid_ds *bs; 198 struct linux_semid_ds *ls; 199 { 200 201 bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm); 202 ls->l_sem_otime = bs->sem_otime; 203 ls->l_sem_ctime = bs->sem_ctime; 204 ls->l_sem_nsems = bs->sem_nsems; 205 ls->l_sem_base = bs->sem_base; 206 } 207 208 static void 209 linux_to_bsd_semid_ds(ls, bs) 210 struct linux_semid_ds *ls; 211 struct semid_ds *bs; 212 { 213 214 linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm); 215 bs->sem_otime = ls->l_sem_otime; 216 bs->sem_ctime = ls->l_sem_ctime; 217 bs->sem_nsems = ls->l_sem_nsems; 218 bs->sem_base = ls->l_sem_base; 219 } 220 221 int 222 linux_semop(p, uap, retval) 223 struct proc *p; 224 struct linux_sys_ipc_args /* { 225 syscallarg(int) what; 226 syscallarg(int) a1; 227 syscallarg(int) a2; 228 syscallarg(int) a3; 229 syscallarg(caddr_t) ptr; 230 } */ *uap; 231 register_t *retval; 232 { 233 struct sys_semop_args bsa; 234 235 SCARG(&bsa, semid) = SCARG(uap, a1); 236 SCARG(&bsa, sops) = (struct sembuf *)SCARG(uap, ptr); 237 SCARG(&bsa, nsops) = SCARG(uap, a2); 238 239 return sys_semop(p, &bsa, retval); 240 } 241 242 int 243 linux_semget(p, uap, retval) 244 struct proc *p; 245 struct linux_sys_ipc_args /* { 246 syscallarg(int) what; 247 syscallarg(int) a1; 248 syscallarg(int) a2; 249 syscallarg(int) a3; 250 syscallarg(caddr_t) ptr; 251 } */ *uap; 252 register_t *retval; 253 { 254 struct sys_semget_args bsa; 255 256 SCARG(&bsa, key) = (key_t)SCARG(uap, a1); 257 SCARG(&bsa, nsems) = SCARG(uap, a2); 258 SCARG(&bsa, semflg) = SCARG(uap, a3); 259 260 return sys_semget(p, &bsa, retval); 261 } 262 263 /* 264 * Most of this can be handled by directly passing the arguments on, 265 * buf IPC_* require a lot of copy{in,out} because of the extra indirection 266 * (we are passed a pointer to a union cointaining a pointer to a semid_ds 267 * structure. 268 */ 269 int 270 linux_semctl(p, uap, retval) 271 struct proc *p; 272 struct linux_sys_ipc_args /* { 273 syscallarg(int) what; 274 syscallarg(int) a1; 275 syscallarg(int) a2; 276 syscallarg(int) a3; 277 syscallarg(caddr_t) ptr; 278 } */ *uap; 279 register_t *retval; 280 { 281 caddr_t sg, unptr, dsp, ldsp; 282 int error, cmd; 283 struct sys___semctl_args bsa; 284 struct linux_semid_ds lm; 285 struct semid_ds bm; 286 287 SCARG(&bsa, semid) = SCARG(uap, a1); 288 SCARG(&bsa, semnum) = SCARG(uap, a2); 289 SCARG(&bsa, cmd) = SCARG(uap, a3); 290 SCARG(&bsa, arg) = (union semun *)SCARG(uap, ptr); 291 switch(SCARG(uap, a3)) { 292 case LINUX_GETVAL: 293 cmd = GETVAL; 294 break; 295 case LINUX_GETPID: 296 cmd = GETPID; 297 break; 298 case LINUX_GETNCNT: 299 cmd = GETNCNT; 300 break; 301 case LINUX_GETZCNT: 302 cmd = GETZCNT; 303 break; 304 case LINUX_SETVAL: 305 cmd = SETVAL; 306 break; 307 case LINUX_IPC_RMID: 308 cmd = IPC_RMID; 309 break; 310 case LINUX_IPC_SET: 311 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp))) 312 return error; 313 if ((error = copyin(ldsp, (caddr_t)&lm, sizeof lm))) 314 return error; 315 linux_to_bsd_semid_ds(&lm, &bm); 316 sg = stackgap_init(p->p_emul); 317 unptr = stackgap_alloc(&sg, sizeof (union semun)); 318 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 319 if ((error = copyout((caddr_t)&bm, dsp, sizeof bm))) 320 return error; 321 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp))) 322 return error; 323 SCARG(&bsa, arg) = (union semun *)unptr; 324 return sys___semctl(p, &bsa, retval); 325 case LINUX_IPC_STAT: 326 sg = stackgap_init(p->p_emul); 327 unptr = stackgap_alloc(&sg, sizeof (union semun *)); 328 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 329 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp))) 330 return error; 331 SCARG(&bsa, arg) = (union semun *)unptr; 332 if ((error = sys___semctl(p, &bsa, retval))) 333 return error; 334 if ((error = copyin(dsp, (caddr_t)&bm, sizeof bm))) 335 return error; 336 bsd_to_linux_semid_ds(&bm, &lm); 337 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp))) 338 return error; 339 return copyout((caddr_t)&lm, ldsp, sizeof lm); 340 default: 341 return EINVAL; 342 } 343 SCARG(&bsa, cmd) = cmd; 344 345 return sys___semctl(p, &bsa, retval); 346 } 347 #endif /* SYSVSEM */ 348 349 #ifdef SYSVMSG 350 351 static void 352 linux_to_bsd_msqid_ds(lmp, bmp) 353 struct linux_msqid_ds *lmp; 354 struct msqid_ds *bmp; 355 { 356 357 linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm); 358 bmp->msg_first = lmp->l_msg_first; 359 bmp->msg_last = lmp->l_msg_last; 360 bmp->msg_cbytes = lmp->l_msg_cbytes; 361 bmp->msg_qnum = lmp->l_msg_qnum; 362 bmp->msg_qbytes = lmp->l_msg_qbytes; 363 bmp->msg_lspid = lmp->l_msg_lspid; 364 bmp->msg_lrpid = lmp->l_msg_lrpid; 365 bmp->msg_stime = lmp->l_msg_stime; 366 bmp->msg_rtime = lmp->l_msg_rtime; 367 bmp->msg_ctime = lmp->l_msg_ctime; 368 } 369 370 static void 371 bsd_to_linux_msqid_ds(bmp, lmp) 372 struct msqid_ds *bmp; 373 struct linux_msqid_ds *lmp; 374 { 375 376 bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm); 377 lmp->l_msg_first = bmp->msg_first; 378 lmp->l_msg_last = bmp->msg_last; 379 lmp->l_msg_cbytes = bmp->msg_cbytes; 380 lmp->l_msg_qnum = bmp->msg_qnum; 381 lmp->l_msg_qbytes = bmp->msg_qbytes; 382 lmp->l_msg_lspid = bmp->msg_lspid; 383 lmp->l_msg_lrpid = bmp->msg_lrpid; 384 lmp->l_msg_stime = bmp->msg_stime; 385 lmp->l_msg_rtime = bmp->msg_rtime; 386 lmp->l_msg_ctime = bmp->msg_ctime; 387 } 388 389 int 390 linux_msgsnd(p, uap, retval) 391 struct proc *p; 392 struct linux_sys_ipc_args /* { 393 syscallarg(int) what; 394 syscallarg(int) a1; 395 syscallarg(int) a2; 396 syscallarg(int) a3; 397 syscallarg(caddr_t) ptr; 398 } */ *uap; 399 register_t *retval; 400 { 401 struct sys_msgsnd_args bma; 402 403 SCARG(&bma, msqid) = SCARG(uap, a1); 404 SCARG(&bma, msgp) = SCARG(uap, ptr); 405 SCARG(&bma, msgsz) = SCARG(uap, a2); 406 SCARG(&bma, msgflg) = SCARG(uap, a3); 407 408 return sys_msgsnd(p, &bma, retval); 409 } 410 411 int 412 linux_msgrcv(p, uap, retval) 413 struct proc *p; 414 struct linux_sys_ipc_args /* { 415 syscallarg(int) what; 416 syscallarg(int) a1; 417 syscallarg(int) a2; 418 syscallarg(int) a3; 419 syscallarg(caddr_t) ptr; 420 } */ *uap; 421 register_t *retval; 422 { 423 struct sys_msgrcv_args bma; 424 struct linux_msgrcv_msgarg kluge; 425 int error; 426 427 if ((error = copyin(SCARG(uap, ptr), &kluge, sizeof kluge))) 428 return error; 429 430 SCARG(&bma, msqid) = SCARG(uap, a1); 431 SCARG(&bma, msgp) = kluge.msg; 432 SCARG(&bma, msgsz) = SCARG(uap, a2); 433 SCARG(&bma, msgtyp) = kluge.type; 434 SCARG(&bma, msgflg) = SCARG(uap, a3); 435 436 return sys_msgrcv(p, &bma, retval); 437 } 438 439 int 440 linux_msgget(p, uap, retval) 441 struct proc *p; 442 struct linux_sys_ipc_args /* { 443 syscallarg(int) what; 444 syscallarg(int) a1; 445 syscallarg(int) a2; 446 syscallarg(int) a3; 447 syscallarg(caddr_t) ptr; 448 } */ *uap; 449 register_t *retval; 450 { 451 struct sys_msgget_args bma; 452 453 SCARG(&bma, key) = (key_t)SCARG(uap, a1); 454 SCARG(&bma, msgflg) = SCARG(uap, a2); 455 456 return sys_msgget(p, &bma, retval); 457 } 458 459 int 460 linux_msgctl(p, uap, retval) 461 struct proc *p; 462 struct linux_sys_ipc_args /* { 463 syscallarg(int) what; 464 syscallarg(int) a1; 465 syscallarg(int) a2; 466 syscallarg(int) a3; 467 syscallarg(caddr_t) ptr; 468 } */ *uap; 469 register_t *retval; 470 { 471 struct sys_msgctl_args bma; 472 caddr_t umsgptr, sg; 473 struct linux_msqid_ds lm; 474 struct msqid_ds bm; 475 int error; 476 477 SCARG(&bma, msqid) = SCARG(uap, a1); 478 SCARG(&bma, cmd) = SCARG(uap, a2); 479 switch (SCARG(uap, a2)) { 480 case LINUX_IPC_RMID: 481 return sys_msgctl(p, &bma, retval); 482 case LINUX_IPC_SET: 483 if ((error = copyin(SCARG(uap, ptr), (caddr_t)&lm, sizeof lm))) 484 return error; 485 linux_to_bsd_msqid_ds(&lm, &bm); 486 sg = stackgap_init(p->p_emul); 487 umsgptr = stackgap_alloc(&sg, sizeof bm); 488 if ((error = copyout((caddr_t)&bm, umsgptr, sizeof bm))) 489 return error; 490 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr; 491 return sys_msgctl(p, &bma, retval); 492 case LINUX_IPC_STAT: 493 sg = stackgap_init(p->p_emul); 494 umsgptr = stackgap_alloc(&sg, sizeof (struct msqid_ds)); 495 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr; 496 if ((error = sys_msgctl(p, &bma, retval))) 497 return error; 498 if ((error = copyin(umsgptr, (caddr_t)&bm, sizeof bm))) 499 return error; 500 bsd_to_linux_msqid_ds(&bm, &lm); 501 return copyout((caddr_t)&lm, SCARG(uap, ptr), sizeof lm); 502 } 503 return EINVAL; 504 } 505 #endif /* SYSVMSG */ 506 507 #ifdef SYSVSHM 508 /* 509 * shmat(2). Very straightforward, except that Linux passes a pointer 510 * in which the return value is to be passed. This is subsequently 511 * handled by libc, apparently. 512 */ 513 int 514 linux_shmat(p, uap, retval) 515 struct proc *p; 516 struct linux_sys_ipc_args /* { 517 syscallarg(int) what; 518 syscallarg(int) a1; 519 syscallarg(int) a2; 520 syscallarg(int) a3; 521 syscallarg(caddr_t) ptr; 522 } */ *uap; 523 register_t *retval; 524 { 525 struct sys_shmat_args bsa; 526 int error; 527 528 SCARG(&bsa, shmid) = SCARG(uap, a1); 529 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 530 SCARG(&bsa, shmflg) = SCARG(uap, a2); 531 532 if ((error = sys_shmat(p, &bsa, retval))) 533 return error; 534 535 if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, a3), 536 sizeof retval[0]))) 537 return error; 538 539 retval[0] = 0; 540 return 0; 541 } 542 543 /* 544 * shmdt(): this could have been mapped directly, if it wasn't for 545 * the extra indirection by the linux_ipc system call. 546 */ 547 int 548 linux_shmdt(p, uap, retval) 549 struct proc *p; 550 struct linux_sys_ipc_args /* { 551 syscallarg(int) what; 552 syscallarg(int) a1; 553 syscallarg(int) a2; 554 syscallarg(int) a3; 555 syscallarg(caddr_t) ptr; 556 } */ *uap; 557 register_t *retval; 558 { 559 struct sys_shmdt_args bsa; 560 561 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 562 563 return sys_shmdt(p, &bsa, retval); 564 } 565 566 /* 567 * Same story as shmdt. 568 */ 569 int 570 linux_shmget(p, uap, retval) 571 struct proc *p; 572 struct linux_sys_ipc_args /* { 573 syscallarg(int) what; 574 syscallarg(int) a1; 575 syscallarg(int) a2; 576 syscallarg(int) a3; 577 syscallarg(caddr_t) ptr; 578 } */ *uap; 579 register_t *retval; 580 { 581 struct sys_shmget_args bsa; 582 583 SCARG(&bsa, key) = SCARG(uap, a1); 584 SCARG(&bsa, size) = SCARG(uap, a2); 585 SCARG(&bsa, shmflg) = SCARG(uap, a3); 586 587 return sys_shmget(p, &bsa, retval); 588 } 589 590 /* 591 * Convert between Linux and NetBSD shmid_ds structures. 592 * The order of the fields is once again the difference, and 593 * we also need a place to store the internal data pointer 594 * in, which is unfortunately stored in this structure. 595 * 596 * We abuse a Linux internal field for that. 597 */ 598 static void 599 linux_to_bsd_shmid_ds(lsp, bsp) 600 struct linux_shmid_ds *lsp; 601 struct shmid_ds *bsp; 602 { 603 604 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 605 bsp->shm_segsz = lsp->l_shm_segsz; 606 bsp->shm_lpid = lsp->l_shm_lpid; 607 bsp->shm_cpid = lsp->l_shm_cpid; 608 bsp->shm_nattch = lsp->l_shm_nattch; 609 bsp->shm_atime = lsp->l_shm_atime; 610 bsp->shm_dtime = lsp->l_shm_dtime; 611 bsp->shm_ctime = lsp->l_shm_ctime; 612 bsp->shm_internal = lsp->l_private2; /* XXX Oh well. */ 613 } 614 615 static void 616 bsd_to_linux_shmid_ds(bsp, lsp) 617 struct shmid_ds *bsp; 618 struct linux_shmid_ds *lsp; 619 { 620 621 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 622 lsp->l_shm_segsz = bsp->shm_segsz; 623 lsp->l_shm_lpid = bsp->shm_lpid; 624 lsp->l_shm_cpid = bsp->shm_cpid; 625 lsp->l_shm_nattch = bsp->shm_nattch; 626 lsp->l_shm_atime = bsp->shm_atime; 627 lsp->l_shm_dtime = bsp->shm_dtime; 628 lsp->l_shm_ctime = bsp->shm_ctime; 629 lsp->l_private2 = bsp->shm_internal; /* XXX */ 630 } 631 632 /* 633 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT 634 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented 635 * by NetBSD itself. 636 * 637 * The usual structure conversion and massaging is done. 638 */ 639 int 640 linux_shmctl(p, uap, retval) 641 struct proc *p; 642 struct linux_sys_ipc_args /* { 643 syscallarg(int) what; 644 syscallarg(int) a1; 645 syscallarg(int) a2; 646 syscallarg(int) a3; 647 syscallarg(caddr_t) ptr; 648 } */ *uap; 649 register_t *retval; 650 { 651 int error; 652 caddr_t sg; 653 struct sys_shmctl_args bsa; 654 struct shmid_ds *bsp, bs; 655 struct linux_shmid_ds lseg; 656 657 switch (SCARG(uap, a2)) { 658 case LINUX_IPC_STAT: 659 sg = stackgap_init(p->p_emul); 660 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 661 SCARG(&bsa, shmid) = SCARG(uap, a1); 662 SCARG(&bsa, cmd) = IPC_STAT; 663 SCARG(&bsa, buf) = bsp; 664 if ((error = sys_shmctl(p, &bsa, retval))) 665 return error; 666 if ((error = copyin((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 667 return error; 668 bsd_to_linux_shmid_ds(&bs, &lseg); 669 return copyout((caddr_t) &lseg, SCARG(uap, ptr), sizeof lseg); 670 case LINUX_IPC_SET: 671 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg, 672 sizeof lseg))) 673 return error; 674 linux_to_bsd_shmid_ds(&lseg, &bs); 675 sg = stackgap_init(p->p_emul); 676 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 677 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 678 return error; 679 SCARG(&bsa, shmid) = SCARG(uap, a1); 680 SCARG(&bsa, cmd) = IPC_SET; 681 SCARG(&bsa, buf) = bsp; 682 return sys_shmctl(p, &bsa, retval); 683 case LINUX_IPC_RMID: 684 case LINUX_SHM_LOCK: 685 case LINUX_SHM_UNLOCK: 686 SCARG(&bsa, shmid) = SCARG(uap, a1); 687 switch (SCARG(uap, a2)) { 688 case LINUX_IPC_RMID: 689 SCARG(&bsa, cmd) = IPC_RMID; 690 break; 691 case LINUX_SHM_LOCK: 692 SCARG(&bsa, cmd) = SHM_LOCK; 693 break; 694 case LINUX_SHM_UNLOCK: 695 SCARG(&bsa, cmd) = SHM_UNLOCK; 696 break; 697 } 698 SCARG(&bsa, buf) = NULL; 699 return sys_shmctl(p, &bsa, retval); 700 case LINUX_IPC_INFO: 701 case LINUX_SHM_STAT: 702 case LINUX_SHM_INFO: 703 default: 704 return EINVAL; 705 } 706 } 707 #endif /* SYSVSHM */ 708