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