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 }
Cache object: 1cd37ce558b96885350b26429d4dacef
|