1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
4 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Test PR_SET_CHILD_SUBREAPER and PR_GET_CHILD_SUBREAPER of prctl(2).
11 *
12 * - If PR_SET_CHILD_SUBREAPER marks a process as a child subreaper, it
13 * fulfills the role of init(1) for its descendant orphaned process.
14 * The PPID of its orphaned process will be reparented to the subreaper
15 * process, and the subreaper process can receive a SIGCHLD signal and
16 * wait(2) on the orphaned process to discover corresponding termination
17 * status.
18 *
19 * - The setting of PR_SET_CHILD_SUBREAPER is not inherited by children
20 * reated by fork(2).
21 *
22 * - PR_GET_CHILD_SUBREAPER can get the setting of PR_SET_CHILD_SUBREAPER.
23 *
24 * These flags was added by kernel commit ebec18a6d3aa:
25 * "prctl: add PR_{SET,GET}_CHILD_SUBREAPER to allow simple process supervision"
26 */
27
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <signal.h>
34 #include <sys/prctl.h>
35
36 #include "tst_test.h"
37 #include "lapi/prctl.h"
38
39 static volatile int sigchild_recv;
40
check_get_subreaper(int exp_val)41 static void check_get_subreaper(int exp_val)
42 {
43 int get_val;
44
45 TEST(prctl(PR_GET_CHILD_SUBREAPER, &get_val));
46 if (TST_RET == -1) {
47 tst_res(TFAIL | TTERRNO, "prctl(PR_GET_CHILD_SUBREAPER) failed");
48 return;
49 }
50
51 if (get_val == exp_val) {
52 tst_res(TPASS, "prctl(PR_GET_CHILD_SUBREAPER) got expected %d",
53 get_val);
54 } else {
55 tst_res(TFAIL, "prctl(PR_GET_CHILD_SUBREAPER) got %d, expected %d",
56 get_val, exp_val);
57 }
58 }
59
verify_prctl(void)60 static void verify_prctl(void)
61 {
62 int status, ret;
63 pid_t pid;
64 pid_t ppid = getpid();
65
66 sigchild_recv = 0;
67
68 TEST(prctl(PR_SET_CHILD_SUBREAPER, 1));
69 if (TST_RET == -1) {
70 if (TST_ERR == EINVAL) {
71 tst_res(TCONF,
72 "prctl() doesn't support PR_SET_CHILD_SUBREAPER");
73 } else {
74 tst_res(TFAIL | TTERRNO,
75 "prctl(PR_SET_CHILD_SUBREAPER) failed");
76 }
77 return;
78 }
79
80 tst_res(TPASS, "prctl(PR_SET_CHILD_SUBREAPER) succeeded");
81
82 pid = SAFE_FORK();
83 if (!pid) {
84 pid_t cpid;
85
86 cpid = SAFE_FORK();
87 if (!cpid) {
88 TST_CHECKPOINT_WAIT(0);
89 if (getppid() != ppid) {
90 tst_res(TFAIL,
91 "PPID of orphaned process was not reparented");
92 exit(0);
93 }
94
95 tst_res(TPASS, "PPID of orphaned process was reparented");
96 exit(0);
97 }
98
99 check_get_subreaper(0);
100 exit(0);
101 }
102
103 SAFE_WAITPID(pid, NULL, 0);
104 TST_CHECKPOINT_WAKE(0);
105 ret = wait(&status);
106 if (ret > 0) {
107 tst_res(TPASS, "wait() got orphaned process, pid %d, status %d",
108 ret, status);
109 } else {
110 tst_res(TFAIL | TERRNO,
111 "wait() failed to get orphaned process");
112 }
113
114 if (sigchild_recv == 2)
115 tst_res(TPASS, "received SIGCHLD from orphaned process");
116 else
117 tst_res(TFAIL, "didn't receive SIGCHLD from orphaned process");
118
119 check_get_subreaper(1);
120 }
121
sighandler(int sig LTP_ATTRIBUTE_UNUSED)122 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
123 {
124 sigchild_recv++;
125 }
126
setup(void)127 static void setup(void)
128 {
129 SAFE_SIGNAL(SIGCHLD, sighandler);
130 }
131
132 static struct tst_test test = {
133 .setup = setup,
134 .forks_child = 1,
135 .needs_checkpoints = 1,
136 .test_all = verify_prctl,
137 };
138