1/* 2 * xnu_quick_test - this tool will do a quick test of every (well, to be 3 * honest most) system calls we support in xnu. 4 * 5 * WARNING - this is not meant to be a full regression test of all the 6 * system calls. The intent is to have a quick test of each system call that 7 * can be run very easily and quickly when a new kerenl is built. 8 * 9 * This tool is meant to grow as we find xnu problems that could have be 10 * caught before we submit to a build train. So please add more tests and 11 * make the existing ones better. Some of the original tests are nothing 12 * more than place holders and quite lame. Just keep in mind that the tool 13 * should run as fast as possible. If it gets too slow then most people 14 * will stop running it. 15 * 16 * LP64 testing tip - when adding or modifying tests, keep in mind the 17 * variants in the LP64 world. If xnu gets passed a structure the varies in 18 * size between 32 and 64-bit processes, try to test that a field in the 19 * sructure contains valid data. For example if we know foo structure 20 * looks like: 21 * struct foo { 22 * int an_int; 23 * long a_long; 24 * int another_int; 25 * } 26 * And if we know what another_int should contain then test for the known 27 * value since it's offset will vary depending on whether the calling process 28 * is 32 or 64 bits. 29 * 30 * NOTE - we have several workarounds and test exceptions for some 31 * outstanding bugs in xnu. All the workarounds are marked with "todo" and 32 * some comments noting the radar number of the offending bug. Do a seach 33 * for "todo" in the source files for this project to locate which tests have 34 * known failures. And please tag any new exceptions you find with "todo" 35 * in the comment and the radar number of the bug. 36 */ 37 38#include <errno.h> 39#include <fcntl.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <time.h> 44#include <grp.h> 45#include <unistd.h> 46#include <ctype.h> 47#include <sys/mount.h> 48#include <sys/param.h> 49#include <sys/select.h> 50#include <sys/stat.h> 51#include <sys/syslimits.h> 52#include <sys/types.h> 53#include <sys/ucred.h> 54#include <sys/uio.h> 55#include <mach-o/ldsyms.h> 56#include <mach-o/loader.h> 57#include <mach-o/arch.h> 58#include "tests.h" 59 60#if !TARGET_OS_EMBEDDED 61#include <XILog/XILog.h> 62#endif 63 64 65 66/* our table of tests to run */ 67struct test_entry g_tests[] = 68{ 69 {1, &syscall_test, NULL, "syscall"}, 70 {1, &fork_wait4_exit_test, NULL, "fork, wait4, exit"}, 71 {1, &read_write_test, NULL, "fsync, ftruncate, lseek, pread, pwrite, read, readv, truncate, write, writev"}, 72 {1, &open_close_test, NULL, "close, fpathconf, fstat, open, pathconf"}, 73 {1, &link_stat_unlink_test, NULL, "link, stat, unlink"}, 74 {1, &chdir_fchdir_test, NULL, "chdir, fchdir"}, 75 {1, &access_chmod_fchmod_test, NULL, "access, chmod, fchmod"}, 76 {1, &chown_fchown_lchown_lstat_symlink_test, NULL, "chown, fchown, lchown, lstat, readlink, symlink"}, 77 {1, &fs_stat_tests, NULL, "fstatfs, getfsstat, statfs, fstatfs64, getfsstat64, statfs64"}, 78#if !TARGET_OS_EMBEDDED 79 {1, &statfs_32bit_inode_tests, NULL, "32-bit inode versions: fstatfs, getfsstat, statfs"}, 80#endif 81 {1, &getpid_getppid_pipe_test, NULL, "getpid, getppid, pipe"}, 82 {1, &uid_tests, NULL, "getauid, gettid, getuid, geteuid, issetugid, setaudit_addr, seteuid, settid, settid_with_pid, setuid"}, 83 {1, &mkdir_rmdir_umask_test, NULL, "mkdir, rmdir, umask"}, 84 {1, &mknod_sync_test, NULL, "mknod, sync"}, 85 {1, &socket2_tests, NULL, "fsync, getsockopt, poll, select, setsockopt, socketpair"}, 86 {1, &socket_tests, NULL, "accept, bind, connect, getpeername, getsockname, listen, socket, recvmsg, sendmsg, sendto, sendfile"}, 87 {1, &chflags_fchflags_test, NULL, "chflags, fchflags"}, 88 {1, &execve_kill_vfork_test, NULL, "kill, vfork, execve, posix_spawn"}, 89 {1, &groups_test, NULL, "getegid, getgid, getgroups, setegid, setgid, setgroups"}, 90 {1, &dup_test, NULL, "dup, dup2, getdtablesize"}, 91 {1, &getrusage_test, NULL, "getrusage"}, 92 {1, &signals_test, NULL, "getitimer, setitimer, sigaction, sigpending, sigprocmask, sigsuspend, sigwait"}, 93 {1, &acct_test, NULL, "acct"}, 94 {1, &ioctl_test, NULL, "ioctl"}, 95 {1, &chroot_test, NULL, "chroot"}, 96 {1, &memory_tests, NULL, "madvise, mincore, minherit, mlock, mlock, mmap, mprotect, msync, munmap"}, 97 {1, &process_group_test, NULL, "getpgrp, getpgid, getsid, setpgid, setpgrp, setsid"}, 98 {1, &fcntl_test, NULL, "fcntl"}, 99 {1, &getlogin_setlogin_test, NULL, "getlogin, setlogin"}, 100 {1, &getpriority_setpriority_test, NULL, "getpriority, setpriority"}, 101 {1, &time_tests, NULL, "futimes, gettimeofday, settimeofday, utimes"}, 102 {1, &rename_test, NULL, "rename, stat"}, 103 {1, &locking_test, NULL, "flock"}, 104 {1, &mkfifo_test, NULL, "mkfifo, read, write"}, 105 {1, "actl_test, NULL, "quotactl"}, 106 {1, &limit_tests, NULL, "getrlimit, setrlimit"}, 107 {1, &directory_tests, NULL, "getattrlist, getdirentriesattr, setattrlist"}, 108#if !TARGET_OS_EMBEDDED 109 {1, &getdirentries_test, NULL, "getdirentries"}, 110 {1, &exchangedata_test, NULL, "exchangedata"}, 111#endif 112 {1, &searchfs_test, NULL, "searchfs"}, 113 {1, &sema2_tests, NULL, "sem_close, sem_open, sem_post, sem_trywait, sem_unlink, sem_wait"}, 114 {1, &sema_tests, NULL, "semctl, semget, semop"}, 115 {1, &bsd_shm_tests, NULL, "shm_open, shm_unlink"}, 116 {1, &shm_tests, NULL, "shmat, shmctl, shmdt, shmget"}, 117 {1, &xattr_tests, NULL, "fgetxattr, flistxattr, fremovexattr, fsetxattr, getxattr, listxattr, removexattr, setxattr"}, 118 {1, &aio_tests, NULL, "aio_cancel, aio_error, aio_read, aio_return, aio_suspend, aio_write, fcntl, lio_listio"}, 119 {1, &kqueue_tests, NULL, "kevent, kqueue"}, 120 {1, &message_queue_tests, NULL, "msgctl, msgget, msgrcv, msgsnd"}, 121 {1, &data_exec_tests, NULL, "data/stack execution"}, 122 {1, &machvm_tests, NULL, "Mach VM calls"}, 123 {1, &commpage_data_tests, NULL, "Commpage data"}, 124#if defined(i386) || defined(__x86_64__) 125 {1, &atomic_fifo_queue_test, NULL, "OSAtomicFifoEnqueue, OSAtomicFifoDequeue"}, 126#endif 127 {1, &sched_tests, NULL, "Scheduler tests"}, 128#if TARGET_OS_EMBEDDED 129 {1, &content_protection_test, NULL, "Content protection tests"}, 130#endif 131 {1, &pipes_test, NULL, "Pipes tests"}, 132 {1, &kaslr_test, NULL, "KASLR tests"}, 133 {0, NULL, NULL, "last one"} 134}; 135 136static void create_target_directory( const char * the_targetp ); 137static void list_all_tests( void ); 138static void mark_tests_to_run( long my_start, long my_end ); 139static int parse_tests_to_run( int argc, const char * argv[], int * indexp ); 140static void usage( void ); 141#if !TARGET_OS_EMBEDDED 142static int setgroups_if_single_user(void); 143#endif 144static const char *current_arch( void ); 145 146/* globals */ 147long g_max_failures = 0; 148int g_skip_setuid_tests = 0; 149int g_xilog_active = 0; 150const char * g_cmd_namep; 151char g_target_path[ PATH_MAX ]; 152int g_is_single_user = 0; 153int g_testbots_active = 0; 154 155int main( int argc, const char * argv[] ) 156{ 157 #pragma unused(argc) 158 #pragma unused(argv) 159 int my_tests_count, i; 160 int err; 161 int my_failures = 0; 162 int list_the_tests = 0; 163 const char * my_targetp; 164 time_t my_start_time, my_end_time; 165 struct stat my_stat_buf; 166 char my_buffer[64]; 167 /* vars for XILog */ 168#if !TARGET_OS_EMBEDDED 169 XILogRef logRef; 170 char *logPath = ""; 171 char *config = NULL; 172 int echo = 0; 173 int xml = 0; 174#endif 175 sranddev( ); /* set up seed for our random name generator */ 176 g_cmd_namep = argv[0]; 177 178 /* NOTE - code in create_target_directory will append '/' if it is necessary */ 179 my_targetp = getenv("TMPDIR"); 180 if ( my_targetp == NULL ) 181 my_targetp = "/tmp"; 182 183 /* make sure our executable is owned by root and has set uid bit */ 184 err = stat( g_cmd_namep, &my_stat_buf ); 185 if ( err != 0 ) { 186 err = errno; 187 printf( "stat call on our executable failed - \"%s\" \n", g_cmd_namep ); 188 printf( " failed with error %d - \"%s\" \n", err, strerror( err) ); 189 exit( -1 ); 190 } 191 if ( my_stat_buf.st_uid != 0 || (my_stat_buf.st_mode & S_ISUID) == 0 ) { 192 printf( "executable file - \"%s\" \n", g_cmd_namep ); 193 printf( "does not have correct owner (must be root) or setuid bit is not set \n" ); 194 exit( -1 ); 195 } 196 197 /* parse input parameters */ 198 for ( i = 1; i < argc; i++ ) { 199 if ( strcmp( argv[i], "-u" ) == 0 ) { 200 usage( ); 201 } 202 if ( strcmp( argv[i], "-t" ) == 0 || 203 strcmp( argv[i], "-target" ) == 0 ) { 204 if ( ++i >= argc ) { 205 printf( "invalid target parameter \n" ); 206 usage( ); 207 } 208 /* verify our target directory exists */ 209 my_targetp = argv[i]; 210 err = stat( my_targetp, &my_stat_buf ); 211 if ( err != 0 || S_ISDIR(my_stat_buf.st_mode) == 0 ) { 212 printf( "invalid target path \n" ); 213 if ( err != 0 ) { 214 printf( "stat call failed with error %d - \"%s\" \n", errno, strerror( errno) ); 215 } 216 usage( ); 217 } 218 continue; 219 } 220 if ( strcmp( argv[i], "-f" ) == 0 || 221 strcmp( argv[i], "-failures" ) == 0 ) { 222 if ( ++i >= argc ) { 223 printf( "invalid failures parameter \n" ); 224 usage( ); 225 } 226 227 /* get our max number of failures */ 228 g_max_failures = strtol( argv[i], NULL, 10 ); 229 continue; 230 } 231 if ( strcmp( argv[i], "-l" ) == 0 || 232 strcmp( argv[i], "-list" ) == 0 ) { 233 /* list all the tests this tool will do. 234 */ 235 list_the_tests = 1; 236 continue; 237 } 238 if ( strcmp( argv[i], "-r" ) == 0 || 239 strcmp( argv[i], "-run" ) == 0 ) { 240 if ( ++i >= argc ) { 241 printf( "invalid run tests parameter \n" ); 242 usage( ); 243 } 244 245 /* get which tests to run */ 246 if ( parse_tests_to_run( argc, argv, &i ) != 0 ) { 247 printf( "invalid run tests parameter \n" ); 248 usage( ); 249 } 250 continue; 251 } 252 if ( strcmp( argv[i], "-s" ) == 0 || 253 strcmp( argv[i], "-skip" ) == 0 ) { 254 /* set that want to skip the setuid related tests - this is useful for debgugging since since I can't 255 * get setuid tests to work while in gdb. 256 */ 257 g_skip_setuid_tests = 1; 258 continue; 259 } 260#if !TARGET_OS_EMBEDDED 261 if ( strcmp( argv[i], "-x" ) == 0 || 262 strcmp( argv[i], "-xilog" ) == 0 ) { 263 g_xilog_active = 1; 264 continue; 265 } 266#endif 267 printf( "invalid argument \"%s\" \n", argv[i] ); 268 usage( ); 269 } 270 271 /* done parsing. 272 */ 273 274/* Check if we are running under testbots */ 275#if RUN_UNDER_TESTBOTS 276g_testbots_active = 1; 277#endif 278 /* Code added to run xnu_quick_test under testbots */ 279 if ( g_testbots_active == 1 ) { 280 printf("[TEST] xnu_quick_test \n"); /* Declare the beginning of test suite */ 281 } 282 283#if !TARGET_OS_EMBEDDED 284 /* Populate groups list if we're in single user mode */ 285 if (setgroups_if_single_user()) { 286 return 1; 287 } 288#endif 289 if ( list_the_tests != 0 ) { 290 list_all_tests( ); 291 return 0; 292 } 293#if !TARGET_OS_EMBEDDED 294 if (g_xilog_active == 1) { 295 logRef = XILogOpenLogExtended( logPath, "xnu_quick_test", "com.apple.coreos", config, xml, 296 echo, NULL, "ResultOwner", "com.apple.coreos", NULL ); 297 if( logRef == NULL ) { 298 fprintf(stderr,"Couldn't create log: %s",logPath); 299 exit(-1); 300 } 301 } 302#endif 303 304 /* build a test target directory that we use as our path to create any test 305 * files and directories. 306 */ 307 create_target_directory( my_targetp ); 308 printf( "Will allow %ld failures before testing is aborted \n", g_max_failures ); 309 310 my_start_time = time( NULL ); 311 printf( "\nBegin testing - %s \n", ctime_r( &my_start_time, &my_buffer[0] ) ); 312 printf( "Current architecture is %s\n", current_arch() ); 313 314 /* Code added to run xnu_quick_test under testbots */ 315 316 /* run each test that is marked to run in our table until we complete all of them or 317 * hit the maximum number of failures. 318 */ 319 my_tests_count = (sizeof( g_tests ) / sizeof( g_tests[0] )); 320 for ( i = 0; i < (my_tests_count - 1); i++ ) { 321 int my_err; 322 test_entryp my_testp; 323 324 my_testp = &g_tests[i]; 325 if ( my_testp->test_run_it == 0 || my_testp->test_routine == NULL ) 326 continue; 327#if !TARGET_OS_EMBEDDED 328 if (g_xilog_active == 1) { 329 XILogBeginTestCase( logRef, my_testp->test_infop, my_testp->test_infop ); 330 XILogMsg( "test #%d - %s \n", (i + 1), my_testp->test_infop ); 331 } 332#endif 333 334 if ( g_testbots_active == 1 ) { 335 printf("[BEGIN] %s \n", my_testp->test_infop); 336 } 337 338 printf( "test #%d - %s \n", (i + 1), my_testp->test_infop ); 339 fflush(stdout); 340 my_err = my_testp->test_routine( my_testp->test_input ); 341 if ( my_err != 0 ) { 342 printf("\t--> FAILED \n"); 343#if !TARGET_OS_EMBEDDED 344 if (g_xilog_active == 1) { 345 XILogMsg("SysCall %s failed", my_testp->test_infop); 346 XILogErr("Result %d", my_err); 347 } 348#endif 349 my_failures++; 350 if ( my_failures > g_max_failures ) { 351#if !TARGET_OS_EMBEDDED 352 if (g_xilog_active == 1) { 353 XILogMsg("Reached the maximum number of failures - Aborting xnu_quick_test."); 354 XILogEndTestCase( logRef, kXILogTestPassOnErrorLevel ); 355 } 356#endif 357 printf( "\n Reached the maximum number of failures - Aborting xnu_quick_test. \n" ); 358 /* Code added to run xnu_quick_test under testbots */ 359 if ( g_testbots_active == 1 ) { 360 printf("[FAIL] %s \n", my_testp->test_infop); 361 } 362 goto exit_this_routine; 363 } 364 /* Code added to run xnu_quick_test under testbots */ 365 if ( g_testbots_active == 1 ) { 366 printf("[FAIL] %s \n", my_testp->test_infop); 367 } 368#if !TARGET_OS_EMBEDDED 369 if (g_xilog_active == 1) { 370 XILogEndTestCase( logRef, kXILogTestPassOnErrorLevel ); 371 } 372#endif 373 continue; 374 } 375#if !TARGET_OS_EMBEDDED 376 if (g_xilog_active == 1) { 377 XILogEndTestCase(logRef, kXILogTestPassOnErrorLevel); 378 } 379#endif 380 /* Code added to run xnu_quick_test under testbots */ 381 if ( g_testbots_active == 1 ) { 382 printf("[PASS] %s \n", my_testp->test_infop); 383 } 384 } 385 386exit_this_routine: 387 my_end_time = time( NULL ); 388 printf( "\nEnd testing - %s \n", ctime_r( &my_end_time, &my_buffer[0] ) ); 389 390 /* clean up our test directory */ 391 rmdir( &g_target_path[0] ); 392 393#if !TARGET_OS_EMBEDDED 394 if (g_xilog_active == 1) { 395 XILogCloseLog(logRef); 396 } 397#endif 398 399 return 0; 400} /* main */ 401 402 403/* 404 * parse_tests_to_run - parse the -run argument parameters. the run argument tells us which tests the user 405 * wants to run. we accept ranges (example 1 - 44) and runs of tests (example 2, 33, 34, 100) or a mix of 406 * both (example 1, 44 - 100, 200, 250) 407 */ 408static int parse_tests_to_run( int argc, const char * argv[], int * indexp ) 409{ 410 int my_tests_count, is_range = 0, i; 411 const char * my_ptr; 412 char * my_temp_ptr; 413 long my_first_test_number, my_last_test_number; 414 char my_buffer[ 128 ]; 415 416 /* set tests table to not run any tests then go back and set the specific tests the caller asked for */ 417 my_tests_count = (sizeof( g_tests ) / sizeof( g_tests[0] )); 418 for ( i = 0; i < (my_tests_count - 1); i++ ) { 419 g_tests[ i ].test_run_it = 0; 420 } 421 422 for ( i = *indexp; i < argc; i++ ) { 423 my_ptr = argv[ i ]; 424 if ( strlen( my_ptr ) > 1 && *my_ptr == '-' && isalpha( *(my_ptr + 1) ) ) { 425 /* we have hit a new argument - need to make sure caller uses this argument on the next 426 * pass through its parse loop (which will bump the index value so we want to be one less 427 * than the actual index). 428 */ 429 *indexp = (i - 1); 430 return 0; 431 } 432 433 if ( strlen( my_ptr ) == 1 && *my_ptr == '-' ) { 434 /* we are dealing with a range of tests, for example: 33 - 44 */ 435 is_range = 1; 436 continue; 437 } 438 439 if ( strlen( my_ptr ) > (sizeof( my_buffer ) - 1) ) { 440 printf( "-run argument has too many test parameters (max of %lu characters) \n", sizeof( my_buffer ) ); 441 return -1; 442 } 443 /* get a local copy of the parameter string to work with - break range into two strings */ 444 strcpy( &my_buffer[0], my_ptr ); 445 446 my_temp_ptr = strrchr( &my_buffer[0], '-' ); 447 if ( my_temp_ptr != NULL ) { 448 /* we are dealing with a range of tests with no white space, for example: 33-44 or 33- 44 */ 449 my_temp_ptr = strrchr( &my_buffer[0], '-' ); 450 *my_temp_ptr = 0x00; 451 my_first_test_number = strtol( &my_buffer[0], NULL, 10 ); 452 if ( *(my_temp_ptr + 1) == 0x00 ) { 453 /* we hit the case where the range indicator is at the end of one string, for example: 33- */ 454 is_range = 1; 455 continue; 456 } 457 my_last_test_number = strtol( (my_temp_ptr + 1), NULL, 10 ); 458 if ( my_first_test_number < 1 || my_first_test_number > my_last_test_number ) { 459 printf( "-run argument has invalid range parmeters \n" ); 460 return -1; 461 } 462 mark_tests_to_run( my_first_test_number, my_last_test_number ); 463 is_range = 0; 464 continue; 465 } 466 467 if ( is_range ) { 468 /* should be the second part of the test number range */ 469 my_last_test_number = strtol( &my_buffer[0], NULL, 10 ); 470 if ( my_first_test_number < 1 || my_first_test_number > my_last_test_number ) { 471 printf( "-run argument has invalid range parmeters \n" ); 472 return -1; 473 } 474 475 mark_tests_to_run( my_first_test_number, my_last_test_number ); 476 is_range = 0; 477 continue; 478 } 479 else { 480 my_first_test_number = strtol( &my_buffer[0], NULL, 10 ); 481 if ( my_first_test_number < 1 ) { 482 printf( "-run argument has invalid test number parameter \n" ); 483 return -1; 484 } 485 mark_tests_to_run( my_first_test_number, my_first_test_number ); 486 continue; 487 } 488 } 489 490 *indexp = i; 491 return 0; 492 493} /* parse_tests_to_run */ 494 495 496static void create_target_directory( const char * the_targetp ) 497{ 498 int err; 499 500 if ( strlen( the_targetp ) > (sizeof(g_target_path) - 1) ) { 501 printf( "target path too long - \"%s\" \n", the_targetp ); 502 exit( 1 ); 503 } 504 505 for ( ;; ) { 506 int my_rand; 507 char my_name[64]; 508 509 my_rand = rand( ); 510 sprintf( &my_name[0], "xnu_quick_test-%d", my_rand ); 511 if ( (strlen( &my_name[0] ) + strlen( the_targetp ) + 2) > PATH_MAX ) { 512 printf( "target path plus our test directory name is too long: \n" ); 513 printf( "target path - \"%s\" \n", the_targetp ); 514 printf( "test directory name - \"%s\" \n", &my_name[0] ); 515 exit( 1 ); 516 } 517 518 /* append generated directory name onto our path */ 519 g_target_path[0] = 0x00; 520 strcat( &g_target_path[0], the_targetp ); 521 if ( g_target_path[ (strlen(the_targetp) - 1) ] != '/' ) { 522 strcat( &g_target_path[0], "/" ); 523 } 524 strcat( &g_target_path[0], &my_name[0] ); 525 526 /* try to create the test directory */ 527 err = mkdir( &g_target_path[0], (S_IRWXU | S_IRWXG | S_IROTH) ); 528 if ( err == 0 ) { 529 break; 530 } 531 err = errno; 532 if ( EEXIST != err ) { 533 printf( "test directory creation failed - \"%s\" \n", &g_target_path[0] ); 534 printf( "mkdir call failed with error %d - \"%s\" \n", errno, strerror( err) ); 535 exit( 1 ); 536 } 537 } 538 printf( "created test directory at \"%s\" \n", &g_target_path[0] ); 539 540} /* create_target_directory */ 541 542 543static void mark_tests_to_run( long my_start, long my_end ) 544{ 545 int my_tests_count, i; 546 547 my_tests_count = (sizeof( g_tests ) / sizeof( g_tests[0] )); 548 my_end = (my_end < (my_tests_count - 1)) ? my_end : (my_tests_count - 1); 549 for ( i = (my_start - 1); i < my_end; i++ ) { 550 g_tests[ i ].test_run_it = 1; /* run this test */ 551 } 552 return; 553} /* mark_tests_to_run */ 554 555 556static void usage( void ) 557{ 558 char * my_ptr; 559 560 /* skip past full path and just show the tool name */ 561 my_ptr = strrchr( g_cmd_namep, '/' ); 562 if ( my_ptr != NULL ) { 563 my_ptr++; 564 } 565 566 printf( "\nUSAGE: %s -target TARGET_PATH \n\n", (my_ptr != NULL) ? my_ptr : g_cmd_namep ); 567 printf( "\t -f[ailures] MAX_FAILS_ALLOWED # number of test cases that may fail before we give up. defaults to 0 \n" ); 568 printf( "\t -l[ist] # list all the tests this tool performs \n" ); 569 printf( "\t -r[un] 1, 3, 10 - 19 # run specific tests. enter individual test numbers and/or range of numbers. use -list to list tests. \n" ); 570 printf( "\t -s[kip] # skip setuid tests \n" ); 571 printf( "\t -t[arget] TARGET_PATH # path to directory where tool will create test files. defaults to \"/tmp/\" \n" ); 572#if !TARGET_OS_EMBEDDED 573 printf( "\t -x[ilog] # use XILog\n"); 574#endif 575 printf( "\nexamples: \n" ); 576 printf( "--- Place all test files and directories at the root of volume \"test_vol\" --- \n" ); 577 printf( "%s -t /Volumes/test_vol/ \n", (my_ptr != NULL) ? my_ptr : g_cmd_namep ); 578 printf( " \n" ); 579 printf( "--- Run the tool for tests 10 thru 15, test 18 and test 20 --- \n" ); 580 printf( "%s -r 10-15, 18, 20 \n", (my_ptr != NULL) ? my_ptr : g_cmd_namep ); 581 printf( " \n" ); 582 exit( 1 ); 583 584} /* usage */ 585 586#if !TARGET_OS_EMBEDDED 587/* This is a private API between Libinfo, Libc, and the DirectoryService daemon. 588 * Since we are trying to determine if an external provider will back group 589 * lookups, we can use this, without relying on additional APIs or tools 590 * that might not work yet */ 591extern int _ds_running(void); 592 593#define NUM_GROUPS 6 594static int 595setgroups_if_single_user(void) 596{ 597 int i, retval = -1; 598 struct group *grp; 599 gid_t gids[NUM_GROUPS]; 600 601 if (!_ds_running()) { 602 printf("In single-user mode.\n"); 603 g_is_single_user = 1; 604 605 /* We skip 'nobody' and 'anyone' */ 606 getgrent(); 607 getgrent(); 608 for (i = 0; i < NUM_GROUPS; i++) { 609 grp = getgrent(); 610 if (!grp) { 611 break; 612 } 613 614 gids[i] = grp->gr_gid; 615 } 616 617 endgrent(); 618 619 /* Only succeed if we find at least NUM_GROUPS */ 620 if (i == NUM_GROUPS) { 621 retval = setgroups(NUM_GROUPS, gids); 622 if (retval == 0) { 623 getgroups(NUM_GROUPS, gids); 624 printf("After single-user hack, groups are: "); 625 for (i = 0; i < NUM_GROUPS; i++) { 626 printf("%d, ", gids[i]); 627 } 628 putchar('\n'); 629 } else { 630 printf("Setgroups failed.\n"); 631 } 632 } else { 633 printf("Couldn't get sufficient number of groups.\n"); 634 } 635 } else { 636 printf("Not in single user mode.\n"); 637 retval = 0; 638 } 639 640 641 return retval; 642} 643#endif 644 645static const char *current_arch( void ) 646{ 647 cpu_type_t cputype = _mh_execute_header.cputype; 648 cpu_subtype_t cpusubtype = _mh_execute_header.cpusubtype; 649 650 const NXArchInfo *arch = NXGetArchInfoFromCpuType(cputype, cpusubtype); 651 652 if (arch) { 653 return arch->name; 654 } else { 655 return "<unknown>"; 656 } 657} 658 659#undef printf /* this makes the "-l" output easier to read */ 660static void list_all_tests( void ) 661{ 662 int i, my_tests_count; 663 664 my_tests_count = (sizeof( g_tests ) / sizeof( g_tests[0] )); 665 printf( "\nList of all tests this tool performs... \n" ); 666 667 for ( i = 0; i < (my_tests_count - 1); i++ ) { 668 printf( " %d \t %s \n", (i + 1), g_tests[ i ].test_infop ); 669 } 670 671 return; 672} /* list_all_tests */ 673