• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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