From 4278e6613f48273e7da0989712f1c18aaffefd84 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 6 Mar 2019 16:02:38 +0000 Subject: [PATCH] tests: check tracing of orphaned process group * tests/orphaned_process_group.c: New file. * tests/.gitignore: Add orphaned_process_group. * tests/Makefile.am (check_PROGRAMS): Likewise. * tests/gen_tests.in (orphaned_process_group): New test. --- tests/.gitignore | 1 + tests/Makefile.am | 1 + tests/gen_tests.in | 1 + tests/orphaned_process_group.c | 155 +++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 tests/orphaned_process_group.c diff --git a/tests/.gitignore b/tests/.gitignore index 781e50a2..b481a82f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -359,6 +359,7 @@ oldselect-efault-P oldstat open openat +orphaned_process_group osf_utimes pause pc diff --git a/tests/Makefile.am b/tests/Makefile.am index 5c52c8d6..667a4bdd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -122,6 +122,7 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \ nsyscalls-d \ oldselect-P \ oldselect-efault-P \ + orphaned_process_group \ pc \ perf_event_open_nonverbose \ perf_event_open_unabbrev \ diff --git a/tests/gen_tests.in b/tests/gen_tests.in index 128f4ca8..f82b0410 100644 --- a/tests/gen_tests.in +++ b/tests/gen_tests.in @@ -307,6 +307,7 @@ oldselect-efault-P -a13 -e trace=select -P /dev/full 9>>/dev/full oldstat -a32 -v -P stat.sample -P /dev/full open -a30 -P $NAME.sample openat -a36 -P $NAME.sample +orphaned_process_group . "${srcdir=.}/PTRACE_SEIZE.sh"; run_strace_match_diff -f -e trace=none -e signal='!chld' osf_utimes -a21 pause -a8 -esignal=none perf_event_open -a1 diff --git a/tests/orphaned_process_group.c b/tests/orphaned_process_group.c new file mode 100644 index 00000000..83ab6e39 --- /dev/null +++ b/tests/orphaned_process_group.c @@ -0,0 +1,155 @@ +/* + * Check tracing of orphaned process group. + * + * Copyright (c) 2019 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "tests.h" +#include +#include +#include +#include +#include +#include + +#define TIMEOUT 5 + +static void +alarm_handler(const int no) +{ + error_msg_and_skip("Orphaned process group semantics" + " is not supported by the kernel"); +} + +int +main(void) +{ + int status; + + /* + * Unblock all signals. + */ + static sigset_t mask; + if (sigprocmask(SIG_SETMASK, &mask, NULL)) + perror_msg_and_fail("sigprocmask"); + + /* + * Create a pipe to track termination of processes. + */ + int pipe_fds[2]; + if (pipe(pipe_fds)) + perror_msg_and_fail("pipe"); + + /* + * Create a leader for its own new process group. + */ + pid_t leader = fork(); + if (leader < 0) + perror_msg_and_fail("fork"); + + if (leader) { + /* + * Close the writing end of the pipe. + */ + close(pipe_fds[1]); + + /* + * Install the SIGALRM signal handler. + */ + static const struct sigaction sa = { + .sa_handler = alarm_handler + }; + if (sigaction(SIGALRM, &sa, NULL)) + perror_msg_and_fail("sigaction"); + + /* + * Set an alarm clock. + */ + alarm(TIMEOUT); + + /* + * Wait for termination of the child process. + */ + if (waitpid(leader, &status, 0) != leader) + perror_msg_and_fail("waitpid leader"); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + error_msg_and_fail("waitpid leader: " + "unexpected wait status %d", + status); + + /* + * Wait for termination of all processes + * in the process group of the child process. + */ + if (read(pipe_fds[0], &status, sizeof(status)) != 0) + perror_msg_and_fail("read"); + + /* + * At this point all processes are gone. + * Let the tracer time to catch up. + */ + alarm(0); + sleep(1); + return 0; + } + + /* + * Close the reading end of the pipe. + */ + close(pipe_fds[0]); + + /* + * Create a new process group. + */ + if (setpgid(0, 0)) + perror_msg_and_fail("setpgid"); + + /* + * When the leader process terminates, the process group becomes orphaned. + * If any member of the orphaned process group is stopped, then + * a SIGHUP signal followed by a SIGCONT signal is sent to each process + * in the orphaned process group. + * Create a process in a stopped state to activate this behaviour. + */ + const pid_t stopped = fork(); + if (stopped < 0) + perror_msg_and_fail("fork"); + if (!stopped) { + static const struct sigaction sa = { .sa_handler = SIG_DFL }; + if (sigaction(SIGHUP, &sa, NULL)) + perror_msg_and_fail("sigaction"); + + raise(SIGSTOP); + _exit(0); + } + + /* + * Wait for the process to stop. + */ + if (waitpid(stopped, &status, WUNTRACED) != stopped) + perror_msg_and_fail("waitpid WUNTRACED"); + if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) + error_msg_and_fail("unexpected wait status %d", status); + + /* + * Print the expected output. + */ + leader = getpid(); + printf("%-5d --- %s {si_signo=%s, si_code=SI_TKILL" + ", si_pid=%d, si_uid=%u} ---\n", + stopped, "SIGSTOP", "SIGSTOP", stopped, geteuid()); + printf("%-5d --- stopped by SIGSTOP ---\n", stopped); + printf("%-5d +++ exited with 0 +++\n", leader); + printf("%-5d --- %s {si_signo=%s, si_code=SI_KERNEL} ---\n", + stopped, "SIGHUP", "SIGHUP"); + printf("%-5d +++ killed by %s +++\n", stopped, "SIGHUP"); + printf("%-5d +++ exited with 0 +++\n", getppid()); + + /* + * Make the process group orphaned. + */ + return 0; +} -- 2.40.0