(root)/
strace-6.5/
tests-m32/
waitid.c
       1  /*
       2   * Check decoding of waitid syscall.
       3   *
       4   * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016-2022 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include <assert.h>
      13  #include <signal.h>
      14  #include <stdio.h>
      15  #include <string.h>
      16  #include <unistd.h>
      17  #include <sys/wait.h>
      18  #include "kernel_rusage.h"
      19  #include "scno.h"
      20  
      21  #ifndef MY_COMM
      22  # define MY_COMM ""
      23  #endif
      24  #ifndef SKIP_IF_PROC_IS_UNAVAILABLE
      25  # define SKIP_IF_PROC_IS_UNAVAILABLE
      26  #endif
      27  
      28  static const char *
      29  sprint_rusage(const kernel_rusage_t *const ru)
      30  {
      31  	static char buf[1024];
      32  	snprintf(buf, sizeof(buf),
      33  		 "{ru_utime={tv_sec=%lld, tv_usec=%llu}"
      34  		 ", ru_stime={tv_sec=%lld, tv_usec=%llu}"
      35  #if VERBOSE
      36  		 ", ru_maxrss=%llu"
      37  		 ", ru_ixrss=%llu"
      38  		 ", ru_idrss=%llu"
      39  		 ", ru_isrss=%llu"
      40  		 ", ru_minflt=%llu"
      41  		 ", ru_majflt=%llu"
      42  		 ", ru_nswap=%llu"
      43  		 ", ru_inblock=%llu"
      44  		 ", ru_oublock=%llu"
      45  		 ", ru_msgsnd=%llu"
      46  		 ", ru_msgrcv=%llu"
      47  		 ", ru_nsignals=%llu"
      48  		 ", ru_nvcsw=%llu"
      49  		 ", ru_nivcsw=%llu}"
      50  #else
      51  		 ", ...}"
      52  #endif
      53  		 , (long long) ru->ru_utime.tv_sec
      54  		 , zero_extend_signed_to_ull(ru->ru_utime.tv_usec)
      55  		 , (long long) ru->ru_stime.tv_sec
      56  		 , zero_extend_signed_to_ull(ru->ru_stime.tv_usec)
      57  #if VERBOSE
      58  		 , zero_extend_signed_to_ull(ru->ru_maxrss)
      59  		 , zero_extend_signed_to_ull(ru->ru_ixrss)
      60  		 , zero_extend_signed_to_ull(ru->ru_idrss)
      61  		 , zero_extend_signed_to_ull(ru->ru_isrss)
      62  		 , zero_extend_signed_to_ull(ru->ru_minflt)
      63  		 , zero_extend_signed_to_ull(ru->ru_majflt)
      64  		 , zero_extend_signed_to_ull(ru->ru_nswap)
      65  		 , zero_extend_signed_to_ull(ru->ru_inblock)
      66  		 , zero_extend_signed_to_ull(ru->ru_oublock)
      67  		 , zero_extend_signed_to_ull(ru->ru_msgsnd)
      68  		 , zero_extend_signed_to_ull(ru->ru_msgrcv)
      69  		 , zero_extend_signed_to_ull(ru->ru_nsignals)
      70  		 , zero_extend_signed_to_ull(ru->ru_nvcsw)
      71  		 , zero_extend_signed_to_ull(ru->ru_nivcsw)
      72  #endif
      73  		 );
      74  	return buf;
      75  }
      76  
      77  #define CASE(x) case x: return #x
      78  
      79  static const char *
      80  si_code_2_name(const int code)
      81  {
      82  	switch (code) {
      83  #ifdef CLD_EXITED
      84  	CASE(CLD_EXITED);
      85  #endif
      86  #ifdef CLD_KILLED
      87  	CASE(CLD_KILLED);
      88  #endif
      89  #ifdef CLD_DUMPED
      90  	CASE(CLD_DUMPED);
      91  #endif
      92  #ifdef CLD_TRAPPED
      93  	CASE(CLD_TRAPPED);
      94  #endif
      95  #ifdef CLD_STOPPED
      96  	CASE(CLD_STOPPED);
      97  #endif
      98  #ifdef CLD_CONTINUED
      99  	CASE(CLD_CONTINUED);
     100  #endif
     101  	default:
     102  		perror_msg_and_fail("unknown si_code %d", code);
     103  	}
     104  }
     105  
     106  static const char *
     107  sprint_siginfo(const siginfo_t *const si, const char *const status_text,
     108  	       const char *const comm)
     109  {
     110  	static char buf[1024];
     111  	char utime_str[64];
     112  	char stime_str[64];
     113  
     114  	snprintf(buf, sizeof(buf),
     115  		 "{si_signo=SIGCHLD"
     116  		 ", si_code=%s"
     117  		 ", si_pid=%d%s"
     118  		 ", si_uid=%d"
     119  		 ", si_status=%s"
     120  		 ", si_utime=%s"
     121  		 ", si_stime=%s}",
     122  		 si_code_2_name(si->si_code),
     123  		 si->si_pid,
     124  		 comm,
     125  		 si->si_uid,
     126  		 status_text,
     127  		 clock_t_str(zero_extend_signed_to_ull(si->si_utime),
     128  			     ARRSZ_PAIR(utime_str)),
     129  		 clock_t_str(zero_extend_signed_to_ull(si->si_stime),
     130  			     ARRSZ_PAIR(stime_str)));
     131  	return buf;
     132  }
     133  
     134  static unsigned long
     135  poison(unsigned int v)
     136  {
     137  	return (unsigned long) 0xfacefeed00000000ULL | v;
     138  }
     139  
     140  static const char *errstr;
     141  
     142  static long
     143  do_waitid(const unsigned int idtype,
     144  	  const unsigned int id,
     145  	  const siginfo_t *const infop,
     146  	  const unsigned int options,
     147  	  const kernel_rusage_t *const rusage)
     148  {
     149  	sigset_t mask = {};
     150  	sigaddset(&mask, SIGCHLD);
     151  
     152  	assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
     153  	long rc = syscall(__NR_waitid, poison(idtype), poison(id),
     154  			  infop, poison(options), rusage);
     155  	assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
     156  	errstr = sprintrc(rc);
     157  	return rc;
     158  }
     159  
     160  int
     161  main(void)
     162  {
     163  	SKIP_IF_PROC_IS_UNAVAILABLE;
     164  
     165  	tprintf("%s", "");
     166  
     167  	int fds[2];
     168  	if (pipe(fds))
     169  		perror_msg_and_fail("pipe");
     170  
     171  	pid_t pid;
     172  	pid = fork();
     173  	if (pid < 0)
     174  		perror_msg_and_fail("fork");
     175  
     176  	if (!pid) {
     177  		char c;
     178  		(void) close(1);
     179  		assert(read(0, &c, sizeof(c)) == 1);
     180  		return 42;
     181  	}
     182  
     183  	(void) close(0);
     184  
     185  	if (do_waitid(P_PID, pid, 0, WNOHANG|WEXITED, 0))
     186  		perror_msg_and_fail("waitid #1");
     187  	tprintf("waitid(P_PID, %d%s, NULL, WNOHANG|WEXITED, NULL) = 0\n",
     188  		pid, MY_COMM);
     189  
     190  	TAIL_ALLOC_OBJECT_CONST_PTR(siginfo_t, sinfo);
     191  	memset(sinfo, 0, sizeof(*sinfo));
     192  	TAIL_ALLOC_OBJECT_CONST_PTR(kernel_rusage_t, 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%s, {}, WNOHANG|WEXITED|WSTOPPED, %s) = 0\n",
     196  		pid, MY_COMM, 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, %s, WEXITED, %s) = 0\n",
     204  		pid, MY_COMM, 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, %s, WEXITED, %s) = 0\n",
     218  		pid, MY_COMM, sprint_siginfo(sinfo, "SIGUSR1", ""),
     219  		sprint_rusage(rusage));
     220  
     221  	if (pipe(fds))
     222  		perror_msg_and_fail("pipe");
     223  	pid = fork();
     224  	if (pid < 0)
     225  		perror_msg_and_fail("fork");
     226  
     227  	if (!pid) {
     228  		(void) close(1);
     229  		raise(SIGSTOP);
     230  		char c;
     231  		assert(read(0, &c, sizeof(c)) == 1);
     232  		return 0;
     233  	}
     234  
     235  	(void) close(0);
     236  
     237  	if (do_waitid(P_PID, pid, sinfo, WSTOPPED, rusage))
     238  		perror_msg_and_fail("waitid #5");
     239  	tprintf("waitid(P_PID, %d%s, %s, WSTOPPED, %s) = 0\n",
     240  		pid, MY_COMM, sprint_siginfo(sinfo, "SIGSTOP", MY_COMM),
     241  		sprint_rusage(rusage));
     242  
     243  	if (kill(pid, SIGCONT))
     244  		perror_msg_and_fail("kill(SIGCONT)");
     245  
     246  #if defined WCONTINUED
     247  	if (do_waitid(P_PID, pid, sinfo, WCONTINUED, rusage))
     248  		perror_msg_and_fail("waitid #6");
     249  	tprintf("waitid(P_PID, %d%s, %s, WCONTINUED, %s) = 0\n",
     250  		pid, MY_COMM, sprint_siginfo(sinfo, "SIGCONT", MY_COMM),
     251  		sprint_rusage(rusage));
     252  #endif /* WCONTINUED */
     253  
     254  	assert(write(1, "", 1) == 1);
     255  	(void) close(1);
     256  
     257  	if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
     258  		perror_msg_and_fail("waitid #7");
     259  	tprintf("waitid(P_PID, %d%s, %s, WEXITED, %s) = 0\n",
     260  		pid, MY_COMM, sprint_siginfo(sinfo, "0", ""),
     261  		sprint_rusage(rusage));
     262  
     263  	pid_t pgid = getpgid(pid);
     264  	do_waitid(P_PGID, pgid, sinfo, WEXITED, rusage);
     265  	tprintf("waitid(P_PGID, %d, %p, WEXITED, %p) = %s\n",
     266  		pgid, sinfo, rusage, errstr);
     267  
     268  	do_waitid(P_ALL, -1, sinfo, WEXITED|WSTOPPED, rusage);
     269  	tprintf("waitid(P_ALL, -1, %p, WEXITED|WSTOPPED, %p) = %s\n",
     270  		sinfo, rusage, errstr);
     271  
     272  	tprintf("%s\n", "+++ exited with 0 +++");
     273  	return 0;
     274  }