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