18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __TIMENS_H__
38c2ecf20Sopenharmony_ci#define __TIMENS_H__
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <fcntl.h>
68c2ecf20Sopenharmony_ci#include <unistd.h>
78c2ecf20Sopenharmony_ci#include <stdlib.h>
88c2ecf20Sopenharmony_ci#include <stdbool.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "../kselftest.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#ifndef CLONE_NEWTIME
138c2ecf20Sopenharmony_ci# define CLONE_NEWTIME	0x00000080
148c2ecf20Sopenharmony_ci#endif
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int config_posix_timers = true;
178c2ecf20Sopenharmony_cistatic int config_alarm_timers = true;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic inline void check_supported_timers(void)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct timespec ts;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	if (timer_create(-1, 0, 0) == -1 && errno == ENOSYS)
248c2ecf20Sopenharmony_ci		config_posix_timers = false;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (clock_gettime(CLOCK_BOOTTIME_ALARM, &ts) == -1 && errno == EINVAL)
278c2ecf20Sopenharmony_ci		config_alarm_timers = false;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic inline bool check_skip(int clockid)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	if (!config_alarm_timers && clockid == CLOCK_BOOTTIME_ALARM) {
338c2ecf20Sopenharmony_ci		ksft_test_result_skip("CLOCK_BOOTTIME_ALARM isn't supported\n");
348c2ecf20Sopenharmony_ci		return true;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (config_posix_timers)
388c2ecf20Sopenharmony_ci		return false;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	switch (clockid) {
418c2ecf20Sopenharmony_ci	/* Only these clocks are supported without CONFIG_POSIX_TIMERS. */
428c2ecf20Sopenharmony_ci	case CLOCK_BOOTTIME:
438c2ecf20Sopenharmony_ci	case CLOCK_MONOTONIC:
448c2ecf20Sopenharmony_ci	case CLOCK_REALTIME:
458c2ecf20Sopenharmony_ci		return false;
468c2ecf20Sopenharmony_ci	default:
478c2ecf20Sopenharmony_ci		ksft_test_result_skip("Posix Clocks & timers are not supported\n");
488c2ecf20Sopenharmony_ci		return true;
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return false;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic inline int unshare_timens(void)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	if (unshare(CLONE_NEWTIME)) {
578c2ecf20Sopenharmony_ci		if (errno == EPERM)
588c2ecf20Sopenharmony_ci			ksft_exit_skip("need to run as root\n");
598c2ecf20Sopenharmony_ci		return pr_perror("Can't unshare() timens");
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci	return 0;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic inline int _settime(clockid_t clk_id, time_t offset)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	int fd, len;
678c2ecf20Sopenharmony_ci	char buf[4096];
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW)
708c2ecf20Sopenharmony_ci		clk_id = CLOCK_MONOTONIC;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	fd = open("/proc/self/timens_offsets", O_WRONLY);
758c2ecf20Sopenharmony_ci	if (fd < 0)
768c2ecf20Sopenharmony_ci		return pr_perror("/proc/self/timens_offsets");
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (write(fd, buf, len) != len)
798c2ecf20Sopenharmony_ci		return pr_perror("/proc/self/timens_offsets");
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	close(fd);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return 0;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic inline int _gettime(clockid_t clk_id, struct timespec *res, bool raw_syscall)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int err;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (!raw_syscall) {
918c2ecf20Sopenharmony_ci		if (clock_gettime(clk_id, res)) {
928c2ecf20Sopenharmony_ci			pr_perror("clock_gettime(%d)", (int)clk_id);
938c2ecf20Sopenharmony_ci			return -1;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci		return 0;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	err = syscall(SYS_clock_gettime, clk_id, res);
998c2ecf20Sopenharmony_ci	if (err)
1008c2ecf20Sopenharmony_ci		pr_perror("syscall(SYS_clock_gettime(%d))", (int)clk_id);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return err;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic inline void nscheck(void)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	if (access("/proc/self/ns/time", F_OK) < 0)
1088c2ecf20Sopenharmony_ci		ksft_exit_skip("Time namespaces are not supported\n");
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#endif
112