1 #include <darwintest.h> 2 #include "xnu_quick_test_helpers.h" 3 4 #include <fcntl.h> 5 #include <stdlib.h> 6 #include <unistd.h> 7 #include <mach/mach.h> 8 #include <sys/stat.h> 9 #include <sys/syscall.h> 10 #include <sys/sysctl.h> 11 #include <sys/wait.h> 12 13 T_GLOBAL_META( 14 T_META_NAMESPACE("xnu.quicktest"), 15 T_META_CHECK_LEAKS(false), 16 T_META_RUN_CONCURRENTLY(true) 17 ); 18 19 char g_target_path[PATH_MAX]; 20 21 T_DECL(syscall, "xnu_quick_test for syscall", T_META_TAG_VM_NOT_PREFERRED) 22 { 23 int my_fd = -1; 24 char * my_pathp; 25 kern_return_t my_kr; 26 27 T_SETUPBEGIN; 28 29 create_target_directory(TEST_DIRECTORY); 30 31 T_SETUPEND; 32 33 my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_pathp, 34 PATH_MAX, VM_FLAGS_ANYWHERE); 35 T_ASSERT_MACH_SUCCESS(my_kr, "Allocating vm to path %s", my_pathp); 36 37 *my_pathp = 0x00; 38 strcpy( my_pathp, &g_target_path[0] ); 39 strcat( my_pathp, "/" ); 40 41 /* create a test file */ 42 43 T_ASSERT_MACH_SUCCESS( create_random_name( my_pathp, 1), "Create random test file" ); 44 /* use an indirect system call to open our test file. 45 * I picked open since it uses a path pointer which grows to 64 bits in an LP64 environment. 46 */ 47 T_EXPECT_NE(my_fd = syscall( SYS_open, my_pathp, (O_RDWR | O_EXCL), 0 ), 48 -1, "Attempt to open file using indirect syscall %s", my_pathp); 49 50 if (my_fd != -1) { 51 close(my_fd); 52 } 53 54 if (my_pathp != NULL) { 55 remove(my_pathp); 56 vm_deallocate(mach_task_self(), (vm_address_t)my_pathp, PATH_MAX); 57 } 58 59 T_ATEND(remove_target_directory); 60 } 61 62 T_DECL(fork_wait4_exit, 63 "Tests forking off a process and waiting for the child to exit", T_META_TAG_VM_NOT_PREFERRED) 64 { 65 int my_err, my_status; 66 pid_t my_pid, my_wait_pid; 67 struct rusage my_usage; 68 69 strncpy(g_target_path, "/", 2); 70 71 /* spin off another process */ 72 T_ASSERT_NE(my_pid = fork(), -1, "Fork off a process"); 73 74 if (my_pid == 0) { 75 struct stat my_sb; 76 77 /* child process does very little then exits */ 78 my_err = stat( &g_target_path[0], &my_sb ); 79 T_WITH_ERRNO; 80 T_ASSERT_TRUE(my_err == 0, "stat call with path: \"%s\" returned \"%d\"", &g_target_path[0], errno); 81 exit( 44 ); 82 } 83 84 /* parent process waits for child to exit */ 85 T_ASSERT_NE(my_wait_pid = wait4( my_pid, &my_status, 0, &my_usage ), -1, 86 "Wait for child to exit\n"); 87 88 /* wait4 should return our child's pid when it exits */ 89 T_ASSERT_EQ(my_wait_pid, my_pid, 90 "wait4 should return our child's pid when it exits"); 91 92 /* kind of just guessing on these values so if this fails we should take a closer 93 * look at the returned rusage structure. 94 */ 95 T_ASSERT_FALSE((my_usage.ru_utime.tv_sec > 1 || 96 my_usage.ru_stime.tv_sec > 1 || my_usage.ru_majflt > 1000 || 97 my_usage.ru_msgsnd > 100), "wait4 returned rusage structure"); 98 99 T_ASSERT_TRUE((WIFEXITED( my_status ) && WEXITSTATUS( my_status ) == 44), 100 "check if wait4 returns right exit status"); 101 } 102 103 T_DECL(getrusage, "check getrusage works", T_META_TAG_VM_NOT_PREFERRED) 104 { 105 struct rusage rubuf; 106 107 int ret = getrusage(RUSAGE_SELF, &rubuf); 108 T_ASSERT_POSIX_SUCCESS(ret, "getrusage for self"); 109 110 T_EXPECT_LT(rubuf.ru_msgrcv, 1000, "upper bound on messages received"); 111 T_EXPECT_GE(rubuf.ru_msgrcv, 0, "lower bound on messages reseived"); 112 T_EXPECT_LT(rubuf.ru_nsignals, 1000, "upper bound on signals"); 113 T_EXPECT_GE(rubuf.ru_nsignals, 0, "lower bound on signals"); 114 } 115