1/*
2 * Copyright (c) 1993 Ulrich Pegelow <pegelow@moorea.uni-muenster.de>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "defs.h"
32#ifdef HAVE_MQUEUE_H
33# include <mqueue.h>
34#endif
35#include <fcntl.h>
36#include <sys/ipc.h>
37#include <sys/sem.h>
38#include <sys/msg.h>
39#include <sys/shm.h>
40
41#ifndef MSG_STAT
42#define MSG_STAT 11
43#endif
44#ifndef MSG_INFO
45#define MSG_INFO 12
46#endif
47#ifndef SHM_STAT
48#define SHM_STAT 13
49#endif
50#ifndef SHM_INFO
51#define SHM_INFO 14
52#endif
53#ifndef SEM_STAT
54#define SEM_STAT 18
55#endif
56#ifndef SEM_INFO
57#define SEM_INFO 19
58#endif
59
60#if !defined IPC_64
61# define IPC_64 0x100
62#endif
63
64extern void printsigevent(struct tcb *tcp, long arg);
65
66#include "xlat/msgctl_flags.h"
67#include "xlat/semctl_flags.h"
68#include "xlat/shmctl_flags.h"
69#include "xlat/resource_flags.h"
70#include "xlat/shm_resource_flags.h"
71#include "xlat/shm_flags.h"
72#include "xlat/ipc_msg_flags.h"
73#include "xlat/semop_flags.h"
74
75int sys_msgget(struct tcb *tcp)
76{
77	if (entering(tcp)) {
78		if (tcp->u_arg[0])
79			tprintf("%#lx, ", tcp->u_arg[0]);
80		else
81			tprints("IPC_PRIVATE, ");
82		if (printflags(resource_flags, tcp->u_arg[1] & ~0777, NULL) != 0)
83			tprints("|");
84		tprintf("%#lo", tcp->u_arg[1] & 0777);
85	}
86	return 0;
87}
88
89#ifdef IPC_64
90# define PRINTCTL(flagset, arg, dflt) \
91	if ((arg) & IPC_64) tprints("IPC_64|"); \
92	printxval((flagset), (arg) &~ IPC_64, dflt)
93#else
94# define PRINTCTL printxval
95#endif
96
97static int
98indirect_ipccall(struct tcb *tcp)
99{
100#ifdef X86_64
101	return current_personality == 1;
102#endif
103#if defined IA64
104	return tcp->scno < 1024; /* ia32 emulation syscalls are low */
105#endif
106#if defined(ALPHA) || defined(MIPS) || defined(HPPA) || defined(__ARM_EABI__) || defined(AARCH64)
107	return 0;
108#endif
109	return 1;
110}
111
112int sys_msgctl(struct tcb *tcp)
113{
114	if (entering(tcp)) {
115		tprintf("%lu, ", tcp->u_arg[0]);
116		PRINTCTL(msgctl_flags, tcp->u_arg[1], "MSG_???");
117		tprintf(", %#lx", tcp->u_arg[indirect_ipccall(tcp) ? 3 : 2]);
118	}
119	return 0;
120}
121
122static void
123tprint_msgsnd(struct tcb *tcp, long addr, unsigned long count,
124	      unsigned long flags)
125{
126	long mtype;
127
128	if (umove(tcp, addr, &mtype) < 0) {
129		tprintf("%#lx", addr);
130	} else {
131		tprintf("{%lu, ", mtype);
132		printstr(tcp, addr + sizeof(mtype), count);
133		tprints("}");
134	}
135	tprintf(", %lu, ", count);
136	printflags(ipc_msg_flags, flags, "MSG_???");
137}
138
139int sys_msgsnd(struct tcb *tcp)
140{
141	if (entering(tcp)) {
142		tprintf("%d, ", (int) tcp->u_arg[0]);
143		if (indirect_ipccall(tcp)) {
144			tprint_msgsnd(tcp, tcp->u_arg[3], tcp->u_arg[1],
145				      tcp->u_arg[2]);
146		} else {
147			tprint_msgsnd(tcp, tcp->u_arg[1], tcp->u_arg[2],
148				      tcp->u_arg[3]);
149		}
150	}
151	return 0;
152}
153
154static void
155tprint_msgrcv(struct tcb *tcp, long addr, unsigned long count, long msgtyp)
156{
157	long mtype;
158
159	if (syserror(tcp) || umove(tcp, addr, &mtype) < 0) {
160		tprintf("%#lx", addr);
161	} else {
162		tprintf("{%lu, ", mtype);
163		printstr(tcp, addr + sizeof(mtype), count);
164		tprints("}");
165	}
166	tprintf(", %lu, %ld, ", count, msgtyp);
167}
168
169int sys_msgrcv(struct tcb *tcp)
170{
171	if (entering(tcp)) {
172		tprintf("%d, ", (int) tcp->u_arg[0]);
173	} else {
174		if (indirect_ipccall(tcp)) {
175			struct ipc_wrapper {
176				struct msgbuf *msgp;
177				long msgtyp;
178			} tmp;
179
180			if (umove(tcp, tcp->u_arg[3], &tmp) < 0) {
181				tprintf("%#lx, %lu, ",
182					tcp->u_arg[3], tcp->u_arg[1]);
183			} else {
184				tprint_msgrcv(tcp, (long) tmp.msgp,
185					tcp->u_arg[1], tmp.msgtyp);
186			}
187			printflags(ipc_msg_flags, tcp->u_arg[2], "MSG_???");
188		} else {
189			tprint_msgrcv(tcp, tcp->u_arg[1],
190				tcp->u_arg[2], tcp->u_arg[3]);
191			printflags(ipc_msg_flags, tcp->u_arg[4], "MSG_???");
192		}
193	}
194	return 0;
195}
196
197static void
198tprint_sembuf(struct tcb *tcp, long addr, unsigned long count)
199{
200	unsigned long i, max_count;
201
202	if (abbrev(tcp))
203		max_count = (max_strlen < count) ? max_strlen : count;
204	else
205		max_count = count;
206
207	if (!max_count) {
208		tprintf("%#lx, %lu", addr, count);
209		return;
210	}
211
212	for (i = 0; i < max_count; ++i) {
213		struct sembuf sb;
214		if (i)
215			tprints(", ");
216		if (umove(tcp, addr + i * sizeof(struct sembuf), &sb) < 0) {
217			if (i) {
218				tprints("{???}");
219				break;
220			} else {
221				tprintf("%#lx, %lu", addr, count);
222				return;
223			}
224		} else {
225			if (!i)
226				tprints("{");
227			tprintf("{%u, %d, ", sb.sem_num, sb.sem_op);
228			printflags(semop_flags, sb.sem_flg, "SEM_???");
229			tprints("}");
230		}
231	}
232
233	if (i < max_count || max_count < count)
234		tprints(", ...");
235
236	tprintf("}, %lu", count);
237}
238
239int sys_semop(struct tcb *tcp)
240{
241	if (entering(tcp)) {
242		tprintf("%lu, ", tcp->u_arg[0]);
243		if (indirect_ipccall(tcp)) {
244			tprint_sembuf(tcp, tcp->u_arg[3], tcp->u_arg[1]);
245		} else {
246			tprint_sembuf(tcp, tcp->u_arg[1], tcp->u_arg[2]);
247		}
248	}
249	return 0;
250}
251
252int sys_semtimedop(struct tcb *tcp)
253{
254	if (entering(tcp)) {
255		tprintf("%lu, ", tcp->u_arg[0]);
256		if (indirect_ipccall(tcp)) {
257			tprint_sembuf(tcp, tcp->u_arg[3], tcp->u_arg[1]);
258			tprints(", ");
259#if defined(S390) || defined(S390X)
260			printtv(tcp, tcp->u_arg[2]);
261#else
262			printtv(tcp, tcp->u_arg[4]);
263#endif
264		} else {
265			tprint_sembuf(tcp, tcp->u_arg[1], tcp->u_arg[2]);
266			tprints(", ");
267			printtv(tcp, tcp->u_arg[3]);
268		}
269	}
270	return 0;
271}
272
273int sys_semget(struct tcb *tcp)
274{
275	if (entering(tcp)) {
276		if (tcp->u_arg[0])
277			tprintf("%#lx", tcp->u_arg[0]);
278		else
279			tprints("IPC_PRIVATE");
280		tprintf(", %lu, ", tcp->u_arg[1]);
281		if (printflags(resource_flags, tcp->u_arg[2] & ~0777, NULL) != 0)
282			tprints("|");
283		tprintf("%#lo", tcp->u_arg[2] & 0777);
284	}
285	return 0;
286}
287
288int sys_semctl(struct tcb *tcp)
289{
290	if (entering(tcp)) {
291		tprintf("%lu, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
292		PRINTCTL(semctl_flags, tcp->u_arg[2], "SEM_???");
293		tprintf(", %#lx", tcp->u_arg[3]);
294	}
295	return 0;
296}
297
298int sys_shmget(struct tcb *tcp)
299{
300	if (entering(tcp)) {
301		if (tcp->u_arg[0])
302			tprintf("%#lx", tcp->u_arg[0]);
303		else
304			tprints("IPC_PRIVATE");
305		tprintf(", %lu, ", tcp->u_arg[1]);
306		if (printflags(shm_resource_flags, tcp->u_arg[2] & ~0777, NULL) != 0)
307			tprints("|");
308		tprintf("%#lo", tcp->u_arg[2] & 0777);
309	}
310	return 0;
311}
312
313int sys_shmctl(struct tcb *tcp)
314{
315	if (entering(tcp)) {
316		tprintf("%lu, ", tcp->u_arg[0]);
317		PRINTCTL(shmctl_flags, tcp->u_arg[1], "SHM_???");
318		if (indirect_ipccall(tcp)) {
319			tprintf(", %#lx", tcp->u_arg[3]);
320		} else {
321			tprintf(", %#lx", tcp->u_arg[2]);
322		}
323	}
324	return 0;
325}
326
327int sys_shmat(struct tcb *tcp)
328{
329	if (exiting(tcp)) {
330		tprintf("%lu", tcp->u_arg[0]);
331		if (indirect_ipccall(tcp)) {
332			tprintf(", %#lx, ", tcp->u_arg[3]);
333			printflags(shm_flags, tcp->u_arg[1], "SHM_???");
334		} else {
335			tprintf(", %#lx, ", tcp->u_arg[1]);
336			printflags(shm_flags, tcp->u_arg[2], "SHM_???");
337		}
338		if (syserror(tcp))
339			return 0;
340		if (indirect_ipccall(tcp)) {
341			unsigned long raddr;
342			if (umove(tcp, tcp->u_arg[2], &raddr) < 0)
343				return RVAL_NONE;
344			tcp->u_rval = raddr;
345		}
346		return RVAL_HEX;
347	}
348	return 0;
349}
350
351int sys_shmdt(struct tcb *tcp)
352{
353	if (entering(tcp)) {
354		if (indirect_ipccall(tcp)) {
355			tprintf("%#lx", tcp->u_arg[3]);
356		} else {
357			tprintf("%#lx", tcp->u_arg[0]);
358		}
359	}
360	return 0;
361}
362
363int
364sys_mq_open(struct tcb *tcp)
365{
366	if (entering(tcp)) {
367		printpath(tcp, tcp->u_arg[0]);
368		tprints(", ");
369		/* flags */
370		tprint_open_modes(tcp->u_arg[1]);
371		if (tcp->u_arg[1] & O_CREAT) {
372# ifndef HAVE_MQUEUE_H
373			tprintf(", %lx", tcp->u_arg[2]);
374# else
375			struct mq_attr attr;
376			/* mode */
377			tprintf(", %#lo, ", tcp->u_arg[2]);
378			if (umove(tcp, tcp->u_arg[3], &attr) < 0)
379				tprints("{???}");
380			else
381				tprintf("{mq_maxmsg=%ld, mq_msgsize=%ld}",
382					(long) attr.mq_maxmsg,
383					(long) attr.mq_msgsize);
384# endif
385		}
386	}
387	return 0;
388}
389
390int
391sys_mq_timedsend(struct tcb *tcp)
392{
393	if (entering(tcp)) {
394		tprintf("%ld, ", tcp->u_arg[0]);
395		printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
396		tprintf(", %lu, %ld, ", tcp->u_arg[2], tcp->u_arg[3]);
397		printtv(tcp, tcp->u_arg[4]);
398	}
399	return 0;
400}
401
402int
403sys_mq_timedreceive(struct tcb *tcp)
404{
405	if (entering(tcp))
406		tprintf("%ld, ", tcp->u_arg[0]);
407	else {
408		printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
409		tprintf(", %lu, %ld, ", tcp->u_arg[2], tcp->u_arg[3]);
410		printtv(tcp, tcp->u_arg[4]);
411	}
412	return 0;
413}
414
415int
416sys_mq_notify(struct tcb *tcp)
417{
418	if (entering(tcp)) {
419		tprintf("%ld, ", tcp->u_arg[0]);
420		printsigevent(tcp, tcp->u_arg[1]);
421	}
422	return 0;
423}
424
425static void
426printmqattr(struct tcb *tcp, long addr)
427{
428	if (addr == 0)
429		tprints("NULL");
430	else {
431# ifndef HAVE_MQUEUE_H
432		tprintf("%#lx", addr);
433# else
434		struct mq_attr attr;
435		if (umove(tcp, addr, &attr) < 0) {
436			tprints("{...}");
437			return;
438		}
439		tprints("{mq_flags=");
440		tprint_open_modes(attr.mq_flags);
441		tprintf(", mq_maxmsg=%ld, mq_msgsize=%ld, mq_curmsg=%ld}",
442			(long) attr.mq_maxmsg, (long) attr.mq_msgsize,
443			(long) attr.mq_curmsgs);
444# endif
445	}
446}
447
448int
449sys_mq_getsetattr(struct tcb *tcp)
450{
451	if (entering(tcp)) {
452		tprintf("%ld, ", tcp->u_arg[0]);
453		printmqattr(tcp, tcp->u_arg[1]);
454		tprints(", ");
455	} else
456		printmqattr(tcp, tcp->u_arg[2]);
457	return 0;
458}
459
460int
461sys_ipc(struct tcb *tcp)
462{
463	return printargs(tcp);
464}
465