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