162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#define _GNU_SOURCE
362306a36Sopenharmony_ci#include <sched.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <sys/timerfd.h>
662306a36Sopenharmony_ci#include <sys/syscall.h>
762306a36Sopenharmony_ci#include <sys/types.h>
862306a36Sopenharmony_ci#include <sys/wait.h>
962306a36Sopenharmony_ci#include <time.h>
1062306a36Sopenharmony_ci#include <unistd.h>
1162306a36Sopenharmony_ci#include <stdlib.h>
1262306a36Sopenharmony_ci#include <stdio.h>
1362306a36Sopenharmony_ci#include <stdint.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "log.h"
1662306a36Sopenharmony_ci#include "timens.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic int tclock_gettime(clock_t clockid, struct timespec *now)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	if (clockid == CLOCK_BOOTTIME_ALARM)
2162306a36Sopenharmony_ci		clockid = CLOCK_BOOTTIME;
2262306a36Sopenharmony_ci	return clock_gettime(clockid, now);
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciint run_test(int clockid, struct timespec now)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct itimerspec new_value;
2862306a36Sopenharmony_ci	long long elapsed;
2962306a36Sopenharmony_ci	int fd, i;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (check_skip(clockid))
3262306a36Sopenharmony_ci		return 0;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (tclock_gettime(clockid, &now))
3562306a36Sopenharmony_ci		return pr_perror("clock_gettime(%d)", clockid);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
3862306a36Sopenharmony_ci		int flags = 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci		new_value.it_value.tv_sec = 3600;
4162306a36Sopenharmony_ci		new_value.it_value.tv_nsec = 0;
4262306a36Sopenharmony_ci		new_value.it_interval.tv_sec = 1;
4362306a36Sopenharmony_ci		new_value.it_interval.tv_nsec = 0;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		if (i == 1) {
4662306a36Sopenharmony_ci			new_value.it_value.tv_sec += now.tv_sec;
4762306a36Sopenharmony_ci			new_value.it_value.tv_nsec += now.tv_nsec;
4862306a36Sopenharmony_ci		}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci		fd = timerfd_create(clockid, 0);
5162306a36Sopenharmony_ci		if (fd == -1)
5262306a36Sopenharmony_ci			return pr_perror("timerfd_create(%d)", clockid);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		if (i == 1)
5562306a36Sopenharmony_ci			flags |= TFD_TIMER_ABSTIME;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		if (timerfd_settime(fd, flags, &new_value, NULL))
5862306a36Sopenharmony_ci			return pr_perror("timerfd_settime(%d)", clockid);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		if (timerfd_gettime(fd, &new_value))
6162306a36Sopenharmony_ci			return pr_perror("timerfd_gettime(%d)", clockid);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		elapsed = new_value.it_value.tv_sec;
6462306a36Sopenharmony_ci		if (abs(elapsed - 3600) > 60) {
6562306a36Sopenharmony_ci			ksft_test_result_fail("clockid: %d elapsed: %lld\n",
6662306a36Sopenharmony_ci					      clockid, elapsed);
6762306a36Sopenharmony_ci			return 1;
6862306a36Sopenharmony_ci		}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci		close(fd);
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	ksft_test_result_pass("clockid=%d\n", clockid);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciint main(int argc, char *argv[])
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	int ret, status, len, fd;
8162306a36Sopenharmony_ci	char buf[4096];
8262306a36Sopenharmony_ci	pid_t pid;
8362306a36Sopenharmony_ci	struct timespec btime_now, mtime_now;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	nscheck();
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	check_supported_timers();
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	ksft_set_plan(3);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &mtime_now);
9262306a36Sopenharmony_ci	clock_gettime(CLOCK_BOOTTIME, &btime_now);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (unshare_timens())
9562306a36Sopenharmony_ci		return 1;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%d %d 0\n%d %d 0",
9862306a36Sopenharmony_ci			CLOCK_MONOTONIC, 70 * 24 * 3600,
9962306a36Sopenharmony_ci			CLOCK_BOOTTIME, 9 * 24 * 3600);
10062306a36Sopenharmony_ci	fd = open("/proc/self/timens_offsets", O_WRONLY);
10162306a36Sopenharmony_ci	if (fd < 0)
10262306a36Sopenharmony_ci		return pr_perror("/proc/self/timens_offsets");
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (write(fd, buf, len) != len)
10562306a36Sopenharmony_ci		return pr_perror("/proc/self/timens_offsets");
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	close(fd);
10862306a36Sopenharmony_ci	mtime_now.tv_sec += 70 * 24 * 3600;
10962306a36Sopenharmony_ci	btime_now.tv_sec += 9 * 24 * 3600;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	pid = fork();
11262306a36Sopenharmony_ci	if (pid < 0)
11362306a36Sopenharmony_ci		return pr_perror("Unable to fork");
11462306a36Sopenharmony_ci	if (pid == 0) {
11562306a36Sopenharmony_ci		ret = 0;
11662306a36Sopenharmony_ci		ret |= run_test(CLOCK_BOOTTIME, btime_now);
11762306a36Sopenharmony_ci		ret |= run_test(CLOCK_MONOTONIC, mtime_now);
11862306a36Sopenharmony_ci		ret |= run_test(CLOCK_BOOTTIME_ALARM, btime_now);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		if (ret)
12162306a36Sopenharmony_ci			ksft_exit_fail();
12262306a36Sopenharmony_ci		ksft_exit_pass();
12362306a36Sopenharmony_ci		return ret;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (waitpid(pid, &status, 0) != pid)
12762306a36Sopenharmony_ci		return pr_perror("Unable to wait the child process");
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (WIFEXITED(status))
13062306a36Sopenharmony_ci		return WEXITSTATUS(status);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return 1;
13362306a36Sopenharmony_ci}
134