1 /* $NetBSD: linux_ipc.c,v 1.12 1997/05/08 14:33:11 kleink 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, unptr, dsp, ldsp; 302 int error, cmd; 303 struct sys___semctl_args bsa; 304 struct linux_semid_ds lm; 305 struct semid_ds bm; 306 307 SCARG(&bsa, semid) = SCARG(uap, a1); 308 SCARG(&bsa, semnum) = SCARG(uap, a2); 309 SCARG(&bsa, cmd) = SCARG(uap, a3); 310 SCARG(&bsa, arg) = (union semun *)SCARG(uap, ptr); 311 switch(SCARG(uap, a3)) { 312 case LINUX_GETVAL: 313 cmd = GETVAL; 314 break; 315 case LINUX_GETPID: 316 cmd = GETPID; 317 break; 318 case LINUX_GETNCNT: 319 cmd = GETNCNT; 320 break; 321 case LINUX_GETZCNT: 322 cmd = GETZCNT; 323 break; 324 case LINUX_SETVAL: 325 cmd = SETVAL; 326 break; 327 case LINUX_IPC_RMID: 328 cmd = IPC_RMID; 329 break; 330 case LINUX_IPC_SET: 331 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp))) 332 return error; 333 if ((error = copyin(ldsp, (caddr_t)&lm, sizeof lm))) 334 return error; 335 linux_to_bsd_semid_ds(&lm, &bm); 336 sg = stackgap_init(p->p_emul); 337 unptr = stackgap_alloc(&sg, sizeof (union semun)); 338 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 339 if ((error = copyout((caddr_t)&bm, dsp, sizeof bm))) 340 return error; 341 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp))) 342 return error; 343 SCARG(&bsa, arg) = (union semun *)unptr; 344 return sys___semctl(p, &bsa, retval); 345 case LINUX_IPC_STAT: 346 sg = stackgap_init(p->p_emul); 347 unptr = stackgap_alloc(&sg, sizeof (union semun *)); 348 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 349 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp))) 350 return error; 351 SCARG(&bsa, arg) = (union semun *)unptr; 352 if ((error = sys___semctl(p, &bsa, retval))) 353 return error; 354 if ((error = copyin(dsp, (caddr_t)&bm, sizeof bm))) 355 return error; 356 bsd_to_linux_semid_ds(&bm, &lm); 357 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp))) 358 return error; 359 return copyout((caddr_t)&lm, ldsp, sizeof lm); 360 default: 361 return EINVAL; 362 } 363 SCARG(&bsa, cmd) = cmd; 364 365 return sys___semctl(p, &bsa, retval); 366 } 367 #endif /* SYSVSEM */ 368 369 #ifdef SYSVMSG 370 371 static void 372 linux_to_bsd_msqid_ds(lmp, bmp) 373 struct linux_msqid_ds *lmp; 374 struct msqid_ds *bmp; 375 { 376 377 linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm); 378 bmp->msg_first = lmp->l_msg_first; 379 bmp->msg_last = lmp->l_msg_last; 380 bmp->msg_cbytes = lmp->l_msg_cbytes; 381 bmp->msg_qnum = lmp->l_msg_qnum; 382 bmp->msg_qbytes = lmp->l_msg_qbytes; 383 bmp->msg_lspid = lmp->l_msg_lspid; 384 bmp->msg_lrpid = lmp->l_msg_lrpid; 385 bmp->msg_stime = lmp->l_msg_stime; 386 bmp->msg_rtime = lmp->l_msg_rtime; 387 bmp->msg_ctime = lmp->l_msg_ctime; 388 } 389 390 static void 391 bsd_to_linux_msqid_ds(bmp, lmp) 392 struct msqid_ds *bmp; 393 struct linux_msqid_ds *lmp; 394 { 395 396 bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm); 397 lmp->l_msg_first = bmp->msg_first; 398 lmp->l_msg_last = bmp->msg_last; 399 lmp->l_msg_cbytes = bmp->msg_cbytes; 400 lmp->l_msg_qnum = bmp->msg_qnum; 401 lmp->l_msg_qbytes = bmp->msg_qbytes; 402 lmp->l_msg_lspid = bmp->msg_lspid; 403 lmp->l_msg_lrpid = bmp->msg_lrpid; 404 lmp->l_msg_stime = bmp->msg_stime; 405 lmp->l_msg_rtime = bmp->msg_rtime; 406 lmp->l_msg_ctime = bmp->msg_ctime; 407 } 408 409 static int 410 linux_msgsnd(p, uap, retval) 411 struct proc *p; 412 struct linux_sys_ipc_args /* { 413 syscallarg(int) what; 414 syscallarg(int) a1; 415 syscallarg(int) a2; 416 syscallarg(int) a3; 417 syscallarg(caddr_t) ptr; 418 } */ *uap; 419 register_t *retval; 420 { 421 struct sys_msgsnd_args bma; 422 423 SCARG(&bma, msqid) = SCARG(uap, a1); 424 SCARG(&bma, msgp) = SCARG(uap, ptr); 425 SCARG(&bma, msgsz) = SCARG(uap, a2); 426 SCARG(&bma, msgflg) = SCARG(uap, a3); 427 428 return sys_msgsnd(p, &bma, retval); 429 } 430 431 static int 432 linux_msgrcv(p, uap, retval) 433 struct proc *p; 434 struct linux_sys_ipc_args /* { 435 syscallarg(int) what; 436 syscallarg(int) a1; 437 syscallarg(int) a2; 438 syscallarg(int) a3; 439 syscallarg(caddr_t) ptr; 440 } */ *uap; 441 register_t *retval; 442 { 443 struct sys_msgrcv_args bma; 444 struct linux_msgrcv_msgarg kluge; 445 int error; 446 447 if ((error = copyin(SCARG(uap, ptr), &kluge, sizeof kluge))) 448 return error; 449 450 SCARG(&bma, msqid) = SCARG(uap, a1); 451 SCARG(&bma, msgp) = kluge.msg; 452 SCARG(&bma, msgsz) = SCARG(uap, a2); 453 SCARG(&bma, msgtyp) = kluge.type; 454 SCARG(&bma, msgflg) = SCARG(uap, a3); 455 456 return sys_msgrcv(p, &bma, retval); 457 } 458 459 static int 460 linux_msgget(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_msgget_args bma; 472 473 SCARG(&bma, key) = (key_t)SCARG(uap, a1); 474 SCARG(&bma, msgflg) = SCARG(uap, a2); 475 476 return sys_msgget(p, &bma, retval); 477 } 478 479 static int 480 linux_msgctl(p, uap, retval) 481 struct proc *p; 482 struct linux_sys_ipc_args /* { 483 syscallarg(int) what; 484 syscallarg(int) a1; 485 syscallarg(int) a2; 486 syscallarg(int) a3; 487 syscallarg(caddr_t) ptr; 488 } */ *uap; 489 register_t *retval; 490 { 491 struct sys_msgctl_args bma; 492 caddr_t umsgptr, sg; 493 struct linux_msqid_ds lm; 494 struct msqid_ds bm; 495 int error; 496 497 SCARG(&bma, msqid) = SCARG(uap, a1); 498 SCARG(&bma, cmd) = SCARG(uap, a2); 499 switch (SCARG(uap, a2)) { 500 case LINUX_IPC_RMID: 501 return sys_msgctl(p, &bma, retval); 502 case LINUX_IPC_SET: 503 if ((error = copyin(SCARG(uap, ptr), (caddr_t)&lm, sizeof lm))) 504 return error; 505 linux_to_bsd_msqid_ds(&lm, &bm); 506 sg = stackgap_init(p->p_emul); 507 umsgptr = stackgap_alloc(&sg, sizeof bm); 508 if ((error = copyout((caddr_t)&bm, umsgptr, sizeof bm))) 509 return error; 510 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr; 511 return sys_msgctl(p, &bma, retval); 512 case LINUX_IPC_STAT: 513 sg = stackgap_init(p->p_emul); 514 umsgptr = stackgap_alloc(&sg, sizeof (struct msqid_ds)); 515 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr; 516 if ((error = sys_msgctl(p, &bma, retval))) 517 return error; 518 if ((error = copyin(umsgptr, (caddr_t)&bm, sizeof bm))) 519 return error; 520 bsd_to_linux_msqid_ds(&bm, &lm); 521 return copyout((caddr_t)&lm, SCARG(uap, ptr), sizeof lm); 522 } 523 return EINVAL; 524 } 525 #endif /* SYSVMSG */ 526 527 #ifdef SYSVSHM 528 /* 529 * shmat(2). Very straightforward, except that Linux passes a pointer 530 * in which the return value is to be passed. This is subsequently 531 * handled by libc, apparently. 532 */ 533 static int 534 linux_shmat(p, uap, retval) 535 struct proc *p; 536 struct linux_sys_ipc_args /* { 537 syscallarg(int) what; 538 syscallarg(int) a1; 539 syscallarg(int) a2; 540 syscallarg(int) a3; 541 syscallarg(caddr_t) ptr; 542 } */ *uap; 543 register_t *retval; 544 { 545 struct sys_shmat_args bsa; 546 int error; 547 548 SCARG(&bsa, shmid) = SCARG(uap, a1); 549 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 550 SCARG(&bsa, shmflg) = SCARG(uap, a2); 551 552 if ((error = sys_shmat(p, &bsa, retval))) 553 return error; 554 555 if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, a3), 556 sizeof retval[0]))) 557 return error; 558 559 retval[0] = 0; 560 return 0; 561 } 562 563 /* 564 * shmdt(): this could have been mapped directly, if it wasn't for 565 * the extra indirection by the linux_ipc system call. 566 */ 567 static int 568 linux_shmdt(p, uap, retval) 569 struct proc *p; 570 struct linux_sys_ipc_args /* { 571 syscallarg(int) what; 572 syscallarg(int) a1; 573 syscallarg(int) a2; 574 syscallarg(int) a3; 575 syscallarg(caddr_t) ptr; 576 } */ *uap; 577 register_t *retval; 578 { 579 struct sys_shmdt_args bsa; 580 581 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 582 583 return sys_shmdt(p, &bsa, retval); 584 } 585 586 /* 587 * Same story as shmdt. 588 */ 589 static int 590 linux_shmget(p, uap, retval) 591 struct proc *p; 592 struct linux_sys_ipc_args /* { 593 syscallarg(int) what; 594 syscallarg(int) a1; 595 syscallarg(int) a2; 596 syscallarg(int) a3; 597 syscallarg(caddr_t) ptr; 598 } */ *uap; 599 register_t *retval; 600 { 601 struct sys_shmget_args bsa; 602 603 SCARG(&bsa, key) = SCARG(uap, a1); 604 SCARG(&bsa, size) = SCARG(uap, a2); 605 SCARG(&bsa, shmflg) = SCARG(uap, a3); 606 607 return sys_shmget(p, &bsa, retval); 608 } 609 610 /* 611 * Convert between Linux and NetBSD shmid_ds structures. 612 * The order of the fields is once again the difference, and 613 * we also need a place to store the internal data pointer 614 * in, which is unfortunately stored in this structure. 615 * 616 * We abuse a Linux internal field for that. 617 */ 618 static void 619 linux_to_bsd_shmid_ds(lsp, bsp) 620 struct linux_shmid_ds *lsp; 621 struct shmid_ds *bsp; 622 { 623 624 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 625 bsp->shm_segsz = lsp->l_shm_segsz; 626 bsp->shm_lpid = lsp->l_shm_lpid; 627 bsp->shm_cpid = lsp->l_shm_cpid; 628 bsp->shm_nattch = lsp->l_shm_nattch; 629 bsp->shm_atime = lsp->l_shm_atime; 630 bsp->shm_dtime = lsp->l_shm_dtime; 631 bsp->shm_ctime = lsp->l_shm_ctime; 632 bsp->shm_internal = lsp->l_private2; /* XXX Oh well. */ 633 } 634 635 static void 636 bsd_to_linux_shmid_ds(bsp, lsp) 637 struct shmid_ds *bsp; 638 struct linux_shmid_ds *lsp; 639 { 640 641 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 642 lsp->l_shm_segsz = bsp->shm_segsz; 643 lsp->l_shm_lpid = bsp->shm_lpid; 644 lsp->l_shm_cpid = bsp->shm_cpid; 645 lsp->l_shm_nattch = bsp->shm_nattch; 646 lsp->l_shm_atime = bsp->shm_atime; 647 lsp->l_shm_dtime = bsp->shm_dtime; 648 lsp->l_shm_ctime = bsp->shm_ctime; 649 lsp->l_private2 = bsp->shm_internal; /* XXX */ 650 } 651 652 /* 653 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT 654 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented 655 * by NetBSD itself. 656 * 657 * The usual structure conversion and massaging is done. 658 */ 659 static int 660 linux_shmctl(p, uap, retval) 661 struct proc *p; 662 struct linux_sys_ipc_args /* { 663 syscallarg(int) what; 664 syscallarg(int) a1; 665 syscallarg(int) a2; 666 syscallarg(int) a3; 667 syscallarg(caddr_t) ptr; 668 } */ *uap; 669 register_t *retval; 670 { 671 int error; 672 caddr_t sg; 673 struct sys_shmctl_args bsa; 674 struct shmid_ds *bsp, bs; 675 struct linux_shmid_ds lseg; 676 677 switch (SCARG(uap, a2)) { 678 case LINUX_IPC_STAT: 679 sg = stackgap_init(p->p_emul); 680 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 681 SCARG(&bsa, shmid) = SCARG(uap, a1); 682 SCARG(&bsa, cmd) = IPC_STAT; 683 SCARG(&bsa, buf) = bsp; 684 if ((error = sys_shmctl(p, &bsa, retval))) 685 return error; 686 if ((error = copyin((caddr_t) bsp, (caddr_t) &bs, sizeof bs))) 687 return error; 688 bsd_to_linux_shmid_ds(&bs, &lseg); 689 return copyout((caddr_t) &lseg, SCARG(uap, ptr), sizeof lseg); 690 case LINUX_IPC_SET: 691 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg, 692 sizeof lseg))) 693 return error; 694 linux_to_bsd_shmid_ds(&lseg, &bs); 695 sg = stackgap_init(p->p_emul); 696 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 697 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 698 return error; 699 SCARG(&bsa, shmid) = SCARG(uap, a1); 700 SCARG(&bsa, cmd) = IPC_SET; 701 SCARG(&bsa, buf) = bsp; 702 return sys_shmctl(p, &bsa, retval); 703 case LINUX_IPC_RMID: 704 case LINUX_SHM_LOCK: 705 case LINUX_SHM_UNLOCK: 706 SCARG(&bsa, shmid) = SCARG(uap, a1); 707 switch (SCARG(uap, a2)) { 708 case LINUX_IPC_RMID: 709 SCARG(&bsa, cmd) = IPC_RMID; 710 break; 711 case LINUX_SHM_LOCK: 712 SCARG(&bsa, cmd) = SHM_LOCK; 713 break; 714 case LINUX_SHM_UNLOCK: 715 SCARG(&bsa, cmd) = SHM_UNLOCK; 716 break; 717 } 718 SCARG(&bsa, buf) = NULL; 719 return sys_shmctl(p, &bsa, retval); 720 case LINUX_IPC_INFO: 721 case LINUX_SHM_STAT: 722 case LINUX_SHM_INFO: 723 default: 724 return EINVAL; 725 } 726 } 727 #endif /* SYSVSHM */ 728