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