brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · 1833ca9 Raw
198 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#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 child21 * 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}198