xref: /linux/tools/testing/selftests/timens/vfork_exec.c (revision 920bc844baa92fe508d9cb7c72765d6f54dfebe1)
1af4fddffSAndrei Vagin // SPDX-License-Identifier: GPL-2.0
2af4fddffSAndrei Vagin #define _GNU_SOURCE
3af4fddffSAndrei Vagin #include <errno.h>
4af4fddffSAndrei Vagin #include <fcntl.h>
5af4fddffSAndrei Vagin #include <sched.h>
6af4fddffSAndrei Vagin #include <stdio.h>
7af4fddffSAndrei Vagin #include <stdbool.h>
8af4fddffSAndrei Vagin #include <sys/stat.h>
9af4fddffSAndrei Vagin #include <sys/syscall.h>
10af4fddffSAndrei Vagin #include <sys/types.h>
11af4fddffSAndrei Vagin #include <sys/wait.h>
12af4fddffSAndrei Vagin #include <time.h>
13af4fddffSAndrei Vagin #include <unistd.h>
14af4fddffSAndrei Vagin #include <string.h>
15af4fddffSAndrei Vagin #include <pthread.h>
16af4fddffSAndrei Vagin 
17af4fddffSAndrei Vagin #include "log.h"
18af4fddffSAndrei Vagin #include "timens.h"
19af4fddffSAndrei Vagin 
20af4fddffSAndrei Vagin #define OFFSET (36000)
21af4fddffSAndrei Vagin 
22af4fddffSAndrei Vagin struct thread_args {
23af4fddffSAndrei Vagin 	char *tst_name;
24af4fddffSAndrei Vagin 	struct timespec *now;
25af4fddffSAndrei Vagin };
26af4fddffSAndrei Vagin 
tcheck(void * _args)27af4fddffSAndrei Vagin static void *tcheck(void *_args)
28af4fddffSAndrei Vagin {
29af4fddffSAndrei Vagin 	struct thread_args *args = _args;
30af4fddffSAndrei Vagin 	struct timespec *now = args->now, tst;
31af4fddffSAndrei Vagin 	int i;
32af4fddffSAndrei Vagin 
33af4fddffSAndrei Vagin 	for (i = 0; i < 2; i++) {
34af4fddffSAndrei Vagin 		_gettime(CLOCK_MONOTONIC, &tst, i);
35*f76f9bc6SJohn Hubbard 		if (labs(tst.tv_sec - now->tv_sec) > 5) {
36af4fddffSAndrei Vagin 			pr_fail("%s: in-thread: unexpected value: %ld (%ld)\n",
37af4fddffSAndrei Vagin 				args->tst_name, tst.tv_sec, now->tv_sec);
38af4fddffSAndrei Vagin 			return (void *)1UL;
39af4fddffSAndrei Vagin 		}
40af4fddffSAndrei Vagin 	}
41af4fddffSAndrei Vagin 	return NULL;
42af4fddffSAndrei Vagin }
43af4fddffSAndrei Vagin 
check_in_thread(char * tst_name,struct timespec * now)44af4fddffSAndrei Vagin static int check_in_thread(char *tst_name, struct timespec *now)
45af4fddffSAndrei Vagin {
46af4fddffSAndrei Vagin 	struct thread_args args = {
47af4fddffSAndrei Vagin 		.tst_name = tst_name,
48af4fddffSAndrei Vagin 		.now = now,
49af4fddffSAndrei Vagin 	};
50af4fddffSAndrei Vagin 	pthread_t th;
51af4fddffSAndrei Vagin 	void *retval;
52af4fddffSAndrei Vagin 
53af4fddffSAndrei Vagin 	if (pthread_create(&th, NULL, tcheck, &args))
54af4fddffSAndrei Vagin 		return pr_perror("thread");
55af4fddffSAndrei Vagin 	if (pthread_join(th, &retval))
56af4fddffSAndrei Vagin 		return pr_perror("pthread_join");
57af4fddffSAndrei Vagin 	return !(retval == NULL);
58af4fddffSAndrei Vagin }
59af4fddffSAndrei Vagin 
check(char * tst_name,struct timespec * now)60af4fddffSAndrei Vagin static int check(char *tst_name, struct timespec *now)
61af4fddffSAndrei Vagin {
62af4fddffSAndrei Vagin 	struct timespec tst;
63af4fddffSAndrei Vagin 	int i;
64af4fddffSAndrei Vagin 
65af4fddffSAndrei Vagin 	for (i = 0; i < 2; i++) {
66af4fddffSAndrei Vagin 		_gettime(CLOCK_MONOTONIC, &tst, i);
67*f76f9bc6SJohn Hubbard 		if (labs(tst.tv_sec - now->tv_sec) > 5)
68af4fddffSAndrei Vagin 			return pr_fail("%s: unexpected value: %ld (%ld)\n",
69af4fddffSAndrei Vagin 					tst_name, tst.tv_sec, now->tv_sec);
70af4fddffSAndrei Vagin 	}
71af4fddffSAndrei Vagin 	if (check_in_thread(tst_name, now))
72af4fddffSAndrei Vagin 		return 1;
73af4fddffSAndrei Vagin 	ksft_test_result_pass("%s\n", tst_name);
74af4fddffSAndrei Vagin 	return 0;
75af4fddffSAndrei Vagin }
76af4fddffSAndrei Vagin 
main(int argc,char * argv[])77af4fddffSAndrei Vagin int main(int argc, char *argv[])
78af4fddffSAndrei Vagin {
79af4fddffSAndrei Vagin 	struct timespec now;
80af4fddffSAndrei Vagin 	int status;
81af4fddffSAndrei Vagin 	pid_t pid;
82af4fddffSAndrei Vagin 
83af4fddffSAndrei Vagin 	if (argc > 1) {
84af4fddffSAndrei Vagin 		char *endptr;
85af4fddffSAndrei Vagin 
86af4fddffSAndrei Vagin 		ksft_cnt.ksft_pass = 1;
87af4fddffSAndrei Vagin 		now.tv_sec = strtoul(argv[1], &endptr, 0);
88af4fddffSAndrei Vagin 		if (*endptr != 0)
89af4fddffSAndrei Vagin 			return pr_perror("strtoul");
90af4fddffSAndrei Vagin 
91af4fddffSAndrei Vagin 		return check("child after exec", &now);
92af4fddffSAndrei Vagin 	}
93af4fddffSAndrei Vagin 
94af4fddffSAndrei Vagin 	nscheck();
95af4fddffSAndrei Vagin 
96af4fddffSAndrei Vagin 	ksft_set_plan(4);
97af4fddffSAndrei Vagin 
98af4fddffSAndrei Vagin 	clock_gettime(CLOCK_MONOTONIC, &now);
99af4fddffSAndrei Vagin 
100af4fddffSAndrei Vagin 	if (unshare_timens())
101af4fddffSAndrei Vagin 		return 1;
102af4fddffSAndrei Vagin 
103af4fddffSAndrei Vagin 	if (_settime(CLOCK_MONOTONIC, OFFSET))
104af4fddffSAndrei Vagin 		return 1;
105af4fddffSAndrei Vagin 
106af4fddffSAndrei Vagin 	if (check("parent before vfork", &now))
107af4fddffSAndrei Vagin 		return 1;
108af4fddffSAndrei Vagin 
109af4fddffSAndrei Vagin 	pid = vfork();
110af4fddffSAndrei Vagin 	if (pid < 0)
111af4fddffSAndrei Vagin 		return pr_perror("fork");
112af4fddffSAndrei Vagin 
113af4fddffSAndrei Vagin 	if (pid == 0) {
114af4fddffSAndrei Vagin 		char now_str[64];
115af4fddffSAndrei Vagin 		char *cargv[] = {"exec", now_str, NULL};
116af4fddffSAndrei Vagin 		char *cenv[] = {NULL};
117af4fddffSAndrei Vagin 
118af4fddffSAndrei Vagin 		/* Check for proper vvar offsets after execve. */
119af4fddffSAndrei Vagin 		snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET);
120af4fddffSAndrei Vagin 		execve("/proc/self/exe", cargv, cenv);
121af4fddffSAndrei Vagin 		pr_perror("execve");
122af4fddffSAndrei Vagin 		_exit(1);
123af4fddffSAndrei Vagin 	}
124af4fddffSAndrei Vagin 
125af4fddffSAndrei Vagin 	if (waitpid(pid, &status, 0) != pid)
126af4fddffSAndrei Vagin 		return pr_perror("waitpid");
127af4fddffSAndrei Vagin 
128af4fddffSAndrei Vagin 	if (status)
129af4fddffSAndrei Vagin 		ksft_exit_fail();
130af4fddffSAndrei Vagin 	ksft_inc_pass_cnt();
131af4fddffSAndrei Vagin 	ksft_test_result_pass("wait for child\n");
132af4fddffSAndrei Vagin 
133af4fddffSAndrei Vagin 	/* Check that we are still in the source timens. */
134af4fddffSAndrei Vagin 	if (check("parent after vfork", &now))
135af4fddffSAndrei Vagin 		return 1;
136af4fddffSAndrei Vagin 
137af4fddffSAndrei Vagin 	ksft_exit_pass();
138af4fddffSAndrei Vagin 	return 0;
139af4fddffSAndrei Vagin }
140