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