]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/tests/xnu_quick_test/main.c
xnu-2782.20.48.tar.gz
[apple/xnu.git] / tools / tests / xnu_quick_test / main.c
index 237d14cdce8cea749e1c6439e4b42dd6eeb33ad6..468249080c95edb813c35c79394522496ad5ebdd 100644 (file)
@@ -41,7 +41,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <grp.h>
 #include <unistd.h>
+#include <ctype.h>
 #include <sys/mount.h>
 #include <sys/param.h>
 #include <sys/select.h>
 #include <sys/types.h>
 #include <sys/ucred.h>
 #include <sys/uio.h>
-#include <XILog/XILog.h>
-
+#include <mach-o/ldsyms.h>
+#include <mach-o/loader.h>
+#include <mach-o/arch.h>
 #include "tests.h"
 
 
+
+
 /* our table of tests to run  */
 struct test_entry   g_tests[] =
 {
@@ -66,18 +71,19 @@ struct test_entry   g_tests[] =
        {1, &chdir_fchdir_test, NULL, "chdir, fchdir"},
        {1, &access_chmod_fchmod_test, NULL, "access, chmod, fchmod"},
        {1, &chown_fchown_lchown_lstat_symlink_test, NULL, "chown, fchown, lchown, lstat, readlink, symlink"},
-       {1, &fs_stat_tests, NULL, "fstatfs, getattrlist, getfsstat, statfs, getfsstat64, statfs64, fstatfs64"},
+       {1, &fs_stat_tests, NULL, "fstatfs, getfsstat, statfs, fstatfs64, getfsstat64, statfs64"},
+       {1, &statfs_32bit_inode_tests, NULL, "32-bit inode versions: fstatfs, getfsstat, statfs"},
        {1, &getpid_getppid_pipe_test, NULL, "getpid, getppid, pipe"},
-       {1, &uid_tests, NULL, "getauid, gettid, getuid, geteuid, issetugid, setauid, seteuid, settid, settid_with_pid, setuid"},
+       {1, &uid_tests, NULL, "getauid, gettid, getuid, geteuid, issetugid, setaudit_addr, seteuid, settid, settid_with_pid, setuid"},
        {1, &mkdir_rmdir_umask_test, NULL, "mkdir, rmdir, umask"},
        {1, &mknod_sync_test, NULL, "mknod, sync"},
        {1, &socket2_tests, NULL, "fsync, getsockopt, poll, select, setsockopt, socketpair"},
-       {1, &socket_tests, NULL, "accept, bind, connect, getpeername, getsockname, listen, socket, recvmsg, sendmsg, sendto"},
+       {1, &socket_tests, NULL, "accept, bind, connect, getpeername, getsockname, listen, socket, recvmsg, sendmsg, sendto, sendfile"},
        {1, &chflags_fchflags_test, NULL, "chflags, fchflags"},
        {1, &execve_kill_vfork_test, NULL, "kill, vfork, execve, posix_spawn"},
        {1, &groups_test, NULL, "getegid, getgid, getgroups, setegid, setgid, setgroups"},
        {1, &dup_test, NULL, "dup, dup2, getdtablesize"},
-       {1, &getrusage_profil_test, NULL, "getrusage, profil"},
+       {1, &getrusage_test, NULL, "getrusage"},
        {1, &signals_test, NULL, "getitimer, setitimer, sigaction, sigpending, sigprocmask, sigsuspend, sigwait"},
        {1, &acct_test, NULL, "acct"},
        {1, &ioctl_test, NULL, "ioctl"},
@@ -93,7 +99,8 @@ struct test_entry   g_tests[] =
        {1, &mkfifo_test, NULL, "mkfifo, read, write"},
        {1, &quotactl_test, NULL, "quotactl"},
        {1, &limit_tests, NULL, "getrlimit, setrlimit"},
-       {1, &directory_tests, NULL, "getattrlist, getdirentries, getdirentriesattr, setattrlist"},
+       {1, &directory_tests, NULL, "getattrlist, getdirentriesattr, setattrlist"},
+       {1, &getdirentries_test, NULL, "getdirentries"},
        {1, &exchangedata_test, NULL, "exchangedata"},
        {1, &searchfs_test, NULL, "searchfs"},
        {1, &sema2_tests, NULL, "sem_close, sem_open, sem_post, sem_trywait, sem_unlink, sem_wait"},
@@ -104,6 +111,23 @@ struct test_entry   g_tests[] =
        {1, &aio_tests, NULL, "aio_cancel, aio_error, aio_read, aio_return, aio_suspend, aio_write, fcntl, lio_listio"},
        {1, &kqueue_tests, NULL, "kevent, kqueue"},
        {1, &message_queue_tests, NULL, "msgctl, msgget, msgrcv, msgsnd"},
+       {1, &data_exec_tests, NULL, "data/stack execution"},
+       {1, &machvm_tests, NULL, "Mach VM calls"},
+       {1, &commpage_data_tests, NULL, "Commpage data"},
+#if defined(i386) || defined(__x86_64__)
+       {1, &atomic_fifo_queue_test, NULL, "OSAtomicFifoEnqueue, OSAtomicFifoDequeue"},
+#endif
+       {1, &sched_tests, NULL, "Scheduler tests"},
+       {1, &pipes_test, NULL, "Pipes tests"},
+       {1, &kaslr_test, NULL, "KASLR tests"},
+       {1, &getattrlistbulk_test, NULL, "getattrlistbulk"},
+       {1, &openat_close_test, NULL, "openat, fpathconf, fstatat, close"},
+       {1, &linkat_fstatat_unlinkat_test, NULL, "linkat, statat, unlinkat"},
+       {1, &faccessat_fchmodat_fchmod_test, NULL, "faccessat, fchmodat, fchmod"},
+       {1, &fchownat_fchown_symlinkat_test, NULL, "fchownat, symlinkat, readlinkat"},
+       {1, &mkdirat_unlinkat_umask_test, NULL, "mkdirat, unlinkat, umask"},
+       {1, &renameat_test, NULL, "renameat, fstatat"},
+       {1, &set_exception_ports_test, NULL, "thread_set_exception_ports, task_set_exception_ports, host_set_exception_ports"},
        {0, NULL, NULL, "last one"}
 };
 
