1 /* $NetBSD: linux_ipc.c,v 1.27 2002/04/03 11:54:37 fvdl 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 <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: linux_ipc.c,v 1.27 2002/04/03 11:54:37 fvdl Exp $"); 41 42 #if defined(_KERNEL_OPT) 43 #include "opt_sysv.h" 44 #endif 45 46 #include <sys/param.h> 47 #include <sys/shm.h> 48 #include <sys/sem.h> 49 #include <sys/msg.h> 50 #include <sys/proc.h> 51 #include <sys/systm.h> 52 53 #include <sys/mount.h> 54 #include <sys/syscallargs.h> 55 56 #include <compat/linux/common/linux_types.h> 57 #include <compat/linux/common/linux_signal.h> 58 #include <compat/linux/common/linux_util.h> 59 60 #include <compat/linux/linux_syscallargs.h> 61 #include <compat/linux/linux_syscall.h> 62 63 #include <compat/linux/common/linux_ipc.h> 64 #include <compat/linux/common/linux_msg.h> 65 #include <compat/linux/common/linux_shm.h> 66 #include <compat/linux/common/linux_sem.h> 67 #include <compat/linux/common/linux_ipccall.h> 68 69 /* 70 * Note: Not all linux architechtures have explicit versions 71 * of the SYSV* syscalls. On the ones that don't 72 * we pretend that they are defined anyway. *_args and 73 * prototypes are defined in individual headers; 74 * syscalls.master lists those syscalls as NOARGS. 75 * 76 * The functions in multiarch are the ones that just need 77 * the arguments shuffled around and then use the 78 * normal NetBSD syscall. 79 * 80 * Function in multiarch: 81 * linux_sys_ipc : linux_ipccall.c 82 * liunx_semop : linux_ipccall.c 83 * linux_semget : linux_ipccall.c 84 * linux_msgsnd : linux_ipccall.c 85 * linux_msgrcv : linux_ipccall.c 86 * linux_msgget : linux_ipccall.c 87 * linux_shmdt : linux_ipccall.c 88 * linux_shmget : linux_ipccall.c 89 */ 90 91 #if defined (SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG) 92 /* 93 * Convert between Linux and NetBSD ipc_perm structures. Only the 94 * order of the fields is different. 95 */ 96 void 97 linux_to_bsd_ipc_perm(lpp, bpp) 98 struct linux_ipc_perm *lpp; 99 struct ipc_perm *bpp; 100 { 101 102 bpp->_key = lpp->l_key; 103 bpp->uid = lpp->l_uid; 104 bpp->gid = lpp->l_gid; 105 bpp->cuid = lpp->l_cuid; 106 bpp->cgid = lpp->l_cgid; 107 bpp->mode = lpp->l_mode; 108 bpp->_seq = lpp->l_seq; 109 } 110 111 void 112 bsd_to_linux_ipc_perm(bpp, lpp) 113 struct ipc_perm *bpp; 114 struct linux_ipc_perm *lpp; 115 { 116 117 lpp->l_key = bpp->_key; 118 lpp->l_uid = bpp->uid; 119 lpp->l_gid = bpp->gid; 120 lpp->l_cuid = bpp->cuid; 121 lpp->l_cgid = bpp->cgid; 122 lpp->l_mode = bpp->mode; 123 lpp->l_seq = bpp->_seq; 124 } 125 #endif 126 127 #ifdef SYSVSEM 128 /* 129 * Semaphore operations. Most constants and structures are the same on 130 * both systems. Only semctl() needs some extra work. 131 */ 132 133 /* 134 * Convert between Linux and NetBSD semid_ds structures. 135 */ 136 void 137 bsd_to_linux_semid_ds(bs, ls) 138 struct semid_ds *bs; 139 struct linux_semid_ds *ls; 140 { 141 142 bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm); 143 ls->l_sem_otime = bs->sem_otime; 144 ls->l_sem_ctime = bs->sem_ctime; 145 ls->l_sem_nsems = bs->sem_nsems; 146 ls->l_sem_base = bs->_sem_base; 147 } 148 149 void 150 linux_to_bsd_semid_ds(ls, bs) 151 struct linux_semid_ds *ls; 152 struct semid_ds *bs; 153 { 154 155 linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm); 156 bs->sem_otime = ls->l_sem_otime; 157 bs->sem_ctime = ls->l_sem_ctime; 158 bs->sem_nsems = ls->l_sem_nsems; 159 bs->_sem_base = ls->l_sem_base; 160 } 161 162 /* 163 * Most of this can be handled by directly passing the arguments on; we 164 * just need to frob the `cmd' and convert the semid_ds and semun. 165 */ 166 int 167 linux_sys_semctl(p, v, retval) 168 struct proc *p; 169 void *v; 170 register_t *retval; 171 { 172 struct linux_sys_semctl_args /* { 173 syscallarg(int) semid; 174 syscallarg(int) semnum; 175 syscallarg(int) cmd; 176 syscallarg(union linux_semun) arg; 177 } */ *uap = v; 178 struct semid_ds sembuf; 179 struct linux_semid_ds lsembuf; 180 union __semun semun; 181 int cmd, error; 182 void *pass_arg = NULL; 183 184 cmd = SCARG(uap, cmd); 185 186 switch (cmd) { 187 case LINUX_IPC_SET: 188 pass_arg = &sembuf; 189 cmd = IPC_SET; 190 break; 191 192 case LINUX_IPC_STAT: 193 pass_arg = &sembuf; 194 cmd = IPC_STAT; 195 break; 196 197 case LINUX_IPC_RMID: 198 cmd = IPC_RMID; 199 break; 200 201 case LINUX_GETVAL: 202 cmd = GETVAL; 203 break; 204 205 case LINUX_GETPID: 206 cmd = GETPID; 207 break; 208 209 case LINUX_GETNCNT: 210 cmd = GETNCNT; 211 break; 212 213 case LINUX_GETZCNT: 214 cmd = GETZCNT; 215 break; 216 217 case LINUX_GETALL: 218 pass_arg = &semun; 219 semun.array = SCARG(uap, arg).l_array; 220 cmd = GETALL; 221 break; 222 223 case LINUX_SETVAL: 224 pass_arg = &semun; 225 semun.val = SCARG(uap, arg).l_val; 226 cmd = SETVAL; 227 break; 228 229 case LINUX_SETALL: 230 pass_arg = &semun; 231 semun.array = SCARG(uap, arg).l_array; 232 cmd = SETALL; 233 break; 234 235 default: 236 return (EINVAL); 237 } 238 239 if (cmd == IPC_SET) { 240 error = copyin(SCARG(uap, arg).l_buf, &lsembuf, 241 sizeof(lsembuf)); 242 if (error) 243 return (error); 244 linux_to_bsd_semid_ds(&lsembuf, &sembuf); 245 } 246 247 error = semctl1(p, SCARG(uap, semid), SCARG(uap, semnum), cmd, 248 pass_arg, retval); 249 250 if (error == 0 && cmd == IPC_STAT) { 251 bsd_to_linux_semid_ds(&sembuf, &lsembuf); 252 error = copyout(&lsembuf, SCARG(uap, arg).l_buf, 253 sizeof(lsembuf)); 254 } 255 256 return (error); 257 } 258 #endif /* SYSVSEM */ 259 260 #ifdef SYSVMSG 261 262 void 263 linux_to_bsd_msqid_ds(lmp, bmp) 264 struct linux_msqid_ds *lmp; 265 struct msqid_ds *bmp; 266 { 267 268 linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm); 269 bmp->_msg_first = lmp->l_msg_first; 270 bmp->_msg_last = lmp->l_msg_last; 271 bmp->_msg_cbytes = lmp->l_msg_cbytes; 272 bmp->msg_qnum = lmp->l_msg_qnum; 273 bmp->msg_qbytes = lmp->l_msg_qbytes; 274 bmp->msg_lspid = lmp->l_msg_lspid; 275 bmp->msg_lrpid = lmp->l_msg_lrpid; 276 bmp->msg_stime = lmp->l_msg_stime; 277 bmp->msg_rtime = lmp->l_msg_rtime; 278 bmp->msg_ctime = lmp->l_msg_ctime; 279 } 280 281 void 282 bsd_to_linux_msqid_ds(bmp, lmp) 283 struct msqid_ds *bmp; 284 struct linux_msqid_ds *lmp; 285 { 286 287 bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm); 288 lmp->l_msg_first = bmp->_msg_first; 289 lmp->l_msg_last = bmp->_msg_last; 290 lmp->l_msg_cbytes = bmp->_msg_cbytes; 291 lmp->l_msg_qnum = bmp->msg_qnum; 292 lmp->l_msg_qbytes = bmp->msg_qbytes; 293 lmp->l_msg_lspid = bmp->msg_lspid; 294 lmp->l_msg_lrpid = bmp->msg_lrpid; 295 lmp->l_msg_stime = bmp->msg_stime; 296 lmp->l_msg_rtime = bmp->msg_rtime; 297 lmp->l_msg_ctime = bmp->msg_ctime; 298 } 299 300 int 301 linux_sys_msgctl(p, v, retval) 302 struct proc *p; 303 void *v; 304 register_t *retval; 305 { 306 struct linux_sys_msgctl_args /* { 307 syscallarg(int) msqid; 308 syscallarg(int) cmd; 309 syscallarg(struct linux_msqid_ds *) buf; 310 } */ *uap = v; 311 caddr_t sg; 312 struct sys___msgctl13_args nua; 313 struct msqid_ds *bmp, bm; 314 struct linux_msqid_ds lm; 315 int error; 316 317 SCARG(&nua, msqid) = SCARG(uap, msqid); 318 switch (SCARG(uap, cmd)) { 319 case LINUX_IPC_STAT: 320 sg = stackgap_init(p, 0); 321 bmp = stackgap_alloc(p, &sg, sizeof (struct msqid_ds)); 322 SCARG(&nua, cmd) = IPC_STAT; 323 SCARG(&nua, buf) = bmp; 324 if ((error = sys___msgctl13(p, &nua, retval))) 325 return error; 326 if ((error = copyin(bmp, &bm, sizeof bm))) 327 return error; 328 bsd_to_linux_msqid_ds(&bm, &lm); 329 return copyout(&lm, SCARG(uap, buf), sizeof lm); 330 case LINUX_IPC_SET: 331 if ((error = copyin(SCARG(uap, buf), &lm, sizeof lm))) 332 return error; 333 linux_to_bsd_msqid_ds(&lm, &bm); 334 sg = stackgap_init(p, 0); 335 bmp = stackgap_alloc(p, &sg, sizeof bm); 336 if ((error = copyout(&bm, bmp, sizeof bm))) 337 return error; 338 SCARG(&nua, cmd) = IPC_SET; 339 SCARG(&nua, buf) = bmp; 340 break; 341 case LINUX_IPC_RMID: 342 SCARG(&nua, cmd) = IPC_RMID; 343 SCARG(&nua, buf) = NULL; 344 break; 345 default: 346 return EINVAL; 347 } 348 return sys___msgctl13(p, &nua, retval); 349 } 350 #endif /* SYSVMSG */ 351 352 #ifdef SYSVSHM 353 /* 354 * shmat(2). Very straightforward, except that Linux passes a pointer 355 * in which the return value is to be passed. This is subsequently 356 * handled by libc, apparently. 357 */ 358 int 359 linux_sys_shmat(p, v, retval) 360 struct proc *p; 361 void *v; 362 register_t *retval; 363 { 364 struct linux_sys_shmat_args /* { 365 syscallarg(int) shmid; 366 syscallarg(void *) shmaddr; 367 syscallarg(int) shmflg; 368 syscallarg(u_long *) raddr; 369 } */ *uap = v; 370 int error; 371 vaddr_t attach_va; 372 u_long raddr; 373 374 if ((error = shmat1(p, SCARG(uap, shmid), SCARG(uap, shmaddr), 375 SCARG(uap, shmflg), &attach_va, 1))) 376 return error; 377 378 raddr = (u_long)attach_va; 379 380 if ((error = copyout(&raddr, (caddr_t) SCARG(uap, raddr), 381 sizeof retval[0]))) 382 return error; 383 384 retval[0] = 0; 385 return 0; 386 } 387 388 /* 389 * Convert between Linux and NetBSD shmid_ds structures. 390 * The order of the fields is once again the difference, and 391 * we also need a place to store the internal data pointer 392 * in, which is unfortunately stored in this structure. 393 * 394 * We abuse a Linux internal field for that. 395 */ 396 void 397 linux_to_bsd_shmid_ds(lsp, bsp) 398 struct linux_shmid_ds *lsp; 399 struct shmid_ds *bsp; 400 { 401 402 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 403 bsp->shm_segsz = lsp->l_shm_segsz; 404 bsp->shm_lpid = lsp->l_shm_lpid; 405 bsp->shm_cpid = lsp->l_shm_cpid; 406 bsp->shm_nattch = lsp->l_shm_nattch; 407 bsp->shm_atime = lsp->l_shm_atime; 408 bsp->shm_dtime = lsp->l_shm_dtime; 409 bsp->shm_ctime = lsp->l_shm_ctime; 410 bsp->_shm_internal = lsp->l_private2; /* XXX Oh well. */ 411 } 412 413 void 414 bsd_to_linux_shmid_ds(bsp, lsp) 415 struct shmid_ds *bsp; 416 struct linux_shmid_ds *lsp; 417 { 418 419 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 420 lsp->l_shm_segsz = bsp->shm_segsz; 421 lsp->l_shm_lpid = bsp->shm_lpid; 422 lsp->l_shm_cpid = bsp->shm_cpid; 423 lsp->l_shm_nattch = bsp->shm_nattch; 424 lsp->l_shm_atime = bsp->shm_atime; 425 lsp->l_shm_dtime = bsp->shm_dtime; 426 lsp->l_shm_ctime = bsp->shm_ctime; 427 lsp->l_private2 = bsp->_shm_internal; /* XXX */ 428 } 429 430 /* 431 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT 432 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented 433 * by NetBSD itself. 434 * 435 * The usual structure conversion and massaging is done. 436 */ 437 int 438 linux_sys_shmctl(p, v, retval) 439 struct proc *p; 440 void *v; 441 register_t *retval; 442 { 443 struct linux_sys_shmctl_args /* { 444 syscallarg(int) shmid; 445 syscallarg(int) cmd; 446 syscallarg(struct linux_shmid_ds *) buf; 447 } */ *uap = v; 448 caddr_t sg; 449 struct sys___shmctl13_args nua; 450 struct shmid_ds *bsp, bs; 451 struct linux_shmid_ds ls; 452 int error; 453 454 SCARG(&nua, shmid) = SCARG(uap, shmid); 455 switch (SCARG(uap, cmd)) { 456 case LINUX_IPC_STAT: 457 sg = stackgap_init(p, 0); 458 bsp = stackgap_alloc(p, &sg, sizeof(struct shmid_ds)); 459 SCARG(&nua, cmd) = IPC_STAT; 460 SCARG(&nua, buf) = bsp; 461 if ((error = sys___shmctl13(p, &nua, retval))) 462 return error; 463 if ((error = copyin(SCARG(&nua, buf), &bs, sizeof bs))) 464 return error; 465 bsd_to_linux_shmid_ds(&bs, &ls); 466 return copyout(&ls, SCARG(uap, buf), sizeof ls); 467 case LINUX_IPC_SET: 468 if ((error = copyin(SCARG(uap, buf), &ls, sizeof ls))) 469 return error; 470 linux_to_bsd_shmid_ds(&ls, &bs); 471 sg = stackgap_init(p, 0); 472 bsp = stackgap_alloc(p, &sg, sizeof bs); 473 if ((error = copyout(&bs, bsp, sizeof bs))) 474 return error; 475 SCARG(&nua, cmd) = IPC_SET; 476 SCARG(&nua, buf) = bsp; 477 break; 478 case LINUX_IPC_RMID: 479 SCARG(&nua, cmd) = IPC_RMID; 480 SCARG(&nua, buf) = NULL; 481 break; 482 case LINUX_SHM_LOCK: 483 SCARG(&nua, cmd) = SHM_LOCK; 484 SCARG(&nua, buf) = NULL; 485 break; 486 case LINUX_SHM_UNLOCK: 487 SCARG(&nua, cmd) = SHM_UNLOCK; 488 SCARG(&nua, buf) = NULL; 489 break; 490 case LINUX_IPC_INFO: 491 case LINUX_SHM_STAT: 492 case LINUX_SHM_INFO: 493 default: 494 return EINVAL; 495 } 496 return sys___shmctl13(p, &nua, retval); 497 } 498 #endif /* SYSVSHM */ 499