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$ 29 */ 30 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/sysproto.h> 35 #include <sys/proc.h> 36 #include <sys/sem.h> 37 #include <sys/shm.h> 38 39 #include <i386/linux/linux.h> 40 #include <i386/linux/linux_proto.h> 41 #include <i386/linux/linux_util.h> 42 43 static int linux_semop __P((struct proc *, struct linux_ipc_args *)); 44 static int linux_semget __P((struct proc *, struct linux_ipc_args *)); 45 static int linux_semctl __P((struct proc *, struct linux_ipc_args *)); 46 static int linux_msgsnd __P((struct proc *, struct linux_ipc_args *)); 47 static int linux_msgrcv __P((struct proc *, struct linux_ipc_args *)); 48 static int linux_msgctl __P((struct proc *, struct linux_ipc_args *)); 49 static int linux_shmat __P((struct proc *, struct linux_ipc_args *)); 50 static int linux_shmdt __P((struct proc *, struct linux_ipc_args *)); 51 static int linux_shmget __P((struct proc *, struct linux_ipc_args *)); 52 static int linux_shmctl __P((struct proc *, struct linux_ipc_args *)); 53 54 struct linux_ipc_perm { 55 linux_key_t key; 56 unsigned short uid; 57 unsigned short gid; 58 unsigned short cuid; 59 unsigned short cgid; 60 unsigned short mode; 61 unsigned short seq; 62 }; 63 64 static void 65 linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp) 66 { 67 bpp->key = lpp->key; 68 bpp->uid = lpp->uid; 69 bpp->gid = lpp->gid; 70 bpp->cuid = lpp->cuid; 71 bpp->cgid = lpp->cgid; 72 bpp->mode = lpp->mode; 73 bpp->seq = lpp->seq; 74 } 75 76 77 static void 78 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp) 79 { 80 lpp->key = bpp->key; 81 lpp->uid = bpp->uid; 82 lpp->gid = bpp->gid; 83 lpp->cuid = bpp->cuid; 84 lpp->cgid = bpp->cgid; 85 lpp->mode = bpp->mode; 86 lpp->seq = bpp->seq; 87 } 88 89 struct linux_semid_ds { 90 struct linux_ipc_perm sem_perm; 91 linux_time_t sem_otime; 92 linux_time_t sem_ctime; 93 void *sem_base; 94 void *sem_pending; 95 void *sem_pending_last; 96 void *undo; 97 ushort sem_nsems; 98 }; 99 100 struct linux_shmid_ds { 101 struct linux_ipc_perm shm_perm; 102 int shm_segsz; 103 linux_time_t shm_atime; 104 linux_time_t shm_dtime; 105 linux_time_t shm_ctime; 106 ushort shm_cpid; 107 ushort shm_lpid; 108 short shm_nattch; 109 ushort private1; 110 void *private2; 111 void *private3; 112 }; 113 114 static void 115 linux_to_bsd_semid_ds(struct linux_semid_ds *lsp, struct semid_ds *bsp) 116 { 117 linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); 118 bsp->sem_otime = lsp->sem_otime; 119 bsp->sem_ctime = lsp->sem_ctime; 120 bsp->sem_nsems = lsp->sem_nsems; 121 bsp->sem_base = lsp->sem_base; 122 } 123 124 static void 125 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct linux_semid_ds *lsp) 126 { 127 bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); 128 lsp->sem_otime = bsp->sem_otime; 129 lsp->sem_ctime = bsp->sem_ctime; 130 lsp->sem_nsems = bsp->sem_nsems; 131 lsp->sem_base = bsp->sem_base; 132 } 133 134 static void 135 linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp) 136 { 137 linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); 138 bsp->shm_segsz = lsp->shm_segsz; 139 bsp->shm_lpid = lsp->shm_lpid; 140 bsp->shm_cpid = lsp->shm_cpid; 141 bsp->shm_nattch = lsp->shm_nattch; 142 bsp->shm_atime = lsp->shm_atime; 143 bsp->shm_dtime = lsp->shm_dtime; 144 bsp->shm_ctime = lsp->shm_ctime; 145 bsp->shm_internal = lsp->private3; /* this goes (yet) SOS */ 146 } 147 148 static void 149 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp) 150 { 151 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); 152 lsp->shm_segsz = bsp->shm_segsz; 153 lsp->shm_lpid = bsp->shm_lpid; 154 lsp->shm_cpid = bsp->shm_cpid; 155 lsp->shm_nattch = bsp->shm_nattch; 156 lsp->shm_atime = bsp->shm_atime; 157 lsp->shm_dtime = bsp->shm_dtime; 158 lsp->shm_ctime = bsp->shm_ctime; 159 lsp->private3 = bsp->shm_internal; /* this goes (yet) SOS */ 160 } 161 162 static int 163 linux_semop(struct proc *p, struct linux_ipc_args *args) 164 { 165 struct semop_args /* { 166 int semid; 167 struct sembuf *sops; 168 int nsops; 169 } */ bsd_args; 170 171 bsd_args.semid = args->arg1; 172 bsd_args.sops = (struct sembuf *)args->ptr; 173 bsd_args.nsops = args->arg2; 174 return semop(p, &bsd_args); 175 } 176 177 static int 178 linux_semget(struct proc *p, struct linux_ipc_args *args) 179 { 180 struct semget_args /* { 181 key_t key; 182 int nsems; 183 int semflg; 184 } */ bsd_args; 185 186 bsd_args.key = args->arg1; 187 bsd_args.nsems = args->arg2; 188 bsd_args.semflg = args->arg3; 189 return semget(p, &bsd_args); 190 } 191 192 static int 193 linux_semctl(struct proc *p, struct linux_ipc_args *args) 194 { 195 struct linux_semid_ds linux_semid; 196 struct semid_ds bsd_semid; 197 struct __semctl_args /* { 198 int semid; 199 int semnum; 200 int cmd; 201 union semun *arg; 202 } */ bsd_args; 203 int error; 204 caddr_t sg, unptr, dsp, ldsp; 205 206 sg = stackgap_init(); 207 bsd_args.semid = args->arg1; 208 bsd_args.semnum = args->arg2; 209 bsd_args.cmd = args->arg3; 210 bsd_args.arg = (union semun *)args->ptr; 211 212 switch (args->arg3) { 213 case LINUX_IPC_RMID: 214 bsd_args.cmd = IPC_RMID; 215 break; 216 case LINUX_GETNCNT: 217 bsd_args.cmd = GETNCNT; 218 break; 219 case LINUX_GETPID: 220 bsd_args.cmd = GETPID; 221 break; 222 case LINUX_GETVAL: 223 bsd_args.cmd = GETVAL; 224 break; 225 case LINUX_GETZCNT: 226 bsd_args.cmd = GETZCNT; 227 break; 228 case LINUX_SETVAL: 229 bsd_args.cmd = SETVAL; 230 break; 231 case LINUX_IPC_SET: 232 bsd_args.cmd = IPC_SET; 233 error = copyin(args->ptr, &ldsp, sizeof(ldsp)); 234 if (error) 235 return error; 236 error = copyin(ldsp, (caddr_t)&linux_semid, sizeof(linux_semid)); 237 if (error) 238 return error; 239 linux_to_bsd_semid_ds(&linux_semid, &bsd_semid); 240 unptr = stackgap_alloc(&sg, sizeof(union semun)); 241 dsp = stackgap_alloc(&sg, sizeof(struct semid_ds)); 242 error = copyout((caddr_t)&bsd_semid, dsp, sizeof(bsd_semid)); 243 if (error) 244 return error; 245 error = copyout((caddr_t)&dsp, unptr, sizeof(dsp)); 246 if (error) 247 return error; 248 bsd_args.arg = (union semun *)unptr; 249 return __semctl(p, &bsd_args); 250 case LINUX_IPC_STAT: 251 bsd_args.cmd = IPC_STAT; 252 unptr = stackgap_alloc(&sg, sizeof(union semun *)); 253 dsp = stackgap_alloc(&sg, sizeof(struct semid_ds)); 254 error = copyout((caddr_t)&dsp, unptr, sizeof(dsp)); 255 if (error) 256 return error; 257 bsd_args.arg = (union semun *)unptr; 258 error = __semctl(p, &bsd_args); 259 if (error) 260 return error; 261 error = copyin(dsp, (caddr_t)&bsd_semid, sizeof(bsd_semid)); 262 if (error) 263 return error; 264 bsd_to_linux_semid_ds(&bsd_semid, &linux_semid); 265 error = copyin(args->ptr, &ldsp, sizeof(ldsp)); 266 if (error) 267 return error; 268 return copyout((caddr_t)&linux_semid, ldsp, sizeof(linux_semid)); 269 case LINUX_GETALL: 270 /* FALLTHROUGH */ 271 case LINUX_SETALL: 272 /* FALLTHROUGH */ 273 default: 274 uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); 275 return EINVAL; 276 } 277 return __semctl(p, &bsd_args); 278 } 279 280 static int 281 linux_msgsnd(struct proc *p, struct linux_ipc_args *args) 282 { 283 struct msgsnd_args /* { 284 int msqid; 285 void *msgp; 286 size_t msgsz; 287 int msgflg; 288 } */ bsd_args; 289 290 bsd_args.msqid = args->arg1; 291 bsd_args.msgp = args->ptr; 292 bsd_args.msgsz = args->arg2; 293 bsd_args.msgflg = args->arg3; 294 return msgsnd(p, &bsd_args); 295 } 296 297 static int 298 linux_msgrcv(struct proc *p, struct linux_ipc_args *args) 299 { 300 struct msgrcv_args /* { 301 int msqid; 302 void *msgp; 303 size_t msgsz; 304 long msgtyp; 305 int msgflg; 306 } */ bsd_args; 307 308 bsd_args.msqid = args->arg1; 309 bsd_args.msgp = args->ptr; 310 bsd_args.msgsz = args->arg2; 311 bsd_args.msgtyp = 0; 312 bsd_args.msgflg = args->arg3; 313 return msgrcv(p, &bsd_args); 314 } 315 316 static int 317 linux_msgget(struct proc *p, struct linux_ipc_args *args) 318 { 319 struct msgget_args /* { 320 key_t key; 321 int msgflg; 322 } */ bsd_args; 323 324 bsd_args.key = args->arg1; 325 bsd_args.msgflg = args->arg2; 326 return msgget(p, &bsd_args); 327 } 328 329 static int 330 linux_msgctl(struct proc *p, struct linux_ipc_args *args) 331 { 332 struct msgctl_args /* { 333 int msqid; 334 int cmd; 335 struct msqid_ds *buf; 336 } */ bsd_args; 337 int error; 338 339 bsd_args.msqid = args->arg1; 340 bsd_args.cmd = args->arg2; 341 bsd_args.buf = (struct msqid_ds *)args->ptr; 342 error = msgctl(p, &bsd_args); 343 return ((args->arg2 == LINUX_IPC_RMID && error == EINVAL) ? 0 : error); 344 } 345 346 static int 347 linux_shmat(struct proc *p, struct linux_ipc_args *args) 348 { 349 struct shmat_args /* { 350 int shmid; 351 void *shmaddr; 352 int shmflg; 353 } */ bsd_args; 354 int error; 355 356 bsd_args.shmid = args->arg1; 357 bsd_args.shmaddr = args->ptr; 358 bsd_args.shmflg = args->arg2; 359 if ((error = shmat(p, &bsd_args))) 360 return error; 361 if ((error = copyout(p->p_retval, (caddr_t)args->arg3, sizeof(int)))) 362 return error; 363 p->p_retval[0] = 0; 364 return 0; 365 } 366 367 static int 368 linux_shmdt(struct proc *p, struct linux_ipc_args *args) 369 { 370 struct shmdt_args /* { 371 void *shmaddr; 372 } */ bsd_args; 373 374 bsd_args.shmaddr = args->ptr; 375 return shmdt(p, &bsd_args); 376 } 377 378 static int 379 linux_shmget(struct proc *p, struct linux_ipc_args *args) 380 { 381 struct shmget_args /* { 382 key_t key; 383 int size; 384 int shmflg; 385 } */ bsd_args; 386 387 bsd_args.key = args->arg1; 388 bsd_args.size = args->arg2; 389 bsd_args.shmflg = args->arg3; 390 return shmget(p, &bsd_args); 391 } 392 393 static int 394 linux_shmctl(struct proc *p, struct linux_ipc_args *args) 395 { 396 struct shmid_ds bsd_shmid; 397 struct linux_shmid_ds linux_shmid; 398 struct shmctl_args /* { 399 int shmid; 400 int cmd; 401 struct shmid_ds *buf; 402 } */ bsd_args; 403 int error; 404 caddr_t sg = stackgap_init(); 405 406 switch (args->arg2) { 407 case LINUX_IPC_STAT: 408 bsd_args.shmid = args->arg1; 409 bsd_args.cmd = IPC_STAT; 410 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 411 if ((error = shmctl(p, &bsd_args))) 412 return error; 413 if ((error = copyin((caddr_t)bsd_args.buf, (caddr_t)&bsd_shmid, 414 sizeof(struct shmid_ds)))) 415 return error; 416 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); 417 return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid)); 418 419 case LINUX_IPC_SET: 420 if ((error = copyin(args->ptr, (caddr_t)&linux_shmid, 421 sizeof(linux_shmid)))) 422 return error; 423 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 424 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 425 if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, 426 sizeof(struct shmid_ds)))) 427 return error; 428 bsd_args.shmid = args->arg1; 429 bsd_args.cmd = IPC_SET; 430 return shmctl(p, &bsd_args); 431 432 case LINUX_IPC_RMID: 433 bsd_args.shmid = args->arg1; 434 bsd_args.cmd = IPC_RMID; 435 if (NULL == args->ptr) 436 bsd_args.buf = NULL; 437 else { 438 if ((error = copyin(args->ptr, (caddr_t)&linux_shmid, 439 sizeof(linux_shmid)))) 440 return error; 441 linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); 442 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 443 if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, 444 sizeof(struct shmid_ds)))) 445 return error; 446 } 447 return shmctl(p, &bsd_args); 448 449 case LINUX_IPC_INFO: 450 case LINUX_SHM_STAT: 451 case LINUX_SHM_INFO: 452 case LINUX_SHM_LOCK: 453 case LINUX_SHM_UNLOCK: 454 default: 455 uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); 456 return EINVAL; 457 } 458 } 459 460 int 461 linux_ipc(struct proc *p, struct linux_ipc_args *args) 462 { 463 switch (args->what) { 464 case LINUX_SEMOP: 465 return linux_semop(p, args); 466 case LINUX_SEMGET: 467 return linux_semget(p, args); 468 case LINUX_SEMCTL: 469 return linux_semctl(p, args); 470 case LINUX_MSGSND: 471 return linux_msgsnd(p, args); 472 case LINUX_MSGRCV: 473 return linux_msgrcv(p, args); 474 case LINUX_MSGGET: 475 return linux_msgget(p, args); 476 case LINUX_MSGCTL: 477 return linux_msgctl(p, args); 478 case LINUX_SHMAT: 479 return linux_shmat(p, args); 480 case LINUX_SHMDT: 481 return linux_shmdt(p, args); 482 case LINUX_SHMGET: 483 return linux_shmget(p, args); 484 case LINUX_SHMCTL: 485 return linux_shmctl(p, args); 486 default: 487 uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); 488 return ENOSYS; 489 } 490 } 491