1 /* $NetBSD: linux_ipc.c,v 1.19 1999/01/03 05:18:01 erh Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden and Eric Haszlakiewicz. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include "opt_sysv.h" 40 41 #include <sys/types.h> 42 #include <sys/param.h> 43 #include <sys/shm.h> 44 #include <sys/sem.h> 45 #include <sys/msg.h> 46 #include <sys/proc.h> 47 #include <sys/systm.h> 48 49 #include <sys/mount.h> 50 #include <sys/syscallargs.h> 51 52 #include <compat/linux/common/linux_types.h> 53 #include <compat/linux/common/linux_signal.h> 54 #include <compat/linux/common/linux_util.h> 55 56 #include <compat/linux/linux_syscallargs.h> 57 #include <compat/linux/linux_syscall.h> 58 59 #include <compat/linux/common/linux_ipc.h> 60 #include <compat/linux/common/linux_msg.h> 61 #include <compat/linux/common/linux_shm.h> 62 #include <compat/linux/common/linux_sem.h> 63 #include <compat/linux/common/linux_ipccall.h> 64 65 /* 66 * Note: Not all linux architechtures have explicit versions 67 * of the SYSV* syscalls. On the ones that don't 68 * we pretend that they are defined anyway. *_args and 69 * prototypes are defined in individual headers; 70 * syscalls.master lists those syscalls as NOARGS. 71 * 72 * The functions in multiarch are the ones that just need 73 * the arguments shuffled around and then use the 74 * normal NetBSD syscall. 75 * 76 * Function in multiarch: 77 * linux_sys_ipc : linux_ipccall.c 78 * liunx_semop : linux_ipccall.c 79 * linux_semget : linux_ipccall.c 80 * linux_msgsnd : linux_ipccall.c 81 * linux_msgrcv : linux_ipccall.c 82 * linux_msgget : linux_ipccall.c 83 * linux_shmdt : linux_ipccall.c 84 * linux_shmget : linux_ipccall.c 85 */ 86 87 #if defined (SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG) 88 /* 89 * Convert between Linux and NetBSD ipc_perm structures. Only the 90 * order of the fields is different. 91 */ 92 void 93 linux_to_bsd_ipc_perm(lpp, bpp) 94 struct linux_ipc_perm *lpp; 95 struct ipc_perm *bpp; 96 { 97 98 bpp->key = lpp->l_key; 99 bpp->uid = lpp->l_uid; 100 bpp->gid = lpp->l_gid; 101 bpp->cuid = lpp->l_cuid; 102 bpp->cgid = lpp->l_cgid; 103 bpp->mode = lpp->l_mode; 104 bpp->seq = lpp->l_seq; 105 } 106 107 void 108 bsd_to_linux_ipc_perm(bpp, lpp) 109 struct ipc_perm *bpp; 110 struct linux_ipc_perm *lpp; 111 { 112 113 lpp->l_key = bpp->key; 114 lpp->l_uid = bpp->uid; 115 lpp->l_gid = bpp->gid; 116 lpp->l_cuid = bpp->cuid; 117 lpp->l_cgid = bpp->cgid; 118 lpp->l_mode = bpp->mode; 119 lpp->l_seq = bpp->seq; 120 } 121 #endif 122 123 #ifdef SYSVSEM 124 /* 125 * Semaphore operations. Most constants and structures are the same on 126 * both systems. Only semctl() needs some extra work. 127 */ 128 129 /* 130 * Convert between Linux and NetBSD semid_ds structures. 131 */ 132 void 133 bsd_to_linux_semid_ds(bs, ls) 134 struct semid_ds *bs; 135 struct linux_semid_ds *ls; 136 { 137 138 bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm); 139 ls->l_sem_otime = bs->sem_otime; 140 ls->l_sem_ctime = bs->sem_ctime; 141 ls->l_sem_nsems = bs->sem_nsems; 142 ls->l_sem_base = bs->sem_base; 143 } 144 145 void 146 linux_to_bsd_semid_ds(ls, bs) 147 struct linux_semid_ds *ls; 148 struct semid_ds *bs; 149 { 150 151 linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm); 152 bs->sem_otime = ls->l_sem_otime; 153 bs->sem_ctime = ls->l_sem_ctime; 154 bs->sem_nsems = ls->l_sem_nsems; 155 bs->sem_base = ls->l_sem_base; 156 } 157 158 /* 159 * Most of this can be handled by directly passing the arguments on, 160 * but IPC_* require a lot of copy{in,out} because of the extra indirection 161 * (we need to pass a pointer to a union cointaining a pointer to a semid_ds 162 * structure. Linux actually handles this better than we do.) 163 */ 164 int 165 linux_sys_semctl(p, v, retval) 166 struct proc *p; 167 void *v; 168 register_t *retval; 169 { 170 struct linux_sys_semctl_args /* { 171 syscallarg(int) semid; 172 syscallarg(int) semnum; 173 syscallarg(int) cmd; 174 syscallarg(union linux_semun) arg; 175 } */ *uap = v; 176 caddr_t sg; 177 struct sys___semctl_args nua; 178 struct semid_ds *bmp, bm; 179 struct linux_semid_ds lm; 180 union semun *bup; 181 int error; 182 183 SCARG(&nua, semid) = SCARG(uap, semid); 184 SCARG(&nua, semnum) = SCARG(uap, semnum); 185 switch (SCARG(uap, cmd)) { 186 case LINUX_IPC_STAT: 187 sg = stackgap_init(p->p_emul); 188 bup = stackgap_alloc(&sg, sizeof (union semun)); 189 bmp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 190 if ((error = copyout(&bmp, bup, sizeof bmp))) 191 return error; 192 SCARG(&nua, cmd) = IPC_STAT; 193 SCARG(&nua, arg) = bup; 194 if ((error = sys___semctl(p, &nua, retval))) 195 return error; 196 if ((error = copyin(bmp, &bm, sizeof bm))) 197 return error; 198 bsd_to_linux_semid_ds(&bm, &lm); 199 return copyout(&lm, SCARG(uap, arg).l_buf, sizeof lm); 200 case LINUX_IPC_SET: 201 if ((error = copyin(SCARG(uap, arg).l_buf, &lm, sizeof lm))) 202 return error; 203 linux_to_bsd_semid_ds(&lm, &bm); 204 sg = stackgap_init(p->p_emul); 205 bup = stackgap_alloc(&sg, sizeof (union semun)); 206 bmp = stackgap_alloc(&sg, sizeof (struct semid_ds)); 207 if ((error = copyout(&bm, bmp, sizeof bm))) 208 return error; 209 if ((error = copyout(&bmp, bup, sizeof bmp))) 210 return error; 211 SCARG(&nua, cmd) = IPC_SET; 212 SCARG(&nua, arg) = bup; 213 break; 214 case LINUX_IPC_RMID: 215 SCARG(&nua, cmd) = IPC_RMID; 216 break; 217 case LINUX_GETVAL: 218 SCARG(&nua, cmd) = GETVAL; 219 break; 220 case LINUX_GETPID: 221 SCARG(&nua, cmd) = GETPID; 222 break; 223 case LINUX_GETNCNT: 224 SCARG(&nua, cmd) = GETNCNT; 225 break; 226 case LINUX_GETZCNT: 227 SCARG(&nua, cmd) = GETZCNT; 228 break; 229 case LINUX_SETVAL: 230 SCARG(&nua, cmd) = SETVAL; 231 break; 232 default: 233 return EINVAL; 234 } 235 return sys___semctl(p, &nua, retval); 236 } 237 #endif /* SYSVSEM */ 238 239 #ifdef SYSVMSG 240 241 void 242 linux_to_bsd_msqid_ds(lmp, bmp) 243 struct linux_msqid_ds *lmp; 244 struct msqid_ds *bmp; 245 { 246 247 linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm); 248 bmp->msg_first = lmp->l_msg_first; 249 bmp->msg_last = lmp->l_msg_last; 250 bmp->msg_cbytes = lmp->l_msg_cbytes; 251 bmp->msg_qnum = lmp->l_msg_qnum; 252 bmp->msg_qbytes = lmp->l_msg_qbytes; 253 bmp->msg_lspid = lmp->l_msg_lspid; 254 bmp->msg_lrpid = lmp->l_msg_lrpid; 255 bmp->msg_stime = lmp->l_msg_stime; 256 bmp->msg_rtime = lmp->l_msg_rtime; 257 bmp->msg_ctime = lmp->l_msg_ctime; 258 } 259 260 void 261 bsd_to_linux_msqid_ds(bmp, lmp) 262 struct msqid_ds *bmp; 263 struct linux_msqid_ds *lmp; 264 { 265 266 bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm); 267 lmp->l_msg_first = bmp->msg_first; 268 lmp->l_msg_last = bmp->msg_last; 269 lmp->l_msg_cbytes = bmp->msg_cbytes; 270 lmp->l_msg_qnum = bmp->msg_qnum; 271 lmp->l_msg_qbytes = bmp->msg_qbytes; 272 lmp->l_msg_lspid = bmp->msg_lspid; 273 lmp->l_msg_lrpid = bmp->msg_lrpid; 274 lmp->l_msg_stime = bmp->msg_stime; 275 lmp->l_msg_rtime = bmp->msg_rtime; 276 lmp->l_msg_ctime = bmp->msg_ctime; 277 } 278 279 int 280 linux_sys_msgctl(p, v, retval) 281 struct proc *p; 282 void *v; 283 register_t *retval; 284 { 285 struct linux_sys_msgctl_args /* { 286 syscallarg(int) msqid; 287 syscallarg(int) cmd; 288 syscallarg(struct linux_msqid_ds *) buf; 289 } */ *uap = v; 290 caddr_t sg; 291 struct sys_msgctl_args nua; 292 struct msqid_ds *bmp, bm; 293 struct linux_msqid_ds lm; 294 int error; 295 296 SCARG(&nua, msqid) = SCARG(uap, msqid); 297 switch (SCARG(uap, cmd)) { 298 case LINUX_IPC_STAT: 299 sg = stackgap_init(p->p_emul); 300 bmp = stackgap_alloc(&sg, sizeof (struct msqid_ds)); 301 SCARG(&nua, cmd) = IPC_STAT; 302 SCARG(&nua, buf) = bmp; 303 if ((error = sys_msgctl(p, &nua, retval))) 304 return error; 305 if ((error = copyin(bmp, &bm, sizeof bm))) 306 return error; 307 bsd_to_linux_msqid_ds(&bm, &lm); 308 return copyout(&lm, SCARG(uap, buf), sizeof lm); 309 case LINUX_IPC_SET: 310 if ((error = copyin(SCARG(uap, buf), &lm, sizeof lm))) 311 return error; 312 linux_to_bsd_msqid_ds(&lm, &bm); 313 sg = stackgap_init(p->p_emul); 314 bmp = stackgap_alloc(&sg, sizeof bm); 315 if ((error = copyout(&bm, bmp, sizeof bm))) 316 return error; 317 SCARG(&nua, cmd) = IPC_SET; 318 SCARG(&nua, buf) = bmp; 319 break; 320 case LINUX_IPC_RMID: 321 SCARG(&nua, cmd) = IPC_RMID; 322 SCARG(&nua, buf) = NULL; 323 break; 324 default: 325 return EINVAL; 326 } 327 return sys_msgctl(p, &nua, retval); 328 } 329 #endif /* SYSVMSG */ 330 331 #ifdef SYSVSHM 332 /* 333 * shmat(2). Very straightforward, except that Linux passes a pointer 334 * in which the return value is to be passed. This is subsequently 335 * handled by libc, apparently. 336 */ 337 int 338 linux_sys_shmat(p, v, retval) 339 struct proc *p; 340 void *v; 341 register_t *retval; 342 { 343 struct linux_sys_shmat_args /* { 344 syscallarg(int) shmid; 345 syscallarg(void *) shmaddr; 346 syscallarg(int) shmflg; 347 syscallarg(u_long *) raddr; 348 } */ *uap = v; 349 int error; 350 351 if ((error = sys_shmat(p, uap, retval))) 352 return error; 353 354 if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, raddr), 355 sizeof retval[0]))) 356 return error; 357 358 retval[0] = 0; 359 return 0; 360 } 361 362 /* 363 * Convert between Linux and NetBSD shmid_ds structures. 364 * The order of the fields is once again the difference, and 365 * we also need a place to store the internal data pointer 366 * in, which is unfortunately stored in this structure. 367 * 368 * We abuse a Linux internal field for that. 369 */ 370 void 371 linux_to_bsd_shmid_ds(lsp, bsp) 372 struct linux_shmid_ds *lsp; 373 struct shmid_ds *bsp; 374 { 375 376 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 377 bsp->shm_segsz = lsp->l_shm_segsz; 378 bsp->shm_lpid = lsp->l_shm_lpid; 379 bsp->shm_cpid = lsp->l_shm_cpid; 380 bsp->shm_nattch = lsp->l_shm_nattch; 381 bsp->shm_atime = lsp->l_shm_atime; 382 bsp->shm_dtime = lsp->l_shm_dtime; 383 bsp->shm_ctime = lsp->l_shm_ctime; 384 bsp->shm_internal = lsp->l_private2; /* XXX Oh well. */ 385 } 386 387 void 388 bsd_to_linux_shmid_ds(bsp, lsp) 389 struct shmid_ds *bsp; 390 struct linux_shmid_ds *lsp; 391 { 392 393 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 394 lsp->l_shm_segsz = bsp->shm_segsz; 395 lsp->l_shm_lpid = bsp->shm_lpid; 396 lsp->l_shm_cpid = bsp->shm_cpid; 397 lsp->l_shm_nattch = bsp->shm_nattch; 398 lsp->l_shm_atime = bsp->shm_atime; 399 lsp->l_shm_dtime = bsp->shm_dtime; 400 lsp->l_shm_ctime = bsp->shm_ctime; 401 lsp->l_private2 = bsp->shm_internal; /* XXX */ 402 } 403 404 /* 405 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT 406 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented 407 * by NetBSD itself. 408 * 409 * The usual structure conversion and massaging is done. 410 */ 411 int 412 linux_sys_shmctl(p, v, retval) 413 struct proc *p; 414 void *v; 415 register_t *retval; 416 { 417 struct linux_sys_shmctl_args /* { 418 syscallarg(int) shmid; 419 syscallarg(int) cmd; 420 syscallarg(struct linux_shmid_ds *) buf; 421 } */ *uap = v; 422 caddr_t sg; 423 struct sys_shmctl_args nua; 424 struct shmid_ds *bsp, bs; 425 struct linux_shmid_ds ls; 426 int error; 427 428 SCARG(&nua, shmid) = SCARG(uap, shmid); 429 switch (SCARG(uap, cmd)) { 430 case LINUX_IPC_STAT: 431 sg = stackgap_init(p->p_emul); 432 bsp = stackgap_alloc(&sg, sizeof(struct shmid_ds)); 433 SCARG(&nua, cmd) = IPC_STAT; 434 SCARG(&nua, buf) = bsp; 435 if ((error = sys_shmctl(p, &nua, retval))) 436 return error; 437 if ((error = copyin(SCARG(&nua, buf), &bs, sizeof bs))) 438 return error; 439 bsd_to_linux_shmid_ds(&bs, &ls); 440 return copyout(&ls, SCARG(uap, buf), sizeof ls); 441 case LINUX_IPC_SET: 442 if ((error = copyin(SCARG(uap, buf), &ls, sizeof ls))) 443 return error; 444 linux_to_bsd_shmid_ds(&ls, &bs); 445 sg = stackgap_init(p->p_emul); 446 bsp = stackgap_alloc(&sg, sizeof bs); 447 if ((error = copyout(&bs, bsp, sizeof bs))) 448 return error; 449 SCARG(&nua, cmd) = IPC_SET; 450 SCARG(&nua, buf) = bsp; 451 break; 452 case LINUX_IPC_RMID: 453 SCARG(&nua, cmd) = IPC_RMID; 454 SCARG(&nua, buf) = NULL; 455 break; 456 case LINUX_SHM_LOCK: 457 SCARG(&nua, cmd) = SHM_LOCK; 458 SCARG(&nua, buf) = NULL; 459 break; 460 case LINUX_SHM_UNLOCK: 461 SCARG(&nua, cmd) = SHM_UNLOCK; 462 SCARG(&nua, buf) = NULL; 463 break; 464 case LINUX_IPC_INFO: 465 case LINUX_SHM_STAT: 466 case LINUX_SHM_INFO: 467 default: 468 return EINVAL; 469 } 470 return sys_shmctl(p, &nua, retval); 471 } 472 #endif /* SYSVSHM */ 473