linux_ipc.c revision 83501
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 83501 2001-09-15 09:50:38Z mr $ 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 bsd_args.semid = args->semid; 228 bsd_args.semnum = args->semnum; 229 bsd_args.arg = (union semun *)&args->arg; 230 231 switch (args->cmd) { 232 case LINUX_IPC_RMID: 233 bsd_args.cmd = IPC_RMID; 234 break; 235 case LINUX_GETNCNT: 236 bsd_args.cmd = GETNCNT; 237 break; 238 case LINUX_GETPID: 239 bsd_args.cmd = GETPID; 240 break; 241 case LINUX_GETVAL: 242 bsd_args.cmd = GETVAL; 243 break; 244 case LINUX_GETZCNT: 245 bsd_args.cmd = GETZCNT; 246 break; 247 case LINUX_SETVAL: 248 bsd_args.cmd = SETVAL; 249 break; 250 case LINUX_IPC_SET: 251 bsd_args.cmd = IPC_SET; 252 error = copyin((caddr_t)args->arg.buf, &linux_semid, 253 sizeof(linux_semid)); 254 if (error) 255 return (error); 256 unptr = stackgap_alloc(&sg, sizeof(union semun)); 257 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 258 linux_to_bsd_semid_ds(&linux_semid, unptr->buf); 259 bsd_args.arg = unptr; 260 return __semctl(td, &bsd_args); 261 case LINUX_IPC_STAT: 262 case LINUX_SEM_STAT: 263 if( args->cmd == LINUX_IPC_STAT ) 264 bsd_args.cmd = IPC_STAT; 265 else 266 bsd_args.cmd = SEM_STAT; 267 unptr = stackgap_alloc(&sg, sizeof(union semun)); 268 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 269 bsd_args.arg = unptr; 270 error = __semctl(td, &bsd_args); 271 if (error) 272 return error; 273 td->td_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid, 274 unptr->buf->sem_perm); 275 bsd_to_linux_semid_ds(unptr->buf, &linux_semid); 276 return copyout(&linux_semid, (caddr_t)args->arg.buf, 277 sizeof(linux_semid)); 278 case LINUX_IPC_INFO: 279 case LINUX_SEM_INFO: 280 error = copyin((caddr_t)args->arg.buf, &linux_seminfo, 281 sizeof(linux_seminfo) ); 282 if (error) 283 return error; 284 bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) ); 285/* XXX BSD equivalent? 286#define used_semids 10 287#define used_sems 10 288 linux_seminfo.semusz = used_semids; 289 linux_seminfo.semaem = used_sems; 290*/ 291 error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf, 292 sizeof(linux_seminfo) ); 293 if (error) 294 return error; 295 td->td_retval[0] = seminfo.semmni; 296 return 0; /* No need for __semctl call */ 297 case LINUX_GETALL: 298 /* FALLTHROUGH */ 299 case LINUX_SETALL: 300 /* FALLTHROUGH */ 301 default: 302 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); 303 return EINVAL; 304 } 305 return __semctl(td, &bsd_args); 306} 307 308int 309linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) 310{ 311 struct msgsnd_args /* { 312 int msqid; 313 void *msgp; 314 size_t msgsz; 315 int msgflg; 316 } */ bsd_args; 317 318 bsd_args.msqid = args->msqid; 319 bsd_args.msgp = args->msgp; 320 bsd_args.msgsz = args->msgsz; 321 bsd_args.msgflg = args->msgflg; 322 return msgsnd(td, &bsd_args); 323} 324 325int 326linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) 327{ 328 struct msgrcv_args /* { 329 int msqid; 330 void *msgp; 331 size_t msgsz; 332 long msgtyp; 333 int msgflg; 334 } */ bsd_args; 335 336 bsd_args.msqid = args->msqid; 337 bsd_args.msgp = args->msgp; 338 bsd_args.msgsz = args->msgsz; 339 bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */ 340 bsd_args.msgflg = args->msgflg; 341 return msgrcv(td, &bsd_args); 342} 343 344int 345linux_msgget(struct thread *td, struct linux_msgget_args *args) 346{ 347 struct msgget_args /* { 348 key_t key; 349 int msgflg; 350 } */ bsd_args; 351 352 bsd_args.key = args->key; 353 bsd_args.msgflg = args->msgflg; 354 return msgget(td, &bsd_args); 355} 356 357int 358linux_msgctl(struct thread *td, struct linux_msgctl_args *args) 359{ 360 struct msgctl_args /* { 361 int msqid; 362 int cmd; 363 struct msqid_ds *buf; 364 } */ bsd_args; 365 int error; 366 367 bsd_args.msqid = args->msqid; 368 bsd_args.cmd = args->cmd; 369 bsd_args.buf = (struct msqid_ds *)args->buf; 370 error = msgctl(td, &bsd_args); 371 return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error); 372} 373 374int 375linux_shmat(struct thread *td, struct linux_shmat_args *args) 376{ 377 struct shmat_args /* { 378 int shmid; 379 void *shmaddr; 380 int shmflg; 381 } */ bsd_args; 382 int error; 383 384 bsd_args.shmid = args->shmid; 385 bsd_args.shmaddr = args->shmaddr; 386 bsd_args.shmflg = args->shmflg; 387 if ((error = shmat(td, &bsd_args))) 388 return error; 389#ifdef __i386__ 390 if ((error = copyout(td->td_retval, (caddr_t)args->raddr, sizeof(l_ulong)))) 391 return error; 392 td->td_retval[0] = 0; 393#endif 394 return 0; 395} 396 397int 398linux_shmdt(struct thread *td, struct linux_shmdt_args *args) 399{ 400 struct shmdt_args /* { 401 void *shmaddr; 402 } */ bsd_args; 403 404 bsd_args.shmaddr = args->shmaddr; 405 return shmdt(td, &bsd_args); 406} 407 408int 409linux_shmget(struct thread *td, struct linux_shmget_args *args) 410{ 411 struct shmget_args /* { 412 key_t key; 413 int size; 414 int shmflg; 415 } */ bsd_args; 416 417 bsd_args.key = args->key; 418 bsd_args.size = args->size; 419 bsd_args.shmflg = args->shmflg; 420 return shmget(td, &bsd_args); 421} 422 423int 424linux_shmctl(struct thread *td, struct linux_shmctl_args *args) 425{ 426 struct l_shmid_ds linux_shmid; 427 struct shmctl_args /* { 428 int shmid; 429 int cmd; 430 struct shmid_ds *buf; 431 } */ bsd_args; 432 int error; 433 caddr_t sg = stackgap_init(); 434 435 switch (args->cmd) { 436 case LINUX_IPC_STAT: 437 bsd_args.shmid = args->shmid; 438 bsd_args.cmd = IPC_STAT; 439 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 440 if ((error = shmctl(td, &bsd_args))) 441 return error; 442 bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); 443 return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid)); 444 445 case LINUX_IPC_SET: 446 if ((error = copyin((caddr_t)args->buf, &linux_shmid, 447 sizeof(linux_shmid)))) 448 return error; 449 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 450 linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); 451 bsd_args.shmid = args->shmid; 452 bsd_args.cmd = IPC_SET; 453 return shmctl(td, &bsd_args); 454 455 case LINUX_IPC_RMID: 456 bsd_args.shmid = args->shmid; 457 bsd_args.cmd = IPC_RMID; 458 if (args->buf == NULL) 459 bsd_args.buf = NULL; 460 else { 461 if ((error = copyin((caddr_t)args->buf, &linux_shmid, 462 sizeof(linux_shmid)))) 463 return error; 464 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 465 linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); 466 } 467 return shmctl(td, &bsd_args); 468 469 case LINUX_IPC_INFO: 470 case LINUX_SHM_STAT: 471 case LINUX_SHM_INFO: 472 case LINUX_SHM_LOCK: 473 case LINUX_SHM_UNLOCK: 474 default: 475 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); 476 return EINVAL; 477 } 478} 479