linux_ipc.c revision 84067
1/*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD: head/sys/compat/linux/linux_ipc.c 84067 2001-09-28 01:15:30Z marcel $ 29 */ 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/sysproto.h> 34#include <sys/proc.h> 35#include <sys/sem.h> 36#include <sys/shm.h> 37 38#include <machine/../linux/linux.h> 39#include <machine/../linux/linux_proto.h> 40#include <compat/linux/linux_ipc.h> 41#include <compat/linux/linux_util.h> 42 43struct l_seminfo { 44 l_int semmap; 45 l_int semmni; 46 l_int semmns; 47 l_int semmnu; 48 l_int semmsl; 49 l_int semopm; 50 l_int semume; 51 l_int semusz; 52 l_int semvmx; 53 l_int semaem; 54}; 55 56struct l_shminfo { 57 l_int shmmax; 58 l_int shmmin; 59 l_int shmmni; 60 l_int shmseg; 61 l_int shmall; 62}; 63 64struct l_shm_info { 65 l_int used_ids; 66 l_ulong shm_tot; /* total allocated shm */ 67 l_ulong shm_rss; /* total resident shm */ 68 l_ulong shm_swp; /* total swapped shm */ 69 l_ulong swap_attempts; 70 l_ulong swap_successes; 71}; 72 73struct l_ipc_perm { 74 l_key_t key; 75 l_uid16_t uid; 76 l_gid16_t gid; 77 l_uid16_t cuid; 78 l_gid16_t cgid; 79 l_ushort mode; 80 l_ushort seq; 81}; 82 83static void 84linux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp) 85{ 86 bpp->key = lpp->key; 87 bpp->uid = lpp->uid; 88 bpp->gid = lpp->gid; 89 bpp->cuid = lpp->cuid; 90 bpp->cgid = lpp->cgid; 91 bpp->mode = lpp->mode; 92 bpp->seq = lpp->seq; 93} 94 95 96static void 97bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp) 98{ 99 lpp->key = bpp->key; 100 lpp->uid = bpp->uid; 101 lpp->gid = bpp->gid; 102 lpp->cuid = bpp->cuid; 103 lpp->cgid = bpp->cgid; 104 lpp->mode = bpp->mode; 105 lpp->seq = bpp->seq; 106} 107 108struct l_semid_ds { 109 struct l_ipc_perm sem_perm; 110 l_time_t sem_otime; 111 l_time_t sem_ctime; 112 void *sem_base; 113 void *sem_pending; 114 void *sem_pending_last; 115 void *undo; 116 l_ushort sem_nsems; 117}; 118 119struct l_shmid_ds { 120 struct l_ipc_perm shm_perm; 121 l_int shm_segsz; 122 l_time_t shm_atime; 123 l_time_t shm_dtime; 124 l_time_t shm_ctime; 125 l_ushort shm_cpid; 126 l_ushort shm_lpid; 127 l_short shm_nattch; 128 l_ushort private1; 129 void *private2; 130 void *private3; 131}; 132 133static void 134linux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp) 135{ 136 linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); 137 bsp->sem_otime = lsp->sem_otime; 138 bsp->sem_ctime = lsp->sem_ctime; 139 bsp->sem_nsems = lsp->sem_nsems; 140 bsp->sem_base = lsp->sem_base; 141} 142 143static void 144bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp) 145{ 146 bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); 147 lsp->sem_otime = bsp->sem_otime; 148 lsp->sem_ctime = bsp->sem_ctime; 149 lsp->sem_nsems = bsp->sem_nsems; 150 lsp->sem_base = bsp->sem_base; 151} 152 153static void 154linux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp) 155{ 156 linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); 157 bsp->shm_segsz = lsp->shm_segsz; 158 bsp->shm_lpid = lsp->shm_lpid; 159 bsp->shm_cpid = lsp->shm_cpid; 160 bsp->shm_nattch = lsp->shm_nattch; 161 bsp->shm_atime = lsp->shm_atime; 162 bsp->shm_dtime = lsp->shm_dtime; 163 bsp->shm_ctime = lsp->shm_ctime; 164 bsp->shm_internal = lsp->private3; /* this goes (yet) SOS */ 165} 166 167static void 168bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp) 169{ 170 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); 171 lsp->shm_segsz = bsp->shm_segsz; 172 lsp->shm_lpid = bsp->shm_lpid; 173 lsp->shm_cpid = bsp->shm_cpid; 174 lsp->shm_nattch = bsp->shm_nattch; 175 lsp->shm_atime = bsp->shm_atime; 176 lsp->shm_dtime = bsp->shm_dtime; 177 lsp->shm_ctime = bsp->shm_ctime; 178 lsp->private3 = bsp->shm_internal; /* this goes (yet) SOS */ 179} 180 181int 182linux_semop(struct thread *td, struct linux_semop_args *args) 183{ 184 struct semop_args /* { 185 int semid; 186 struct sembuf *sops; 187 int nsops; 188 } */ bsd_args; 189 190 bsd_args.semid = args->semid; 191 bsd_args.sops = (struct sembuf *)args->tsops; 192 bsd_args.nsops = args->nsops; 193 return semop(td, &bsd_args); 194} 195 196int 197linux_semget(struct thread *td, struct linux_semget_args *args) 198{ 199 struct semget_args /* { 200 key_t key; 201 int nsems; 202 int semflg; 203 } */ bsd_args; 204 205 bsd_args.key = args->key; 206 bsd_args.nsems = args->nsems; 207 bsd_args.semflg = args->semflg; 208 return semget(td, &bsd_args); 209} 210 211int 212linux_semctl(struct thread *td, struct linux_semctl_args *args) 213{ 214 struct l_semid_ds linux_semid; 215 struct __semctl_args /* { 216 int semid; 217 int semnum; 218 int cmd; 219 union semun *arg; 220 } */ bsd_args; 221 struct l_seminfo linux_seminfo; 222 int error; 223 union semun *unptr; 224 caddr_t sg; 225 226 sg = stackgap_init(); 227 228 /* Make sure the arg parameter can be copied in. */ 229 unptr = stackgap_alloc(&sg, sizeof(union semun)); 230 bcopy(&args->arg, unptr, sizeof(union semun)); 231 232 bsd_args.semid = args->semid; 233 bsd_args.semnum = args->semnum; 234 bsd_args.arg = unptr; 235 236 switch (args->cmd) { 237 case LINUX_IPC_RMID: 238 bsd_args.cmd = IPC_RMID; 239 break; 240 case LINUX_GETNCNT: 241 bsd_args.cmd = GETNCNT; 242 break; 243 case LINUX_GETPID: 244 bsd_args.cmd = GETPID; 245 break; 246 case LINUX_GETVAL: 247 bsd_args.cmd = GETVAL; 248 break; 249 case LINUX_GETZCNT: 250 bsd_args.cmd = GETZCNT; 251 break; 252 case LINUX_SETVAL: 253 bsd_args.cmd = SETVAL; 254 break; 255 case LINUX_IPC_SET: 256 bsd_args.cmd = IPC_SET; 257 error = copyin((caddr_t)args->arg.buf, &linux_semid, 258 sizeof(linux_semid)); 259 if (error) 260 return (error); 261 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 262 linux_to_bsd_semid_ds(&linux_semid, unptr->buf); 263 return __semctl(td, &bsd_args); 264 case LINUX_IPC_STAT: 265 case LINUX_SEM_STAT: 266 if( args->cmd == LINUX_IPC_STAT ) 267 bsd_args.cmd = IPC_STAT; 268 else 269 bsd_args.cmd = SEM_STAT; 270 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 271 error = __semctl(td, &bsd_args); 272 if (error) 273 return error; 274 td->td_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid, 275 unptr->buf->sem_perm); 276 bsd_to_linux_semid_ds(unptr->buf, &linux_semid); 277 return copyout(&linux_semid, (caddr_t)args->arg.buf, 278 sizeof(linux_semid)); 279 case LINUX_IPC_INFO: 280 case LINUX_SEM_INFO: 281 error = copyin((caddr_t)args->arg.buf, &linux_seminfo, 282 sizeof(linux_seminfo) ); 283 if (error) 284 return error; 285 bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) ); 286/* XXX BSD equivalent? 287#define used_semids 10 288#define used_sems 10 289 linux_seminfo.semusz = used_semids; 290 linux_seminfo.semaem = used_sems; 291*/ 292 error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf, 293 sizeof(linux_seminfo) ); 294 if (error) 295 return error; 296 td->td_retval[0] = seminfo.semmni; 297 return 0; /* No need for __semctl call */ 298 case LINUX_GETALL: 299 /* FALLTHROUGH */ 300 case LINUX_SETALL: 301 /* FALLTHROUGH */ 302 default: 303 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); 304 return EINVAL; 305 } 306 return __semctl(td, &bsd_args); 307} 308 309int 310linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) 311{ 312 struct msgsnd_args /* { 313 int msqid; 314 void *msgp; 315 size_t msgsz; 316 int msgflg; 317 } */ bsd_args; 318 319 bsd_args.msqid = args->msqid; 320 bsd_args.msgp = args->msgp; 321 bsd_args.msgsz = args->msgsz; 322 bsd_args.msgflg = args->msgflg; 323 return msgsnd(td, &bsd_args); 324} 325 326int 327linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) 328{ 329 struct msgrcv_args /* { 330 int msqid; 331 void *msgp; 332 size_t msgsz; 333 long msgtyp; 334 int msgflg; 335 } */ bsd_args; 336 337 bsd_args.msqid = args->msqid; 338 bsd_args.msgp = args->msgp; 339 bsd_args.msgsz = args->msgsz; 340 bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */ 341 bsd_args.msgflg = args->msgflg; 342 return msgrcv(td, &bsd_args); 343} 344 345int 346linux_msgget(struct thread *td, struct linux_msgget_args *args) 347{ 348 struct msgget_args /* { 349 key_t key; 350 int msgflg; 351 } */ bsd_args; 352 353 bsd_args.key = args->key; 354 bsd_args.msgflg = args->msgflg; 355 return msgget(td, &bsd_args); 356} 357 358int 359linux_msgctl(struct thread *td, struct linux_msgctl_args *args) 360{ 361 struct msgctl_args /* { 362 int msqid; 363 int cmd; 364 struct msqid_ds *buf; 365 } */ bsd_args; 366 int error; 367 368 bsd_args.msqid = args->msqid; 369 bsd_args.cmd = args->cmd; 370 bsd_args.buf = (struct msqid_ds *)args->buf; 371 error = msgctl(td, &bsd_args); 372 return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error); 373} 374 375int 376linux_shmat(struct thread *td, struct linux_shmat_args *args) 377{ 378 struct shmat_args /* { 379 int shmid; 380 void *shmaddr; 381 int shmflg; 382 } */ bsd_args; 383 int error; 384 385 bsd_args.shmid = args->shmid; 386 bsd_args.shmaddr = args->shmaddr; 387 bsd_args.shmflg = args->shmflg; 388 if ((error = shmat(td, &bsd_args))) 389 return error; 390#ifdef __i386__ 391 if ((error = copyout(td->td_retval, (caddr_t)args->raddr, sizeof(l_ulong)))) 392 return error; 393 td->td_retval[0] = 0; 394#endif 395 return 0; 396} 397 398int 399linux_shmdt(struct thread *td, struct linux_shmdt_args *args) 400{ 401 struct shmdt_args /* { 402 void *shmaddr; 403 } */ bsd_args; 404 405 bsd_args.shmaddr = args->shmaddr; 406 return shmdt(td, &bsd_args); 407} 408 409int 410linux_shmget(struct thread *td, struct linux_shmget_args *args) 411{ 412 struct shmget_args /* { 413 key_t key; 414 int size; 415 int shmflg; 416 } */ bsd_args; 417 418 bsd_args.key = args->key; 419 bsd_args.size = args->size; 420 bsd_args.shmflg = args->shmflg; 421 return shmget(td, &bsd_args); 422} 423 424int 425linux_shmctl(struct thread *td, struct linux_shmctl_args *args) 426{ 427 struct l_shmid_ds linux_shmid; 428 struct shmctl_args /* { 429 int shmid; 430 int cmd; 431 struct shmid_ds *buf; 432 } */ bsd_args; 433 int error; 434 caddr_t sg = stackgap_init(); 435 436 switch (args->cmd) { 437 case LINUX_IPC_STAT: 438 bsd_args.shmid = args->shmid; 439 bsd_args.cmd = IPC_STAT; 440 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 441 if ((error = shmctl(td, &bsd_args))) 442 return error; 443 bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); 444 return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid)); 445 446 case LINUX_IPC_SET: 447 if ((error = copyin((caddr_t)args->buf, &linux_shmid, 448 sizeof(linux_shmid)))) 449 return error; 450 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 451 linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); 452 bsd_args.shmid = args->shmid; 453 bsd_args.cmd = IPC_SET; 454 return shmctl(td, &bsd_args); 455 456 case LINUX_IPC_RMID: 457 bsd_args.shmid = args->shmid; 458 bsd_args.cmd = IPC_RMID; 459 if (args->buf == NULL) 460 bsd_args.buf = NULL; 461 else { 462 if ((error = copyin((caddr_t)args->buf, &linux_shmid, 463 sizeof(linux_shmid)))) 464 return error; 465 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 466 linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); 467 } 468 return shmctl(td, &bsd_args); 469 470 case LINUX_IPC_INFO: 471 case LINUX_SHM_STAT: 472 case LINUX_SHM_INFO: 473 case LINUX_SHM_LOCK: 474 case LINUX_SHM_UNLOCK: 475 default: 476 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); 477 return EINVAL; 478 } 479} 480