Exemple #1
0
pid_t vfork_and_run(void (*fn)(void*) /*NORETURN*/, void *arg) {
	/* GNO's fork2 call will return immediately and allow the parent and 
	 * child processes to execute concurrently using the same memory
	 * space.  To prevent them stomping on each other, we want to get
	 * behavior like a traditional vfork() implementation, where the
	 * parent blocks until the child terminates or execs.
	 *
	 * Our approach is to check the process tables to make sure the
	 * child has actually finished or exec'd.  If not, we loop and try again.
	 * We can't just rely on the fact that the child signaled us, because
	 * it may still be running in libc's implementation of exec*.
	 */
	
	long oldmask;
	pid_t pid;
	kvmt *kvm_context;
	struct pentry *proc_entry;
	int done = 0;
	
	/* Isolate child process's environment from parent */
	if (environPush() != 0)
		return  -1;
	
	/* Block all signals for now */
	oldmask = sigblock(-1);
	
	pid = fork2(fork_thunk, CHILD_STACKSIZE, 0, forked_child_name, 
				(sizeof(fn) + sizeof(arg) + sizeof(oldmask) + 1) / 2, 
				fn, arg, oldmask);
	if (pid < 0) 
		goto ret;
	
	while (!done) {
		/* Wait for ~100 ms.  If procsend worked, the child could send a 
		 * message with it to end the waiting earlier, but this isn't 
		 * possible in GNO 2.0.6 because procsend is broken.  This isn't
		 * too big an issue, since 100ms isn't very long to wait anyhow. */
		procrecvtim(1);
		
		/* Check if the child is really dead or forked by inspecting
		 * the kernel's process entry for it. */
		kvm_context = kvm_open();
		if (kvm_context == NULL)
			break;
		proc_entry = kvmgetproc(kvm_context, pid);
		if (proc_entry == NULL 
			|| (proc_entry->args != NULL 
				&& strcmp(forked_child_name, proc_entry->args + 8) != 0))
			done = 1;
		kvm_close(kvm_context);
	}
	
ret:
	sigsetmask(oldmask);
	environPop();
	return pid;
}
Exemple #2
0
int
main (int argc, char **argv) {

	int i=1; /* the number of the test */
	unsigned int result;

	if (argc > 1) {
		use_environ = 1;
	} else {
		use_environ = 0;
		printf("NOT ");
	}
	printf("using environ global variable\n");

	/*
	 * initial         Test 1:1
	 */

	result = test_environ();
	if (result != NONE_SET) {
		printf("Please unset the variable \"%s\" for this test.\n",
			string1);
		return -1;
	}
	printf("Test %d passed.\n",i);
	i++;

#define FAIL(fmt) { printf(fmt, i, string1); exit(1); }

	/*
	 * environInit();	Test  :2
	 */

	if (use_environ) {
		environInit();
		result = test_environ();
		switch (result) {
		case BOTH_SET:	FAIL("Test %d failed.  %s prematurely set\n");
		case ORCA_SET:	FAIL("Test %d failed.  %s set internally\n");
		case UNIX_SET:	FAIL("Test %d failed.  %s set in environ\n");
		case NONE_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		default:
			printf("Test internal error:  test %d returned %ud\n",
				i, result);
			return -1;
		}
	}  

	/*
	 * setenv();       Test 2:3
	 */

	if (setenv(string1,string2,1) != 0) {
		printf("Test %d:  setenv() failed\n",i);
		return -1;
	}
	result = test_environ();
	if (use_environ) {
		switch (result) {
		case BOTH_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		case ORCA_SET:
			FAIL("Test %d failed.  %s not set in environ\n");
		case UNIX_SET:
			FAIL("Test %d failed.  %s not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			printf("Test internal error:  test %d returned %ud\n",
				i, result);
			return -1;
		}
	} else {
		switch (result) {
		case BOTH_SET:
			FAIL("Test %d failed.  %s set in environ\n");
		case ORCA_SET:
			printf("Test %d passed.\n", i);
			i++;
			break;
		case UNIX_SET:
			FAIL("Test %d failed.  %s set in environ, not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			printf("Test internal error:  test %d returned %ud\n",
				i, result);
			return -1;
		}
	}

	/*
	 * unsetenv()	Test 3:4
	 */

	unsetenv(string1);
	result = test_environ();
	if (use_environ) {
		switch (result) {
		case BOTH_SET:
			FAIL("Test %d failed.  %s set\n");
		case ORCA_SET:
			FAIL("Test %d failed.  %s set internally\n");
		case UNIX_SET:
			FAIL("Test %d failed.  %s set in in environ\n");
		case NONE_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		default:
			printf("Test internal error:  test %d returned %ud\n",
				i, result);
			return -1;
		}
	} else {
		switch (result) {
		case BOTH_SET:
			FAIL("Test %d failed.  %s set\n");
		case ORCA_SET:
			FAIL("Test %d failed.  %s set internally\n");
		case UNIX_SET:
			FAIL("Test %d failed.  %s set in environ\n");
		case NONE_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		default:
			printf("Test internal error:  test %d returned %ud\n",
				i, result);
			return -1;
		}
	}

	/*
	 * environPush()	Test 4:5 bork
	 */
	
	if (setenv(string1,string2,1) != 0) {
		printf("Test %d:  setenv() failed\n",i);
		return -1;
	}

	if (environPush() != 0) { 		
		printf("Test %d:  environPush() failed\n",i);
		return -1;
	}

	result = test_environ();    
	if (use_environ) {
		switch (result) {
		case BOTH_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		case ORCA_SET:
			FAIL("Test %d failed.  %s not set in environ\n");
		case UNIX_SET:
			FAIL("Test %d failed.  %s not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			assert(0);
		}
	} else {
		switch (result) {
		case BOTH_SET:
			FAIL("Test %d failed.  %s set in environ\n");
		case ORCA_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		case UNIX_SET:
			FAIL("Test %d failed.  %s set in environ, not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			assert(0);
		}
	}


	/*
	 * environPop()		  Test 5:6
	 */

	unsetenv(string1);
	environPop();
	result = test_environ();
	if (use_environ) {
		switch (result) {
		case BOTH_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		case ORCA_SET:
			FAIL("Test %d failed.  %s not set in environ\n");
		case UNIX_SET:
			FAIL("Test %d failed.  %s not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			assert(0);
		}
	} else {
		switch (result) {
		case BOTH_SET:
			FAIL("Test %d failed.  %s set in environ\n");
		case ORCA_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		case UNIX_SET:
			FAIL("Test %d failed.  %s set in environ, not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			assert(0);
		}
	}


	/*
	 * putenv()	  Test 6:7
	 */

	unsetenv(string1);
	if (putenv(string3) != 0) {				  
		printf("Test %d:  putenv() failed\n",i);
		return -1;
	}
	result = test_environ();
	if (use_environ) {
		switch (result) {
		case BOTH_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		case ORCA_SET:
			FAIL("Test %d failed.  %s not set in environ\n");
		case UNIX_SET:
			FAIL("Test %d failed.  %s not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			assert(0);
		}
	} else {
		switch (result) {
		case BOTH_SET:
			FAIL("Test %d failed.  %s set in environ\n");
		case ORCA_SET:
			printf("Test %d passed.\n",i);
			i++;
			break;
		case UNIX_SET:
			FAIL("Test %d failed.  %s set in environ, not set internally\n");
		case NONE_SET:
			FAIL("Test %d failed.  %s not set\n");
		default:
			assert(0);
		}
	}

	unsetenv(string1);
	printf("Tests done.\n");
	return 0;
}