1 2#include "tests.h" 3#include <mach/mach.h> 4 5extern int g_testbots_active; 6 7/* 8 * create_random_name - creates a file with a random / unique name in the given directory. 9 * when do_open is true we create a file else we generaate a name that does not exist in the 10 * given directory (we do not create anything when do_open is 0). 11 * WARNING - caller provides enough space in path buffer for longest possible name. 12 * WARNING - assumes caller has appended a trailing '/' on the path passed to us. 13 * RAND_MAX is currently 2147483647 (ten characters plus one for a slash) 14 */ 15int create_random_name( char *the_pathp, int do_open ) { 16 int i, my_err; 17 int my_fd = -1; 18 19 for ( i = 0; i < 1; i++ ) { 20 int my_rand; 21 char *myp; 22 char my_name[32]; 23 24 my_rand = rand( ); 25 sprintf( &my_name[0], "%d", my_rand ); 26 if ( (strlen( &my_name[0] ) + strlen( the_pathp ) + 2) > PATH_MAX ) { 27 printf( "%s - path to test file greater than PATH_MAX \n", __FUNCTION__ ); 28 return( -1 ); 29 } 30 31 // append generated file name onto our path 32 myp = strrchr( the_pathp, '/' ); 33 *(myp + 1) = 0x00; 34 strcat( the_pathp, &my_name[0] ); 35 if ( do_open ) { 36 /* create a file with this name */ 37 my_fd = open( the_pathp, (O_RDWR | O_CREAT | O_EXCL), 38 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) ); 39 if ( my_fd == -1 ) { 40 if ( errno != EEXIST ) { 41 printf( "%s - open failed with errno %d - %s \n", 42 __FUNCTION__, errno, strerror( errno ) ); 43 return( -1 ); 44 } 45 // name already exists, try another 46 i--; 47 continue; 48 } 49 } 50 else { 51 /* make sure the name is unique */ 52 struct stat my_sb; 53 my_err = stat( the_pathp, &my_sb ); 54 if ( my_err != 0 ) { 55 if ( errno == ENOENT ) { 56 break; 57 } 58 else { 59 printf( "%s - open failed with errno %d - %s \n", 60 __FUNCTION__, errno, strerror( errno ) ); 61 return( -1 ); 62 } 63 } 64 /* name already exists, try another */ 65 i--; 66 continue; 67 } 68 } 69 70 if ( my_fd != -1 ) 71 close( my_fd ); 72 73 return( 0 ); 74 75} /* create_random_name */ 76 77/* 78 * create_file_with_name - create a file in the given target directory using the given name. 79 * If an existing file or directory is present use the value of remove_existing to determine if the 80 * object is to be deleted. 81 * returns 0 if file could be created, 1 if file exists, 2 if directory exists, else -1 82 * NOTE - will fail if a directory is present with the given name and it is not empty. 83 */ 84int create_file_with_name( char *the_target_dirp, char *the_namep, int remove_existing ) { 85 int create_test_file, my_err, my_result; 86 int my_fd = -1; 87 char * my_pathp = NULL; 88 struct stat my_sb; 89 kern_return_t my_kr; 90 91 create_test_file = 0; 92 my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_pathp, PATH_MAX, VM_FLAGS_ANYWHERE); 93 if(my_kr != KERN_SUCCESS){ 94 printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); 95 goto failure_exit; 96 } 97 98 strcpy( my_pathp, the_target_dirp ); 99 strcat( my_pathp, the_namep ); 100 101 /* make sure the name is unique */ 102 my_result = 0; 103 my_err = stat( my_pathp, &my_sb ); 104 if ( my_err != 0 ) { 105 create_test_file = 1; 106 if ( errno != ENOENT ) { 107 goto failure_exit; 108 } 109 } 110 else { 111 /* name already exists */ 112 if ( S_ISDIR( my_sb.st_mode ) ) { 113 my_result = 2; /* tell caller directory exists with target name */ 114 if ( remove_existing ) { 115 my_err = rmdir( my_pathp ); 116 if ( my_err == -1 ) { 117 printf( "rmdir failed with error %d - \"%s\" \n", errno, strerror( errno) ); 118 goto failure_exit; 119 } 120 create_test_file = 1; 121 } 122 } 123 else { 124 my_result = 1; /* tell caller file exists with target name */ 125 if ( remove_existing ) { 126 my_err = unlink( my_pathp ); 127 if ( my_err == -1 ) { 128 printf( "unlink failed with error %d - \"%s\" \n", errno, strerror( errno) ); 129 goto failure_exit; 130 } 131 create_test_file = 1; 132 } 133 } 134 } 135 136 if ( create_test_file ) { 137 /* create a file with this name */ 138 my_fd = open( my_pathp, (O_RDWR | O_CREAT | O_EXCL), 139 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) ); 140 if ( my_fd == -1 ) { 141 printf( "open failed with error %d - \"%s\" \n", errno, strerror( errno) ); 142 goto failure_exit; 143 } 144 fcntl( my_fd, F_FULLFSYNC ); 145 close( my_fd ); 146 } 147 goto routine_exit; 148 149failure_exit: 150 my_result = -1; 151routine_exit: 152 if ( my_pathp != NULL ) { 153 if ( my_result == -1 && create_test_file ) { 154 remove( my_pathp ); 155 } 156 vm_deallocate(mach_task_self(), (vm_address_t)my_pathp, PATH_MAX); 157 } 158 159 return( my_result ); 160 161} /* create_file_with_name */ 162 163 164 165 166/* 167 * This function is needed by both xnu_quick_test proper and the execve() helper 168 * program. It forks a child process and then exec()s an image on that child. 169 * Path, argv, and envp are fed directly to the execve() call. 170 * Parameter killwait decides how long to wait before killing the child. 171 */ 172int do_execve_test(char * path, char * argv[], void * envp, int killwait) 173{ 174 int my_err = 0, my_status; 175 pid_t my_pid, my_wait_pid; 176 177#if DEBUG 178 printf("do_execve_test(path = %s)\n", path); 179 printf("CWD= %s\n", getwd(NULL)); 180 fflush(stdout); 181#endif 182 183 /* vfork then execve sleep system command (which we will kill from the parent process) */ 184 my_pid = vfork(); 185 if (my_pid == -1) { 186 printf( "vfork failed with errno %d - %s \n", errno, strerror( errno ) ); 187 goto test_failed_exit; 188 } 189 if ( my_pid == 0 ) { 190 /* 191 * child process - use execve to start one of the customized helper 192 * binaries, which just sleep for 120 seconds. Let our parent kill us. 193 */ 194 195 my_err = execve(path, argv, envp); 196 if ( my_err != 0 ) { /* TODO: execve() on x86_64 inca returns weird error codes, see rdar://4655612 */ 197 printf( "execve call failed with return value: %d, errno: %d - \"%s\"; path: %s \n", 198 my_err, errno, strerror( errno), path ); 199 fflush(stdout); 200 exit(-2); 201 } 202 203 /* should never get here */ 204 printf("Execve failed and it was not caught by our test\n"); 205 return(-1); 206 } 207 /* 208 * parent process - let's kill our sleeping child 209 */ 210 sleep(killwait); 211 my_err = kill( my_pid, SIGKILL ); 212 if ( my_err == -1 ) { 213 printf( "kill call failed with error %d - \"%s\" \n", errno, strerror( errno) ); 214 goto test_failed_exit; 215 } 216 217 /* wait for child to exit */ 218 my_wait_pid = wait4( my_pid, &my_status, 0, NULL ); 219 if ( my_wait_pid == -1 ) { 220 printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) ); 221 goto test_failed_exit; 222 } 223 224 /* wait4 should return our child's pid when it exits */ 225 if ( my_wait_pid != my_pid ) { 226 printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid ); 227 goto test_failed_exit; 228 } 229 230 if (!(WIFSIGNALED( my_status ))) { 231 printf( "child process was not signaled and should have been\n", my_status ); 232 goto test_failed_exit; 233 } 234 235 if (WTERMSIG( my_status ) != SIGKILL) { 236 printf( "wait4 returned wrong signal status - 0x%02X \n", my_status ); 237 goto test_failed_exit; 238 } 239 240 my_err = 0; 241 goto test_passed_exit; 242 243test_failed_exit: 244 my_err = 1; 245 246test_passed_exit: 247 return( my_err ); 248} /* do_execve_test */ 249 250/* 251 * Helper function for posix_spawn test 252 * arch: target architecture to spawn for 253 */ 254int do_spawn_test(int arch, int shouldfail) 255{ 256 int my_err, my_pid, my_status; 257 size_t my_size; 258 posix_spawnattr_t attr; 259 260 char * args[] = {"helpers/arch", NULL}; 261 262 my_err = posix_spawnattr_init(&attr); 263 if (my_err != 0) { 264 printf("posix_spawnattr_init failed\n"); 265 goto done; 266 } 267 268 /* set spawn to only succeed for arch 'arch' */ 269 my_err = posix_spawnattr_setbinpref_np(&attr, 1, &arch, &my_size); 270 if (my_err != 0 || my_size != 1) { 271 printf("posix_spawnattr_setbinpref_np failed\n"); 272 goto done; 273 } 274 275 /* spawn off child process */ 276 my_err = posix_spawn(&my_pid, args[0], NULL, &attr, args, NULL); 277 if (shouldfail) { 278 if( my_err == 0) { 279 printf("posix_spawn should have failed on arch %d\n", arch); 280 goto done; 281 } 282 my_err = 0; 283 } else { 284 /* 285 * child should exit with return code == arch; note that the 286 * posix_spawn error numers are *returned*, NOT set in errno!!! 287 */ 288 if (my_err != 0) { 289 printf("posix_spawn failed with errno %d - %s\n", my_err, strerror(my_err)); 290 goto done; 291 } 292 293 my_err = wait4(my_pid, &my_status, 0, NULL); 294 if (my_err == -1) { 295 printf("wait4 failed with errno %d - %s\n", errno, strerror(errno)); 296 goto done; 297 } 298 my_err = 0; 299 300 if (WEXITSTATUS(my_status) != (arch & 0xff)) { 301 printf("child exited with status %d (expected %d)\n", 302 (WEXITSTATUS(my_status)), 303 (arch & 0xff)); 304 my_err = -1; 305 goto done; 306 } 307 } 308 309done: 310 return my_err; 311} 312 313/* 314 * Uses sysctlbyname to determine the cpu type. Currently, XNU classifies G5 as a 315 * 32-bit CPU, so this shouldn't be used to determine whether or not a CPU 316 * is 64-bit. 317 */ 318int get_architecture() 319{ 320 int rval = -1; 321 size_t length = 0; 322 int my_err, buf; 323 char *errmsg = NULL; 324 325 errmsg = "sysctlbyname() failed when getting hw.cputype"; 326 if ((my_err = sysctlbyname("hw.cputype", NULL, &length, NULL, 0))) goto finished; /* get length of data */ 327 if (length != sizeof(buf)) goto finished; 328 if ((my_err = sysctlbyname("hw.cputype", &buf, &length, NULL, 0))) goto finished; /* copy data */ 329 switch (buf) { 330 case CPU_TYPE_X86: 331 case CPU_TYPE_X86_64: 332 rval = INTEL; 333 break; 334 case CPU_TYPE_ARM: 335#ifdef CPU_TYPE_ARM64 336 case CPU_TYPE_ARM64: 337#endif 338 rval = ARM; 339 break; 340 } 341 342finished: 343 if (rval == -1 && errmsg) 344 printf("%s", errmsg); 345 346 return rval; 347} 348 349 350/* 351 * Gets the bit'ed-ness of the current host. Returns either 32 or 64. 352 * This get the hardware capability, but does not tell us whether this 353 * binary is executing in 64 bit or 32 bit mode. Check sizeof long 354 * or pointer to determine that. 355 */ 356int get_bits() 357{ 358 int my_err, buf; 359 size_t len = 0; 360 int rval = 32; /* 361 * On 32-bit systems the sysctls 64bitops and x86_64 don't 362 * even exists, so if we don't find them then we assume 363 * a 32-bit system. 364 */ 365 366 /* Check for PPC 64 */ 367 if ((my_err = sysctlbyname("hw.optional.64bitops", NULL, &len, NULL, 0))) goto check64bit; /* Request size */ 368 if (len > sizeof(buf)) goto check64bit; 369 if ((my_err = sysctlbyname("hw.optional.64bitops", &buf, &len, NULL, 0))) goto check64bit; /* Copy value out from kernel */ 370 if (buf == 1) rval = 64; 371 goto finished; 372 373check64bit: 374#if defined(__i386__) || defined(__x86_64__) 375 /* Check for x86_64 */ 376 if ((my_err = sysctlbyname("hw.optional.x86_64", NULL, &len, NULL, 0))) goto finished; /* Request size */ 377 if (len > sizeof(buf)) goto finished; 378 if ((my_err = sysctlbyname("hw.optional.x86_64", &buf, &len, NULL, 0))) goto finished; /* Copy value out from kernel */ 379 if (buf == 1) rval = 64; 380 381#else 382#error Unknown architecture. 383#endif 384 385finished: 386 return rval; 387} 388 389/* 390 * printf with a date and time stamp so that we can correlate printf's 391 * with the log files of a system in case of test failure. 392 * 393 * NB: MY_PRINTF_DATE_FMT chosen to look like syslog to aid "grep". 394 */ 395#define MY_PRINTF_DATE_FMT "%b %e %T" 396#undef printf /* was my_printf */ 397int 398my_printf(const char * __restrict fmt, ...) 399{ 400 char *bufp; 401 char datebuf[256]; 402 struct tm *timeptr; 403 time_t result; 404 int rv; 405 va_list ap; 406 407 /* if we are running under a TestBot, do a normal printf */ 408 if (g_testbots_active) { 409 va_start(ap, fmt); 410 rv = vprintf(fmt, ap); 411 va_end(ap); 412 return rv; 413 } 414 415 /* Get the timestamp for this printf */ 416 result = time(NULL); 417 timeptr = localtime(&result); 418 strftime(datebuf, sizeof(datebuf), MY_PRINTF_DATE_FMT, timeptr); 419 420 /* do the printf of the requested data to a local buffer */ 421 va_start(ap, fmt); 422 rv = vasprintf(&bufp, fmt, ap); 423 va_end(ap); 424 425 /* 426 * if we successfully got a local buffer, then we want to 427 * print a timestamp plus what we would have printed before, 428 * then free the allocated memory. 429 */ 430 if (rv != -1) { 431 rv = printf("%s %s", datebuf, bufp); 432 free(bufp); 433 } 434 435 return(rv); 436} 437