Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2#define _GNU_SOURCE
  3#include <errno.h>
  4#include <fcntl.h>
  5#include <math.h>
  6#include <sched.h>
  7#include <stdio.h>
  8#include <stdbool.h>
  9#include <stdlib.h>
 10#include <sys/stat.h>
 11#include <sys/syscall.h>
 12#include <sys/types.h>
 13#include <time.h>
 14#include <unistd.h>
 15
 16#include "log.h"
 17#include "timens.h"
 18
 19/*
 20 * Test shouldn't be run for a day, so add 10 days to child
 21 * time and check parent's time to be in the same day.
 22 */
 23#define MAX_TEST_TIME_SEC		(60*5)
 24#define DAY_IN_SEC			(60*60*24)
 25#define TEN_DAYS_IN_SEC			(10*DAY_IN_SEC)
 26
 27#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 28
 29static int child_ns, parent_ns;
 30
 31static int switch_ns(int fd)
 32{
 33	if (setns(fd, CLONE_NEWTIME))
 34		return pr_perror("setns()");
 35
 36	return 0;
 37}
 38
 39static int init_namespaces(void)
 40{
 41	char path[] = "/proc/self/ns/time_for_children";
 42	struct stat st1, st2;
 43
 44	parent_ns = open(path, O_RDONLY);
 45	if (parent_ns <= 0)
 46		return pr_perror("Unable to open %s", path);
 47
 48	if (fstat(parent_ns, &st1))
 49		return pr_perror("Unable to stat the parent timens");
 50
 51	if (unshare_timens())
 52		return -1;
 53
 54	child_ns = open(path, O_RDONLY);
 55	if (child_ns <= 0)
 56		return pr_perror("Unable to open %s", path);
 57
 58	if (fstat(child_ns, &st2))
 59		return pr_perror("Unable to stat the timens");
 60
 61	if (st1.st_ino == st2.st_ino)
 62		return pr_err("The same child_ns after CLONE_NEWTIME");
 63
 64	if (_settime(CLOCK_BOOTTIME, TEN_DAYS_IN_SEC))
 65		return -1;
 66
 67	return 0;
 68}
 69
 70static int read_proc_uptime(struct timespec *uptime)
 71{
 72	unsigned long up_sec, up_nsec;
 73	FILE *proc;
 74
 75	proc = fopen("/proc/uptime", "r");
 76	if (proc == NULL) {
 77		pr_perror("Unable to open /proc/uptime");
 78		return -1;
 79	}
 80
 81	if (fscanf(proc, "%lu.%02lu", &up_sec, &up_nsec) != 2) {
 82		if (errno) {
 83			pr_perror("fscanf");
 84			return -errno;
 85		}
 86		pr_err("failed to parse /proc/uptime");
 87		return -1;
 88	}
 89	fclose(proc);
 90
 91	uptime->tv_sec = up_sec;
 92	uptime->tv_nsec = up_nsec;
 93	return 0;
 94}
 95
 96static int check_uptime(void)
 97{
 98	struct timespec uptime_new, uptime_old;
 99	time_t uptime_expected;
100	double prec = MAX_TEST_TIME_SEC;
101
102	if (switch_ns(parent_ns))
103		return pr_err("switch_ns(%d)", parent_ns);
104
105	if (read_proc_uptime(&uptime_old))
106		return 1;
107
108	if (switch_ns(child_ns))
109		return pr_err("switch_ns(%d)", child_ns);
110
111	if (read_proc_uptime(&uptime_new))
112		return 1;
113
114	uptime_expected = uptime_old.tv_sec + TEN_DAYS_IN_SEC;
115	if (fabs(difftime(uptime_new.tv_sec, uptime_expected)) > prec) {
116		pr_fail("uptime in /proc/uptime: old %ld, new %ld [%ld]",
117			uptime_old.tv_sec, uptime_new.tv_sec,
118			uptime_old.tv_sec + TEN_DAYS_IN_SEC);
119		return 1;
120	}
121
122	ksft_test_result_pass("Passed for /proc/uptime\n");
123	return 0;
124}
125
126int main(int argc, char *argv[])
127{
128	int ret = 0;
129
130	nscheck();
131
132	ksft_set_plan(1);
133
134	if (init_namespaces())
135		return 1;
136
137	ret |= check_uptime();
138
139	if (ret)
140		ksft_exit_fail();
141	ksft_exit_pass();
142	return ret;
143}