@@ -112,17 +136,21 @@ static void list_all_tests( void );
 static void mark_tests_to_run( long my_start, long my_end );
 static int parse_tests_to_run( int argc, const char * argv[], int * indexp );
 static void usage( void );
+static int setgroups_if_single_user(void);
+static const char *current_arch( void );
 
 /* globals */
 long           g_max_failures = 0;
 int            g_skip_setuid_tests = 0;
-int            g_xilog_active = 0;
 const char *   g_cmd_namep;
 char           g_target_path[ PATH_MAX ];
-int            g_is_under_rosetta = 0;
+int            g_is_single_user = 0;
+int            g_testbots_active = 0;
  
 int main( int argc, const char * argv[] ) 
 {
+       #pragma unused(argc)
+       #pragma unused(argv)
        int                             my_tests_count, i;
        int                             err;
        int                             my_failures = 0;
@@ -131,35 +159,58 @@ int main( int argc, const char * argv[] )
        time_t                  my_start_time, my_end_time;
        struct stat             my_stat_buf;
        char                    my_buffer[64];
-       /* vars for XILog */
-       XILogRef                logRef;
-       char                    *logPath = "";
-       char                    *config = NULL;
-       int                             echo = 0;
-       int                             xml = 0;
-       
+       uid_t           sudo_uid = 0;
+       const char *    sudo_uid_env;
+       gid_t           sudo_gid;
+       const char *    sudo_gid_env;
        sranddev( );                            /* set up seed for our random name generator */
        g_cmd_namep = argv[0];
-       
+
+       /* make sure SIGCHLD is not ignored, so wait4 calls work */
+       signal(SIGCHLD, SIG_DFL);
+
        /* NOTE - code in create_target_directory will append '/' if it is necessary */
        my_targetp = getenv("TMPDIR");
        if ( my_targetp == NULL )
                my_targetp = "/tmp";
        
-       /* make sure our executable is owned by root and has set uid bit */
-       err = stat( g_cmd_namep, &my_stat_buf );
-       if ( err != 0 ) {
-               err = errno;
-               printf( "stat call on our executable failed -  \"%s\" \n", g_cmd_namep );
-               printf( " failed with error %d - \"%s\" \n", err, strerror( err) );
+       /* make sure we are running as root */
+       if ( ( getuid() != 0 ) || ( geteuid() != 0 ) ) {
+               printf( "Test must be run as root\n", g_cmd_namep );
                exit( -1 );
        }
-       if ( my_stat_buf.st_uid != 0 || (my_stat_buf.st_mode & S_ISUID) == 0 ) {
-               printf( "executable file -  \"%s\" \n", g_cmd_namep );
-               printf( "does not have correct owner (must be root) or setuid bit is not set \n" );
-               exit( -1 );
+
+       sudo_uid_env = getenv("SUDO_UID");
+       if ( sudo_uid_env ) {
+               sudo_uid = strtol(sudo_uid_env, NULL, 10);
+       }
+
+       /* switch real uid to a non_root user, while keeping effective uid as root */
+       if ( sudo_uid != 0 ) {
+               setreuid( sudo_uid, 0 );
+       }
+       else {
+               /* Default to 501 if no sudo uid found */
+               setreuid( 501, 0 );
+       }
+
+       /* restore the gid if run through sudo */
+       sudo_gid_env = getenv("SUDO_GID");
+       if ( sudo_gid_env ) {
+               sudo_gid = strtol(sudo_gid_env, NULL, 10);
        }
        
+       if ( getgid() == 0 ) {
+
+               if ( sudo_gid != 0 ) {
+                       setgid( sudo_gid );
+               }
+               else {
+                       /* Default to 20 if no sudo gid found */
+                       setgid( 20 );
+               }
+       }
+
        /* parse input parameters */
        for ( i = 1; i < argc; i++ ) {
                if ( strcmp( argv[i], "-u" ) == 0 ) {
@@ -223,60 +274,47 @@ int main( int argc, const char * argv[] )
                        g_skip_setuid_tests = 1;
                        continue;
                }
-               if ( strcmp( argv[i], "-x" ) == 0 ||
-                        strcmp( argv[i], "-xilog" ) == 0 ) {
-                       g_xilog_active = 1;
+               if ( strcmp( argv[i], "-testbot" ) == 0 ) {
+                       g_testbots_active = 1;
                        continue;
                }
-
                printf( "invalid argument \"%s\" \n", argv[i] );
                usage( );
        }
 
        /* done parsing.
         */
-    
-#ifdef __ppc__
-       /* determine if we are running under Rosetta 
-        */
-       {
-           int val = 0;
-           size_t size = sizeof val;
-           if (sysctlbyname("sysctl.proc_native", &val, &size, NULL, 0) == -1)
-               g_is_under_rosetta = 0;
-           else
-               g_is_under_rosetta = val ? 0 : 1;
-       }
+
+/* Check if we are running under testbots */
+#if RUN_UNDER_TESTBOTS
+g_testbots_active = 1;
 #endif
-    
+       /* Code added to run xnu_quick_test under testbots */
+       if ( g_testbots_active == 1 ) {
+               printf("[TEST] xnu_quick_test \n");     /* Declare the beginning of test suite */
+       }
+
+       /* Populate groups list if we're in single user mode */
+       if (setgroups_if_single_user()) {
+               return 1;
+       }
        if ( list_the_tests != 0 ) {
                list_all_tests( );
                return 0;
        }
-
-       if (g_xilog_active == 1) {      
-               logRef = XILogOpenLogExtended( logPath, "xnu_quick_test", "com.apple.coreos", 
-                                                                               config, xml, echo, NULL, "ResultOwner", 
-                                                                               "com.apple.coreos", NULL );
-               if( logRef == NULL )  {
-                       fprintf(stderr,"Couldn't create log: %s",logPath);
-                       exit(-1);
-               }
-       }
        
        /* build a test target directory that we use as our path to create any test
         * files and directories.
         */
        create_target_directory( my_targetp );
-       printf( "Will allow %d failures before testing is aborted \n", g_max_failures );
+       printf( "Will allow %ld failures before testing is aborted \n", g_max_failures );
        
-        if (g_is_under_rosetta) {
-                printf("Running under Rosetta.\n");
-        }
-        
        my_start_time = time( NULL );
        printf( "\nBegin testing - %s \n", ctime_r( &my_start_time, &my_buffer[0] ) );
-       
+       printf( "Current architecture is %s\n", current_arch() );
+
+       /* Code added to run xnu_quick_test under testbots */
+               
        /* run each test that is marked to run in our table until we complete all of them or
         * hit the maximum number of failures.
         */
@@ -288,30 +326,37 @@ int main( int argc, const char * argv[] )
                my_testp = &g_tests[i];
                if ( my_testp->test_run_it == 0 || my_testp->test_routine == NULL )
                        continue;
-               if (g_xilog_active == 1) {      
-                       XILogBeginTestCase( logRef, my_testp->test_infop, my_testp->test_infop );       
-                       XILogMsg( "test #%d - %s \n", (i + 1), my_testp->test_infop );
+
+               if ( g_testbots_active == 1 ) {
+                       printf("[BEGIN] %s \n", my_testp->test_infop);
                }
+
                printf( "test #%d - %s \n", (i + 1), my_testp->test_infop );
+               fflush(stdout);
                my_err = my_testp->test_routine( my_testp->test_input );
                if ( my_err != 0 ) {
                        printf("\t--> FAILED \n");
-                       if (g_xilog_active == 1) {      
-                               XILogMsg("SysCall %s failed", my_testp->test_infop);
-                               XILogErr("Result %d", my_err);
-                       }
+                       printf("SysCall %s failed", my_testp->test_infop);
+                       printf("Result %d", my_err);
                        my_failures++;
                        if ( my_failures > g_max_failures ) {
-                               if (g_xilog_active == 1) {      
-                                       XILogEndTestCase( logRef, kXILogTestPassOnErrorLevel );
-                               }
-                               printf( "\n too many failures - test aborted \n" );
+                               printf( "\n Reached the maximum number of failures - Aborting xnu_quick_test. \n" );
+                               /* Code added to run xnu_quick_test under testbots */
+                               if ( g_testbots_active == 1 ) {
+                                       printf("[FAIL] %s \n", my_testp->test_infop);
+                               }       
                                goto exit_this_routine;
                        }
+                       /* Code added to run xnu_quick_test under testbots */
+                       if ( g_testbots_active == 1 ) {
+                               printf("\n[FAIL] %s \n", my_testp->test_infop);
+                       }                       
+                       continue;
                }
-               if (g_xilog_active == 1) {      
-                       XILogEndTestCase(logRef, kXILogTestPassOnErrorLevel);
-               }
+               /* Code added to run xnu_quick_test under testbots */
+               if ( g_testbots_active == 1 ) {
+                       printf("[PASS] %s \n", my_testp->test_infop);
+               }       
        }
        
 exit_this_routine:
@@ -321,11 +366,8 @@ exit_this_routine:
        /* clean up our test directory */
        rmdir( &g_target_path[0] );     
 
-       if (g_xilog_active == 1) {      
-               XILogCloseLog(logRef);
-       }
-       
-    return 0;
+       /* exit non zero if there are any failures */
+       return my_failures != 0;
 } /* main */
 
 
@@ -366,7 +408,7 @@ static int parse_tests_to_run( int argc, const char * argv[], int * indexp )
                }
 
                if ( strlen( my_ptr ) > (sizeof( my_buffer ) - 1) ) {
-                       printf( "-run argument has too many test parameters (max of %d characters) \n", sizeof( my_buffer ) );
+                       printf( "-run argument has too many test parameters (max of %lu characters) \n", sizeof( my_buffer ) );
                        return -1;
                }
                /* get a local copy of the parameter string to work with - break range into two strings */
@@ -469,21 +511,6 @@ static void create_target_directory( const char * the_targetp )
 } /* create_target_directory */
 
 
-static void list_all_tests( void )
-{
-       int             i, my_tests_count;
-       
-       my_tests_count = (sizeof( g_tests ) / sizeof( g_tests[0] ));
-       printf( "\nList of all tests this tool performs... \n" );
-
-       for ( i = 0; i < (my_tests_count - 1); i++ ) {
-               printf( " %d \t   %s \n", (i + 1), g_tests[ i ].test_infop );
-       }
-       
-       return;
-} /* list_all_tests */
-
-
 static void mark_tests_to_run( long my_start, long my_end )
 {
        int                     my_tests_count, i;
@@ -513,7 +540,7 @@ static void usage( void )
        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" );
        printf( "\t -s[kip]                         # skip setuid tests   \n" );
        printf( "\t -t[arget] TARGET_PATH           # path to directory where tool will create test files.  defaults to \"/tmp/\"   \n" );
-       printf( "\t -x[ilog]                        # use XILog\n");
+       printf( "\t -testbot                        # output results in CoreOS TestBot compatible format  \n" );
        printf( "\nexamples:  \n" );
        printf( "--- Place all test files and directories at the root of volume \"test_vol\" --- \n" );
        printf( "%s -t /Volumes/test_vol/ \n", (my_ptr != NULL) ? my_ptr : g_cmd_namep );
@@ -525,3 +552,88 @@ static void usage( void )
 
 } /* usage */
 
+/* This is a private API between Libinfo, Libc, and the DirectoryService daemon.
+ * Since we are trying to determine if an external provider will back group
+ * lookups, we can use this, without relying on additional APIs or tools
+ * that might not work yet */
+extern int _ds_running(void);
+
+#define NUM_GROUPS     6
+static int
+setgroups_if_single_user(void)
+{
+       int i, retval = -1;
+       struct group *grp;
+       gid_t gids[NUM_GROUPS];
+
+       if (!_ds_running()) {
+               printf("In single-user mode.\n");
+               g_is_single_user = 1;           
+
+               /* We skip 'nobody' and 'anyone' */
+               getgrent();
+               getgrent();
+               for (i = 0; i < NUM_GROUPS; i++) {
+                       grp = getgrent();
+                       if (!grp) {
+                               break;
+                       }
+
+                       gids[i] = grp->gr_gid;
+               }
+               
+               endgrent();
+               
+               /* Only succeed if we find at least NUM_GROUPS */
+               if (i == NUM_GROUPS) {
+                       retval = setgroups(NUM_GROUPS, gids);
+                       if (retval == 0) { 
+                               getgroups(NUM_GROUPS, gids);
+                               printf("After single-user hack, groups are: ");
+                               for (i = 0; i < NUM_GROUPS; i++) {
+                                       printf("%d, ", gids[i]);
+                               }
+                               putchar('\n');
+                       } else {
+                               printf("Setgroups failed.\n");
+                       }
+               } else {
+                       printf("Couldn't get sufficient number of groups.\n");
+               }
+       } else {
+               printf("Not in single user mode.\n");
+               retval = 0;
+       }
+
+
+       return retval;
+}
+
+static const char *current_arch( void )
+{
+       cpu_type_t cputype = _mh_execute_header.cputype;
+       cpu_subtype_t cpusubtype = _mh_execute_header.cpusubtype;
+
+       const NXArchInfo *arch = NXGetArchInfoFromCpuType(cputype, cpusubtype);
+
+       if (arch) {
+               return arch->name;
+       } else {
+               return "<unknown>";
+       }
+}
+
+#undef printf  /* this makes the "-l" output easier to read */
+static void list_all_tests( void )
+{
+       int             i, my_tests_count;
+       
+       my_tests_count = (sizeof( g_tests ) / sizeof( g_tests[0] ));
+       printf( "\nList of all tests this tool performs... \n" );
+
+       for ( i = 0; i < (my_tests_count - 1); i++ ) {
+               printf( " %d \t   %s \n", (i + 1), g_tests[ i ].test_infop );
+       }
+       
+       return;
+} /* list_all_tests */