1d5b0117dSAndrei Vagin // SPDX-License-Identifier: GPL-2.0
2d5b0117dSAndrei Vagin #define _GNU_SOURCE
3d5b0117dSAndrei Vagin #include <sched.h>
4d5b0117dSAndrei Vagin 
5d5b0117dSAndrei Vagin #include <sys/syscall.h>
6d5b0117dSAndrei Vagin #include <sys/types.h>
7d5b0117dSAndrei Vagin #include <sys/wait.h>
8d5b0117dSAndrei Vagin #include <time.h>
9d5b0117dSAndrei Vagin #include <unistd.h>
10d5b0117dSAndrei Vagin #include <stdlib.h>
11d5b0117dSAndrei Vagin #include <stdio.h>
12d5b0117dSAndrei Vagin #include <stdint.h>
13d5b0117dSAndrei Vagin #include <signal.h>
14d5b0117dSAndrei Vagin 
15d5b0117dSAndrei Vagin #include "log.h"
16d5b0117dSAndrei Vagin #include "timens.h"
17d5b0117dSAndrei Vagin 
run_test(int clockid,struct timespec now)18d5b0117dSAndrei Vagin int run_test(int clockid, struct timespec now)
19d5b0117dSAndrei Vagin {
20d5b0117dSAndrei Vagin 	struct itimerspec new_value;
21d5b0117dSAndrei Vagin 	long long elapsed;
22d5b0117dSAndrei Vagin 	timer_t fd;
23d5b0117dSAndrei Vagin 	int i;
24d5b0117dSAndrei Vagin 
25558ae035SAndrei Vagin 	if (check_skip(clockid))
26558ae035SAndrei Vagin 		return 0;
27558ae035SAndrei Vagin 
28d5b0117dSAndrei Vagin 	for (i = 0; i < 2; i++) {
29d5b0117dSAndrei Vagin 		struct sigevent sevp = {.sigev_notify = SIGEV_NONE};
30d5b0117dSAndrei Vagin 		int flags = 0;
31d5b0117dSAndrei Vagin 
32d5b0117dSAndrei Vagin 		new_value.it_value.tv_sec = 3600;
33d5b0117dSAndrei Vagin 		new_value.it_value.tv_nsec = 0;
34d5b0117dSAndrei Vagin 		new_value.it_interval.tv_sec = 1;
35d5b0117dSAndrei Vagin 		new_value.it_interval.tv_nsec = 0;
36d5b0117dSAndrei Vagin 
37d5b0117dSAndrei Vagin 		if (i == 1) {
38d5b0117dSAndrei Vagin 			new_value.it_value.tv_sec += now.tv_sec;
39d5b0117dSAndrei Vagin 			new_value.it_value.tv_nsec += now.tv_nsec;
40d5b0117dSAndrei Vagin 		}
41d5b0117dSAndrei Vagin 
42d5b0117dSAndrei Vagin 		if (timer_create(clockid, &sevp, &fd) == -1) {
43d5b0117dSAndrei Vagin 			if (errno == ENOSYS) {
44d5b0117dSAndrei Vagin 				ksft_test_result_skip("Posix Clocks & timers are supported\n");
45d5b0117dSAndrei Vagin 				return 0;
46d5b0117dSAndrei Vagin 			}
47d5b0117dSAndrei Vagin 			return pr_perror("timerfd_create");
48d5b0117dSAndrei Vagin 		}
49d5b0117dSAndrei Vagin 
50d5b0117dSAndrei Vagin 		if (i == 1)
51d5b0117dSAndrei Vagin 			flags |= TIMER_ABSTIME;
52d5b0117dSAndrei Vagin 		if (timer_settime(fd, flags, &new_value, NULL) == -1)
53d5b0117dSAndrei Vagin 			return pr_perror("timerfd_settime");
54d5b0117dSAndrei Vagin 
55d5b0117dSAndrei Vagin 		if (timer_gettime(fd, &new_value) == -1)
56d5b0117dSAndrei Vagin 			return pr_perror("timerfd_gettime");
57d5b0117dSAndrei Vagin 
58d5b0117dSAndrei Vagin 		elapsed = new_value.it_value.tv_sec;
59*f76f9bc6SJohn Hubbard 		if (llabs(elapsed - 3600) > 60) {
60d5b0117dSAndrei Vagin 			ksft_test_result_fail("clockid: %d elapsed: %lld\n",
61d5b0117dSAndrei Vagin 					      clockid, elapsed);
62d5b0117dSAndrei Vagin 			return 1;
63d5b0117dSAndrei Vagin 		}
64d5b0117dSAndrei Vagin 	}
65d5b0117dSAndrei Vagin 
66d5b0117dSAndrei Vagin 	ksft_test_result_pass("clockid=%d\n", clockid);
67d5b0117dSAndrei Vagin 
68d5b0117dSAndrei Vagin 	return 0;
69d5b0117dSAndrei Vagin }
70d5b0117dSAndrei Vagin 
main(int argc,char * argv[])71d5b0117dSAndrei Vagin int main(int argc, char *argv[])
72d5b0117dSAndrei Vagin {
73d5b0117dSAndrei Vagin 	int ret, status, len, fd;
74d5b0117dSAndrei Vagin 	char buf[4096];
75d5b0117dSAndrei Vagin 	pid_t pid;
76d5b0117dSAndrei Vagin 	struct timespec btime_now, mtime_now;
77d5b0117dSAndrei Vagin 
78d5b0117dSAndrei Vagin 	nscheck();
79d5b0117dSAndrei Vagin 
80558ae035SAndrei Vagin 	check_supported_timers();
81558ae035SAndrei Vagin 
82d5b0117dSAndrei Vagin 	ksft_set_plan(3);
83d5b0117dSAndrei Vagin 
84d5b0117dSAndrei Vagin 	clock_gettime(CLOCK_MONOTONIC, &mtime_now);
85d5b0117dSAndrei Vagin 	clock_gettime(CLOCK_BOOTTIME, &btime_now);
86d5b0117dSAndrei Vagin 
87d5b0117dSAndrei Vagin 	if (unshare_timens())
88d5b0117dSAndrei Vagin 		return 1;
89d5b0117dSAndrei Vagin 
90d5b0117dSAndrei Vagin 	len = snprintf(buf, sizeof(buf), "%d %d 0\n%d %d 0",
91d5b0117dSAndrei Vagin 			CLOCK_MONOTONIC, 70 * 24 * 3600,
92d5b0117dSAndrei Vagin 			CLOCK_BOOTTIME, 9 * 24 * 3600);
93d5b0117dSAndrei Vagin 	fd = open("/proc/self/timens_offsets", O_WRONLY);
94d5b0117dSAndrei Vagin 	if (fd < 0)
95d5b0117dSAndrei Vagin 		return pr_perror("/proc/self/timens_offsets");
96d5b0117dSAndrei Vagin 
97d5b0117dSAndrei Vagin 	if (write(fd, buf, len) != len)
98d5b0117dSAndrei Vagin 		return pr_perror("/proc/self/timens_offsets");
99d5b0117dSAndrei Vagin 
100d5b0117dSAndrei Vagin 	close(fd);
101d5b0117dSAndrei Vagin 	mtime_now.tv_sec += 70 * 24 * 3600;
102d5b0117dSAndrei Vagin 	btime_now.tv_sec += 9 * 24 * 3600;
103d5b0117dSAndrei Vagin 
104d5b0117dSAndrei Vagin 	pid = fork();
105d5b0117dSAndrei Vagin 	if (pid < 0)
106d5b0117dSAndrei Vagin 		return pr_perror("Unable to fork");
107d5b0117dSAndrei Vagin 	if (pid == 0) {
108d5b0117dSAndrei Vagin 		ret = 0;
109d5b0117dSAndrei Vagin 		ret |= run_test(CLOCK_BOOTTIME, btime_now);
110d5b0117dSAndrei Vagin 		ret |= run_test(CLOCK_MONOTONIC, mtime_now);
111d5b0117dSAndrei Vagin 		ret |= run_test(CLOCK_BOOTTIME_ALARM, btime_now);
112d5b0117dSAndrei Vagin 
113d5b0117dSAndrei Vagin 		if (ret)
114d5b0117dSAndrei Vagin 			ksft_exit_fail();
115d5b0117dSAndrei Vagin 		ksft_exit_pass();
116d5b0117dSAndrei Vagin 		return ret;
117d5b0117dSAndrei Vagin 	}
118d5b0117dSAndrei Vagin 
119d5b0117dSAndrei Vagin 	if (waitpid(pid, &status, 0) != pid)
120d5b0117dSAndrei Vagin 		return pr_perror("Unable to wait the child process");
121d5b0117dSAndrei Vagin 
122d5b0117dSAndrei Vagin 	if (WIFEXITED(status))
123d5b0117dSAndrei Vagin 		return WEXITSTATUS(status);
124d5b0117dSAndrei Vagin 
125d5b0117dSAndrei Vagin 	return 1;
126d5b0117dSAndrei Vagin }
127