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