18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#define _GNU_SOURCE
38c2ecf20Sopenharmony_ci#include <sched.h>
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <sys/timerfd.h>
68c2ecf20Sopenharmony_ci#include <sys/syscall.h>
78c2ecf20Sopenharmony_ci#include <sys/types.h>
88c2ecf20Sopenharmony_ci#include <sys/wait.h>
98c2ecf20Sopenharmony_ci#include <time.h>
108c2ecf20Sopenharmony_ci#include <unistd.h>
118c2ecf20Sopenharmony_ci#include <stdlib.h>
128c2ecf20Sopenharmony_ci#include <stdio.h>
138c2ecf20Sopenharmony_ci#include <stdint.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "log.h"
168c2ecf20Sopenharmony_ci#include "timens.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic int tclock_gettime(clock_t clockid, struct timespec *now)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	if (clockid == CLOCK_BOOTTIME_ALARM)
218c2ecf20Sopenharmony_ci		clockid = CLOCK_BOOTTIME;
228c2ecf20Sopenharmony_ci	return clock_gettime(clockid, now);
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciint run_test(int clockid, struct timespec now)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	struct itimerspec new_value;
288c2ecf20Sopenharmony_ci	long long elapsed;
298c2ecf20Sopenharmony_ci	int fd, i;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (check_skip(clockid))
328c2ecf20Sopenharmony_ci		return 0;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (tclock_gettime(clockid, &now))
358c2ecf20Sopenharmony_ci		return pr_perror("clock_gettime(%d)", clockid);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
388c2ecf20Sopenharmony_ci		int flags = 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci		new_value.it_value.tv_sec = 3600;
418c2ecf20Sopenharmony_ci		new_value.it_value.tv_nsec = 0;
428c2ecf20Sopenharmony_ci		new_value.it_interval.tv_sec = 1;
438c2ecf20Sopenharmony_ci		new_value.it_interval.tv_nsec = 0;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci		if (i == 1) {
468c2ecf20Sopenharmony_ci			new_value.it_value.tv_sec += now.tv_sec;
478c2ecf20Sopenharmony_ci			new_value.it_value.tv_nsec += now.tv_nsec;
488c2ecf20Sopenharmony_ci		}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci		fd = timerfd_create(clockid, 0);
518c2ecf20Sopenharmony_ci		if (fd == -1)
528c2ecf20Sopenharmony_ci			return pr_perror("timerfd_create(%d)", clockid);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		if (i == 1)
558c2ecf20Sopenharmony_ci			flags |= TFD_TIMER_ABSTIME;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		if (timerfd_settime(fd, flags, &new_value, NULL))
588c2ecf20Sopenharmony_ci			return pr_perror("timerfd_settime(%d)", clockid);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		if (timerfd_gettime(fd, &new_value))
618c2ecf20Sopenharmony_ci			return pr_perror("timerfd_gettime(%d)", clockid);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		elapsed = new_value.it_value.tv_sec;
648c2ecf20Sopenharmony_ci		if (abs(elapsed - 3600) > 60) {
658c2ecf20Sopenharmony_ci			ksft_test_result_fail("clockid: %d elapsed: %lld\n",
668c2ecf20Sopenharmony_ci					      clockid, elapsed);
678c2ecf20Sopenharmony_ci			return 1;
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		close(fd);
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	ksft_test_result_pass("clockid=%d\n", clockid);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return 0;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	int ret, status, len, fd;
818c2ecf20Sopenharmony_ci	char buf[4096];
828c2ecf20Sopenharmony_ci	pid_t pid;
838c2ecf20Sopenharmony_ci	struct timespec btime_now, mtime_now;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	nscheck();
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	check_supported_timers();
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	ksft_set_plan(3);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &mtime_now);
928c2ecf20Sopenharmony_ci	clock_gettime(CLOCK_BOOTTIME, &btime_now);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (unshare_timens())
958c2ecf20Sopenharmony_ci		return 1;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%d %d 0\n%d %d 0",
988c2ecf20Sopenharmony_ci			CLOCK_MONOTONIC, 70 * 24 * 3600,
998c2ecf20Sopenharmony_ci			CLOCK_BOOTTIME, 9 * 24 * 3600);
1008c2ecf20Sopenharmony_ci	fd = open("/proc/self/timens_offsets", O_WRONLY);
1018c2ecf20Sopenharmony_ci	if (fd < 0)
1028c2ecf20Sopenharmony_ci		return pr_perror("/proc/self/timens_offsets");
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (write(fd, buf, len) != len)
1058c2ecf20Sopenharmony_ci		return pr_perror("/proc/self/timens_offsets");
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	close(fd);
1088c2ecf20Sopenharmony_ci	mtime_now.tv_sec += 70 * 24 * 3600;
1098c2ecf20Sopenharmony_ci	btime_now.tv_sec += 9 * 24 * 3600;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	pid = fork();
1128c2ecf20Sopenharmony_ci	if (pid < 0)
1138c2ecf20Sopenharmony_ci		return pr_perror("Unable to fork");
1148c2ecf20Sopenharmony_ci	if (pid == 0) {
1158c2ecf20Sopenharmony_ci		ret = 0;
1168c2ecf20Sopenharmony_ci		ret |= run_test(CLOCK_BOOTTIME, btime_now);
1178c2ecf20Sopenharmony_ci		ret |= run_test(CLOCK_MONOTONIC, mtime_now);
1188c2ecf20Sopenharmony_ci		ret |= run_test(CLOCK_BOOTTIME_ALARM, btime_now);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci		if (ret)
1218c2ecf20Sopenharmony_ci			ksft_exit_fail();
1228c2ecf20Sopenharmony_ci		ksft_exit_pass();
1238c2ecf20Sopenharmony_ci		return ret;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (waitpid(pid, &status, 0) != pid)
1278c2ecf20Sopenharmony_ci		return pr_perror("Unable to wait the child process");
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (WIFEXITED(status))
1308c2ecf20Sopenharmony_ci		return WEXITSTATUS(status);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return 1;
1338c2ecf20Sopenharmony_ci}
134