Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1#include <assert.h> 2#include <errno.h> 3#include <fcntl.h> 4#include <limits.h> 5#include <spawn.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <string.h> 9#include <unistd.h> 10 11#include <sys/stat.h> 12#include <sys/types.h> 13#include <sys/wait.h> 14 15#define TESTDIR "/bar/baz" 16#define TESTPATH "/foo/bar/test" 17#define SUBTEST "./test sub" 18 19extern char **environ; 20 21void test_spawn(void) { 22 pid_t pid; 23 int ret; 24 posix_spawn_file_actions_t file_actions; 25 char *argv[] = {"true", NULL}; 26 27 assert(posix_spawn_file_actions_init(&file_actions) == 0); 28 29 ret = posix_spawn(&pid, TESTPATH, &file_actions, NULL, argv, environ); 30 31 assert(ret == 0); 32 assert(waitpid(pid, NULL, 0) != -1); 33} 34 35void test_execv(void) { 36 char *argv[] = {"true", NULL}; 37 assert(execv(TESTPATH, argv) == 0); 38} 39 40void test_system(void) { 41 assert(system(TESTPATH) == 0); 42} 43 44void test_subprocess(void) { 45 assert(system(SUBTEST) == 0); 46} 47 48void test_stat_with_null_path(void) { 49 // This checks whether the compiler optimizes away the null pointer check 50 // on the path passed to stat(). If that's the case, the following code 51 // should segfault. 52 struct stat buf; 53#pragma GCC diagnostic push 54#pragma GCC diagnostic ignored "-Wnonnull" 55 stat(NULL, &buf); 56#pragma GCC diagnostic pop 57} 58 59void assert_mktemp_path( 60 const char * orig_prefix, 61 const char * orig_suffix, 62 const char * updated 63) { 64 // prefix unchanged 65 assert(strncmp(updated, orig_prefix, strlen(orig_prefix)) == 0); 66 // wildcards replaced 67 assert(strcmp(updated + strlen(orig_prefix), "XXXXXX") != 0); 68 // suffix unchanged 69 assert(strcmp(updated + strlen(orig_prefix) + 6, orig_suffix) == 0); 70} 71 72int main(int argc, char *argv[]) 73{ 74 FILE *testfp; 75 int testfd; 76 struct stat testsb; 77#ifdef __GLIBC__ 78 struct stat64 testsb64; 79#endif 80#if defined(__linux__) && defined(STATX_TYPE) 81 struct statx testsbx; 82#endif 83 char buf[PATH_MAX]; 84 85 testfp = fopen(TESTPATH, "r"); 86 assert(testfp != NULL); 87 fclose(testfp); 88 89 testfd = open(TESTPATH, O_RDONLY); 90 assert(testfd != -1); 91 close(testfd); 92 93 assert(access(TESTPATH, X_OK) == 0); 94 95 // On EOVERFLOW checks below: when TESTPATH lands on a filesystem 96 // that requires 64-bit inode values (like btrfs used for a while) 97 // it will fail on 32-bit systems. 98 99 assert(stat(TESTPATH, &testsb) != -1 || errno == EOVERFLOW); 100#ifdef __GLIBC__ 101 assert(stat64(TESTPATH, &testsb64) != -1); 102#endif 103 assert(fstatat(123, TESTPATH, &testsb, 0) != -1 || errno == EOVERFLOW); 104#ifdef __GLIBC__ 105 assert(fstatat64(123, TESTPATH, &testsb64, 0) != -1); 106#endif 107#if defined(__linux__) && defined(STATX_TYPE) 108 assert(statx(123, TESTPATH, 0, STATX_ALL, &testsbx) != -1); 109#endif 110 111 assert(getcwd(buf, PATH_MAX) != NULL); 112 assert(chdir(TESTDIR) == 0); 113 assert(chdir(buf) == 0); 114 115 assert(mkdir(TESTDIR "/dir-mkdir", 0777) == 0); 116 assert(unlink(TESTDIR "/dir-mkdir") == -1); // it's a directory! 117#ifndef __APPLE__ 118 assert(errno == EISDIR); 119#endif 120 assert(rmdir(TESTDIR "/dir-mkdir") == 0); 121 assert(unlink(TESTDIR "/dir-mkdir") == -1); 122 assert(errno == ENOENT); 123 124 assert(mkdirat(123, TESTDIR "/dir-mkdirat", 0777) == 0); 125 assert(unlinkat(123, TESTDIR "/dir-mkdirat", 0) == -1); // it's a directory! 126#ifndef __APPLE__ 127 assert(errno == EISDIR); 128#endif 129 assert(unlinkat(123, TESTDIR "/dir-mkdirat", AT_REMOVEDIR) == 0); 130 131 strncpy(buf, TESTDIR "/tempXXXXXX", PATH_MAX); 132 testfd = mkstemp(buf); 133 assert(testfd > 0); 134 assert_mktemp_path(TESTDIR "/temp", "", buf); 135 close(testfd); 136 137 strncpy(buf, TESTDIR "/tempXXXXXX", PATH_MAX); 138 testfd = mkostemp(buf, 0); 139 assert(testfd > 0); 140 assert_mktemp_path(TESTDIR "/temp", "", buf); 141 close(testfd); 142 143 strncpy(buf, TESTDIR "/tempXXXXXX.test", PATH_MAX); 144 testfd = mkstemps(buf, strlen(".test")); 145 assert(testfd > 0); 146 assert_mktemp_path(TESTDIR "/temp", ".test", buf); 147 close(testfd); 148 149 strncpy(buf, TESTDIR "/tempXXXXXX.test", PATH_MAX); 150 testfd = mkostemps(buf, strlen(".test"), 0); 151 assert(testfd > 0); 152 assert_mktemp_path(TESTDIR "/temp", ".test", buf); 153 close(testfd); 154 155 strncpy(buf, TESTDIR "/tempXXXXXX", PATH_MAX); 156 assert(mkdtemp(buf) == buf); 157 assert_mktemp_path(TESTDIR "/temp", "", buf); 158 159 strncpy(buf, TESTDIR "/tempXXXXXX", PATH_MAX); 160 assert(mktemp(buf) == buf); 161 assert_mktemp_path(TESTDIR "/temp", "", buf); 162 163 test_spawn(); 164 test_system(); 165 test_stat_with_null_path(); 166 167 // Only run subprocess if no arguments are given 168 // as the subprocess will be called without argument 169 // otherwise we will have infinite recursion 170 if (argc == 1) { 171 test_subprocess(); 172 } 173 174 test_execv(); 175 176 /* If all goes well, this is never reached because test_execv() replaces 177 * the current process. 178 */ 179 return 0; 180}