linux_ipc.c revision 114724
11187Srgrimes/*- 250476Speter * Copyright (c) 1994-1995 S�ren Schmidt 31052Sdg * All rights reserved. 4137290Speter * 5145573Speter * Redistribution and use in source and binary forms, with or without 6145573Speter * modification, are permitted provided that the following conditions 7145571Speter * are met: 8145573Speter * 1. Redistributions of source code must retain the above copyright 9145573Speter * notice, this list of conditions and the following disclaimer 101052Sdg * in this position and unchanged. 11119724Speter * 2. Redistributions in binary form must reproduce the above copyright 12119724Speter * notice, this list of conditions and the following disclaimer in the 1334388Sjb * documentation and/or other materials provided with the distribution. 1434388Sjb * 3. The name of the author may not be used to endorse or promote products 15184789Sed * derived from this software without specific prior written permission 1634388Sjb * 1771770Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18171218Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19171218Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20171218Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2134388Sjb * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2274870Sru * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2374870Sru * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241052Sdg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2537946Sbde * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 261052Sdg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2766174Sbsd * 28 * $FreeBSD: head/sys/compat/linux/linux_ipc.c 114724 2003-05-05 09:22:58Z mbr $ 29 */ 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/syscallsubr.h> 34#include <sys/sysproto.h> 35#include <sys/proc.h> 36#include <sys/limits.h> 37#include <sys/msg.h> 38#include <sys/sem.h> 39#include <sys/shm.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 47struct 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 60struct l_shminfo { 61 l_int shmmax; 62 l_int shmmin; 63 l_int shmmni; 64 l_int shmseg; 65 l_int shmall; 66}; 67 68struct 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 77static void 78bsd_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 87static void 88bsd_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 98struct 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 108static void 109linux_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 121static void 122bsd_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 133struct 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 149struct 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 160struct 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 174static void 175linux_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 184static void 185bsd_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 194static void 195linux_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 208static void 209bsd_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 222static void 223linux_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 236static void 237bsd_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 250static void 251linux_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 264static int 265linux_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 291static int 292linux_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 327static int 328linux_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 349static int 350linux_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 370static int 371linux_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 392static int 393linux_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 417static int 418linux_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 439int 440linux_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 454int 455linux_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 471int 472linux_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(&linux_seminfo, 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 linux_msg(td, "ipc type %d is not implemented", 560 args->cmd & ~LINUX_IPC_64); 561 return EINVAL; 562 } 563 return __semctl(td, &bsd_args); 564} 565 566int 567linux_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 583int 584linux_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 602int 603linux_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 615int 616linux_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 652int 653linux_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, args->raddr, sizeof(l_ulong)))) 669 return error; 670 td->td_retval[0] = 0; 671#endif 672 return 0; 673} 674 675int 676linux_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 686int 687linux_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 701int 702linux_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 shmid_ds bsd_shmid; 708 size_t bufsz; 709 int error; 710 711 switch (args->cmd & ~LINUX_IPC_64) { 712 713 case LINUX_IPC_INFO: { 714 struct shminfo bsd_shminfo; 715 716 /* Perform shmctl wanting removed segments lookup */ 717 error = kern_shmctl(td, args->shmid, IPC_INFO, 718 (void *)&bsd_shminfo, &bufsz, 1); 719 if (error) 720 return error; 721 722 bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo); 723 724 return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, 725 &linux_shminfo, (caddr_t)args->buf)); 726 } 727 728 case LINUX_SHM_INFO: { 729 struct shm_info bsd_shm_info; 730 731 /* Perform shmctl wanting removed segments lookup */ 732 error = kern_shmctl(td, args->shmid, SHM_INFO, 733 (void *)&bsd_shm_info, &bufsz, 1); 734 if (error) 735 return error; 736 737 bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); 738 739 return copyout(&linux_shm_info, (caddr_t)args->buf, 740 sizeof(struct l_shm_info)); 741 } 742 743 case LINUX_IPC_STAT: 744 /* Perform shmctl wanting removed segments lookup */ 745 error = kern_shmctl(td, args->shmid, IPC_STAT, 746 (void *)&bsd_shmid, &bufsz, 1); 747 if (error) 748 return error; 749 750 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 751 752 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 753 &linux_shmid, (caddr_t)args->buf)); 754 755 case LINUX_SHM_STAT: 756 /* Perform shmctl wanting removed segments lookup */ 757 error = kern_shmctl(td, args->shmid, IPC_STAT, 758 (void *)&bsd_shmid, &bufsz, 1); 759 if (error) 760 return error; 761 762 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 763 764 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 765 &linux_shmid, (caddr_t)args->buf)); 766 767 case LINUX_IPC_SET: 768 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 769 &linux_shmid, (caddr_t)args->buf); 770 if (error) 771 return error; 772 773 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 774 775 /* Perform shmctl wanting removed segments lookup */ 776 return kern_shmctl(td, args->shmid, IPC_SET, 777 (void *)&bsd_shmid, &bufsz, 1); 778 779 case LINUX_IPC_RMID: { 780 void *buf; 781 782 if (args->buf == NULL) 783 buf = NULL; 784 else { 785 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 786 &linux_shmid, (caddr_t)args->buf); 787 if (error) 788 return error; 789 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 790 buf = (void *)&bsd_shmid; 791 } 792 return kern_shmctl(td, args->shmid, IPC_RMID, buf, &bufsz, 1); 793 } 794 795 case LINUX_SHM_LOCK: 796 case LINUX_SHM_UNLOCK: 797 default: 798 linux_msg(td, "ipc typ=%d not implemented", args->cmd & ~LINUX_IPC_64); 799 return EINVAL; 800 } 801} 802