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