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