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