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