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 /* vfork then execve sleep system command (which we will kill from the parent process) */ 183 my_pid = vfork(); 184 if (my_pid == -1) { 185 printf( "vfork failed with errno %d - %s \n", errno, strerror( errno ) ); 186 goto test_failed_exit; 187 } 188 if ( my_pid == 0 ) { 189 /* 190 * child process - use execve to start one of the customized helper 191 * binaries, which just sleep for 120 seconds. Let our parent kill us. 192 */ 193 194 my_err = execve(path, argv, envp); 195 if ( my_err != 0 ) { /* TODO: execve() on x86_64 inca returns weird error codes, see rdar://4655612 */ 196 printf( "execve call failed with return value: %d, errno: %d - \"%s\"; path: %s \n", 197 my_err, errno, strerror( errno), path ); 198 fflush(stdout); 199 exit(-2); 200 } 201 202 /* should never get here */ 203 printf("Execve failed and it was not caught by our test\n"); 204 return(-1); 205 } 206 /* 207 * parent process - let's kill our sleeping child 208 */ 209 sleep(killwait); 210 my_err = kill( my_pid, SIGKILL ); 211 if ( my_err == -1 ) { 212 printf( "kill call failed with error %d - \"%s\" \n", errno, strerror( errno) ); 213 goto test_failed_exit; 214 } 215 216 /* wait for child to exit */ 217 my_wait_pid = wait4( my_pid, &my_status, 0, NULL ); 218 if ( my_wait_pid == -1 ) { 219 printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) ); 220 goto test_failed_exit; 221 } 222 223 /* wait4 should return our child's pid when it exits */ 224 if ( my_wait_pid != my_pid ) { 225 printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid ); 226 goto test_failed_exit; 227 } 228 229 if (!(WIFSIGNALED( my_status ))) { 230 printf( "child process was not signaled and should have been\n", my_status ); 231 goto test_failed_exit; 232 } 233 234 if (WTERMSIG( my_status ) != SIGKILL) { 235 printf( "wait4 returned wrong signal status - 0x%02X \n", my_status ); 236 goto test_failed_exit; 237 } 238 239 my_err = 0; 240 goto test_passed_exit; 241 242test_failed_exit: 243 my_err = 1; 244 245test_passed_exit: 246 return( my_err ); 247} /* do_execve_test */ 248 249/* 250 * Helper function for posix_spawn test 251 * arch: target architecture to spawn for 252 */ 253int do_spawn_test(int arch, int shouldfail) 254{ 255 int my_err, my_pid, my_status; 256 size_t my_size; 257 posix_spawnattr_t attr; 258 259 char * args[] = {"helpers/arch", NULL}; 260 261 my_err = posix_spawnattr_init(&attr); 262 if (my_err != 0) { 263 printf("posix_spawnattr_init failed\n"); 264 goto done; 265 } 266 267 /* set spawn to only succeed for arch 'arch' */ 268 my_err = posix_spawnattr_setbinpref_np(&attr, 1, &arch, &my_size); 269 if (my_err != 0 || my_size != 1) { 270 printf("posix_spawnattr_setbinpref_np failed\n"); 271 goto done; 272 } 273 274 /* spawn off child process */ 275 my_err = posix_spawn(&my_pid, args[0], NULL, &attr, args, NULL); 276 if (shouldfail) { 277 if( my_err == 0) { 278 printf("posix_spawn should have failed on arch %d\n", arch); 279 goto done; 280 } 281 my_err = 0; 282 } else { 283 /* 284 * child should exit with return code == arch; note that the 285 * posix_spawn error numers are *returned*, NOT set in errno!!! 286 */ 287 if (my_err != 0) { 288 printf("posix_spawn failed with errno %d - %s\n", my_err, strerror(my_err)); 289 goto done; 290 } 291 292 my_err = wait4(my_pid, &my_status, 0, NULL); 293 if (my_err == -1) { 294 printf("wait4 failed with errno %d - %s\n", errno, strerror(errno)); 295 goto done; 296 } 297 my_err = 0; 298 299 if (WEXITSTATUS(my_status) != (arch & 0xff)) { 300 printf("child exited with status %d (expected %d)\n", 301 (WEXITSTATUS(my_status)), 302 (arch & 0xff)); 303 my_err = -1; 304 goto done; 305 } 306 } 307 308done: 309 return my_err; 310} 311 312/* 313 * Uses sysctlbyname to determine the cpu type. Currently, XNU classifies G5 as a 314 * 32-bit CPU, so this shouldn't be used to determine whether or not a CPU 315 * is 64-bit. 316 */ 317int get_architecture() 318{ 319 int rval = -1; 320 size_t length = 0; 321 int my_err, buf; 322 char *errmsg = NULL; 323 324 errmsg = "sysctlbyname() failed when getting hw.cputype"; 325 if ((my_err = sysctlbyname("hw.cputype", NULL, &length, NULL, 0))) goto finished; /* get length of data */ 326 if (length != sizeof(buf)) goto finished; 327 if ((my_err = sysctlbyname("hw.cputype", &buf, &length, NULL, 0))) goto finished; /* copy data */ 328 switch (buf) { 329 case CPU_TYPE_X86: 330 case CPU_TYPE_X86_64: 331 rval = INTEL; 332 break; 333 case CPU_TYPE_ARM: 334 rval = ARM; 335 break; 336 } 337 338finished: 339 if (rval == -1 && errmsg) 340 printf("%s", errmsg); 341 342 return rval; 343} 344 345 346/* 347 * Gets the bit'ed-ness of the current host. Returns either 32 or 64. 348 * This get the hardware capability, but does not tell us whether this 349 * binary is executing in 64 bit or 32 bit mode. Check sizeof long 350 * or pointer to determine that. 351 */ 352int get_bits() 353{ 354 int my_err, buf; 355 size_t len = 0; 356 int rval = 32; /* 357 * On 32-bit systems the sysctls 64bitops and x86_64 don't 358 * even exists, so if we don't find them then we assume 359 * a 32-bit system. 360 */ 361 362 /* Check for PPC 64 */ 363 if ((my_err = sysctlbyname("hw.optional.64bitops", NULL, &len, NULL, 0))) goto check64bit; /* Request size */ 364 if (len > sizeof(buf)) goto check64bit; 365 if ((my_err = sysctlbyname("hw.optional.64bitops", &buf, &len, NULL, 0))) goto check64bit; /* Copy value out from kernel */ 366 if (buf == 1) rval = 64; 367 goto finished; 368 369check64bit: 370#if defined(__i386__) || defined(__x86_64__) 371 /* Check for x86_64 */ 372 if ((my_err = sysctlbyname("hw.optional.x86_64", NULL, &len, NULL, 0))) goto finished; /* Request size */ 373 if (len > sizeof(buf)) goto finished; 374 if ((my_err = sysctlbyname("hw.optional.x86_64", &buf, &len, NULL, 0))) goto finished; /* Copy value out from kernel */ 375 if (buf == 1) rval = 64; 376 377#else 378#error Unknown architecture. 379#endif 380 381finished: 382 return rval; 383} 384 385/* 386 * printf with a date and time stamp so that we can correlate printf's 387 * with the log files of a system in case of test failure. 388 * 389 * NB: MY_PRINTF_DATE_FMT chosen to look like syslog to aid "grep". 390 */ 391#define MY_PRINTF_DATE_FMT "%b %e %T" 392#undef printf /* was my_printf */ 393int 394my_printf(const char * __restrict fmt, ...) 395{ 396 char *bufp; 397 char datebuf[256]; 398 struct tm *timeptr; 399 time_t result; 400 int rv; 401 va_list ap; 402 403 /* if we are running under a TestBot, do a normal printf */ 404 if (g_testbots_active) { 405 va_start(ap, fmt); 406 rv = vprintf(fmt, ap); 407 va_end(ap); 408 return rv; 409 } 410 411 /* Get the timestamp for this printf */ 412 result = time(NULL); 413 timeptr = localtime(&result); 414 strftime(datebuf, sizeof(datebuf), MY_PRINTF_DATE_FMT, timeptr); 415 416 /* do the printf of the requested data to a local buffer */ 417 va_start(ap, fmt); 418 rv = vasprintf(&bufp, fmt, ap); 419 va_end(ap); 420 421 /* 422 * if we successfully got a local buffer, then we want to 423 * print a timestamp plus what we would have printed before, 424 * then free the allocated memory. 425 */ 426 if (rv != -1) { 427 rv = printf("%s %s", datebuf, bufp); 428 free(bufp); 429 } 430 431 return(rv); 432} 433