Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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  * Test shouldn't be run for a day, so add 10 days to child
0021  * time and check parent's time to be in the same day.
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 }