1 /* $NetBSD: linux_ipccall.c,v 1.10 1996/04/05 00:01:44 christos 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 static void bsd_to_linux_semid_ds __P((struct semid_ds *, 79 struct linux_semid_ds *)); 80 static void linux_to_bsd_semid_ds __P((struct linux_semid_ds *, 81 struct semid_ds *)); 82 #endif 83 84 #ifdef SYSVMSG 85 static int linux_msgsnd __P((struct proc *, struct linux_sys_ipc_args *, 86 register_t *)); 87 static int linux_msgrcv __P((struct proc *, struct linux_sys_ipc_args *, 88 register_t *)); 89 static int linux_msgget __P((struct proc *, struct linux_sys_ipc_args *, 90 register_t *)); 91 static int linux_msgctl __P((struct proc *, struct linux_sys_ipc_args *, 92 register_t *)); 93 static void linux_to_bsd_msqid_ds __P((struct linux_msqid_ds *, 94 struct msqid_ds *)); 95 static void bsd_to_linux_msqid_ds __P((struct msqid_ds *, 96 struct linux_msqid_ds *)); 97 #endif 98 99 #ifdef SYSVSHM 100 static int linux_shmat __P((struct proc *, struct linux_sys_ipc_args *, 101 register_t *)); 102 static int linux_shmdt __P((struct proc *, struct linux_sys_ipc_args *, 103 register_t *)); 104 static int linux_shmget __P((struct proc *, struct linux_sys_ipc_args *, 105 register_t *)); 106 static int linux_shmctl __P((struct proc *, struct linux_sys_ipc_args *, 107 register_t *)); 108 static void linux_to_bsd_shmid_ds __P((struct linux_shmid_ds *, 109 struct shmid_ds *)); 110 static void bsd_to_linux_shmid_ds __P((struct shmid_ds *, 111 struct linux_shmid_ds *)); 112 #endif 113 114 115 static void linux_to_bsd_ipc_perm __P((struct linux_ipc_perm *, 116 struct ipc_perm *)); 117 static void bsd_to_linux_ipc_perm __P((struct ipc_perm *, 118 struct linux_ipc_perm *)); 119 120 int 121 linux_sys_ipc(p, v, retval) 122 struct proc *p; 123 void *v; 124 register_t *retval; 125 { 126 struct linux_sys_ipc_args /* { 127 syscallarg(int) what; 128 syscallarg(int) a1; 129 syscallarg(int) a2; 130 syscallarg(int) a3; 131 syscallarg(caddr_t) ptr; 132 } */ *uap = v; 133 134 switch (SCARG(uap, what)) { 135 #ifdef SYSVSEM 136 case LINUX_SYS_semop: 137 return linux_semop(p, uap, retval); 138 case LINUX_SYS_semget: 139 return linux_semget(p, uap, retval); 140 case LINUX_SYS_semctl: 141 return linux_semctl(p, uap, retval); 142 #endif 143 #ifdef SYSVMSG 144 case LINUX_SYS_msgsnd: 145 return linux_msgsnd(p, uap, retval); 146 case LINUX_SYS_msgrcv: 147 return linux_msgrcv(p, uap, retval); 148 case LINUX_SYS_msgget: 149 return linux_msgget(p, uap, retval); 150 case LINUX_SYS_msgctl: 151 return linux_msgctl(p, uap, retval); 152 #endif 153 #ifdef SYSVSHM 154 case LINUX_SYS_shmat: 155 return linux_shmat(p, uap, retval); 156 case LINUX_SYS_shmdt: 157 return linux_shmdt(p, uap, retval); 158 case LINUX_SYS_shmget: 159 return linux_shmget(p, uap, retval); 160 case LINUX_SYS_shmctl: 161 return linux_shmctl(p, uap, retval); 162 #endif 163 default: 164 return ENOSYS; 165 } 166 } 167 168 /* 169 * Convert between Linux and NetBSD ipc_perm structures. Only the 170 * order of the fields is different. 171 */ 172 static void 173 linux_to_bsd_ipc_perm(lpp, bpp) 174 struct linux_ipc_perm *lpp; 175 struct ipc_perm *bpp; 176 { 177 178 bpp->key = lpp->l_key; 179 bpp->uid = lpp->l_uid; 180 bpp->gid = lpp->l_gid; 181 bpp->cuid = lpp->l_cuid; 182 bpp->cgid = lpp->l_cgid; 183 bpp->mode = lpp->l_mode; 184 bpp->seq = lpp->l_seq; 185 } 186 187 static void 188 bsd_to_linux_ipc_perm(bpp, lpp) 189 struct ipc_perm *bpp; 190 struct linux_ipc_perm *lpp; 191 { 192 193 lpp->l_key = bpp->key; 194 lpp->l_uid = bpp->uid; 195 lpp->l_gid = bpp->gid; 196 lpp->l_cuid = bpp->cuid; 197 lpp->l_cgid = bpp->cgid; 198 lpp->l_mode = bpp->mode; 199 lpp->l_seq = bpp->seq; 200 } 201 202 #ifdef SYSVSEM 203 /* 204 * Semaphore operations. Most constants and structures are the same on 205 * both systems. Only semctl() needs some extra work. 206 */ 207 208 /* 209 * Convert between Linux and NetBSD semid_ds structures. 210 */ 211 static void 212 bsd_to_linux_semid_ds(bs, ls) 213 struct semid_ds *bs; 214 struct linux_semid_ds *ls; 215 { 216 217 bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm); 218 ls->l_sem_otime = bs->sem_otime; 219 ls->l_sem_ctime = bs->sem_ctime; 220 ls->l_sem_nsems = bs->sem_nsems; 221 ls->l_sem_base = bs->sem_base; 222 } 223 224 static void 225 linux_to_bsd_semid_ds(ls, bs) 226 struct linux_semid_ds *ls; 227 struct semid_ds *bs; 228 { 229 230 linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm); 231 bs->sem_otime = ls->l_sem_otime; 232 bs->sem_ctime = ls->l_sem_ctime; 233 bs->sem_nsems = ls->l_sem_nsems; 234 bs->sem_base = ls->l_sem_base; 235 } 236 237 int 238 linux_semop(p, uap, retval) 239 struct proc *p; 240 struct linux_sys_ipc_args /* { 241 syscallarg(int) what; 242 syscallarg(int) a1; 243 syscallarg(int) a2; 244 syscallarg(int) a3; 245 syscallarg(caddr_t) ptr; 246 } */ *uap; 247 register_t *retval; 248 { 249 struct sys_semop_args bsa; 250 251 SCARG(&bsa, semid) = SCARG(uap, a1); 252 SCARG(&bsa, sops) = (struct sembuf *)SCARG(uap, ptr); 253 SCARG(&bsa, nsops) = SCARG(uap, a2); 254 255 return sys_semop(p, &bsa, retval); 256 } 257 258 int 259 linux_semget(p, uap, retval) 260 struct proc *p; 261 struct linux_sys_ipc_args /* { 262 syscallarg(int) what; 263 syscallarg(int) a1; 264 syscallarg(int) a2; 265 syscallarg(int) a3; 266 syscallarg(caddr_t) ptr; 267 } */ *uap; 268 register_t *retval; 269 { 270 struct sys_semget_args bsa; 271 272 SCARG(&bsa, key) = (key_t)SCARG(uap, a1); 273 SCARG(&bsa, nsems) = SCARG(uap, a2); 274 SCARG(&bsa, semflg) = SCARG(uap, a3); 275 276 return sys_semget(p, &bsa, retval); 277 } 278 279 /* 280 * Most of this can be handled by directly passing the arguments on, 281 * buf IPC_* require a lot of copy{in,out} because of the extra indirection 282 * (we are passed a pointer to a union cointaining a pointer to a semid_ds 283 * structure. 284 */ 285 int 286 linux_semctl(p, uap, retval) 287 struct proc *p; 288 struct linux_sys_ipc_args /* { 289 syscallarg(int) what; 290 syscallarg(int) a1; 291 syscallarg(int) a2; 292 syscallarg(int) a3; 293 syscallarg(caddr_t) ptr; 294 } */ *uap; 295 register_t *retval; 296 { 297 caddr_t sg, unptr, dsp, ldsp; 298 int error, cmd; 299 struct sys___semctl_args bsa; 300 struct linux_semid_ds lm; 301 struct semid_ds bm; 302 303 SCARG(&bsa, semid) = SCARG(uap, a1); 304 SCARG(&bsa, semnum) = SCARG(uap, a2); 305 SCARG(&bsa, cmd) = SCARG(uap, a3); 306 SCARG(&bsa, arg) = (union semun *)SCARG(uap, ptr); 307 switch(SCARG(uap, a3)) { 308 case LINUX_GETVAL: 309 cmd = GETVAL; 310 break; 311 case LINUX_GETPID: 312 cmd = GETPID; 313 break; 314 case LINUX_GETNCNT: 315 cmd = GETNCNT; 316 break; 317 case LINUX_GETZCNT: 318 cmd = GETZCNT; 319 break; 320 case LINUX_SETVAL: 321 cmd = SETVAL; 322 break; 323 case LINUX_IPC_RMID: 324 cmd = IPC_RMID; 325 break; 326 case LINUX_IPC_SET: 327 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp))) 328 return error; 329 if ((error = copyin(ldsp, (caddr_t)&lm, sizeof lm))) 330 return error; 331 linux_to_bsd_semid_ds(&lm, &bm); 332 sg = stackgap_init(p->p_emul); 333 unptr = stackgap_alloc(&sg, sizeof (union semun)); 334 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 335 if ((error = copyout((caddr_t)&bm, dsp, sizeof bm))) 336 return error; 337 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp))) 338 return error; 339 SCARG(&bsa, arg) = (union semun *)unptr; 340 return sys___semctl(p, &bsa, retval); 341 case LINUX_IPC_STAT: 342 sg = stackgap_init(p->p_emul); 343 unptr = stackgap_alloc(&sg, sizeof (union semun *)); 344 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 345 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp))) 346 return error; 347 SCARG(&bsa, arg) = (union semun *)unptr; 348 if ((error = sys___semctl(p, &bsa, retval))) 349 return error; 350 if ((error = copyin(dsp, (caddr_t)&bm, sizeof bm))) 351 return error; 352 bsd_to_linux_semid_ds(&bm, &lm); 353 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp))) 354 return error; 355 return copyout((caddr_t)&lm, ldsp, sizeof lm); 356 default: 357 return EINVAL; 358 } 359 SCARG(&bsa, cmd) = cmd; 360 361 return sys___semctl(p, &bsa, retval); 362 } 363 #endif /* SYSVSEM */ 364 365 #ifdef SYSVMSG 366 367 static void 368 linux_to_bsd_msqid_ds(lmp, bmp) 369 struct linux_msqid_ds *lmp; 370 struct msqid_ds *bmp; 371 { 372 373 linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm); 374 bmp->msg_first = lmp->l_msg_first; 375 bmp->msg_last = lmp->l_msg_last; 376 bmp->msg_cbytes = lmp->l_msg_cbytes; 377 bmp->msg_qnum = lmp->l_msg_qnum; 378 bmp->msg_qbytes = lmp->l_msg_qbytes; 379 bmp->msg_lspid = lmp->l_msg_lspid; 380 bmp->msg_lrpid = lmp->l_msg_lrpid; 381 bmp->msg_stime = lmp->l_msg_stime; 382 bmp->msg_rtime = lmp->l_msg_rtime; 383 bmp->msg_ctime = lmp->l_msg_ctime; 384 } 385 386 static void 387 bsd_to_linux_msqid_ds(bmp, lmp) 388 struct msqid_ds *bmp; 389 struct linux_msqid_ds *lmp; 390 { 391 392 bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm); 393 lmp->l_msg_first = bmp->msg_first; 394 lmp->l_msg_last = bmp->msg_last; 395 lmp->l_msg_cbytes = bmp->msg_cbytes; 396 lmp->l_msg_qnum = bmp->msg_qnum; 397 lmp->l_msg_qbytes = bmp->msg_qbytes; 398 lmp->l_msg_lspid = bmp->msg_lspid; 399 lmp->l_msg_lrpid = bmp->msg_lrpid; 400 lmp->l_msg_stime = bmp->msg_stime; 401 lmp->l_msg_rtime = bmp->msg_rtime; 402 lmp->l_msg_ctime = bmp->msg_ctime; 403 } 404 405 static int 406 linux_msgsnd(p, uap, retval) 407 struct proc *p; 408 struct linux_sys_ipc_args /* { 409 syscallarg(int) what; 410 syscallarg(int) a1; 411 syscallarg(int) a2; 412 syscallarg(int) a3; 413 syscallarg(caddr_t) ptr; 414 } */ *uap; 415 register_t *retval; 416 { 417 struct sys_msgsnd_args bma; 418 419 SCARG(&bma, msqid) = SCARG(uap, a1); 420 SCARG(&bma, msgp) = SCARG(uap, ptr); 421 SCARG(&bma, msgsz) = SCARG(uap, a2); 422 SCARG(&bma, msgflg) = SCARG(uap, a3); 423 424 return sys_msgsnd(p, &bma, retval); 425 } 426 427 static int 428 linux_msgrcv(p, uap, retval) 429 struct proc *p; 430 struct linux_sys_ipc_args /* { 431 syscallarg(int) what; 432 syscallarg(int) a1; 433 syscallarg(int) a2; 434 syscallarg(int) a3; 435 syscallarg(caddr_t) ptr; 436 } */ *uap; 437 register_t *retval; 438 { 439 struct sys_msgrcv_args bma; 440 struct linux_msgrcv_msgarg kluge; 441 int error; 442 443 if ((error = copyin(SCARG(uap, ptr), &kluge, sizeof kluge))) 444 return error; 445 446 SCARG(&bma, msqid) = SCARG(uap, a1); 447 SCARG(&bma, msgp) = kluge.msg; 448 SCARG(&bma, msgsz) = SCARG(uap, a2); 449 SCARG(&bma, msgtyp) = kluge.type; 450 SCARG(&bma, msgflg) = SCARG(uap, a3); 451 452 return sys_msgrcv(p, &bma, retval); 453 } 454 455 static int 456 linux_msgget(p, uap, retval) 457 struct proc *p; 458 struct linux_sys_ipc_args /* { 459 syscallarg(int) what; 460 syscallarg(int) a1; 461 syscallarg(int) a2; 462 syscallarg(int) a3; 463 syscallarg(caddr_t) ptr; 464 } */ *uap; 465 register_t *retval; 466 { 467 struct sys_msgget_args bma; 468 469 SCARG(&bma, key) = (key_t)SCARG(uap, a1); 470 SCARG(&bma, msgflg) = SCARG(uap, a2); 471 472 return sys_msgget(p, &bma, retval); 473 } 474 475 static int 476 linux_msgctl(p, uap, retval) 477 struct proc *p; 478 struct linux_sys_ipc_args /* { 479 syscallarg(int) what; 480 syscallarg(int) a1; 481 syscallarg(int) a2; 482 syscallarg(int) a3; 483 syscallarg(caddr_t) ptr; 484 } */ *uap; 485 register_t *retval; 486 { 487 struct sys_msgctl_args bma; 488 caddr_t umsgptr, sg; 489 struct linux_msqid_ds lm; 490 struct msqid_ds bm; 491 int error; 492 493 SCARG(&bma, msqid) = SCARG(uap, a1); 494 SCARG(&bma, cmd) = SCARG(uap, a2); 495 switch (SCARG(uap, a2)) { 496 case LINUX_IPC_RMID: 497 return sys_msgctl(p, &bma, retval); 498 case LINUX_IPC_SET: 499 if ((error = copyin(SCARG(uap, ptr), (caddr_t)&lm, sizeof lm))) 500 return error; 501 linux_to_bsd_msqid_ds(&lm, &bm); 502 sg = stackgap_init(p->p_emul); 503 umsgptr = stackgap_alloc(&sg, sizeof bm); 504 if ((error = copyout((caddr_t)&bm, umsgptr, sizeof bm))) 505 return error; 506 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr; 507 return sys_msgctl(p, &bma, retval); 508 case LINUX_IPC_STAT: 509 sg = stackgap_init(p->p_emul); 510 umsgptr = stackgap_alloc(&sg, sizeof (struct msqid_ds)); 511 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr; 512 if ((error = sys_msgctl(p, &bma, retval))) 513 return error; 514 if ((error = copyin(umsgptr, (caddr_t)&bm, sizeof bm))) 515 return error; 516 bsd_to_linux_msqid_ds(&bm, &lm); 517 return copyout((caddr_t)&lm, SCARG(uap, ptr), sizeof lm); 518 } 519 return EINVAL; 520 } 521 #endif /* SYSVMSG */ 522 523 #ifdef SYSVSHM 524 /* 525 * shmat(2). Very straightforward, except that Linux passes a pointer 526 * in which the return value is to be passed. This is subsequently 527 * handled by libc, apparently. 528 */ 529 static int 530 linux_shmat(p, uap, retval) 531 struct proc *p; 532 struct linux_sys_ipc_args /* { 533 syscallarg(int) what; 534 syscallarg(int) a1; 535 syscallarg(int) a2; 536 syscallarg(int) a3; 537 syscallarg(caddr_t) ptr; 538 } */ *uap; 539 register_t *retval; 540 { 541 struct sys_shmat_args bsa; 542 int error; 543 544 SCARG(&bsa, shmid) = SCARG(uap, a1); 545 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 546 SCARG(&bsa, shmflg) = SCARG(uap, a2); 547 548 if ((error = sys_shmat(p, &bsa, retval))) 549 return error; 550 551 if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, a3), 552 sizeof retval[0]))) 553 return error; 554 555 retval[0] = 0; 556 return 0; 557 } 558 559 /* 560 * shmdt(): this could have been mapped directly, if it wasn't for 561 * the extra indirection by the linux_ipc system call. 562 */ 563 static int 564 linux_shmdt(p, uap, retval) 565 struct proc *p; 566 struct linux_sys_ipc_args /* { 567 syscallarg(int) what; 568 syscallarg(int) a1; 569 syscallarg(int) a2; 570 syscallarg(int) a3; 571 syscallarg(caddr_t) ptr; 572 } */ *uap; 573 register_t *retval; 574 { 575 struct sys_shmdt_args bsa; 576 577 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 578 579 return sys_shmdt(p, &bsa, retval); 580 } 581 582 /* 583 * Same story as shmdt. 584 */ 585 static int 586 linux_shmget(p, uap, retval) 587 struct proc *p; 588 struct linux_sys_ipc_args /* { 589 syscallarg(int) what; 590 syscallarg(int) a1; 591 syscallarg(int) a2; 592 syscallarg(int) a3; 593 syscallarg(caddr_t) ptr; 594 } */ *uap; 595 register_t *retval; 596 { 597 struct sys_shmget_args bsa; 598 599 SCARG(&bsa, key) = SCARG(uap, a1); 600 SCARG(&bsa, size) = SCARG(uap, a2); 601 SCARG(&bsa, shmflg) = SCARG(uap, a3); 602 603 return sys_shmget(p, &bsa, retval); 604 } 605 606 /* 607 * Convert between Linux and NetBSD shmid_ds structures. 608 * The order of the fields is once again the difference, and 609 * we also need a place to store the internal data pointer 610 * in, which is unfortunately stored in this structure. 611 * 612 * We abuse a Linux internal field for that. 613 */ 614 static void 615 linux_to_bsd_shmid_ds(lsp, bsp) 616 struct linux_shmid_ds *lsp; 617 struct shmid_ds *bsp; 618 { 619 620 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 621 bsp->shm_segsz = lsp->l_shm_segsz; 622 bsp->shm_lpid = lsp->l_shm_lpid; 623 bsp->shm_cpid = lsp->l_shm_cpid; 624 bsp->shm_nattch = lsp->l_shm_nattch; 625 bsp->shm_atime = lsp->l_shm_atime; 626 bsp->shm_dtime = lsp->l_shm_dtime; 627 bsp->shm_ctime = lsp->l_shm_ctime; 628 bsp->shm_internal = lsp->l_private2; /* XXX Oh well. */ 629 } 630 631 static void 632 bsd_to_linux_shmid_ds(bsp, lsp) 633 struct shmid_ds *bsp; 634 struct linux_shmid_ds *lsp; 635 { 636 637 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 638 lsp->l_shm_segsz = bsp->shm_segsz; 639 lsp->l_shm_lpid = bsp->shm_lpid; 640 lsp->l_shm_cpid = bsp->shm_cpid; 641 lsp->l_shm_nattch = bsp->shm_nattch; 642 lsp->l_shm_atime = bsp->shm_atime; 643 lsp->l_shm_dtime = bsp->shm_dtime; 644 lsp->l_shm_ctime = bsp->shm_ctime; 645 lsp->l_private2 = bsp->shm_internal; /* XXX */ 646 } 647 648 /* 649 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT 650 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented 651 * by NetBSD itself. 652 * 653 * The usual structure conversion and massaging is done. 654 */ 655 static int 656 linux_shmctl(p, uap, retval) 657 struct proc *p; 658 struct linux_sys_ipc_args /* { 659 syscallarg(int) what; 660 syscallarg(int) a1; 661 syscallarg(int) a2; 662 syscallarg(int) a3; 663 syscallarg(caddr_t) ptr; 664 } */ *uap; 665 register_t *retval; 666 { 667 int error; 668 caddr_t sg; 669 struct sys_shmctl_args bsa; 670 struct shmid_ds *bsp, bs; 671 struct linux_shmid_ds lseg; 672 673 switch (SCARG(uap, a2)) { 674 case LINUX_IPC_STAT: 675 sg = stackgap_init(p->p_emul); 676 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 677 SCARG(&bsa, shmid) = SCARG(uap, a1); 678 SCARG(&bsa, cmd) = IPC_STAT; 679 SCARG(&bsa, buf) = bsp; 680 if ((error = sys_shmctl(p, &bsa, retval))) 681 return error; 682 if ((error = copyin((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 683 return error; 684 bsd_to_linux_shmid_ds(&bs, &lseg); 685 return copyout((caddr_t) &lseg, SCARG(uap, ptr), sizeof lseg); 686 case LINUX_IPC_SET: 687 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg, 688 sizeof lseg))) 689 return error; 690 linux_to_bsd_shmid_ds(&lseg, &bs); 691 sg = stackgap_init(p->p_emul); 692 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 693 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 694 return error; 695 SCARG(&bsa, shmid) = SCARG(uap, a1); 696 SCARG(&bsa, cmd) = IPC_SET; 697 SCARG(&bsa, buf) = bsp; 698 return sys_shmctl(p, &bsa, retval); 699 case LINUX_IPC_RMID: 700 case LINUX_SHM_LOCK: 701 case LINUX_SHM_UNLOCK: 702 SCARG(&bsa, shmid) = SCARG(uap, a1); 703 switch (SCARG(uap, a2)) { 704 case LINUX_IPC_RMID: 705 SCARG(&bsa, cmd) = IPC_RMID; 706 break; 707 case LINUX_SHM_LOCK: 708 SCARG(&bsa, cmd) = SHM_LOCK; 709 break; 710 case LINUX_SHM_UNLOCK: 711 SCARG(&bsa, cmd) = SHM_UNLOCK; 712 break; 713 } 714 SCARG(&bsa, buf) = NULL; 715 return sys_shmctl(p, &bsa, retval); 716 case LINUX_IPC_INFO: 717 case LINUX_SHM_STAT: 718 case LINUX_SHM_INFO: 719 default: 720 return EINVAL; 721 } 722 } 723 #endif /* SYSVSHM */ 724