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