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