19313Ssos/*- 29313Ssos * Copyright (c) 1994-1995 S�ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Redistribution and use in source and binary forms, with or without 69313Ssos * modification, are permitted provided that the following conditions 79313Ssos * are met: 89313Ssos * 1. Redistributions of source code must retain the above copyright 9111798Sdes * notice, this list of conditions and the following disclaimer 109313Ssos * in this position and unchanged. 119313Ssos * 2. Redistributions in binary form must reproduce the above copyright 129313Ssos * notice, this list of conditions and the following disclaimer in the 139313Ssos * documentation and/or other materials provided with the distribution. 149313Ssos * 3. The name of the author may not be used to endorse or promote products 1597748Sschweikh * derived from this software without specific prior written permission 169313Ssos * 179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279313Ssos */ 289313Ssos 29116173Sobrien#include <sys/cdefs.h> 30116173Sobrien__FBSDID("$FreeBSD$"); 31116173Sobrien 329313Ssos#include <sys/param.h> 339313Ssos#include <sys/systm.h> 34114724Smbr#include <sys/syscallsubr.h> 3512458Sbde#include <sys/sysproto.h> 369313Ssos#include <sys/proc.h> 37114216Skan#include <sys/limits.h> 38104893Ssobomax#include <sys/msg.h> 3930804Skato#include <sys/sem.h> 409313Ssos#include <sys/shm.h> 419313Ssos 42156874Sru#include "opt_compat.h" 43156874Sru 44140214Sobrien#ifdef COMPAT_LINUX32 45140214Sobrien#include <machine/../linux32/linux.h> 46140214Sobrien#include <machine/../linux32/linux32_proto.h> 47140214Sobrien#include <machine/../linux32/linux32_ipc64.h> 48140214Sobrien#else 4964906Smarcel#include <machine/../linux/linux.h> 5068583Smarcel#include <machine/../linux/linux_proto.h> 51104893Ssobomax#include <machine/../linux/linux_ipc64.h> 52133816Stjr#endif 5364906Smarcel#include <compat/linux/linux_ipc.h> 5464906Smarcel#include <compat/linux/linux_util.h> 559313Ssos 5683501Smrstruct l_seminfo { 5783501Smr l_int semmap; 5883501Smr l_int semmni; 5983501Smr l_int semmns; 6083501Smr l_int semmnu; 6183501Smr l_int semmsl; 6283501Smr l_int semopm; 6383501Smr l_int semume; 6483501Smr l_int semusz; 6583501Smr l_int semvmx; 6683501Smr l_int semaem; 6783501Smr}; 6883501Smr 6983501Smrstruct l_shminfo { 7083501Smr l_int shmmax; 7183501Smr l_int shmmin; 7283501Smr l_int shmmni; 7383501Smr l_int shmseg; 7483501Smr l_int shmall; 7583501Smr}; 7683501Smr 7783501Smrstruct l_shm_info { 7883501Smr l_int used_ids; 7983501Smr l_ulong shm_tot; /* total allocated shm */ 8083501Smr l_ulong shm_rss; /* total resident shm */ 8183501Smr l_ulong shm_swp; /* total swapped shm */ 8283501Smr l_ulong swap_attempts; 8383501Smr l_ulong swap_successes; 8483501Smr}; 8583501Smr 86165407Sjkimstruct l_msginfo { 87165407Sjkim l_int msgpool; 88165407Sjkim l_int msgmap; 89165407Sjkim l_int msgmax; 90165407Sjkim l_int msgmnb; 91165407Sjkim l_int msgmni; 92165407Sjkim l_int msgssz; 93165407Sjkim l_int msgtql; 94165407Sjkim l_ushort msgseg; 95165407Sjkim}; 96165407Sjkim 9785623Smrstatic void 9885623Smrbsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp) 9985623Smr{ 100219558Sdchagin 10185623Smr lpp->shmmax = bpp->shmmax; 10285623Smr lpp->shmmin = bpp->shmmin; 10385623Smr lpp->shmmni = bpp->shmmni; 10485623Smr lpp->shmseg = bpp->shmseg; 10585623Smr lpp->shmall = bpp->shmall; 10685623Smr} 10785623Smr 10885623Smrstatic void 10985623Smrbsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp) 11085623Smr{ 111219558Sdchagin 11285623Smr lpp->used_ids = bpp->used_ids ; 11385623Smr lpp->shm_tot = bpp->shm_tot ; 11485623Smr lpp->shm_rss = bpp->shm_rss ; 11585623Smr lpp->shm_swp = bpp->shm_swp ; 11685623Smr lpp->swap_attempts = bpp->swap_attempts ; 11785623Smr lpp->swap_successes = bpp->swap_successes ; 11885623Smr} 11985623Smr 12083221Smarcelstruct l_ipc_perm { 12183221Smarcel l_key_t key; 12283221Smarcel l_uid16_t uid; 12383221Smarcel l_gid16_t gid; 12483221Smarcel l_uid16_t cuid; 12583221Smarcel l_gid16_t cgid; 12683221Smarcel l_ushort mode; 12783221Smarcel l_ushort seq; 1289313Ssos}; 1299313Ssos 1309313Ssosstatic void 13183221Smarcellinux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp) 1329313Ssos{ 133219558Sdchagin 134219558Sdchagin bpp->key = lpp->key; 135219558Sdchagin bpp->uid = lpp->uid; 136219558Sdchagin bpp->gid = lpp->gid; 137219558Sdchagin bpp->cuid = lpp->cuid; 138219558Sdchagin bpp->cgid = lpp->cgid; 139219558Sdchagin bpp->mode = lpp->mode; 140219558Sdchagin bpp->seq = lpp->seq; 1419313Ssos} 1429313Ssos 1439313Ssos 1449313Ssosstatic void 14583221Smarcelbsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp) 1469313Ssos{ 147219558Sdchagin 148219558Sdchagin lpp->key = bpp->key; 149219558Sdchagin lpp->uid = bpp->uid; 150219558Sdchagin lpp->gid = bpp->gid; 151219558Sdchagin lpp->cuid = bpp->cuid; 152219558Sdchagin lpp->cgid = bpp->cgid; 153219558Sdchagin lpp->mode = bpp->mode; 154219558Sdchagin lpp->seq = bpp->seq; 1559313Ssos} 1569313Ssos 157104893Ssobomaxstruct l_msqid_ds { 158104893Ssobomax struct l_ipc_perm msg_perm; 159133816Stjr l_uintptr_t msg_first; /* first message on queue,unused */ 160133816Stjr l_uintptr_t msg_last; /* last message in queue,unused */ 161104893Ssobomax l_time_t msg_stime; /* last msgsnd time */ 162104893Ssobomax l_time_t msg_rtime; /* last msgrcv time */ 163104893Ssobomax l_time_t msg_ctime; /* last change time */ 164104893Ssobomax l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */ 165104893Ssobomax l_ulong msg_lqbytes; /* ditto */ 166104893Ssobomax l_ushort msg_cbytes; /* current number of bytes on queue */ 167104893Ssobomax l_ushort msg_qnum; /* number of messages in queue */ 168104893Ssobomax l_ushort msg_qbytes; /* max number of bytes on queue */ 169104893Ssobomax l_pid_t msg_lspid; /* pid of last msgsnd */ 170104893Ssobomax l_pid_t msg_lrpid; /* last receive pid */ 171133816Stjr} 172140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 173133816Stjr__packed 174133816Stjr#endif 175133816Stjr; 176104893Ssobomax 17783221Smarcelstruct l_semid_ds { 17883221Smarcel struct l_ipc_perm sem_perm; 17983221Smarcel l_time_t sem_otime; 18083221Smarcel l_time_t sem_ctime; 181133816Stjr l_uintptr_t sem_base; 182133816Stjr l_uintptr_t sem_pending; 183133816Stjr l_uintptr_t sem_pending_last; 184133816Stjr l_uintptr_t undo; 18583221Smarcel l_ushort sem_nsems; 186133816Stjr} 187140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 188133816Stjr__packed 189133816Stjr#endif 190133816Stjr; 19130804Skato 19283221Smarcelstruct l_shmid_ds { 19383221Smarcel struct l_ipc_perm shm_perm; 19483221Smarcel l_int shm_segsz; 19583221Smarcel l_time_t shm_atime; 19683221Smarcel l_time_t shm_dtime; 19783221Smarcel l_time_t shm_ctime; 19883221Smarcel l_ushort shm_cpid; 19983221Smarcel l_ushort shm_lpid; 20083221Smarcel l_short shm_nattch; 20183221Smarcel l_ushort private1; 202133816Stjr l_uintptr_t private2; 203133816Stjr l_uintptr_t private3; 2049313Ssos}; 2059313Ssos 2069313Ssosstatic void 20783221Smarcellinux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp) 20830804Skato{ 209219558Sdchagin 210219558Sdchagin linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); 211219558Sdchagin bsp->sem_otime = lsp->sem_otime; 212219558Sdchagin bsp->sem_ctime = lsp->sem_ctime; 213219558Sdchagin bsp->sem_nsems = lsp->sem_nsems; 214219558Sdchagin bsp->sem_base = PTRIN(lsp->sem_base); 21530804Skato} 21630804Skato 21730804Skatostatic void 21883221Smarcelbsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp) 21930804Skato{ 220219558Sdchagin 22130804Skato bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); 22230804Skato lsp->sem_otime = bsp->sem_otime; 22330804Skato lsp->sem_ctime = bsp->sem_ctime; 22430804Skato lsp->sem_nsems = bsp->sem_nsems; 225133816Stjr lsp->sem_base = PTROUT(bsp->sem_base); 22630804Skato} 22730804Skato 22830804Skatostatic void 22983221Smarcellinux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp) 2309313Ssos{ 231219558Sdchagin 232219558Sdchagin linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); 233219558Sdchagin bsp->shm_segsz = lsp->shm_segsz; 234219558Sdchagin bsp->shm_lpid = lsp->shm_lpid; 235219558Sdchagin bsp->shm_cpid = lsp->shm_cpid; 236219558Sdchagin bsp->shm_nattch = lsp->shm_nattch; 237219558Sdchagin bsp->shm_atime = lsp->shm_atime; 238219558Sdchagin bsp->shm_dtime = lsp->shm_dtime; 239219558Sdchagin bsp->shm_ctime = lsp->shm_ctime; 2409313Ssos} 2419313Ssos 2429313Ssosstatic void 24383221Smarcelbsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp) 2449313Ssos{ 245219558Sdchagin 246219558Sdchagin bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); 247219558Sdchagin if (bsp->shm_segsz > INT_MAX) 248219558Sdchagin lsp->shm_segsz = INT_MAX; 249219558Sdchagin else 250219558Sdchagin lsp->shm_segsz = bsp->shm_segsz; 251219558Sdchagin lsp->shm_lpid = bsp->shm_lpid; 252219558Sdchagin lsp->shm_cpid = bsp->shm_cpid; 253219558Sdchagin if (bsp->shm_nattch > SHRT_MAX) 254219558Sdchagin lsp->shm_nattch = SHRT_MAX; 255219558Sdchagin else 256219558Sdchagin lsp->shm_nattch = bsp->shm_nattch; 257219558Sdchagin lsp->shm_atime = bsp->shm_atime; 258219558Sdchagin lsp->shm_dtime = bsp->shm_dtime; 259219558Sdchagin lsp->shm_ctime = bsp->shm_ctime; 260219558Sdchagin lsp->private3 = 0; 2619313Ssos} 2629313Ssos 263104893Ssobomaxstatic void 264104893Ssobomaxlinux_to_bsd_msqid_ds(struct l_msqid_ds *lsp, struct msqid_ds *bsp) 265104893Ssobomax{ 266219558Sdchagin 267219558Sdchagin linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm); 268219558Sdchagin bsp->msg_cbytes = lsp->msg_cbytes; 269219558Sdchagin bsp->msg_qnum = lsp->msg_qnum; 270219558Sdchagin bsp->msg_qbytes = lsp->msg_qbytes; 271219558Sdchagin bsp->msg_lspid = lsp->msg_lspid; 272219558Sdchagin bsp->msg_lrpid = lsp->msg_lrpid; 273219558Sdchagin bsp->msg_stime = lsp->msg_stime; 274219558Sdchagin bsp->msg_rtime = lsp->msg_rtime; 275219558Sdchagin bsp->msg_ctime = lsp->msg_ctime; 276104893Ssobomax} 277104893Ssobomax 278104893Ssobomaxstatic void 279104893Ssobomaxbsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid_ds *lsp) 280104893Ssobomax{ 281219558Sdchagin 282219558Sdchagin bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm); 283219558Sdchagin lsp->msg_cbytes = bsp->msg_cbytes; 284219558Sdchagin lsp->msg_qnum = bsp->msg_qnum; 285219558Sdchagin lsp->msg_qbytes = bsp->msg_qbytes; 286219558Sdchagin lsp->msg_lspid = bsp->msg_lspid; 287219558Sdchagin lsp->msg_lrpid = bsp->msg_lrpid; 288219558Sdchagin lsp->msg_stime = bsp->msg_stime; 289219558Sdchagin lsp->msg_rtime = bsp->msg_rtime; 290219558Sdchagin lsp->msg_ctime = bsp->msg_ctime; 291104893Ssobomax} 292104893Ssobomax 293104893Ssobomaxstatic void 294104893Ssobomaxlinux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out) 295104893Ssobomax{ 296104893Ssobomax 297104893Ssobomax /* XXX: do we really need to do something here? */ 298104893Ssobomax out->key = in->key; 299104893Ssobomax out->uid = in->uid; 300104893Ssobomax out->gid = in->gid; 301104893Ssobomax out->cuid = in->cuid; 302104893Ssobomax out->cgid = in->cgid; 303104893Ssobomax out->mode = in->mode; 304104893Ssobomax out->seq = in->seq; 305104893Ssobomax} 306111798Sdes 307104893Ssobomaxstatic int 308104893Ssobomaxlinux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) 309104893Ssobomax{ 310104893Ssobomax struct l_msqid64_ds linux_msqid64; 311104893Ssobomax int error; 312104893Ssobomax 313104893Ssobomax if (ver == LINUX_IPC_64) { 314104893Ssobomax error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64)); 315104893Ssobomax if (error != 0) 316104893Ssobomax return (error); 317104893Ssobomax 318104893Ssobomax bzero(linux_msqid, sizeof(*linux_msqid)); 319104893Ssobomax 320104893Ssobomax linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid; 321104893Ssobomax linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid; 322104893Ssobomax linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode; 323104893Ssobomax 324104893Ssobomax if (linux_msqid64.msg_qbytes > USHRT_MAX) 325104893Ssobomax linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes; 326104893Ssobomax else 327104893Ssobomax linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes; 328219558Sdchagin } else 329104893Ssobomax error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid)); 330219558Sdchagin 331104893Ssobomax return (error); 332104893Ssobomax} 333104893Ssobomax 334104893Ssobomaxstatic int 335104893Ssobomaxlinux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) 336104893Ssobomax{ 337104893Ssobomax struct l_msqid64_ds linux_msqid64; 338104893Ssobomax 339104893Ssobomax if (ver == LINUX_IPC_64) { 340104893Ssobomax bzero(&linux_msqid64, sizeof(linux_msqid64)); 341104893Ssobomax 342104893Ssobomax linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm, 343104893Ssobomax &linux_msqid64.msg_perm); 344104893Ssobomax 345104893Ssobomax linux_msqid64.msg_stime = linux_msqid->msg_stime; 346104893Ssobomax linux_msqid64.msg_rtime = linux_msqid->msg_rtime; 347104893Ssobomax linux_msqid64.msg_ctime = linux_msqid->msg_ctime; 348104893Ssobomax 349104893Ssobomax if (linux_msqid->msg_cbytes == 0) 350104893Ssobomax linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes; 351104893Ssobomax else 352104893Ssobomax linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes; 353104893Ssobomax 354104893Ssobomax linux_msqid64.msg_qnum = linux_msqid->msg_qnum; 355104893Ssobomax 356104893Ssobomax if (linux_msqid->msg_qbytes == 0) 357104893Ssobomax linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes; 358104893Ssobomax else 359104893Ssobomax linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes; 360104893Ssobomax 361104893Ssobomax linux_msqid64.msg_lspid = linux_msqid->msg_lspid; 362104893Ssobomax linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid; 363104893Ssobomax 364104893Ssobomax return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64))); 365219558Sdchagin } else 366104893Ssobomax return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid))); 367104893Ssobomax} 368104893Ssobomax 369104893Ssobomaxstatic int 370104893Ssobomaxlinux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) 371104893Ssobomax{ 372104893Ssobomax struct l_semid64_ds linux_semid64; 373104893Ssobomax int error; 374104893Ssobomax 375104893Ssobomax if (ver == LINUX_IPC_64) { 376104893Ssobomax error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64)); 377104893Ssobomax if (error != 0) 378104893Ssobomax return (error); 379104893Ssobomax 380104893Ssobomax bzero(linux_semid, sizeof(*linux_semid)); 381104893Ssobomax 382104893Ssobomax linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid; 383104893Ssobomax linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid; 384104893Ssobomax linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode; 385219558Sdchagin } else 386104893Ssobomax error = copyin(uaddr, linux_semid, sizeof(*linux_semid)); 387219558Sdchagin 388104893Ssobomax return (error); 389104893Ssobomax} 390104893Ssobomax 391104893Ssobomaxstatic int 392104893Ssobomaxlinux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) 393104893Ssobomax{ 394104893Ssobomax struct l_semid64_ds linux_semid64; 395104893Ssobomax 396104893Ssobomax if (ver == LINUX_IPC_64) { 397104893Ssobomax bzero(&linux_semid64, sizeof(linux_semid64)); 398104893Ssobomax 399104893Ssobomax linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm, 400104893Ssobomax &linux_semid64.sem_perm); 401104893Ssobomax 402104893Ssobomax linux_semid64.sem_otime = linux_semid->sem_otime; 403104893Ssobomax linux_semid64.sem_ctime = linux_semid->sem_ctime; 404104893Ssobomax linux_semid64.sem_nsems = linux_semid->sem_nsems; 405104893Ssobomax 406104893Ssobomax return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64))); 407219558Sdchagin } else 408104893Ssobomax return (copyout(linux_semid, uaddr, sizeof(*linux_semid))); 409104893Ssobomax} 410104893Ssobomax 411104893Ssobomaxstatic int 412104893Ssobomaxlinux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) 413104893Ssobomax{ 414104893Ssobomax struct l_shmid64_ds linux_shmid64; 415104893Ssobomax int error; 416104893Ssobomax 417104893Ssobomax if (ver == LINUX_IPC_64) { 418104893Ssobomax error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64)); 419104893Ssobomax if (error != 0) 420104893Ssobomax return (error); 421104893Ssobomax 422104893Ssobomax bzero(linux_shmid, sizeof(*linux_shmid)); 423104893Ssobomax 424104893Ssobomax linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid; 425104893Ssobomax linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid; 426104893Ssobomax linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode; 427219558Sdchagin } else 428104893Ssobomax error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid)); 429219558Sdchagin 430104893Ssobomax return (error); 431104893Ssobomax} 432104893Ssobomax 433104893Ssobomaxstatic int 434104893Ssobomaxlinux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) 435104893Ssobomax{ 436104893Ssobomax struct l_shmid64_ds linux_shmid64; 437104893Ssobomax 438194910Sjhb /* 439194910Sjhb * XXX: This is backwards and loses information in shm_nattch 440194910Sjhb * and shm_segsz. We should probably either expose the BSD 441194910Sjhb * shmid structure directly and convert it to either the 442194910Sjhb * non-64 or 64 variant directly or the code should always 443194910Sjhb * convert to the 64 variant and then truncate values into the 444194910Sjhb * non-64 variant if needed since the 64 variant has more 445194910Sjhb * precision. 446194910Sjhb */ 447104893Ssobomax if (ver == LINUX_IPC_64) { 448104893Ssobomax bzero(&linux_shmid64, sizeof(linux_shmid64)); 449104893Ssobomax 450104893Ssobomax linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm, 451104893Ssobomax &linux_shmid64.shm_perm); 452104893Ssobomax 453104893Ssobomax linux_shmid64.shm_segsz = linux_shmid->shm_segsz; 454104893Ssobomax linux_shmid64.shm_atime = linux_shmid->shm_atime; 455104893Ssobomax linux_shmid64.shm_dtime = linux_shmid->shm_dtime; 456104893Ssobomax linux_shmid64.shm_ctime = linux_shmid->shm_ctime; 457104893Ssobomax linux_shmid64.shm_cpid = linux_shmid->shm_cpid; 458104893Ssobomax linux_shmid64.shm_lpid = linux_shmid->shm_lpid; 459104893Ssobomax linux_shmid64.shm_nattch = linux_shmid->shm_nattch; 460104893Ssobomax 461104893Ssobomax return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64))); 462219558Sdchagin } else 463104893Ssobomax return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid))); 464104893Ssobomax} 465104893Ssobomax 466104893Ssobomaxstatic int 467104893Ssobomaxlinux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo, 468104893Ssobomax caddr_t uaddr) 469104893Ssobomax{ 470104893Ssobomax struct l_shminfo64 linux_shminfo64; 471104893Ssobomax 472104893Ssobomax if (ver == LINUX_IPC_64) { 473104893Ssobomax bzero(&linux_shminfo64, sizeof(linux_shminfo64)); 474104893Ssobomax 475104893Ssobomax linux_shminfo64.shmmax = linux_shminfo->shmmax; 476104893Ssobomax linux_shminfo64.shmmin = linux_shminfo->shmmin; 477104893Ssobomax linux_shminfo64.shmmni = linux_shminfo->shmmni; 478104893Ssobomax linux_shminfo64.shmseg = linux_shminfo->shmseg; 479104893Ssobomax linux_shminfo64.shmall = linux_shminfo->shmall; 480104893Ssobomax 481104893Ssobomax return (copyout(&linux_shminfo64, uaddr, 482104893Ssobomax sizeof(linux_shminfo64))); 483219558Sdchagin } else 484104893Ssobomax return (copyout(linux_shminfo, uaddr, sizeof(*linux_shminfo))); 485104893Ssobomax} 486104893Ssobomax 48764906Smarcelint 48883366Sjulianlinux_semop(struct thread *td, struct linux_semop_args *args) 4899313Ssos{ 49030804Skato struct semop_args /* { 49130804Skato int semid; 49230804Skato struct sembuf *sops; 49330804Skato int nsops; 49430804Skato } */ bsd_args; 49530804Skato 49683221Smarcel bsd_args.semid = args->semid; 497163215Sjhb bsd_args.sops = PTRIN(args->tsops); 49883221Smarcel bsd_args.nsops = args->nsops; 499225617Skmacy return (sys_semop(td, &bsd_args)); 5009313Ssos} 5019313Ssos 50264906Smarcelint 50383366Sjulianlinux_semget(struct thread *td, struct linux_semget_args *args) 5049313Ssos{ 50530804Skato struct semget_args /* { 50630804Skato key_t key; 50730804Skato int nsems; 50830804Skato int semflg; 50930804Skato } */ bsd_args; 51030804Skato 511104893Ssobomax if (args->nsems < 0) 512104893Ssobomax return (EINVAL); 51383221Smarcel bsd_args.key = args->key; 51483221Smarcel bsd_args.nsems = args->nsems; 51583221Smarcel bsd_args.semflg = args->semflg; 516225617Skmacy return (sys_semget(td, &bsd_args)); 5179313Ssos} 5189313Ssos 51964906Smarcelint 52083366Sjulianlinux_semctl(struct thread *td, struct linux_semctl_args *args) 5219313Ssos{ 52283221Smarcel struct l_semid_ds linux_semid; 52383501Smr struct l_seminfo linux_seminfo; 524159991Sjhb struct semid_ds semid; 525159991Sjhb union semun semun; 526160187Sjhb register_t rval; 527159991Sjhb int cmd, error; 52830804Skato 529104893Ssobomax switch (args->cmd & ~LINUX_IPC_64) { 53030804Skato case LINUX_IPC_RMID: 531159991Sjhb cmd = IPC_RMID; 53230804Skato break; 53330804Skato case LINUX_GETNCNT: 534159991Sjhb cmd = GETNCNT; 53530804Skato break; 53630804Skato case LINUX_GETPID: 537159991Sjhb cmd = GETPID; 53830804Skato break; 53930804Skato case LINUX_GETVAL: 540159991Sjhb cmd = GETVAL; 54130804Skato break; 54230804Skato case LINUX_GETZCNT: 543159991Sjhb cmd = GETZCNT; 54430804Skato break; 54530804Skato case LINUX_SETVAL: 546159991Sjhb cmd = SETVAL; 547159991Sjhb semun.val = args->arg.val; 54830804Skato break; 54930804Skato case LINUX_IPC_SET: 550159991Sjhb cmd = IPC_SET; 551104893Ssobomax error = linux_semid_pullup(args->cmd & LINUX_IPC_64, 552163215Sjhb &linux_semid, PTRIN(args->arg.buf)); 55330804Skato if (error) 55483221Smarcel return (error); 555159991Sjhb linux_to_bsd_semid_ds(&linux_semid, &semid); 556159991Sjhb semun.buf = &semid; 557160187Sjhb return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, 558160187Sjhb td->td_retval)); 55930804Skato case LINUX_IPC_STAT: 56083501Smr case LINUX_SEM_STAT: 561160187Sjhb if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) 562159991Sjhb cmd = IPC_STAT; 56383501Smr else 564159991Sjhb cmd = SEM_STAT; 565159991Sjhb semun.buf = &semid; 566159991Sjhb error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, 567160187Sjhb &rval); 56830804Skato if (error) 569159991Sjhb return (error); 570159991Sjhb bsd_to_linux_semid_ds(&semid, &linux_semid); 571160187Sjhb error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, 572163215Sjhb &linux_semid, PTRIN(args->arg.buf)); 573160187Sjhb if (error == 0) 574160187Sjhb td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0; 575160187Sjhb return (error); 57683501Smr case LINUX_IPC_INFO: 57783501Smr case LINUX_SEM_INFO: 578224016Sbz bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) - 579224016Sbz sizeof(linux_seminfo.semmap) ); 580224016Sbz /* 581224123Sbz * Linux does not use the semmap field but populates it with 582224123Sbz * the defined value from SEMMAP, which really is redefined to 583224123Sbz * SEMMNS, which they define as SEMMNI * SEMMSL. Try to 584224123Sbz * simulate this returning our dynamic semmns value. 585224016Sbz */ 586224016Sbz linux_seminfo.semmap = linux_seminfo.semmns; 58783501Smr/* XXX BSD equivalent? 58883501Smr#define used_semids 10 58983501Smr#define used_sems 10 59083501Smr linux_seminfo.semusz = used_semids; 59183501Smr linux_seminfo.semaem = used_sems; 59283501Smr*/ 593133816Stjr error = copyout(&linux_seminfo, 594133816Stjr PTRIN(args->arg.buf), sizeof(linux_seminfo)); 59583501Smr if (error) 596219558Sdchagin return (error); 59783501Smr td->td_retval[0] = seminfo.semmni; 598219558Sdchagin return (0); /* No need for __semctl call */ 59930804Skato case LINUX_GETALL: 600166008Snetchild cmd = GETALL; 601166008Snetchild semun.val = args->arg.val; 602166008Snetchild break; 60330804Skato case LINUX_SETALL: 604166008Snetchild cmd = SETALL; 605166008Snetchild semun.val = args->arg.val; 606166008Snetchild break; 60730804Skato default: 608108541Salfred linux_msg(td, "ipc type %d is not implemented", 609104893Ssobomax args->cmd & ~LINUX_IPC_64); 610219558Sdchagin return (EINVAL); 61130804Skato } 612160187Sjhb return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, 613160187Sjhb td->td_retval)); 6149313Ssos} 6159313Ssos 61664906Smarcelint 61783366Sjulianlinux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) 6189313Ssos{ 619165404Sjkim const void *msgp; 620165404Sjkim long mtype; 621165404Sjkim l_long lmtype; 622165404Sjkim int error; 62313111Ssos 624165407Sjkim if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) 625165404Sjkim return (EINVAL); 626165404Sjkim msgp = PTRIN(args->msgp); 627165404Sjkim if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0) 628165404Sjkim return (error); 629165404Sjkim mtype = (long)lmtype; 630165404Sjkim return (kern_msgsnd(td, args->msqid, 631165404Sjkim (const char *)msgp + sizeof(lmtype), 632165404Sjkim args->msgsz, args->msgflg, mtype)); 6339313Ssos} 6349313Ssos 63564906Smarcelint 63683366Sjulianlinux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) 6379313Ssos{ 638165404Sjkim void *msgp; 639165404Sjkim long mtype; 640165404Sjkim l_long lmtype; 641165404Sjkim int error; 64213111Ssos 643165407Sjkim if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) 644165404Sjkim return (EINVAL); 645165404Sjkim msgp = PTRIN(args->msgp); 646165404Sjkim if ((error = kern_msgrcv(td, args->msqid, 647165404Sjkim (char *)msgp + sizeof(lmtype), args->msgsz, 648165404Sjkim args->msgtyp, args->msgflg, &mtype)) != 0) 649165404Sjkim return (error); 650165404Sjkim lmtype = (l_long)mtype; 651165404Sjkim return (copyout(&lmtype, msgp, sizeof(lmtype))); 6529313Ssos} 6539313Ssos 65464906Smarcelint 65583366Sjulianlinux_msgget(struct thread *td, struct linux_msgget_args *args) 6569313Ssos{ 657219558Sdchagin struct msgget_args /* { 658219558Sdchagin key_t key; 659219558Sdchagin int msgflg; 660219558Sdchagin } */ bsd_args; 66113111Ssos 662219558Sdchagin bsd_args.key = args->key; 663219558Sdchagin bsd_args.msgflg = args->msgflg; 664225617Skmacy return (sys_msgget(td, &bsd_args)); 6659313Ssos} 6669313Ssos 66764906Smarcelint 66883366Sjulianlinux_msgctl(struct thread *td, struct linux_msgctl_args *args) 6699313Ssos{ 670219558Sdchagin int error, bsd_cmd; 671219558Sdchagin struct l_msqid_ds linux_msqid; 672219558Sdchagin struct msqid_ds bsd_msqid; 67313111Ssos 674219558Sdchagin bsd_cmd = args->cmd & ~LINUX_IPC_64; 675219558Sdchagin switch (bsd_cmd) { 676219558Sdchagin case LINUX_IPC_INFO: 677219558Sdchagin case LINUX_MSG_INFO: { 678219558Sdchagin struct l_msginfo linux_msginfo; 679165407Sjkim 680219558Sdchagin /* 681219558Sdchagin * XXX MSG_INFO uses the same data structure but returns different 682219558Sdchagin * dynamic counters in msgpool, msgmap, and msgtql fields. 683219558Sdchagin */ 684219558Sdchagin linux_msginfo.msgpool = (long)msginfo.msgmni * 685219558Sdchagin (long)msginfo.msgmnb / 1024L; /* XXX MSG_INFO. */ 686219558Sdchagin linux_msginfo.msgmap = msginfo.msgmnb; /* XXX MSG_INFO. */ 687219558Sdchagin linux_msginfo.msgmax = msginfo.msgmax; 688219558Sdchagin linux_msginfo.msgmnb = msginfo.msgmnb; 689219558Sdchagin linux_msginfo.msgmni = msginfo.msgmni; 690219558Sdchagin linux_msginfo.msgssz = msginfo.msgssz; 691219558Sdchagin linux_msginfo.msgtql = msginfo.msgtql; /* XXX MSG_INFO. */ 692219558Sdchagin linux_msginfo.msgseg = msginfo.msgseg; 693219558Sdchagin error = copyout(&linux_msginfo, PTRIN(args->buf), 694219558Sdchagin sizeof(linux_msginfo)); 695219558Sdchagin if (error == 0) 696219558Sdchagin td->td_retval[0] = msginfo.msgmni; /* XXX */ 697165407Sjkim 698219558Sdchagin return (error); 699219558Sdchagin } 700165407Sjkim 701219558Sdchagin /* 702219558Sdchagin * TODO: implement this 703219558Sdchagin * case LINUX_MSG_STAT: 704219558Sdchagin */ 705219558Sdchagin case LINUX_IPC_STAT: 706219558Sdchagin /* NOTHING */ 707219558Sdchagin break; 708185337Srdivacky 709219558Sdchagin case LINUX_IPC_SET: 710219558Sdchagin error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, 711219558Sdchagin &linux_msqid, PTRIN(args->buf)); 712219558Sdchagin if (error) 713219558Sdchagin return (error); 714219558Sdchagin linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid); 715219558Sdchagin break; 716185337Srdivacky 717219558Sdchagin case LINUX_IPC_RMID: 718219558Sdchagin /* NOTHING */ 719219558Sdchagin break; 720185337Srdivacky 721219558Sdchagin default: 722219558Sdchagin return (EINVAL); 723219558Sdchagin break; 724219558Sdchagin } 725104893Ssobomax 726219558Sdchagin error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid); 727219558Sdchagin if (error != 0) 728219558Sdchagin if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) 729219558Sdchagin return (error); 730104893Ssobomax 731219558Sdchagin if (bsd_cmd == LINUX_IPC_STAT) { 732219558Sdchagin bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid); 733219558Sdchagin return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, 734219558Sdchagin &linux_msqid, PTRIN(args->buf))); 735219558Sdchagin } 736104893Ssobomax 737219558Sdchagin return (0); 7389313Ssos} 7399313Ssos 74064906Smarcelint 74183366Sjulianlinux_shmat(struct thread *td, struct linux_shmat_args *args) 7429313Ssos{ 743219558Sdchagin struct shmat_args /* { 744219558Sdchagin int shmid; 745219558Sdchagin void *shmaddr; 746219558Sdchagin int shmflg; 747219558Sdchagin } */ bsd_args; 748219558Sdchagin int error; 749140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 750219558Sdchagin l_uintptr_t addr; 751133816Stjr#endif 7529313Ssos 753219558Sdchagin bsd_args.shmid = args->shmid; 754219558Sdchagin bsd_args.shmaddr = PTRIN(args->shmaddr); 755219558Sdchagin bsd_args.shmflg = args->shmflg; 756225617Skmacy if ((error = sys_shmat(td, &bsd_args))) 757219558Sdchagin return (error); 758140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 759219558Sdchagin addr = td->td_retval[0]; 760219558Sdchagin if ((error = copyout(&addr, PTRIN(args->raddr), sizeof(addr)))) 761219558Sdchagin return (error); 762219558Sdchagin td->td_retval[0] = 0; 76368214Sgallatin#endif 764219558Sdchagin return (0); 7659313Ssos} 7669313Ssos 76764906Smarcelint 76883366Sjulianlinux_shmdt(struct thread *td, struct linux_shmdt_args *args) 7699313Ssos{ 770219558Sdchagin struct shmdt_args /* { 771219558Sdchagin void *shmaddr; 772219558Sdchagin } */ bsd_args; 7739313Ssos 774219558Sdchagin bsd_args.shmaddr = PTRIN(args->shmaddr); 775225617Skmacy return (sys_shmdt(td, &bsd_args)); 7769313Ssos} 7779313Ssos 77864906Smarcelint 77983366Sjulianlinux_shmget(struct thread *td, struct linux_shmget_args *args) 7809313Ssos{ 781219558Sdchagin struct shmget_args /* { 782219558Sdchagin key_t key; 783219558Sdchagin int size; 784219558Sdchagin int shmflg; 785219558Sdchagin } */ bsd_args; 7869313Ssos 787219558Sdchagin bsd_args.key = args->key; 788219558Sdchagin bsd_args.size = args->size; 789219558Sdchagin bsd_args.shmflg = args->shmflg; 790225617Skmacy return (sys_shmget(td, &bsd_args)); 7919313Ssos} 7929313Ssos 79364906Smarcelint 79483366Sjulianlinux_shmctl(struct thread *td, struct linux_shmctl_args *args) 7959313Ssos{ 796219558Sdchagin struct l_shmid_ds linux_shmid; 79785623Smr struct l_shminfo linux_shminfo; 79885623Smr struct l_shm_info linux_shm_info; 799114724Smbr struct shmid_ds bsd_shmid; 800219558Sdchagin int error; 8019313Ssos 802219558Sdchagin switch (args->cmd & ~LINUX_IPC_64) { 80385623Smr 804114724Smbr case LINUX_IPC_INFO: { 805219558Sdchagin struct shminfo bsd_shminfo; 806114724Smbr 807219558Sdchagin /* Perform shmctl wanting removed segments lookup */ 808219558Sdchagin error = kern_shmctl(td, args->shmid, IPC_INFO, 809219558Sdchagin (void *)&bsd_shminfo, NULL); 810219558Sdchagin if (error) 811219558Sdchagin return (error); 81285623Smr 813219558Sdchagin bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo); 814219558Sdchagin 815219558Sdchagin return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, 816219558Sdchagin &linux_shminfo, PTRIN(args->buf))); 817114724Smbr } 81885623Smr 819114724Smbr case LINUX_SHM_INFO: { 820219558Sdchagin struct shm_info bsd_shm_info; 8219313Ssos 822219558Sdchagin /* Perform shmctl wanting removed segments lookup */ 823219558Sdchagin error = kern_shmctl(td, args->shmid, SHM_INFO, 824219558Sdchagin (void *)&bsd_shm_info, NULL); 825219558Sdchagin if (error) 826219558Sdchagin return (error); 827114724Smbr 828219558Sdchagin bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); 829114724Smbr 830219558Sdchagin return (copyout(&linux_shm_info, PTRIN(args->buf), 831219558Sdchagin sizeof(struct l_shm_info))); 83285623Smr } 833114724Smbr 834114724Smbr case LINUX_IPC_STAT: 835219558Sdchagin /* Perform shmctl wanting removed segments lookup */ 836219558Sdchagin error = kern_shmctl(td, args->shmid, IPC_STAT, 837219558Sdchagin (void *)&bsd_shmid, NULL); 838219558Sdchagin if (error) 839219558Sdchagin return (error); 840114724Smbr 841219558Sdchagin bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 842114724Smbr 843219558Sdchagin return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 844219558Sdchagin &linux_shmid, PTRIN(args->buf))); 84585623Smr 846219558Sdchagin case LINUX_SHM_STAT: 847219558Sdchagin /* Perform shmctl wanting removed segments lookup */ 848219558Sdchagin error = kern_shmctl(td, args->shmid, IPC_STAT, 849219558Sdchagin (void *)&bsd_shmid, NULL); 850219558Sdchagin if (error) 851219558Sdchagin return (error); 852114724Smbr 853219558Sdchagin bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 854114724Smbr 855219558Sdchagin return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 856219558Sdchagin &linux_shmid, PTRIN(args->buf))); 8579313Ssos 858219558Sdchagin case LINUX_IPC_SET: 859219558Sdchagin error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 860163215Sjhb &linux_shmid, PTRIN(args->buf)); 861114724Smbr if (error) 862219558Sdchagin return (error); 863219558Sdchagin 864114724Smbr linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 865219558Sdchagin 866219558Sdchagin /* Perform shmctl wanting removed segments lookup */ 867219558Sdchagin return (kern_shmctl(td, args->shmid, IPC_SET, 868219558Sdchagin (void *)&bsd_shmid, NULL)); 869219558Sdchagin 870219558Sdchagin case LINUX_IPC_RMID: { 871219558Sdchagin void *buf; 872219558Sdchagin 873219558Sdchagin if (args->buf == 0) 874219558Sdchagin buf = NULL; 875219558Sdchagin else { 876219558Sdchagin error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 877219558Sdchagin &linux_shmid, PTRIN(args->buf)); 878219558Sdchagin if (error) 879219558Sdchagin return (error); 880219558Sdchagin linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 881219558Sdchagin buf = (void *)&bsd_shmid; 882219558Sdchagin } 883219558Sdchagin return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL)); 88436587Sjkh } 8859313Ssos 886219558Sdchagin case LINUX_SHM_LOCK: 887219558Sdchagin /* FALLTHROUGH */ 888219558Sdchagin case LINUX_SHM_UNLOCK: 889219558Sdchagin /* FALLTHROUGH */ 890219558Sdchagin default: 891219558Sdchagin linux_msg(td, "ipc type %d not implemented", 892219558Sdchagin args->cmd & ~LINUX_IPC_64); 893219558Sdchagin return (EINVAL); 894219558Sdchagin } 8959313Ssos} 896148540Sjhb 897148540SjhbMODULE_DEPEND(linux, sysvmsg, 1, 1, 1); 898148540SjhbMODULE_DEPEND(linux, sysvsem, 1, 1, 1); 899148540SjhbMODULE_DEPEND(linux, sysvshm, 1, 1, 1); 900