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