--- /dev/null
+
+#include "tests.h"
+
+/*
+ * create_random_name - creates a file with a random / unique name in the given directory.
+ * when do_open is true we create a file else we generaate a name that does not exist in the
+ * given directory (we do not create anything when do_open is 0).
+ * WARNING - caller provides enough space in path buffer for longest possible name.
+ * WARNING - assumes caller has appended a trailing '/' on the path passed to us.
+ * RAND_MAX is currently 2147483647 (ten characters plus one for a slash)
+ */
+int create_random_name( char *the_pathp, int do_open ) {
+ int i, my_err;
+ int my_fd = -1;
+
+ for ( i = 0; i < 1; i++ ) {
+ int my_rand;
+ char *myp;
+ char my_name[32];
+
+ my_rand = rand( );
+ sprintf( &my_name[0], "%d", my_rand );
+ if ( (strlen( &my_name[0] ) + strlen( the_pathp ) + 2) > PATH_MAX ) {
+ printf( "%s - path to test file greater than PATH_MAX \n", __FUNCTION__ );
+ return( -1 );
+ }
+
+ // append generated file name onto our path
+ myp = strrchr( the_pathp, '/' );
+ *(myp + 1) = 0x00;
+ strcat( the_pathp, &my_name[0] );
+ if ( do_open ) {
+ /* create a file with this name */
+ my_fd = open( the_pathp, (O_RDWR | O_CREAT | O_EXCL),
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) );
+ if ( my_fd == -1 ) {
+ if ( errno != EEXIST ) {
+ printf( "%s - open failed with errno %d - %s \n",
+ __FUNCTION__, errno, strerror( errno ) );
+ return( -1 );
+ }
+ // name already exists, try another
+ i--;
+ continue;
+ }
+ }
+ else {
+ /* make sure the name is unique */
+ struct stat my_sb;
+ my_err = stat( the_pathp, &my_sb );
+ if ( my_err != 0 ) {
+ if ( errno == ENOENT ) {
+ break;
+ }
+ else {
+ printf( "%s - open failed with errno %d - %s \n",
+ __FUNCTION__, errno, strerror( errno ) );
+ return( -1 );
+ }
+ }
+ /* name already exists, try another */
+ i--;
+ continue;
+ }
+ }
+
+ if ( my_fd != -1 )
+ close( my_fd );
+
+ return( 0 );
+
+} /* create_random_name */
+
+/*
+ * create_file_with_name - create a file in the given target directory using the given name.
+ * If an existing file or directory is present use the value of remove_existing to determine if the
+ * object is to be deleted.
+ * returns 0 if file could be created, 1 if file exists, 2 if directory exists, else -1
+ * NOTE - will fail if a directory is present with the given name and it is not empty.
+ */
+int create_file_with_name( char *the_target_dirp, char *the_namep, int remove_existing ) {
+ int create_test_file, my_err, my_result;
+ int my_fd = -1;
+ char * my_pathp = NULL;
+ struct stat my_sb;
+
+ create_test_file = 0;
+ my_pathp = (char *) malloc( PATH_MAX );
+ if ( my_pathp == NULL ) {
+ printf( "malloc failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto failure_exit;
+ }
+ strcpy( my_pathp, the_target_dirp );
+ strcat( my_pathp, the_namep );
+
+ /* make sure the name is unique */
+ my_result = 0;
+ my_err = stat( my_pathp, &my_sb );
+ if ( my_err != 0 ) {
+ create_test_file = 1;
+ if ( errno != ENOENT ) {
+ goto failure_exit;
+ }
+ }
+ else {
+ /* name already exists */
+ if ( S_ISDIR( my_sb.st_mode ) ) {
+ my_result = 2; /* tell caller directory exists with target name */
+ if ( remove_existing ) {
+ my_err = rmdir( my_pathp );
+ if ( my_err == -1 ) {
+ printf( "rmdir failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto failure_exit;
+ }
+ create_test_file = 1;
+ }
+ }
+ else {
+ my_result = 1; /* tell caller file exists with target name */
+ if ( remove_existing ) {
+ my_err = unlink( my_pathp );
+ if ( my_err == -1 ) {
+ printf( "unlink failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto failure_exit;
+ }
+ create_test_file = 1;
+ }
+ }
+ }
+
+ if ( create_test_file ) {
+ /* create a file with this name */
+ my_fd = open( my_pathp, (O_RDWR | O_CREAT | O_EXCL),
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) );
+ if ( my_fd == -1 ) {
+ printf( "open failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto failure_exit;
+ }
+ close( my_fd );
+ }
+ goto routine_exit;
+
+failure_exit:
+ my_result = -1;
+routine_exit:
+ if ( my_pathp != NULL ) {
+ if ( my_result == -1 && create_test_file ) {
+ remove( my_pathp );
+ }
+ free( my_pathp );
+ }
+
+ return( my_result );
+
+} /* create_file_with_name */
+
+
+
+
+/*
+ * This function is needed by both xnu_quick_test proper and the execve() helper
+ * program. It forks a child process and then exec()s an image on that child.
+ * Path, argv, and envp are fed directly to the execve() call.
+ * Parameter killwait decides how long to wait before killing the child.
+ */
+int do_execve_test(char * path, char * argv[], void * envp, int killwait)
+{
+ int my_err = 0, my_status;
+ pid_t my_pid, my_wait_pid;
+
+#if DEBUG
+ printf("do_execve_test(path = %s)\n", path);
+ printf("CWD= %s\n", getwd(NULL));
+ fflush(stdout);
+#endif
+ /* vfork then execve sleep system command (which we will kill from the parent process) */
+ my_pid = vfork();
+ if (my_pid == -1) {
+ printf( "vfork failed with errno %d - %s \n", errno, strerror( errno ) );
+ goto test_failed_exit;
+ }
+ if ( my_pid == 0 ) {
+ /*
+ * child process - use execve to start one of the customized helper
+ * binaries, which just sleep for 120 seconds. Let our parent kill us.
+ */
+
+ my_err = execve(path, argv, envp);
+ if ( my_err != 0 ) { /* TODO: execve() on x86_64 inca returns weird error codes, see rdar://4655612 */
+ printf( "execve call failed with return value: %d, errno: %d - \"%s\"; path: %s \n",
+ my_err, errno, strerror( errno), path );
+ fflush(stdout);
+ exit(-2);
+ }
+
+ /* should never get here */
+ printf("Execve failed and it was not caught by our test\n");
+ return(-1);
+ }
+ /*
+ * parent process - let's kill our sleeping child
+ */
+ sleep(killwait);
+ my_err = kill( my_pid, SIGKILL );
+ if ( my_err == -1 ) {
+ printf( "kill call failed with error %d - \"%s\" \n", errno, strerror( errno) );
+ goto test_failed_exit;
+ }
+
+ /* wait for child to exit */
+ my_wait_pid = wait4( my_pid, &my_status, 0, NULL );
+ if ( my_wait_pid == -1 ) {
+ printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) );
+ goto test_failed_exit;
+ }
+
+ /* wait4 should return our child's pid when it exits */
+ if ( my_wait_pid != my_pid ) {
+ printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid );
+ goto test_failed_exit;
+ }
+
+ if ( WIFSIGNALED( my_status ) && WTERMSIG( my_status ) != SIGKILL ) {
+ printf( "wait4 returned wrong signal status - 0x%02X \n", my_status );
+ goto test_failed_exit;
+ }
+
+ my_err = 0;
+ goto test_passed_exit;
+
+test_failed_exit:
+ my_err = 1;
+
+test_passed_exit:
+ return( my_err );
+} /* do_execve_test */
+
+/*
+ * Helper function for posix_spawn test
+ * arch: target architecture to spawn for
+ */
+int do_spawn_test(int arch, int shouldfail)
+{
+ int my_err, my_pid, my_status;
+ size_t my_size;
+ posix_spawnattr_t attr;
+
+ char * args[] = {"helpers/arch", NULL};
+
+ my_err = posix_spawnattr_init(&attr);
+ if (my_err != 0) {
+ printf("posix_spawnattr_init failed\n");
+ goto done;
+ }
+
+ /* set spawn to only succeed for arch 'arch' */
+ my_err = posix_spawnattr_setbinpref_np(&attr, 1, &arch, &my_size);
+ if (my_err != 0 || my_size != 1) {
+ printf("posix_spawnattr_setbinpref_np failed\n");
+ goto done;
+ }
+
+ /* spawn off child process */
+ my_err = posix_spawn(&my_pid, args[0], NULL, &attr, args, NULL);
+ if (shouldfail) {
+ if( my_err == 0) {
+ printf("posix_spawn should have failed on arch %d\n", arch);
+ goto done;
+ }
+ my_err = 0;
+ } else {
+ /* child should exit with return code == arch */
+ if (my_err != 0) {
+ printf("posix_spawn failed with errno %d - %s\n", errno, strerror(errno));
+ goto done;
+ }
+
+ my_err = wait4(my_pid, &my_status, 0, NULL);
+ if (my_err == -1) {
+ printf("wait4 failed with errno %d - %s\n", errno, strerror(errno));
+ goto done;
+ }
+ my_err = 0;
+
+ if (WEXITSTATUS(my_status) != (arch & 0xff)) {
+ printf("child exited with status %d (expected %d)\n",
+ (WEXITSTATUS(my_status)),
+ (arch & 0xff));
+ my_err = -1;
+ goto done;
+ }
+ }
+
+done:
+ return my_err;
+}
+
+/*
+ * Uses sysctlbyname to determine the cpu type. Currently, XNU classifies G5 as a
+ * 32-bit CPU, so this shouldn't be used to determine whether or not a CPU
+ * is 64-bit.
+ */
+int get_architecture()
+{
+ int rval = -1;
+ size_t length = 0;
+ int my_err, buf;
+ char *errmsg = NULL;
+
+ errmsg = "sysctlbyname() failed when getting hw.cputype";
+ if (my_err = sysctlbyname("hw.cputype", NULL, &length, NULL, 0)) goto finished; /* get length of data */
+ if (length != sizeof(buf)) goto finished;
+ if (my_err = sysctlbyname("hw.cputype", &buf, &length, NULL, 0)) goto finished; /* copy data */
+ switch (buf) {
+ case CPU_TYPE_X86:
+ case CPU_TYPE_X86_64:
+ rval = INTEL;
+ break;
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ rval = POWERPC;
+ break;
+ }
+
+finished:
+ if (rval == -1 && errmsg)
+ printf("%s", errmsg);
+
+ return rval;
+}
+
+
+/*
+ * Gets the bit'ed-ness of the current host. Returns either 32 or 64.
+ * This get the hardware capability, but does not tell us whether this
+ * binary is executing in 64 bit or 32 bit mode. Check sizeof long
+ * or pointer to determine that.
+ */
+int get_bits()
+{
+ int my_err, buf;
+ size_t len = 0;
+ int rval = 32; /*
+ * On 32-bit systems the sysctls 64bitops and x86_64 don't
+ * even exists, so if we don't find them then we assume
+ * a 32-bit system.
+ */
+
+ /* Check for PPC 64 */
+ if ((my_err = sysctlbyname("hw.optional.64bitops", NULL, &len, NULL, 0))) goto x86_64check; /* Request size */
+ if (len > sizeof(buf)) goto x86_64check;
+ if ((my_err = sysctlbyname("hw.optional.64bitops", &buf, &len, NULL, 0))) goto x86_64check; /* Copy value out from kernel */
+ if (buf == 1) rval = 64;
+ goto finished;
+
+x86_64check:
+ /* Check for x86_64 */
+ if ((my_err = sysctlbyname("hw.optional.x86_64", NULL, &len, NULL, 0))) goto finished; /* Request size */
+ if (len > sizeof(buf)) goto finished;
+ if ((my_err = sysctlbyname("hw.optional.x86_64", &buf, &len, NULL, 0))) goto finished; /* Copy value out from kernel */
+ if (buf == 1) rval = 64;
+
+finished:
+ return rval;
+}
+