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