1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef __TIMENS_H__ |
3 | #define __TIMENS_H__ |
4 | |
5 | #include <fcntl.h> |
6 | #include <unistd.h> |
7 | #include <stdlib.h> |
8 | #include <stdbool.h> |
9 | |
10 | #include "../kselftest.h" |
11 | |
12 | #ifndef CLONE_NEWTIME |
13 | # define CLONE_NEWTIME 0x00000080 |
14 | #endif |
15 | |
16 | static int config_posix_timers = true; |
17 | static int config_alarm_timers = true; |
18 | |
19 | static inline void check_supported_timers(void) |
20 | { |
21 | struct timespec ts; |
22 | |
23 | if (timer_create(-1, 0, 0) == -1 && errno == ENOSYS) |
24 | config_posix_timers = false; |
25 | |
26 | if (clock_gettime(CLOCK_BOOTTIME_ALARM, &ts) == -1 && errno == EINVAL) |
27 | config_alarm_timers = false; |
28 | } |
29 | |
30 | static inline bool check_skip(int clockid) |
31 | { |
32 | if (!config_alarm_timers && clockid == CLOCK_BOOTTIME_ALARM) { |
33 | ksft_test_result_skip(msg: "CLOCK_BOOTTIME_ALARM isn't supported\n" ); |
34 | return true; |
35 | } |
36 | |
37 | if (config_posix_timers) |
38 | return false; |
39 | |
40 | switch (clockid) { |
41 | /* Only these clocks are supported without CONFIG_POSIX_TIMERS. */ |
42 | case CLOCK_BOOTTIME: |
43 | case CLOCK_MONOTONIC: |
44 | case CLOCK_REALTIME: |
45 | return false; |
46 | default: |
47 | ksft_test_result_skip(msg: "Posix Clocks & timers are not supported\n" ); |
48 | return true; |
49 | } |
50 | |
51 | return false; |
52 | } |
53 | |
54 | static inline int unshare_timens(void) |
55 | { |
56 | if (unshare(CLONE_NEWTIME)) { |
57 | if (errno == EPERM) |
58 | ksft_exit_skip(msg: "need to run as root\n" ); |
59 | return pr_perror("Can't unshare() timens" ); |
60 | } |
61 | return 0; |
62 | } |
63 | |
64 | static inline int _settime(clockid_t clk_id, time_t offset) |
65 | { |
66 | int fd, len; |
67 | char buf[4096]; |
68 | |
69 | if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW) |
70 | clk_id = CLOCK_MONOTONIC; |
71 | |
72 | len = snprintf(buf, sizeof(buf), "%d %ld 0" , clk_id, offset); |
73 | |
74 | fd = open("/proc/self/timens_offsets" , O_WRONLY); |
75 | if (fd < 0) |
76 | return pr_perror("/proc/self/timens_offsets" ); |
77 | |
78 | if (write(fd, buf, len) != len) |
79 | return pr_perror("/proc/self/timens_offsets" ); |
80 | |
81 | close(fd); |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | static inline int _gettime(clockid_t clk_id, struct timespec *res, bool raw_syscall) |
87 | { |
88 | int err; |
89 | |
90 | if (!raw_syscall) { |
91 | if (clock_gettime(clk_id, res)) { |
92 | pr_perror("clock_gettime(%d)" , (int)clk_id); |
93 | return -1; |
94 | } |
95 | return 0; |
96 | } |
97 | |
98 | err = syscall(SYS_clock_gettime, clk_id, res); |
99 | if (err) |
100 | pr_perror("syscall(SYS_clock_gettime(%d))" , (int)clk_id); |
101 | |
102 | return err; |
103 | } |
104 | |
105 | static inline void nscheck(void) |
106 | { |
107 | if (access("/proc/self/ns/time" , F_OK) < 0) |
108 | ksft_exit_skip(msg: "Time namespaces are not supported\n" ); |
109 | } |
110 | |
111 | #endif |
112 | |