(root)/
strace-6.5/
tests/
orphaned_process_group.c
       1  /*
       2   * Check tracing of orphaned process group.
       3   *
       4   * Copyright (c) 2019-2020 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include <signal.h>
      12  #include <stdio.h>
      13  #include <stdlib.h>
      14  #include <string.h>
      15  #include <unistd.h>
      16  #include <sys/wait.h>
      17  
      18  #define TIMEOUT 5
      19  
      20  static void
      21  alarm_handler(const int no)
      22  {
      23  	error_msg_and_skip("Orphaned process group semantics"
      24  			   " is not supported by the kernel");
      25  }
      26  
      27  int
      28  main(void)
      29  {
      30  	int status;
      31  
      32  	/*
      33  	 * Unblock all signals.
      34  	 */
      35  	static sigset_t mask;
      36  	if (sigprocmask(SIG_SETMASK, &mask, NULL))
      37  		perror_msg_and_fail("sigprocmask");
      38  
      39  	/*
      40  	 * Create a pipe to track termination of processes.
      41  	 */
      42  	int pipe_fds[2];
      43  	if (pipe(pipe_fds))
      44  		perror_msg_and_fail("pipe");
      45  
      46  	/*
      47  	 * Create a leader for its own new process group.
      48  	 */
      49  	pid_t leader = fork();
      50  	if (leader < 0)
      51  		perror_msg_and_fail("fork");
      52  
      53  	if (leader) {
      54  		/*
      55  		 * Close the writing end of the pipe.
      56  		 */
      57  		close(pipe_fds[1]);
      58  
      59  		/*
      60  		 * Install the SIGALRM signal handler.
      61  		 */
      62  		static const struct sigaction sa = {
      63  			.sa_handler = alarm_handler
      64  		};
      65  		if (sigaction(SIGALRM, &sa, NULL))
      66  			perror_msg_and_fail("sigaction");
      67  
      68  		/*
      69  		 * Set an alarm clock.
      70  		 */
      71  		alarm(TIMEOUT);
      72  
      73  		/*
      74  		 * Wait for termination of the child process.
      75  		 */
      76  		if (waitpid(leader, &status, 0) != leader)
      77  			perror_msg_and_fail("waitpid leader");
      78  		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
      79  			error_msg_and_fail("waitpid leader: "
      80  					   "unexpected wait status %d",
      81  					   status);
      82  
      83  		/*
      84  		 * Wait for termination of all processes
      85  		 * in the process group of the child process.
      86  		 */
      87  		if (read(pipe_fds[0], &status, sizeof(status)) != 0)
      88  			perror_msg_and_fail("read");
      89  
      90  		/*
      91  		 * At this point all processes are gone.
      92  		 * Let the tracer time to catch up.
      93  		 */
      94  		alarm(0);
      95  		sleep(1);
      96  		return 0;
      97  	}
      98  
      99  	/*
     100  	 * Close the reading end of the pipe.
     101  	 */
     102  	close(pipe_fds[0]);
     103  
     104  	/*
     105  	 * Create a new process group.
     106  	 */
     107  	if (setpgid(0, 0))
     108  		perror_msg_and_fail("setpgid");
     109  
     110  	/*
     111  	 * When the leader process terminates, the process group becomes orphaned.
     112  	 * If any member of the orphaned process group is stopped, then
     113  	 * a SIGHUP signal followed by a SIGCONT signal is sent to each process
     114  	 * in the orphaned process group.
     115  	 * Create a process in a stopped state to activate this behaviour.
     116  	 */
     117  	const pid_t stopped = fork();
     118  	if (stopped < 0)
     119  		perror_msg_and_fail("fork");
     120  	if (!stopped) {
     121  		static const struct sigaction sa = { .sa_handler = SIG_DFL };
     122  		if (sigaction(SIGHUP, &sa, NULL))
     123  			perror_msg_and_fail("sigaction");
     124  
     125  		raise(SIGSTOP);
     126  		_exit(0);
     127  	}
     128  
     129  	/*
     130  	 * Wait for the process to stop.
     131  	 */
     132  	if (waitpid(stopped, &status, WUNTRACED) != stopped)
     133  		perror_msg_and_fail("waitpid WUNTRACED");
     134  	if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP)
     135                  error_msg_and_fail("unexpected wait status %d", status);
     136  
     137  	/*
     138  	 * Print the expected output.
     139  	 */
     140  	leader = getpid();
     141  	printf("%-5d --- %s {si_signo=%s, si_code=SI_TKILL"
     142  	       ", si_pid=%d, si_uid=%d} ---\n",
     143  	       stopped, "SIGSTOP", "SIGSTOP", stopped, geteuid());
     144  	printf("%-5d --- stopped by SIGSTOP ---\n", stopped);
     145  	printf("%-5d +++ exited with 0 +++\n", leader);
     146  	printf("%-5d --- %s {si_signo=%s, si_code=SI_KERNEL} ---\n",
     147  	       stopped, "SIGHUP", "SIGHUP");
     148  	printf("%-5d +++ killed by %s +++\n", stopped, "SIGHUP");
     149  	printf("%-5d +++ exited with 0 +++\n", getppid());
     150  
     151  	/*
     152  	 * Make the process group orphaned.
     153  	 */
     154  	return 0;
     155  }