brintos

brintos / linux-shallow public Read only

0
0
Text · 2.7 KiB · 5b8907b Raw
140 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#include <errno.h>4#include <fcntl.h>5#include <sched.h>6#include <stdio.h>7#include <stdbool.h>8#include <sys/stat.h>9#include <sys/syscall.h>10#include <sys/types.h>11#include <sys/wait.h>12#include <time.h>13#include <unistd.h>14#include <string.h>15#include <pthread.h>16 17#include "log.h"18#include "timens.h"19 20#define OFFSET (36000)21 22struct thread_args {23	char *tst_name;24	struct timespec *now;25};26 27static void *tcheck(void *_args)28{29	struct thread_args *args = _args;30	struct timespec *now = args->now, tst;31	int i;32 33	for (i = 0; i < 2; i++) {34		_gettime(CLOCK_MONOTONIC, &tst, i);35		if (labs(tst.tv_sec - now->tv_sec) > 5) {36			pr_fail("%s: in-thread: unexpected value: %ld (%ld)\n",37				args->tst_name, tst.tv_sec, now->tv_sec);38			return (void *)1UL;39		}40	}41	return NULL;42}43 44static int check_in_thread(char *tst_name, struct timespec *now)45{46	struct thread_args args = {47		.tst_name = tst_name,48		.now = now,49	};50	pthread_t th;51	void *retval;52 53	if (pthread_create(&th, NULL, tcheck, &args))54		return pr_perror("thread");55	if (pthread_join(th, &retval))56		return pr_perror("pthread_join");57	return !(retval == NULL);58}59 60static int check(char *tst_name, struct timespec *now)61{62	struct timespec tst;63	int i;64 65	for (i = 0; i < 2; i++) {66		_gettime(CLOCK_MONOTONIC, &tst, i);67		if (labs(tst.tv_sec - now->tv_sec) > 5)68			return pr_fail("%s: unexpected value: %ld (%ld)\n",69					tst_name, tst.tv_sec, now->tv_sec);70	}71	if (check_in_thread(tst_name, now))72		return 1;73	ksft_test_result_pass("%s\n", tst_name);74	return 0;75}76 77int main(int argc, char *argv[])78{79	struct timespec now;80	int status;81	pid_t pid;82 83	if (argc > 1) {84		char *endptr;85 86		ksft_cnt.ksft_pass = 1;87		now.tv_sec = strtoul(argv[1], &endptr, 0);88		if (*endptr != 0)89			return pr_perror("strtoul");90 91		return check("child after exec", &now);92	}93 94	nscheck();95 96	ksft_set_plan(4);97 98	clock_gettime(CLOCK_MONOTONIC, &now);99 100	if (unshare_timens())101		return 1;102 103	if (_settime(CLOCK_MONOTONIC, OFFSET))104		return 1;105 106	if (check("parent before vfork", &now))107		return 1;108 109	pid = vfork();110	if (pid < 0)111		return pr_perror("fork");112 113	if (pid == 0) {114		char now_str[64];115		char *cargv[] = {"exec", now_str, NULL};116		char *cenv[] = {NULL};117 118		/* Check for proper vvar offsets after execve. */119		snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET);120		execve("/proc/self/exe", cargv, cenv);121		pr_perror("execve");122		_exit(1);123	}124 125	if (waitpid(pid, &status, 0) != pid)126		return pr_perror("waitpid");127 128	if (status)129		ksft_exit_fail();130	ksft_inc_pass_cnt();131	ksft_test_result_pass("wait for child\n");132 133	/* Check that we are still in the source timens. */134	if (check("parent after vfork", &now))135		return 1;136 137	ksft_exit_pass();138	return 0;139}140