linux_ipc.c revision 293522
1100784Sfenner/*- 2100784Sfenner * Copyright (c) 1994-1995 S��ren Schmidt 3100784Sfenner * All rights reserved. 4100784Sfenner * 5100784Sfenner * Redistribution and use in source and binary forms, with or without 6100784Sfenner * modification, are permitted provided that the following conditions 7100784Sfenner * are met: 8100784Sfenner * 1. Redistributions of source code must retain the above copyright 9100784Sfenner * notice, this list of conditions and the following disclaimer 10100784Sfenner * in this position and unchanged. 11100784Sfenner * 2. Redistributions in binary form must reproduce the above copyright 12100784Sfenner * notice, this list of conditions and the following disclaimer in the 13100784Sfenner * documentation and/or other materials provided with the distribution. 14100784Sfenner * 3. The name of the author may not be used to endorse or promote products 15100784Sfenner * derived from this software without specific prior written permission 16100784Sfenner * 17100784Sfenner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18100784Sfenner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19100784Sfenner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20100784Sfenner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21100784Sfenner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22100784Sfenner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23100784Sfenner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24100784Sfenner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25100784Sfenner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26100784Sfenner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27100784Sfenner */ 28100784Sfenner 29100784Sfenner#include <sys/cdefs.h> 30100784Sfenner__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_ipc.c 293522 2016-01-09 15:56:01Z dchagin $"); 31100784Sfenner 32100905Sfenner#include <sys/param.h> 33100905Sfenner#include <sys/systm.h> 34100784Sfenner#include <sys/syscallsubr.h> 35100784Sfenner#include <sys/sysproto.h> 36100784Sfenner#include <sys/proc.h> 37100784Sfenner#include <sys/limits.h> 38100784Sfenner#include <sys/msg.h> 39100784Sfenner#include <sys/sem.h> 40100784Sfenner#include <sys/shm.h> 41100784Sfenner 42100784Sfenner#include "opt_compat.h" 43100784Sfenner 44100784Sfenner#ifdef COMPAT_LINUX32 45100784Sfenner#include <machine/../linux32/linux.h> 46100784Sfenner#include <machine/../linux32/linux32_proto.h> 47100784Sfenner#include <machine/../linux32/linux32_ipc64.h> 48100784Sfenner#else 49100784Sfenner#include <machine/../linux/linux.h> 50100784Sfenner#include <machine/../linux/linux_proto.h> 51100784Sfenner#include <machine/../linux/linux_ipc64.h> 52100784Sfenner#endif 53100784Sfenner#include <compat/linux/linux_ipc.h> 54100784Sfenner#include <compat/linux/linux_util.h> 55100784Sfenner 56100784Sfennerstruct l_seminfo { 57100784Sfenner l_int semmap; 58100784Sfenner l_int semmni; 59100784Sfenner l_int semmns; 60100784Sfenner l_int semmnu; 61100784Sfenner l_int semmsl; 62100784Sfenner l_int semopm; 63100784Sfenner l_int semume; 64100784Sfenner l_int semusz; 65100784Sfenner l_int semvmx; 66100784Sfenner l_int semaem; 67100784Sfenner}; 68100784Sfenner 69100784Sfennerstruct l_shminfo { 70100784Sfenner l_int shmmax; 71100784Sfenner l_int shmmin; 72100784Sfenner l_int shmmni; 73100784Sfenner l_int shmseg; 74100784Sfenner l_int shmall; 75100784Sfenner}; 76100784Sfenner 77100784Sfennerstruct l_shm_info { 78100784Sfenner l_int used_ids; 79100784Sfenner l_ulong shm_tot; /* total allocated shm */ 80100784Sfenner l_ulong shm_rss; /* total resident shm */ 81100784Sfenner l_ulong shm_swp; /* total swapped shm */ 82100784Sfenner l_ulong swap_attempts; 83100784Sfenner l_ulong swap_successes; 84100784Sfenner}; 85100784Sfenner 86100784Sfennerstruct l_msginfo { 87100784Sfenner l_int msgpool; 88100784Sfenner l_int msgmap; 89100784Sfenner l_int msgmax; 90100784Sfenner l_int msgmnb; 91100784Sfenner l_int msgmni; 92100784Sfenner l_int msgssz; 93100784Sfenner l_int msgtql; 94100784Sfenner l_ushort msgseg; 95100784Sfenner}; 96100784Sfenner 97100784Sfennerstatic void 98100784Sfennerbsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp) 99100784Sfenner{ 100100784Sfenner 101100784Sfenner lpp->shmmax = bpp->shmmax; 102100784Sfenner lpp->shmmin = bpp->shmmin; 103100784Sfenner lpp->shmmni = bpp->shmmni; 104100784Sfenner lpp->shmseg = bpp->shmseg; 105100784Sfenner lpp->shmall = bpp->shmall; 106100784Sfenner} 107100784Sfenner 108100784Sfennerstatic void 109100784Sfennerbsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp) 110100784Sfenner{ 111100784Sfenner 112100784Sfenner lpp->used_ids = bpp->used_ids ; 113100784Sfenner lpp->shm_tot = bpp->shm_tot ; 114100784Sfenner lpp->shm_rss = bpp->shm_rss ; 115100784Sfenner lpp->shm_swp = bpp->shm_swp ; 116100784Sfenner lpp->swap_attempts = bpp->swap_attempts ; 117100784Sfenner lpp->swap_successes = bpp->swap_successes ; 118100784Sfenner} 119100784Sfenner 120100784Sfennerstatic void 121100784Sfennerlinux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp) 122100784Sfenner{ 123100784Sfenner 124100784Sfenner bpp->key = lpp->key; 125100784Sfenner bpp->uid = lpp->uid; 126100784Sfenner bpp->gid = lpp->gid; 127100784Sfenner bpp->cuid = lpp->cuid; 128100784Sfenner bpp->cgid = lpp->cgid; 129100784Sfenner bpp->mode = lpp->mode; 130100784Sfenner bpp->seq = lpp->seq; 131100784Sfenner} 132100784Sfenner 133100784Sfenner 134100784Sfennerstatic void 135100784Sfennerbsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp) 136100784Sfenner{ 137100784Sfenner 138100784Sfenner lpp->key = bpp->key; 139100784Sfenner lpp->uid = bpp->uid; 140100784Sfenner lpp->gid = bpp->gid; 141100784Sfenner lpp->cuid = bpp->cuid; 142100784Sfenner lpp->cgid = bpp->cgid; 143100784Sfenner lpp->mode = bpp->mode; 144100784Sfenner lpp->seq = bpp->seq; 145100784Sfenner} 146100784Sfenner 147100784Sfennerstruct l_msqid_ds { 148100784Sfenner struct l_ipc_perm msg_perm; 149100784Sfenner l_uintptr_t msg_first; /* first message on queue,unused */ 150100784Sfenner l_uintptr_t msg_last; /* last message in queue,unused */ 151100784Sfenner l_time_t msg_stime; /* last msgsnd time */ 152100784Sfenner l_time_t msg_rtime; /* last msgrcv time */ 153100784Sfenner l_time_t msg_ctime; /* last change time */ 154100784Sfenner l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */ 155100784Sfenner l_ulong msg_lqbytes; /* ditto */ 156100784Sfenner l_ushort msg_cbytes; /* current number of bytes on queue */ 157100784Sfenner l_ushort msg_qnum; /* number of messages in queue */ 158100784Sfenner l_ushort msg_qbytes; /* max number of bytes on queue */ 159100784Sfenner l_pid_t msg_lspid; /* pid of last msgsnd */ 160100784Sfenner l_pid_t msg_lrpid; /* last receive pid */ 161100784Sfenner} 162100784Sfenner#if defined(__amd64__) && defined(COMPAT_LINUX32) 163100784Sfenner__packed 164100784Sfenner#endif 165100784Sfenner; 166100784Sfenner 167100784Sfennerstruct l_semid_ds { 168100784Sfenner struct l_ipc_perm sem_perm; 169100784Sfenner l_time_t sem_otime; 170100784Sfenner l_time_t sem_ctime; 171100784Sfenner l_uintptr_t sem_base; 172100784Sfenner l_uintptr_t sem_pending; 173100784Sfenner l_uintptr_t sem_pending_last; 174100784Sfenner l_uintptr_t undo; 175100784Sfenner l_ushort sem_nsems; 176100784Sfenner} 177100784Sfenner#if defined(__amd64__) && defined(COMPAT_LINUX32) 178100784Sfenner__packed 179100784Sfenner#endif 180100784Sfenner; 181100784Sfenner 182100784Sfennerstruct l_shmid_ds { 183100784Sfenner struct l_ipc_perm shm_perm; 184100784Sfenner l_int shm_segsz; 185100784Sfenner l_time_t shm_atime; 186100784Sfenner l_time_t shm_dtime; 187100784Sfenner l_time_t shm_ctime; 188100784Sfenner l_ushort shm_cpid; 189100784Sfenner l_ushort shm_lpid; 190100784Sfenner l_short shm_nattch; 191100784Sfenner l_ushort private1; 192100784Sfenner l_uintptr_t private2; 193100784Sfenner l_uintptr_t private3; 194100784Sfenner}; 195100784Sfenner 196100905Sfennerstatic void 197100784Sfennerlinux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp) 198100905Sfenner{ 199100784Sfenner 200100784Sfenner linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); 201100784Sfenner bsp->sem_otime = lsp->sem_otime; 202100784Sfenner bsp->sem_ctime = lsp->sem_ctime; 203100784Sfenner bsp->sem_nsems = lsp->sem_nsems; 204100784Sfenner bsp->sem_base = PTRIN(lsp->sem_base); 205100784Sfenner} 206100784Sfenner 207100784Sfennerstatic void 208100784Sfennerbsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp) 209100784Sfenner{ 210100784Sfenner 211100784Sfenner bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); 212100784Sfenner lsp->sem_otime = bsp->sem_otime; 213100784Sfenner lsp->sem_ctime = bsp->sem_ctime; 214100784Sfenner lsp->sem_nsems = bsp->sem_nsems; 215100784Sfenner lsp->sem_base = PTROUT(bsp->sem_base); 216100784Sfenner} 217100784Sfenner 218100784Sfennerstatic void 219100784Sfennerlinux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp) 220100784Sfenner{ 221 222 linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); 223 bsp->shm_segsz = lsp->shm_segsz; 224 bsp->shm_lpid = lsp->shm_lpid; 225 bsp->shm_cpid = lsp->shm_cpid; 226 bsp->shm_nattch = lsp->shm_nattch; 227 bsp->shm_atime = lsp->shm_atime; 228 bsp->shm_dtime = lsp->shm_dtime; 229 bsp->shm_ctime = lsp->shm_ctime; 230} 231 232static void 233bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp) 234{ 235 236 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); 237 if (bsp->shm_segsz > INT_MAX) 238 lsp->shm_segsz = INT_MAX; 239 else 240 lsp->shm_segsz = bsp->shm_segsz; 241 lsp->shm_lpid = bsp->shm_lpid; 242 lsp->shm_cpid = bsp->shm_cpid; 243 if (bsp->shm_nattch > SHRT_MAX) 244 lsp->shm_nattch = SHRT_MAX; 245 else 246 lsp->shm_nattch = bsp->shm_nattch; 247 lsp->shm_atime = bsp->shm_atime; 248 lsp->shm_dtime = bsp->shm_dtime; 249 lsp->shm_ctime = bsp->shm_ctime; 250 lsp->private3 = 0; 251} 252 253static void 254linux_to_bsd_msqid_ds(struct l_msqid_ds *lsp, struct msqid_ds *bsp) 255{ 256 257 linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm); 258 bsp->msg_cbytes = lsp->msg_cbytes; 259 bsp->msg_qnum = lsp->msg_qnum; 260 bsp->msg_qbytes = lsp->msg_qbytes; 261 bsp->msg_lspid = lsp->msg_lspid; 262 bsp->msg_lrpid = lsp->msg_lrpid; 263 bsp->msg_stime = lsp->msg_stime; 264 bsp->msg_rtime = lsp->msg_rtime; 265 bsp->msg_ctime = lsp->msg_ctime; 266} 267 268static void 269bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid_ds *lsp) 270{ 271 272 bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm); 273 lsp->msg_cbytes = bsp->msg_cbytes; 274 lsp->msg_qnum = bsp->msg_qnum; 275 lsp->msg_qbytes = bsp->msg_qbytes; 276 lsp->msg_lspid = bsp->msg_lspid; 277 lsp->msg_lrpid = bsp->msg_lrpid; 278 lsp->msg_stime = bsp->msg_stime; 279 lsp->msg_rtime = bsp->msg_rtime; 280 lsp->msg_ctime = bsp->msg_ctime; 281} 282 283static void 284linux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out) 285{ 286 287 /* XXX: do we really need to do something here? */ 288 out->key = in->key; 289 out->uid = in->uid; 290 out->gid = in->gid; 291 out->cuid = in->cuid; 292 out->cgid = in->cgid; 293 out->mode = in->mode; 294 out->seq = in->seq; 295} 296 297static int 298linux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) 299{ 300 struct l_msqid64_ds linux_msqid64; 301 int error; 302 303 if (ver == LINUX_IPC_64) { 304 error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64)); 305 if (error != 0) 306 return (error); 307 308 bzero(linux_msqid, sizeof(*linux_msqid)); 309 310 linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid; 311 linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid; 312 linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode; 313 314 if (linux_msqid64.msg_qbytes > USHRT_MAX) 315 linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes; 316 else 317 linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes; 318 } else 319 error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid)); 320 321 return (error); 322} 323 324static int 325linux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) 326{ 327 struct l_msqid64_ds linux_msqid64; 328 329 if (ver == LINUX_IPC_64) { 330 bzero(&linux_msqid64, sizeof(linux_msqid64)); 331 332 linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm, 333 &linux_msqid64.msg_perm); 334 335 linux_msqid64.msg_stime = linux_msqid->msg_stime; 336 linux_msqid64.msg_rtime = linux_msqid->msg_rtime; 337 linux_msqid64.msg_ctime = linux_msqid->msg_ctime; 338 339 if (linux_msqid->msg_cbytes == 0) 340 linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes; 341 else 342 linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes; 343 344 linux_msqid64.msg_qnum = linux_msqid->msg_qnum; 345 346 if (linux_msqid->msg_qbytes == 0) 347 linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes; 348 else 349 linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes; 350 351 linux_msqid64.msg_lspid = linux_msqid->msg_lspid; 352 linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid; 353 354 return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64))); 355 } else 356 return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid))); 357} 358 359static int 360linux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) 361{ 362 struct l_semid64_ds linux_semid64; 363 int error; 364 365 if (ver == LINUX_IPC_64) { 366 error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64)); 367 if (error != 0) 368 return (error); 369 370 bzero(linux_semid, sizeof(*linux_semid)); 371 372 linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid; 373 linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid; 374 linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode; 375 } else 376 error = copyin(uaddr, linux_semid, sizeof(*linux_semid)); 377 378 return (error); 379} 380 381static int 382linux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) 383{ 384 struct l_semid64_ds linux_semid64; 385 386 if (ver == LINUX_IPC_64) { 387 bzero(&linux_semid64, sizeof(linux_semid64)); 388 389 linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm, 390 &linux_semid64.sem_perm); 391 392 linux_semid64.sem_otime = linux_semid->sem_otime; 393 linux_semid64.sem_ctime = linux_semid->sem_ctime; 394 linux_semid64.sem_nsems = linux_semid->sem_nsems; 395 396 return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64))); 397 } else 398 return (copyout(linux_semid, uaddr, sizeof(*linux_semid))); 399} 400 401static int 402linux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) 403{ 404 struct l_shmid64_ds linux_shmid64; 405 int error; 406 407 if (ver == LINUX_IPC_64) { 408 error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64)); 409 if (error != 0) 410 return (error); 411 412 bzero(linux_shmid, sizeof(*linux_shmid)); 413 414 linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid; 415 linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid; 416 linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode; 417 } else 418 error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid)); 419 420 return (error); 421} 422 423static int 424linux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) 425{ 426 struct l_shmid64_ds linux_shmid64; 427 428 /* 429 * XXX: This is backwards and loses information in shm_nattch 430 * and shm_segsz. We should probably either expose the BSD 431 * shmid structure directly and convert it to either the 432 * non-64 or 64 variant directly or the code should always 433 * convert to the 64 variant and then truncate values into the 434 * non-64 variant if needed since the 64 variant has more 435 * precision. 436 */ 437 if (ver == LINUX_IPC_64) { 438 bzero(&linux_shmid64, sizeof(linux_shmid64)); 439 440 linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm, 441 &linux_shmid64.shm_perm); 442 443 linux_shmid64.shm_segsz = linux_shmid->shm_segsz; 444 linux_shmid64.shm_atime = linux_shmid->shm_atime; 445 linux_shmid64.shm_dtime = linux_shmid->shm_dtime; 446 linux_shmid64.shm_ctime = linux_shmid->shm_ctime; 447 linux_shmid64.shm_cpid = linux_shmid->shm_cpid; 448 linux_shmid64.shm_lpid = linux_shmid->shm_lpid; 449 linux_shmid64.shm_nattch = linux_shmid->shm_nattch; 450 451 return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64))); 452 } else 453 return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid))); 454} 455 456static int 457linux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo, 458 caddr_t uaddr) 459{ 460 struct l_shminfo64 linux_shminfo64; 461 462 if (ver == LINUX_IPC_64) { 463 bzero(&linux_shminfo64, sizeof(linux_shminfo64)); 464 465 linux_shminfo64.shmmax = linux_shminfo->shmmax; 466 linux_shminfo64.shmmin = linux_shminfo->shmmin; 467 linux_shminfo64.shmmni = linux_shminfo->shmmni; 468 linux_shminfo64.shmseg = linux_shminfo->shmseg; 469 linux_shminfo64.shmall = linux_shminfo->shmall; 470 471 return (copyout(&linux_shminfo64, uaddr, 472 sizeof(linux_shminfo64))); 473 } else 474 return (copyout(linux_shminfo, uaddr, sizeof(*linux_shminfo))); 475} 476 477int 478linux_semop(struct thread *td, struct linux_semop_args *args) 479{ 480 struct semop_args /* { 481 int semid; 482 struct sembuf *sops; 483 int nsops; 484 } */ bsd_args; 485 486 bsd_args.semid = args->semid; 487 bsd_args.sops = PTRIN(args->tsops); 488 bsd_args.nsops = args->nsops; 489 return (sys_semop(td, &bsd_args)); 490} 491 492int 493linux_semget(struct thread *td, struct linux_semget_args *args) 494{ 495 struct semget_args /* { 496 key_t key; 497 int nsems; 498 int semflg; 499 } */ bsd_args; 500 501 if (args->nsems < 0) 502 return (EINVAL); 503 bsd_args.key = args->key; 504 bsd_args.nsems = args->nsems; 505 bsd_args.semflg = args->semflg; 506 return (sys_semget(td, &bsd_args)); 507} 508 509int 510linux_semctl(struct thread *td, struct linux_semctl_args *args) 511{ 512 struct l_semid_ds linux_semid; 513 struct l_seminfo linux_seminfo; 514 struct semid_ds semid; 515 union semun semun; 516 register_t rval; 517 int cmd, error; 518 519 switch (args->cmd & ~LINUX_IPC_64) { 520 case LINUX_IPC_RMID: 521 cmd = IPC_RMID; 522 break; 523 case LINUX_GETNCNT: 524 cmd = GETNCNT; 525 break; 526 case LINUX_GETPID: 527 cmd = GETPID; 528 break; 529 case LINUX_GETVAL: 530 cmd = GETVAL; 531 break; 532 case LINUX_GETZCNT: 533 cmd = GETZCNT; 534 break; 535 case LINUX_SETVAL: 536 cmd = SETVAL; 537 semun.val = args->arg.val; 538 break; 539 case LINUX_IPC_SET: 540 cmd = IPC_SET; 541 error = linux_semid_pullup(args->cmd & LINUX_IPC_64, 542 &linux_semid, PTRIN(args->arg.buf)); 543 if (error) 544 return (error); 545 linux_to_bsd_semid_ds(&linux_semid, &semid); 546 semun.buf = &semid; 547 return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, 548 td->td_retval)); 549 case LINUX_IPC_STAT: 550 case LINUX_SEM_STAT: 551 if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) 552 cmd = IPC_STAT; 553 else 554 cmd = SEM_STAT; 555 semun.buf = &semid; 556 error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, 557 &rval); 558 if (error) 559 return (error); 560 bsd_to_linux_semid_ds(&semid, &linux_semid); 561 error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, 562 &linux_semid, PTRIN(args->arg.buf)); 563 if (error == 0) 564 td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0; 565 return (error); 566 case LINUX_IPC_INFO: 567 case LINUX_SEM_INFO: 568 bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) - 569 sizeof(linux_seminfo.semmap) ); 570 /* 571 * Linux does not use the semmap field but populates it with 572 * the defined value from SEMMAP, which really is redefined to 573 * SEMMNS, which they define as SEMMNI * SEMMSL. Try to 574 * simulate this returning our dynamic semmns value. 575 */ 576 linux_seminfo.semmap = linux_seminfo.semmns; 577/* XXX BSD equivalent? 578#define used_semids 10 579#define used_sems 10 580 linux_seminfo.semusz = used_semids; 581 linux_seminfo.semaem = used_sems; 582*/ 583 error = copyout(&linux_seminfo, 584 PTRIN(args->arg.buf), sizeof(linux_seminfo)); 585 if (error) 586 return (error); 587 td->td_retval[0] = seminfo.semmni; 588 return (0); /* No need for __semctl call */ 589 case LINUX_GETALL: 590 cmd = GETALL; 591 semun.val = args->arg.val; 592 break; 593 case LINUX_SETALL: 594 cmd = SETALL; 595 semun.val = args->arg.val; 596 break; 597 default: 598 linux_msg(td, "ipc type %d is not implemented", 599 args->cmd & ~LINUX_IPC_64); 600 return (EINVAL); 601 } 602 return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, 603 td->td_retval)); 604} 605 606int 607linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) 608{ 609 const void *msgp; 610 long mtype; 611 l_long lmtype; 612 int error; 613 614 if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) 615 return (EINVAL); 616 msgp = PTRIN(args->msgp); 617 if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0) 618 return (error); 619 mtype = (long)lmtype; 620 return (kern_msgsnd(td, args->msqid, 621 (const char *)msgp + sizeof(lmtype), 622 args->msgsz, args->msgflg, mtype)); 623} 624 625int 626linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) 627{ 628 void *msgp; 629 long mtype; 630 l_long lmtype; 631 int error; 632 633 if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) 634 return (EINVAL); 635 msgp = PTRIN(args->msgp); 636 if ((error = kern_msgrcv(td, args->msqid, 637 (char *)msgp + sizeof(lmtype), args->msgsz, 638 args->msgtyp, args->msgflg, &mtype)) != 0) 639 return (error); 640 lmtype = (l_long)mtype; 641 return (copyout(&lmtype, msgp, sizeof(lmtype))); 642} 643 644int 645linux_msgget(struct thread *td, struct linux_msgget_args *args) 646{ 647 struct msgget_args /* { 648 key_t key; 649 int msgflg; 650 } */ bsd_args; 651 652 bsd_args.key = args->key; 653 bsd_args.msgflg = args->msgflg; 654 return (sys_msgget(td, &bsd_args)); 655} 656 657int 658linux_msgctl(struct thread *td, struct linux_msgctl_args *args) 659{ 660 int error, bsd_cmd; 661 struct l_msqid_ds linux_msqid; 662 struct msqid_ds bsd_msqid; 663 664 bsd_cmd = args->cmd & ~LINUX_IPC_64; 665 switch (bsd_cmd) { 666 case LINUX_IPC_INFO: 667 case LINUX_MSG_INFO: { 668 struct l_msginfo linux_msginfo; 669 670 /* 671 * XXX MSG_INFO uses the same data structure but returns different 672 * dynamic counters in msgpool, msgmap, and msgtql fields. 673 */ 674 linux_msginfo.msgpool = (long)msginfo.msgmni * 675 (long)msginfo.msgmnb / 1024L; /* XXX MSG_INFO. */ 676 linux_msginfo.msgmap = msginfo.msgmnb; /* XXX MSG_INFO. */ 677 linux_msginfo.msgmax = msginfo.msgmax; 678 linux_msginfo.msgmnb = msginfo.msgmnb; 679 linux_msginfo.msgmni = msginfo.msgmni; 680 linux_msginfo.msgssz = msginfo.msgssz; 681 linux_msginfo.msgtql = msginfo.msgtql; /* XXX MSG_INFO. */ 682 linux_msginfo.msgseg = msginfo.msgseg; 683 error = copyout(&linux_msginfo, PTRIN(args->buf), 684 sizeof(linux_msginfo)); 685 if (error == 0) 686 td->td_retval[0] = msginfo.msgmni; /* XXX */ 687 688 return (error); 689 } 690 691 /* 692 * TODO: implement this 693 * case LINUX_MSG_STAT: 694 */ 695 case LINUX_IPC_STAT: 696 /* NOTHING */ 697 break; 698 699 case LINUX_IPC_SET: 700 error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, 701 &linux_msqid, PTRIN(args->buf)); 702 if (error) 703 return (error); 704 linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid); 705 break; 706 707 case LINUX_IPC_RMID: 708 /* NOTHING */ 709 break; 710 711 default: 712 return (EINVAL); 713 break; 714 } 715 716 error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid); 717 if (error != 0) 718 if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) 719 return (error); 720 721 if (bsd_cmd == LINUX_IPC_STAT) { 722 bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid); 723 return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, 724 &linux_msqid, PTRIN(args->buf))); 725 } 726 727 return (0); 728} 729 730int 731linux_shmat(struct thread *td, struct linux_shmat_args *args) 732{ 733 struct shmat_args /* { 734 int shmid; 735 void *shmaddr; 736 int shmflg; 737 } */ bsd_args; 738 int error; 739#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 740 l_uintptr_t addr; 741#endif 742 743 bsd_args.shmid = args->shmid; 744 bsd_args.shmaddr = PTRIN(args->shmaddr); 745 bsd_args.shmflg = args->shmflg; 746 if ((error = sys_shmat(td, &bsd_args))) 747 return (error); 748#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 749 addr = td->td_retval[0]; 750 if ((error = copyout(&addr, PTRIN(args->raddr), sizeof(addr)))) 751 return (error); 752 td->td_retval[0] = 0; 753#endif 754 return (0); 755} 756 757int 758linux_shmdt(struct thread *td, struct linux_shmdt_args *args) 759{ 760 struct shmdt_args /* { 761 void *shmaddr; 762 } */ bsd_args; 763 764 bsd_args.shmaddr = PTRIN(args->shmaddr); 765 return (sys_shmdt(td, &bsd_args)); 766} 767 768int 769linux_shmget(struct thread *td, struct linux_shmget_args *args) 770{ 771 struct shmget_args /* { 772 key_t key; 773 int size; 774 int shmflg; 775 } */ bsd_args; 776 777 bsd_args.key = args->key; 778 bsd_args.size = args->size; 779 bsd_args.shmflg = args->shmflg; 780 return (sys_shmget(td, &bsd_args)); 781} 782 783int 784linux_shmctl(struct thread *td, struct linux_shmctl_args *args) 785{ 786 struct l_shmid_ds linux_shmid; 787 struct l_shminfo linux_shminfo; 788 struct l_shm_info linux_shm_info; 789 struct shmid_ds bsd_shmid; 790 int error; 791 792 switch (args->cmd & ~LINUX_IPC_64) { 793 794 case LINUX_IPC_INFO: { 795 struct shminfo bsd_shminfo; 796 797 /* Perform shmctl wanting removed segments lookup */ 798 error = kern_shmctl(td, args->shmid, IPC_INFO, 799 (void *)&bsd_shminfo, NULL); 800 if (error) 801 return (error); 802 803 bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo); 804 805 return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, 806 &linux_shminfo, PTRIN(args->buf))); 807 } 808 809 case LINUX_SHM_INFO: { 810 struct shm_info bsd_shm_info; 811 812 /* Perform shmctl wanting removed segments lookup */ 813 error = kern_shmctl(td, args->shmid, SHM_INFO, 814 (void *)&bsd_shm_info, NULL); 815 if (error) 816 return (error); 817 818 bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); 819 820 return (copyout(&linux_shm_info, PTRIN(args->buf), 821 sizeof(struct l_shm_info))); 822 } 823 824 case LINUX_IPC_STAT: 825 /* Perform shmctl wanting removed segments lookup */ 826 error = kern_shmctl(td, args->shmid, IPC_STAT, 827 (void *)&bsd_shmid, NULL); 828 if (error) 829 return (error); 830 831 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 832 833 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 834 &linux_shmid, PTRIN(args->buf))); 835 836 case LINUX_SHM_STAT: 837 /* Perform shmctl wanting removed segments lookup */ 838 error = kern_shmctl(td, args->shmid, IPC_STAT, 839 (void *)&bsd_shmid, NULL); 840 if (error) 841 return (error); 842 843 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 844 845 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 846 &linux_shmid, PTRIN(args->buf))); 847 848 case LINUX_IPC_SET: 849 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 850 &linux_shmid, PTRIN(args->buf)); 851 if (error) 852 return (error); 853 854 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 855 856 /* Perform shmctl wanting removed segments lookup */ 857 return (kern_shmctl(td, args->shmid, IPC_SET, 858 (void *)&bsd_shmid, NULL)); 859 860 case LINUX_IPC_RMID: { 861 void *buf; 862 863 if (args->buf == 0) 864 buf = NULL; 865 else { 866 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 867 &linux_shmid, PTRIN(args->buf)); 868 if (error) 869 return (error); 870 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 871 buf = (void *)&bsd_shmid; 872 } 873 return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL)); 874 } 875 876 case LINUX_SHM_LOCK: 877 /* FALLTHROUGH */ 878 case LINUX_SHM_UNLOCK: 879 /* FALLTHROUGH */ 880 default: 881 linux_msg(td, "ipc type %d not implemented", 882 args->cmd & ~LINUX_IPC_64); 883 return (EINVAL); 884 } 885} 886 887MODULE_DEPEND(linux, sysvmsg, 1, 1, 1); 888MODULE_DEPEND(linux, sysvsem, 1, 1, 1); 889MODULE_DEPEND(linux, sysvshm, 1, 1, 1); 890