• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Check decoding of waitid syscall.
3   *
4   * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
5   * Copyright (c) 2016-2017 The strace developers.
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 "tests.h"
32  #include <assert.h>
33  #include <signal.h>
34  #include <stdio.h>
35  #include <string.h>
36  #include <unistd.h>
37  #include <sys/wait.h>
38  #include <sys/resource.h>
39  #include <asm/unistd.h>
40  
41  static const char *
sprint_rusage(const struct rusage * const ru)42  sprint_rusage(const struct rusage *const ru)
43  {
44  	static char buf[1024];
45  	snprintf(buf, sizeof(buf),
46  		 "{ru_utime={tv_sec=%lld, tv_usec=%llu}"
47  		 ", ru_stime={tv_sec=%lld, tv_usec=%llu}"
48  #if VERBOSE
49  		 ", ru_maxrss=%llu"
50  		 ", ru_ixrss=%llu"
51  		 ", ru_idrss=%llu"
52  		 ", ru_isrss=%llu"
53  		 ", ru_minflt=%llu"
54  		 ", ru_majflt=%llu"
55  		 ", ru_nswap=%llu"
56  		 ", ru_inblock=%llu"
57  		 ", ru_oublock=%llu"
58  		 ", ru_msgsnd=%llu"
59  		 ", ru_msgrcv=%llu"
60  		 ", ru_nsignals=%llu"
61  		 ", ru_nvcsw=%llu"
62  		 ", ru_nivcsw=%llu}"
63  #else
64  		 ", ...}"
65  #endif
66  		 , (long long) ru->ru_utime.tv_sec
67  		 , zero_extend_signed_to_ull(ru->ru_utime.tv_usec)
68  		 , (long long) ru->ru_stime.tv_sec
69  		 , zero_extend_signed_to_ull(ru->ru_stime.tv_usec)
70  #if VERBOSE
71  		 , zero_extend_signed_to_ull(ru->ru_maxrss)
72  		 , zero_extend_signed_to_ull(ru->ru_ixrss)
73  		 , zero_extend_signed_to_ull(ru->ru_idrss)
74  		 , zero_extend_signed_to_ull(ru->ru_isrss)
75  		 , zero_extend_signed_to_ull(ru->ru_minflt)
76  		 , zero_extend_signed_to_ull(ru->ru_majflt)
77  		 , zero_extend_signed_to_ull(ru->ru_nswap)
78  		 , zero_extend_signed_to_ull(ru->ru_inblock)
79  		 , zero_extend_signed_to_ull(ru->ru_oublock)
80  		 , zero_extend_signed_to_ull(ru->ru_msgsnd)
81  		 , zero_extend_signed_to_ull(ru->ru_msgrcv)
82  		 , zero_extend_signed_to_ull(ru->ru_nsignals)
83  		 , zero_extend_signed_to_ull(ru->ru_nvcsw)
84  		 , zero_extend_signed_to_ull(ru->ru_nivcsw)
85  #endif
86  		 );
87  	return buf;
88  }
89  
90  #define CASE(x) case x: return #x
91  
92  static const char *
si_code_2_name(const int code)93  si_code_2_name(const int code)
94  {
95  	switch (code) {
96  #ifdef CLD_EXITED
97  	CASE(CLD_EXITED);
98  #endif
99  #ifdef CLD_KILLED
100  	CASE(CLD_KILLED);
101  #endif
102  #ifdef CLD_DUMPED
103  	CASE(CLD_DUMPED);
104  #endif
105  #ifdef CLD_TRAPPED
106  	CASE(CLD_TRAPPED);
107  #endif
108  #ifdef CLD_STOPPED
109  	CASE(CLD_STOPPED);
110  #endif
111  #ifdef CLD_CONTINUED
112  	CASE(CLD_CONTINUED);
113  #endif
114  	default:
115  		perror_msg_and_fail("unknown si_code %d", code);
116  	}
117  }
118  
119  static const char *
sprint_siginfo(const siginfo_t * const si,const char * const status_text)120  sprint_siginfo(const siginfo_t *const si, const char *const status_text)
121  {
122  	static char buf[1024];
123  	snprintf(buf, sizeof(buf),
124  		 "{si_signo=SIGCHLD"
125  		 ", si_code=%s"
126  		 ", si_pid=%u"
127  		 ", si_uid=%u"
128  		 ", si_status=%s"
129  		 ", si_utime=%llu"
130  		 ", si_stime=%llu}",
131  		 si_code_2_name(si->si_code),
132  		 si->si_pid,
133  		 si->si_uid,
134  		 status_text,
135  		 zero_extend_signed_to_ull(si->si_utime),
136  		 zero_extend_signed_to_ull(si->si_stime));
137  	return buf;
138  }
139  
140  static unsigned long
poison(unsigned int v)141  poison(unsigned int v)
142  {
143  	return (unsigned long) 0xfacefeed00000000ULL | v;
144  }
145  
146  static long
do_waitid(const unsigned int idtype,const unsigned int id,const siginfo_t * const infop,const unsigned int options,const struct rusage * const rusage)147  do_waitid(const unsigned int idtype,
148  	  const unsigned int id,
149  	  const siginfo_t *const infop,
150  	  const unsigned int options,
151  	  const struct rusage *const rusage)
152  {
153  	sigset_t mask = {};
154  	sigaddset(&mask, SIGCHLD);
155  
156  	assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
157  	long rc = syscall(__NR_waitid, poison(idtype), poison(id),
158  			  infop, poison(options), rusage);
159  	assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
160  	return rc;
161  }
162  
163  int
main(void)164  main(void)
165  {
166  	tprintf("%s", "");
167  
168  	int fds[2];
169  	if (pipe(fds))
170  		perror_msg_and_fail("pipe");
171  
172  	pid_t pid;
173  	pid = fork();
174  	if (pid < 0)
175  		perror_msg_and_fail("fork");
176  
177  	if (!pid) {
178  		char c;
179  		(void) close(1);
180  		assert(read(0, &c, sizeof(c)) == 1);
181  		return 42;
182  	}
183  
184  	(void) close(0);
185  
186  	if (do_waitid(P_PID, pid, 0, WNOHANG|WEXITED, 0))
187  		perror_msg_and_fail("waitid #1");
188  	tprintf("waitid(P_PID, %d, NULL, WNOHANG|WEXITED, NULL) = 0\n", pid);
189  
190  	TAIL_ALLOC_OBJECT_CONST_PTR(siginfo_t, sinfo);
191  	memset(sinfo, 0, sizeof(*sinfo));
192  	TAIL_ALLOC_OBJECT_CONST_PTR(struct rusage, rusage);
193  	if (do_waitid(P_PID, pid, sinfo, WNOHANG|WEXITED|WSTOPPED, rusage))
194  		perror_msg_and_fail("waitid #2");
195  	tprintf("waitid(P_PID, %d, {}, WNOHANG|WEXITED|WSTOPPED, %s) = 0\n",
196  		pid, sprint_rusage(rusage));
197  
198  	assert(write(1, "", 1) == 1);
199  	(void) close(1);
200  
201  	if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
202  		perror_msg_and_fail("waitid #3");
203  	tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n",
204  		pid, sprint_siginfo(sinfo, "42"), sprint_rusage(rusage));
205  
206  	pid = fork();
207  	if (pid < 0)
208  		perror_msg_and_fail("fork");
209  
210  	if (!pid) {
211  		(void) raise(SIGUSR1);
212  		return 1;
213  	}
214  
215  	if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
216  		perror_msg_and_fail("waitid #4");
217  	tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n",
218  		pid, sprint_siginfo(sinfo, "SIGUSR1"), sprint_rusage(rusage));
219  
220  	if (pipe(fds))
221  		perror_msg_and_fail("pipe");
222  	pid = fork();
223  	if (pid < 0)
224  		perror_msg_and_fail("fork");
225  
226  	if (!pid) {
227  		(void) close(1);
228  		raise(SIGSTOP);
229  		char c;
230  		assert(read(0, &c, sizeof(c)) == 1);
231  		return 0;
232  	}
233  
234  	(void) close(0);
235  
236  	if (do_waitid(P_PID, pid, sinfo, WSTOPPED, rusage))
237  		perror_msg_and_fail("waitid #5");
238  	tprintf("waitid(P_PID, %d, %s, WSTOPPED, %s) = 0\n",
239  		pid, sprint_siginfo(sinfo, "SIGSTOP"), sprint_rusage(rusage));
240  
241  	if (kill(pid, SIGCONT))
242  		perror_msg_and_fail("kill(SIGCONT)");
243  
244  #if defined WCONTINUED
245  	if (do_waitid(P_PID, pid, sinfo, WCONTINUED, rusage))
246  		perror_msg_and_fail("waitid #6");
247  	tprintf("waitid(P_PID, %d, %s, WCONTINUED, %s) = 0\n",
248  		pid, sprint_siginfo(sinfo, "SIGCONT"), sprint_rusage(rusage));
249  #endif /* WCONTINUED */
250  
251  	assert(write(1, "", 1) == 1);
252  	(void) close(1);
253  
254  	if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
255  		perror_msg_and_fail("waitid #7");
256  	tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n",
257  		pid, sprint_siginfo(sinfo, "0"), sprint_rusage(rusage));
258  
259  	long rc = do_waitid(P_ALL, -1, sinfo, WEXITED|WSTOPPED, rusage);
260  	tprintf("waitid(P_ALL, -1, %p, WEXITED|WSTOPPED, %p)"
261  		" = %ld %s (%m)\n", sinfo, rusage, rc, errno2name());
262  
263  	tprintf("%s\n", "+++ exited with 0 +++");
264  	return 0;
265  }
266