0001
0002 #define _GNU_SOURCE
0003 #include <errno.h>
0004 #include <fcntl.h>
0005 #include <math.h>
0006 #include <sched.h>
0007 #include <stdio.h>
0008 #include <stdbool.h>
0009 #include <stdlib.h>
0010 #include <sys/stat.h>
0011 #include <sys/syscall.h>
0012 #include <sys/types.h>
0013 #include <time.h>
0014 #include <unistd.h>
0015
0016 #include "log.h"
0017 #include "timens.h"
0018
0019
0020
0021
0022
0023 #define MAX_TEST_TIME_SEC (60*5)
0024 #define DAY_IN_SEC (60*60*24)
0025 #define TEN_DAYS_IN_SEC (10*DAY_IN_SEC)
0026
0027 static int child_ns, parent_ns;
0028
0029 static int switch_ns(int fd)
0030 {
0031 if (setns(fd, CLONE_NEWTIME))
0032 return pr_perror("setns()");
0033
0034 return 0;
0035 }
0036
0037 static int init_namespaces(void)
0038 {
0039 char path[] = "/proc/self/ns/time_for_children";
0040 struct stat st1, st2;
0041
0042 parent_ns = open(path, O_RDONLY);
0043 if (parent_ns <= 0)
0044 return pr_perror("Unable to open %s", path);
0045
0046 if (fstat(parent_ns, &st1))
0047 return pr_perror("Unable to stat the parent timens");
0048
0049 if (unshare_timens())
0050 return -1;
0051
0052 child_ns = open(path, O_RDONLY);
0053 if (child_ns <= 0)
0054 return pr_perror("Unable to open %s", path);
0055
0056 if (fstat(child_ns, &st2))
0057 return pr_perror("Unable to stat the timens");
0058
0059 if (st1.st_ino == st2.st_ino)
0060 return pr_err("The same child_ns after CLONE_NEWTIME");
0061
0062 if (_settime(CLOCK_BOOTTIME, TEN_DAYS_IN_SEC))
0063 return -1;
0064
0065 return 0;
0066 }
0067
0068 static int read_proc_uptime(struct timespec *uptime)
0069 {
0070 unsigned long up_sec, up_nsec;
0071 FILE *proc;
0072
0073 proc = fopen("/proc/uptime", "r");
0074 if (proc == NULL) {
0075 pr_perror("Unable to open /proc/uptime");
0076 return -1;
0077 }
0078
0079 if (fscanf(proc, "%lu.%02lu", &up_sec, &up_nsec) != 2) {
0080 if (errno) {
0081 pr_perror("fscanf");
0082 return -errno;
0083 }
0084 pr_err("failed to parse /proc/uptime");
0085 return -1;
0086 }
0087 fclose(proc);
0088
0089 uptime->tv_sec = up_sec;
0090 uptime->tv_nsec = up_nsec;
0091 return 0;
0092 }
0093
0094 static int read_proc_stat_btime(unsigned long long *boottime_sec)
0095 {
0096 FILE *proc;
0097 char line_buf[2048];
0098
0099 proc = fopen("/proc/stat", "r");
0100 if (proc == NULL) {
0101 pr_perror("Unable to open /proc/stat");
0102 return -1;
0103 }
0104
0105 while (fgets(line_buf, 2048, proc)) {
0106 if (sscanf(line_buf, "btime %llu", boottime_sec) != 1)
0107 continue;
0108 fclose(proc);
0109 return 0;
0110 }
0111 if (errno) {
0112 pr_perror("fscanf");
0113 fclose(proc);
0114 return -errno;
0115 }
0116 pr_err("failed to parse /proc/stat");
0117 fclose(proc);
0118 return -1;
0119 }
0120
0121 static int check_uptime(void)
0122 {
0123 struct timespec uptime_new, uptime_old;
0124 time_t uptime_expected;
0125 double prec = MAX_TEST_TIME_SEC;
0126
0127 if (switch_ns(parent_ns))
0128 return pr_err("switch_ns(%d)", parent_ns);
0129
0130 if (read_proc_uptime(&uptime_old))
0131 return 1;
0132
0133 if (switch_ns(child_ns))
0134 return pr_err("switch_ns(%d)", child_ns);
0135
0136 if (read_proc_uptime(&uptime_new))
0137 return 1;
0138
0139 uptime_expected = uptime_old.tv_sec + TEN_DAYS_IN_SEC;
0140 if (fabs(difftime(uptime_new.tv_sec, uptime_expected)) > prec) {
0141 pr_fail("uptime in /proc/uptime: old %ld, new %ld [%ld]",
0142 uptime_old.tv_sec, uptime_new.tv_sec,
0143 uptime_old.tv_sec + TEN_DAYS_IN_SEC);
0144 return 1;
0145 }
0146
0147 ksft_test_result_pass("Passed for /proc/uptime\n");
0148 return 0;
0149 }
0150
0151 static int check_stat_btime(void)
0152 {
0153 unsigned long long btime_new, btime_old;
0154 unsigned long long btime_expected;
0155
0156 if (switch_ns(parent_ns))
0157 return pr_err("switch_ns(%d)", parent_ns);
0158
0159 if (read_proc_stat_btime(&btime_old))
0160 return 1;
0161
0162 if (switch_ns(child_ns))
0163 return pr_err("switch_ns(%d)", child_ns);
0164
0165 if (read_proc_stat_btime(&btime_new))
0166 return 1;
0167
0168 btime_expected = btime_old - TEN_DAYS_IN_SEC;
0169 if (btime_new != btime_expected) {
0170 pr_fail("btime in /proc/stat: old %llu, new %llu [%llu]",
0171 btime_old, btime_new, btime_expected);
0172 return 1;
0173 }
0174
0175 ksft_test_result_pass("Passed for /proc/stat btime\n");
0176 return 0;
0177 }
0178
0179 int main(int argc, char *argv[])
0180 {
0181 int ret = 0;
0182
0183 nscheck();
0184
0185 ksft_set_plan(2);
0186
0187 if (init_namespaces())
0188 return 1;
0189
0190 ret |= check_uptime();
0191 ret |= check_stat_btime();
0192
0193 if (ret)
0194 ksft_exit_fail();
0195 ksft_exit_pass();
0196 return ret;
0197 }