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