Linux Audio

Check our new training course

Loading...
  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
 27static int child_ns, parent_ns;
 28
 29static int switch_ns(int fd)
 30{
 31	if (setns(fd, CLONE_NEWTIME))
 32		return pr_perror("setns()");
 33
 34	return 0;
 35}
 36
 37static int init_namespaces(void)
 38{
 39	char path[] = "/proc/self/ns/time_for_children";
 40	struct stat st1, st2;
 41
 42	parent_ns = open(path, O_RDONLY);
 43	if (parent_ns <= 0)
 44		return pr_perror("Unable to open %s", path);
 45
 46	if (fstat(parent_ns, &st1))
 47		return pr_perror("Unable to stat the parent timens");
 48
 49	if (unshare_timens())
 50		return -1;
 51
 52	child_ns = open(path, O_RDONLY);
 53	if (child_ns <= 0)
 54		return pr_perror("Unable to open %s", path);
 55
 56	if (fstat(child_ns, &st2))
 57		return pr_perror("Unable to stat the timens");
 58
 59	if (st1.st_ino == st2.st_ino)
 60		return pr_err("The same child_ns after CLONE_NEWTIME");
 61
 62	if (_settime(CLOCK_BOOTTIME, TEN_DAYS_IN_SEC))
 63		return -1;
 64
 65	return 0;
 66}
 67
 68static int read_proc_uptime(struct timespec *uptime)
 69{
 70	unsigned long up_sec, up_nsec;
 71	FILE *proc;
 72
 73	proc = fopen("/proc/uptime", "r");
 74	if (proc == NULL) {
 75		pr_perror("Unable to open /proc/uptime");
 76		return -1;
 77	}
 78
 79	if (fscanf(proc, "%lu.%02lu", &up_sec, &up_nsec) != 2) {
 80		if (errno) {
 81			pr_perror("fscanf");
 82			return -errno;
 83		}
 84		pr_err("failed to parse /proc/uptime");
 85		return -1;
 86	}
 87	fclose(proc);
 88
 89	uptime->tv_sec = up_sec;
 90	uptime->tv_nsec = up_nsec;
 91	return 0;
 92}
 93
 94static int read_proc_stat_btime(unsigned long long *boottime_sec)
 95{
 96	FILE *proc;
 97	char line_buf[2048];
 98
 99	proc = fopen("/proc/stat", "r");
100	if (proc == NULL) {
101		pr_perror("Unable to open /proc/stat");
102		return -1;
103	}
104
105	while (fgets(line_buf, 2048, proc)) {
106		if (sscanf(line_buf, "btime %llu", boottime_sec) != 1)
107			continue;
108		fclose(proc);
109		return 0;
110	}
111	if (errno) {
112		pr_perror("fscanf");
113		fclose(proc);
114		return -errno;
115	}
116	pr_err("failed to parse /proc/stat");
117	fclose(proc);
118	return -1;
119}
120
121static int check_uptime(void)
122{
123	struct timespec uptime_new, uptime_old;
124	time_t uptime_expected;
125	double prec = MAX_TEST_TIME_SEC;
126
127	if (switch_ns(parent_ns))
128		return pr_err("switch_ns(%d)", parent_ns);
129
130	if (read_proc_uptime(&uptime_old))
131		return 1;
132
133	if (switch_ns(child_ns))
134		return pr_err("switch_ns(%d)", child_ns);
135
136	if (read_proc_uptime(&uptime_new))
137		return 1;
138
139	uptime_expected = uptime_old.tv_sec + TEN_DAYS_IN_SEC;
140	if (fabs(difftime(uptime_new.tv_sec, uptime_expected)) > prec) {
141		pr_fail("uptime in /proc/uptime: old %ld, new %ld [%ld]",
142			uptime_old.tv_sec, uptime_new.tv_sec,
143			uptime_old.tv_sec + TEN_DAYS_IN_SEC);
144		return 1;
145	}
146
147	ksft_test_result_pass("Passed for /proc/uptime\n");
148	return 0;
149}
150
151static int check_stat_btime(void)
152{
153	unsigned long long btime_new, btime_old;
154	unsigned long long btime_expected;
155
156	if (switch_ns(parent_ns))
157		return pr_err("switch_ns(%d)", parent_ns);
158
159	if (read_proc_stat_btime(&btime_old))
160		return 1;
161
162	if (switch_ns(child_ns))
163		return pr_err("switch_ns(%d)", child_ns);
164
165	if (read_proc_stat_btime(&btime_new))
166		return 1;
167
168	btime_expected = btime_old - TEN_DAYS_IN_SEC;
169	if (btime_new != btime_expected) {
170		pr_fail("btime in /proc/stat: old %llu, new %llu [%llu]",
171			btime_old, btime_new, btime_expected);
172		return 1;
173	}
174
175	ksft_test_result_pass("Passed for /proc/stat btime\n");
176	return 0;
177}
178
179int main(int argc, char *argv[])
180{
181	int ret = 0;
182
183	nscheck();
184
185	ksft_set_plan(2);
186
187	if (init_namespaces())
188		return 1;
189
190	ret |= check_uptime();
191	ret |= check_stat_btime();
192
193	if (ret)
194		ksft_exit_fail();
195	ksft_exit_pass();
196	return ret;
197}