1 /*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/syscallsubr.h> 35 #include <sys/sysproto.h> 36 #include <sys/proc.h> 37 #include <sys/limits.h> 38 #include <sys/msg.h> 39 #include <sys/sem.h> 40 #include <sys/shm.h> 41 42 #include "opt_compat.h" 43 44 #ifdef COMPAT_LINUX32 45 #include <machine/../linux32/linux.h> 46 #include <machine/../linux32/linux32_proto.h> 47 #include <machine/../linux32/linux32_ipc64.h> 48 #else 49 #include <machine/../linux/linux.h> 50 #include <machine/../linux/linux_proto.h> 51 #include <machine/../linux/linux_ipc64.h> 52 #endif 53 #include <compat/linux/linux_ipc.h> 54 #include <compat/linux/linux_util.h> 55 56 struct l_seminfo { 57 l_int semmap; 58 l_int semmni; 59 l_int semmns; 60 l_int semmnu; 61 l_int semmsl; 62 l_int semopm; 63 l_int semume; 64 l_int semusz; 65 l_int semvmx; 66 l_int semaem; 67 }; 68 69 struct l_shminfo { 70 l_int shmmax; 71 l_int shmmin; 72 l_int shmmni; 73 l_int shmseg; 74 l_int shmall; 75 }; 76 77 struct l_shm_info { 78 l_int used_ids; 79 l_ulong shm_tot; /* total allocated shm */ 80 l_ulong shm_rss; /* total resident shm */ 81 l_ulong shm_swp; /* total swapped shm */ 82 l_ulong swap_attempts; 83 l_ulong swap_successes; 84 }; 85 86 static void 87 bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp) 88 { 89 lpp->shmmax = bpp->shmmax; 90 lpp->shmmin = bpp->shmmin; 91 lpp->shmmni = bpp->shmmni; 92 lpp->shmseg = bpp->shmseg; 93 lpp->shmall = bpp->shmall; 94 } 95 96 static void 97 bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp) 98 { 99 lpp->used_ids = bpp->used_ids ; 100 lpp->shm_tot = bpp->shm_tot ; 101 lpp->shm_rss = bpp->shm_rss ; 102 lpp->shm_swp = bpp->shm_swp ; 103 lpp->swap_attempts = bpp->swap_attempts ; 104 lpp->swap_successes = bpp->swap_successes ; 105 } 106 107 struct l_ipc_perm { 108 l_key_t key; 109 l_uid16_t uid; 110 l_gid16_t gid; 111 l_uid16_t cuid; 112 l_gid16_t cgid; 113 l_ushort mode; 114 l_ushort seq; 115 }; 116 117 static void 118 linux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp) 119 { 120 bpp->key = lpp->key; 121 bpp->uid = lpp->uid; 122 bpp->gid = lpp->gid; 123 bpp->cuid = lpp->cuid; 124 bpp->cgid = lpp->cgid; 125 bpp->mode = lpp->mode; 126 bpp->seq = lpp->seq; 127 } 128 129 130 static void 131 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp) 132 { 133 lpp->key = bpp->key; 134 lpp->uid = bpp->uid; 135 lpp->gid = bpp->gid; 136 lpp->cuid = bpp->cuid; 137 lpp->cgid = bpp->cgid; 138 lpp->mode = bpp->mode; 139 lpp->seq = bpp->seq; 140 } 141 142 struct l_msqid_ds { 143 struct l_ipc_perm msg_perm; 144 l_uintptr_t msg_first; /* first message on queue,unused */ 145 l_uintptr_t msg_last; /* last message in queue,unused */ 146 l_time_t msg_stime; /* last msgsnd time */ 147 l_time_t msg_rtime; /* last msgrcv time */ 148 l_time_t msg_ctime; /* last change time */ 149 l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */ 150 l_ulong msg_lqbytes; /* ditto */ 151 l_ushort msg_cbytes; /* current number of bytes on queue */ 152 l_ushort msg_qnum; /* number of messages in queue */ 153 l_ushort msg_qbytes; /* max number of bytes on queue */ 154 l_pid_t msg_lspid; /* pid of last msgsnd */ 155 l_pid_t msg_lrpid; /* last receive pid */ 156 } 157 #if defined(__amd64__) && defined(COMPAT_LINUX32) 158 __packed 159 #endif 160 ; 161 162 struct l_semid_ds { 163 struct l_ipc_perm sem_perm; 164 l_time_t sem_otime; 165 l_time_t sem_ctime; 166 l_uintptr_t sem_base; 167 l_uintptr_t sem_pending; 168 l_uintptr_t sem_pending_last; 169 l_uintptr_t undo; 170 l_ushort sem_nsems; 171 } 172 #if defined(__amd64__) && defined(COMPAT_LINUX32) 173 __packed 174 #endif 175 ; 176 177 struct l_shmid_ds { 178 struct l_ipc_perm shm_perm; 179 l_int shm_segsz; 180 l_time_t shm_atime; 181 l_time_t shm_dtime; 182 l_time_t shm_ctime; 183 l_ushort shm_cpid; 184 l_ushort shm_lpid; 185 l_short shm_nattch; 186 l_ushort private1; 187 l_uintptr_t private2; 188 l_uintptr_t private3; 189 }; 190 191 static void 192 linux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp) 193 { 194 linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); 195 bsp->sem_otime = lsp->sem_otime; 196 bsp->sem_ctime = lsp->sem_ctime; 197 bsp->sem_nsems = lsp->sem_nsems; 198 bsp->sem_base = PTRIN(lsp->sem_base); 199 } 200 201 static void 202 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp) 203 { 204 bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); 205 lsp->sem_otime = bsp->sem_otime; 206 lsp->sem_ctime = bsp->sem_ctime; 207 lsp->sem_nsems = bsp->sem_nsems; 208 lsp->sem_base = PTROUT(bsp->sem_base); 209 } 210 211 static void 212 linux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp) 213 { 214 linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); 215 bsp->shm_segsz = lsp->shm_segsz; 216 bsp->shm_lpid = lsp->shm_lpid; 217 bsp->shm_cpid = lsp->shm_cpid; 218 bsp->shm_nattch = lsp->shm_nattch; 219 bsp->shm_atime = lsp->shm_atime; 220 bsp->shm_dtime = lsp->shm_dtime; 221 bsp->shm_ctime = lsp->shm_ctime; 222 /* this goes (yet) SOS */ 223 bsp->shm_internal = PTRIN(lsp->private3); 224 } 225 226 static void 227 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp) 228 { 229 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); 230 lsp->shm_segsz = bsp->shm_segsz; 231 lsp->shm_lpid = bsp->shm_lpid; 232 lsp->shm_cpid = bsp->shm_cpid; 233 lsp->shm_nattch = bsp->shm_nattch; 234 lsp->shm_atime = bsp->shm_atime; 235 lsp->shm_dtime = bsp->shm_dtime; 236 lsp->shm_ctime = bsp->shm_ctime; 237 /* this goes (yet) SOS */ 238 lsp->private3 = PTROUT(bsp->shm_internal); 239 } 240 241 static void 242 linux_to_bsd_msqid_ds(struct l_msqid_ds *lsp, struct msqid_ds *bsp) 243 { 244 linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm); 245 bsp->msg_cbytes = lsp->msg_cbytes; 246 bsp->msg_qnum = lsp->msg_qnum; 247 bsp->msg_qbytes = lsp->msg_qbytes; 248 bsp->msg_lspid = lsp->msg_lspid; 249 bsp->msg_lrpid = lsp->msg_lrpid; 250 bsp->msg_stime = lsp->msg_stime; 251 bsp->msg_rtime = lsp->msg_rtime; 252 bsp->msg_ctime = lsp->msg_ctime; 253 } 254 255 static void 256 bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid_ds *lsp) 257 { 258 bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm); 259 lsp->msg_cbytes = bsp->msg_cbytes; 260 lsp->msg_qnum = bsp->msg_qnum; 261 lsp->msg_qbytes = bsp->msg_qbytes; 262 lsp->msg_lspid = bsp->msg_lspid; 263 lsp->msg_lrpid = bsp->msg_lrpid; 264 lsp->msg_stime = bsp->msg_stime; 265 lsp->msg_rtime = bsp->msg_rtime; 266 lsp->msg_ctime = bsp->msg_ctime; 267 } 268 269 static void 270 linux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out) 271 { 272 273 /* XXX: do we really need to do something here? */ 274 out->key = in->key; 275 out->uid = in->uid; 276 out->gid = in->gid; 277 out->cuid = in->cuid; 278 out->cgid = in->cgid; 279 out->mode = in->mode; 280 out->seq = in->seq; 281 } 282 283 static int 284 linux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) 285 { 286 struct l_msqid64_ds linux_msqid64; 287 int error; 288 289 if (ver == LINUX_IPC_64) { 290 error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64)); 291 if (error != 0) 292 return (error); 293 294 bzero(linux_msqid, sizeof(*linux_msqid)); 295 296 linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid; 297 linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid; 298 linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode; 299 300 if (linux_msqid64.msg_qbytes > USHRT_MAX) 301 linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes; 302 else 303 linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes; 304 } else { 305 error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid)); 306 } 307 return (error); 308 } 309 310 static int 311 linux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) 312 { 313 struct l_msqid64_ds linux_msqid64; 314 315 if (ver == LINUX_IPC_64) { 316 bzero(&linux_msqid64, sizeof(linux_msqid64)); 317 318 linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm, 319 &linux_msqid64.msg_perm); 320 321 linux_msqid64.msg_stime = linux_msqid->msg_stime; 322 linux_msqid64.msg_rtime = linux_msqid->msg_rtime; 323 linux_msqid64.msg_ctime = linux_msqid->msg_ctime; 324 325 if (linux_msqid->msg_cbytes == 0) 326 linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes; 327 else 328 linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes; 329 330 linux_msqid64.msg_qnum = linux_msqid->msg_qnum; 331 332 if (linux_msqid->msg_qbytes == 0) 333 linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes; 334 else 335 linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes; 336 337 linux_msqid64.msg_lspid = linux_msqid->msg_lspid; 338 linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid; 339 340 return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64))); 341 } else { 342 return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid))); 343 } 344 } 345 346 static int 347 linux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) 348 { 349 struct l_semid64_ds linux_semid64; 350 int error; 351 352 if (ver == LINUX_IPC_64) { 353 error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64)); 354 if (error != 0) 355 return (error); 356 357 bzero(linux_semid, sizeof(*linux_semid)); 358 359 linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid; 360 linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid; 361 linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode; 362 } else { 363 error = copyin(uaddr, linux_semid, sizeof(*linux_semid)); 364 } 365 return (error); 366 } 367 368 static int 369 linux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) 370 { 371 struct l_semid64_ds linux_semid64; 372 373 if (ver == LINUX_IPC_64) { 374 bzero(&linux_semid64, sizeof(linux_semid64)); 375 376 linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm, 377 &linux_semid64.sem_perm); 378 379 linux_semid64.sem_otime = linux_semid->sem_otime; 380 linux_semid64.sem_ctime = linux_semid->sem_ctime; 381 linux_semid64.sem_nsems = linux_semid->sem_nsems; 382 383 return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64))); 384 } else { 385 return (copyout(linux_semid, uaddr, sizeof(*linux_semid))); 386 } 387 } 388 389 static int 390 linux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) 391 { 392 struct l_shmid64_ds linux_shmid64; 393 int error; 394 395 if (ver == LINUX_IPC_64) { 396 error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64)); 397 if (error != 0) 398 return (error); 399 400 bzero(linux_shmid, sizeof(*linux_shmid)); 401 402 linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid; 403 linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid; 404 linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode; 405 } else { 406 error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid)); 407 } 408 return (error); 409 } 410 411 static int 412 linux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) 413 { 414 struct l_shmid64_ds linux_shmid64; 415 416 if (ver == LINUX_IPC_64) { 417 bzero(&linux_shmid64, sizeof(linux_shmid64)); 418 419 linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm, 420 &linux_shmid64.shm_perm); 421 422 linux_shmid64.shm_segsz = linux_shmid->shm_segsz; 423 linux_shmid64.shm_atime = linux_shmid->shm_atime; 424 linux_shmid64.shm_dtime = linux_shmid->shm_dtime; 425 linux_shmid64.shm_ctime = linux_shmid->shm_ctime; 426 linux_shmid64.shm_cpid = linux_shmid->shm_cpid; 427 linux_shmid64.shm_lpid = linux_shmid->shm_lpid; 428 linux_shmid64.shm_nattch = linux_shmid->shm_nattch; 429 430 return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64))); 431 } else { 432 return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid))); 433 } 434 } 435 436 static int 437 linux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo, 438 caddr_t uaddr) 439 { 440 struct l_shminfo64 linux_shminfo64; 441 442 if (ver == LINUX_IPC_64) { 443 bzero(&linux_shminfo64, sizeof(linux_shminfo64)); 444 445 linux_shminfo64.shmmax = linux_shminfo->shmmax; 446 linux_shminfo64.shmmin = linux_shminfo->shmmin; 447 linux_shminfo64.shmmni = linux_shminfo->shmmni; 448 linux_shminfo64.shmseg = linux_shminfo->shmseg; 449 linux_shminfo64.shmall = linux_shminfo->shmall; 450 451 return (copyout(&linux_shminfo64, uaddr, 452 sizeof(linux_shminfo64))); 453 } else { 454 return (copyout(linux_shminfo, uaddr, sizeof(*linux_shminfo))); 455 } 456 } 457 458 int 459 linux_semop(struct thread *td, struct linux_semop_args *args) 460 { 461 struct semop_args /* { 462 int semid; 463 struct sembuf *sops; 464 int nsops; 465 } */ bsd_args; 466 467 bsd_args.semid = args->semid; 468 bsd_args.sops = (struct sembuf *)PTRIN(args->tsops); 469 bsd_args.nsops = args->nsops; 470 return semop(td, &bsd_args); 471 } 472 473 int 474 linux_semget(struct thread *td, struct linux_semget_args *args) 475 { 476 struct semget_args /* { 477 key_t key; 478 int nsems; 479 int semflg; 480 } */ bsd_args; 481 482 if (args->nsems < 0) 483 return (EINVAL); 484 bsd_args.key = args->key; 485 bsd_args.nsems = args->nsems; 486 bsd_args.semflg = args->semflg; 487 return semget(td, &bsd_args); 488 } 489 490 int 491 linux_semctl(struct thread *td, struct linux_semctl_args *args) 492 { 493 struct l_semid_ds linux_semid; 494 struct __semctl_args /* { 495 int semid; 496 int semnum; 497 int cmd; 498 union semun *arg; 499 } */ bsd_args; 500 struct l_seminfo linux_seminfo; 501 int error; 502 union semun *unptr; 503 caddr_t sg; 504 505 sg = stackgap_init(); 506 507 /* Make sure the arg parameter can be copied in. */ 508 unptr = stackgap_alloc(&sg, sizeof(union semun)); 509 bcopy(&args->arg, unptr, sizeof(union semun)); 510 511 bsd_args.semid = args->semid; 512 bsd_args.semnum = args->semnum; 513 bsd_args.arg = unptr; 514 515 switch (args->cmd & ~LINUX_IPC_64) { 516 case LINUX_IPC_RMID: 517 bsd_args.cmd = IPC_RMID; 518 break; 519 case LINUX_GETNCNT: 520 bsd_args.cmd = GETNCNT; 521 break; 522 case LINUX_GETPID: 523 bsd_args.cmd = GETPID; 524 break; 525 case LINUX_GETVAL: 526 bsd_args.cmd = GETVAL; 527 break; 528 case LINUX_GETZCNT: 529 bsd_args.cmd = GETZCNT; 530 break; 531 case LINUX_SETVAL: 532 bsd_args.cmd = SETVAL; 533 break; 534 case LINUX_IPC_SET: 535 bsd_args.cmd = IPC_SET; 536 error = linux_semid_pullup(args->cmd & LINUX_IPC_64, 537 &linux_semid, (caddr_t)PTRIN(args->arg.buf)); 538 if (error) 539 return (error); 540 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 541 linux_to_bsd_semid_ds(&linux_semid, unptr->buf); 542 return __semctl(td, &bsd_args); 543 case LINUX_IPC_STAT: 544 case LINUX_SEM_STAT: 545 if((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) 546 bsd_args.cmd = IPC_STAT; 547 else 548 bsd_args.cmd = SEM_STAT; 549 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 550 error = __semctl(td, &bsd_args); 551 if (error) 552 return error; 553 td->td_retval[0] = (bsd_args.cmd == SEM_STAT) ? 554 IXSEQ_TO_IPCID(bsd_args.semid, unptr->buf->sem_perm) : 555 0; 556 bsd_to_linux_semid_ds(unptr->buf, &linux_semid); 557 return (linux_semid_pushdown(args->cmd & LINUX_IPC_64, 558 &linux_semid, (caddr_t)PTRIN(args->arg.buf))); 559 case LINUX_IPC_INFO: 560 case LINUX_SEM_INFO: 561 bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) ); 562 /* XXX BSD equivalent? 563 #define used_semids 10 564 #define used_sems 10 565 linux_seminfo.semusz = used_semids; 566 linux_seminfo.semaem = used_sems; 567 */ 568 error = copyout(&linux_seminfo, 569 PTRIN(args->arg.buf), sizeof(linux_seminfo)); 570 if (error) 571 return error; 572 td->td_retval[0] = seminfo.semmni; 573 return 0; /* No need for __semctl call */ 574 case LINUX_GETALL: 575 /* FALLTHROUGH */ 576 case LINUX_SETALL: 577 /* FALLTHROUGH */ 578 default: 579 linux_msg(td, "ipc type %d is not implemented", 580 args->cmd & ~LINUX_IPC_64); 581 return EINVAL; 582 } 583 return __semctl(td, &bsd_args); 584 } 585 586 int 587 linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) 588 { 589 struct msgsnd_args /* { 590 int msqid; 591 void *msgp; 592 size_t msgsz; 593 int msgflg; 594 } */ bsd_args; 595 596 bsd_args.msqid = args->msqid; 597 bsd_args.msgp = PTRIN(args->msgp); 598 bsd_args.msgsz = args->msgsz; 599 bsd_args.msgflg = args->msgflg; 600 return msgsnd(td, &bsd_args); 601 } 602 603 int 604 linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) 605 { 606 struct msgrcv_args /* { 607 int msqid; 608 void *msgp; 609 size_t msgsz; 610 long msgtyp; 611 int msgflg; 612 } */ bsd_args; 613 614 bsd_args.msqid = args->msqid; 615 bsd_args.msgp = PTRIN(args->msgp); 616 bsd_args.msgsz = args->msgsz; 617 bsd_args.msgtyp = args->msgtyp; 618 bsd_args.msgflg = args->msgflg; 619 return msgrcv(td, &bsd_args); 620 } 621 622 int 623 linux_msgget(struct thread *td, struct linux_msgget_args *args) 624 { 625 struct msgget_args /* { 626 key_t key; 627 int msgflg; 628 } */ bsd_args; 629 630 bsd_args.key = args->key; 631 bsd_args.msgflg = args->msgflg; 632 return msgget(td, &bsd_args); 633 } 634 635 int 636 linux_msgctl(struct thread *td, struct linux_msgctl_args *args) 637 { 638 int error, bsd_cmd; 639 struct l_msqid_ds linux_msqid; 640 struct msqid_ds bsd_msqid; 641 642 error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, 643 &linux_msqid, (caddr_t)PTRIN(args->buf)); 644 if (error != 0) 645 return (error); 646 bsd_cmd = args->cmd & ~LINUX_IPC_64; 647 if (bsd_cmd == LINUX_IPC_SET) 648 linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid); 649 650 error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid); 651 if (error != 0) 652 if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) 653 return (error); 654 655 if (bsd_cmd == LINUX_IPC_STAT) { 656 bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid); 657 return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, 658 &linux_msqid, (caddr_t)PTRIN(args->buf))); 659 } 660 661 return (0); 662 } 663 664 int 665 linux_shmat(struct thread *td, struct linux_shmat_args *args) 666 { 667 struct shmat_args /* { 668 int shmid; 669 void *shmaddr; 670 int shmflg; 671 } */ bsd_args; 672 int error; 673 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 674 l_uintptr_t addr; 675 #endif 676 677 bsd_args.shmid = args->shmid; 678 bsd_args.shmaddr = PTRIN(args->shmaddr); 679 bsd_args.shmflg = args->shmflg; 680 if ((error = shmat(td, &bsd_args))) 681 return error; 682 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 683 addr = td->td_retval[0]; 684 if ((error = copyout(&addr, PTRIN(args->raddr), sizeof(addr)))) 685 return error; 686 td->td_retval[0] = 0; 687 #endif 688 return 0; 689 } 690 691 int 692 linux_shmdt(struct thread *td, struct linux_shmdt_args *args) 693 { 694 struct shmdt_args /* { 695 void *shmaddr; 696 } */ bsd_args; 697 698 bsd_args.shmaddr = PTRIN(args->shmaddr); 699 return shmdt(td, &bsd_args); 700 } 701 702 int 703 linux_shmget(struct thread *td, struct linux_shmget_args *args) 704 { 705 struct shmget_args /* { 706 key_t key; 707 int size; 708 int shmflg; 709 } */ bsd_args; 710 711 bsd_args.key = args->key; 712 bsd_args.size = args->size; 713 bsd_args.shmflg = args->shmflg; 714 return shmget(td, &bsd_args); 715 } 716 717 int 718 linux_shmctl(struct thread *td, struct linux_shmctl_args *args) 719 { 720 struct l_shmid_ds linux_shmid; 721 struct l_shminfo linux_shminfo; 722 struct l_shm_info linux_shm_info; 723 struct shmid_ds bsd_shmid; 724 size_t bufsz; 725 int error; 726 727 switch (args->cmd & ~LINUX_IPC_64) { 728 729 case LINUX_IPC_INFO: { 730 struct shminfo bsd_shminfo; 731 732 /* Perform shmctl wanting removed segments lookup */ 733 error = kern_shmctl(td, args->shmid, IPC_INFO, 734 (void *)&bsd_shminfo, &bufsz); 735 if (error) 736 return error; 737 738 bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo); 739 740 return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, 741 &linux_shminfo, (caddr_t)PTRIN(args->buf))); 742 } 743 744 case LINUX_SHM_INFO: { 745 struct shm_info bsd_shm_info; 746 747 /* Perform shmctl wanting removed segments lookup */ 748 error = kern_shmctl(td, args->shmid, SHM_INFO, 749 (void *)&bsd_shm_info, &bufsz); 750 if (error) 751 return error; 752 753 bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); 754 755 return copyout(&linux_shm_info, (caddr_t)PTRIN(args->buf), 756 sizeof(struct l_shm_info)); 757 } 758 759 case LINUX_IPC_STAT: 760 /* Perform shmctl wanting removed segments lookup */ 761 error = kern_shmctl(td, args->shmid, IPC_STAT, 762 (void *)&bsd_shmid, &bufsz); 763 if (error) 764 return error; 765 766 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 767 768 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 769 &linux_shmid, (caddr_t)PTRIN(args->buf))); 770 771 case LINUX_SHM_STAT: 772 /* Perform shmctl wanting removed segments lookup */ 773 error = kern_shmctl(td, args->shmid, IPC_STAT, 774 (void *)&bsd_shmid, &bufsz); 775 if (error) 776 return error; 777 778 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 779 780 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 781 &linux_shmid, (caddr_t)PTRIN(args->buf))); 782 783 case LINUX_IPC_SET: 784 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 785 &linux_shmid, (caddr_t)PTRIN(args->buf)); 786 if (error) 787 return error; 788 789 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 790 791 /* Perform shmctl wanting removed segments lookup */ 792 return kern_shmctl(td, args->shmid, IPC_SET, 793 (void *)&bsd_shmid, &bufsz); 794 795 case LINUX_IPC_RMID: { 796 void *buf; 797 798 if (args->buf == 0) 799 buf = NULL; 800 else { 801 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 802 &linux_shmid, (caddr_t)PTRIN(args->buf)); 803 if (error) 804 return error; 805 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 806 buf = (void *)&bsd_shmid; 807 } 808 return kern_shmctl(td, args->shmid, IPC_RMID, buf, &bufsz); 809 } 810 811 case LINUX_SHM_LOCK: 812 case LINUX_SHM_UNLOCK: 813 default: 814 linux_msg(td, "ipc typ=%d not implemented", args->cmd & ~LINUX_IPC_64); 815 return EINVAL; 816 } 817 } 818