Beispiel #1
0
int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
		     int clone_flags, int (*tramp)(void *))
{
	struct tramp arg;
	unsigned long sp;
	int new_pid, status, err;

	/* The trampoline will run on the temporary stack */
	sp = stack_sp(temp_stack);

	clone_flags |= CLONE_FILES | SIGCHLD;

	arg.tramp = tramp;
	arg.tramp_data = thread_arg;
	arg.temp_stack = temp_stack;
	arg.flags = clone_flags;

	/* Start the process and wait for it to kill itself */
	new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
	if(new_pid < 0)
		return(new_pid);

	CATCH_EINTR(err = waitpid(new_pid, &status, 0));
	if(err < 0)
		panic("Waiting for outer trampoline failed - errno = %d",
		      errno);

	if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
		panic("outer trampoline didn't exit with SIGKILL, "
		      "status = %d", status);

	return(arg.pid);
}
Beispiel #2
0
static void handle_trap(int pid, union uml_pt_regs *regs)
{
	int err, syscall_nr, status;

	syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
	UPT_SYSCALL_NR(regs) = syscall_nr;
	if(syscall_nr < 1){
		relay_signal(SIGTRAP, regs);
		return;
	}

	err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
	if(err < 0)
	        panic("handle_trap - nullifying syscall failed errno = %d\n", 
		      errno);

	err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
	if(err < 0)
	        panic("handle_trap - continuing to end of syscall failed, "
		      "errno = %d\n", errno);

	CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
	if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
		panic("handle_trap - failed to wait at end of syscall, "
		      "errno = %d, status = %d\n", errno, status);

	handle_syscall(regs);
}
Beispiel #3
0
void os_kill_process(int pid, int reap_child)
{
	kill(pid, SIGKILL);
	if(reap_child)
		CATCH_EINTR(waitpid(pid, NULL, 0));
		
}
static void slirp_close(int fd, void *data)
{
	struct slirp_data *pri = data;
	int status,err;

	os_close_file(fd);
	os_close_file(pri->slave);

	pri->slave = -1;

	if(pri->pid<1) {
		printk("slirp_close: no child process to shut down\n");
		return;
	}

#if 0
	if(kill(pri->pid, SIGHUP)<0) {
		printk("slirp_close: sending hangup to %d failed (%d)\n",
			pri->pid, errno);
	}
#endif

	CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
	if(err < 0) {
		printk("slirp_close: waitpid returned %d\n", errno);
		return;
	}

	if(err == 0) {
		printk("slirp_close: process %d has not exited\n", pri->pid);
		return;
	}

	pri->pid = -1;
}
Beispiel #5
0
unsigned long os_process_pc(int pid)
{
	char proc_stat[STAT_PATH_LEN], buf[256];
	unsigned long pc = ARBITRARY_ADDR;
	int fd, err;

	sprintf(proc_stat, "/proc/%d/stat", pid);
	fd = open(proc_stat, O_RDONLY, 0);
	if (fd < 0) {
		printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', "
		       "errno = %d\n", proc_stat, errno);
		goto out;
	}
	CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
	if (err < 0) {
		printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', "
		       "err = %d\n", proc_stat, errno);
		goto out_close;
	}
	os_close_file(fd);
	pc = ARBITRARY_ADDR;
	if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
		   "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
		   "%*d %*d %*d %*d %*d %lu", &pc) != 1)
		printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n",
		       buf);
 out_close:
	close(fd);
 out:
	return pc;
}
Beispiel #6
0
int os_process_parent(int pid)
{
	char stat[STAT_PATH_LEN];
	char data[256];
	int parent, n, fd;

	if(pid == -1)
		return -1;

	snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
	fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
	if(fd < 0){
		printk("Couldn't open '%s', err = %d\n", stat, -fd);
		return FAILURE_PID;
	}

	CATCH_EINTR(n = read(fd, data, sizeof(data)));
	os_close_file(fd);

	if(n < 0){
		printk("Couldn't read '%s', err = %d\n", stat, errno);
		return FAILURE_PID;
	}

	parent = FAILURE_PID;
	n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
	if(n != 1)
		printk("Failed to scan '%s'\n", data);

	return parent;
}
Beispiel #7
0
unsigned long os_process_pc(int pid)
{
	char proc_stat[STAT_PATH_LEN], buf[256];
	unsigned long pc;
	int fd, err;

	sprintf(proc_stat, "/proc/%d/stat", pid);
	fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
	if(fd < 0){
		printk("os_process_pc - couldn't open '%s', err = %d\n",
		       proc_stat, -fd);
		return ARBITRARY_ADDR;
	}
	CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
	if(err < 0){
		printk("os_process_pc - couldn't read '%s', err = %d\n",
		       proc_stat, errno);
		os_close_file(fd);
		return ARBITRARY_ADDR;
	}
	os_close_file(fd);
	pc = ARBITRARY_ADDR;
	if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
		  "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
		  "%*d %*d %*d %*d %*d %lu", &pc) != 1){
		printk("os_process_pc - couldn't find pc in '%s'\n", buf);
	}
	return pc;
}
Beispiel #8
0
int os_process_parent(int pid)
{
	char stat[STAT_PATH_LEN];
	char data[256];
	int parent = FAILURE_PID, n, fd;

	if (pid == -1)
		return parent;

	snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
	fd = open(stat, O_RDONLY, 0);
	if (fd < 0) {
		printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat,
		       errno);
		return parent;
	}

	CATCH_EINTR(n = read(fd, data, sizeof(data)));
	close(fd);

	if (n < 0) {
		printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat,
		       errno);
		return parent;
	}

	parent = FAILURE_PID;
	n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
	if (n != 1)
		printk(UM_KERN_ERR "Failed to scan '%s'\n", data);

	return parent;
}
Beispiel #9
0
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, 
		      unsigned long *stack_out, int stack_order)
{
	unsigned long stack, sp;
	int pid, status;

	stack = alloc_stack(stack_order, um_in_interrupt());
	if(stack == 0) return(-ENOMEM);

	sp = stack + (page_size() << stack_order) - sizeof(void *);
	pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
	if(pid < 0){
		printk("run_helper_thread : clone failed, errno = %d\n", 
		       errno);
		return(-errno);
	}
	if(stack_out == NULL){
		CATCH_EINTR(pid = waitpid(pid, &status, 0));
		if(pid < 0){
			printk("run_helper_thread - wait failed, errno = %d\n",
			       errno);
			pid = -errno;
		}
		if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
			printk("run_helper_thread - thread returned status "
			       "0x%x\n", status);
		free_stack(stack, stack_order);
	}
        else *stack_out = stack;
	return(pid);
}
Beispiel #10
0
void start_userspace(int cpu)
{
	void *stack;
	unsigned long sp;
	int pid, status, n;

	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	if(stack == MAP_FAILED)
		panic("start_userspace : mmap failed, errno = %d", errno);
	sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);

	pid = clone(userspace_tramp, (void *) sp, 
		    CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
	if(pid < 0)
		panic("start_userspace : clone failed, errno = %d", errno);

	do {
		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
		if(n < 0)
			panic("start_userspace : wait failed, errno = %d", 
			      errno);
	} while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));

	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
		panic("start_userspace : expected SIGSTOP, got status = %d",
		      status);

	if(munmap(stack, PAGE_SIZE) < 0)
		panic("start_userspace : munmap failed, errno = %d\n", errno);

	userspace_pid[cpu] = pid;
}
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
		      unsigned long *stack_out)
{
	unsigned long stack, sp;
	int pid, status, err;

	stack = alloc_stack(0, __cant_sleep());
	if (stack == 0)
		return -ENOMEM;

	sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
	pid = clone(proc, (void *) sp, flags, arg);
	if (pid < 0) {
		err = -errno;
		printk(UM_KERN_ERR "run_helper_thread : clone failed, "
		       "errno = %d\n", errno);
		return err;
	}
	if (stack_out == NULL) {
		CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE));
		if (pid < 0) {
			err = -errno;
			printk(UM_KERN_ERR "run_helper_thread - wait failed, "
			       "errno = %d\n", errno);
			pid = err;
		}
		if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
			printk(UM_KERN_ERR "run_helper_thread - thread "
			       "returned status 0x%x\n", status);
		free_stack(stack, 0);
	} else
		*stack_out = stack;
	return pid;
}
Beispiel #12
0
/* When testing for SYSEMU support, if it is one of the broken versions, we must
 * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
 * So only for SYSEMU features we test mustpanic, while normal host features
 * must work anyway!*/
static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
{
	int status, n, ret = 0;

	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
		panic("check_ptrace : ptrace failed, errno = %d", errno);
	CATCH_EINTR(n = waitpid(pid, &status, 0));
	if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
		int exit_with = WEXITSTATUS(status);
		if (exit_with == 2)
			printk("check_ptrace : child exited with status 2. "
			       "Serious trouble happening! Try updating your "
			       "host skas patch!\nDisabling SYSEMU support.");
		printk("check_ptrace : child exited with exitcode %d, while "
		      "expecting %d; status 0x%x", exit_with,
		      exitcode, status);
		if (mustpanic)
			panic("\n");
		else
			printk("\n");
		ret = -1;
	}

	if(munmap(stack, PAGE_SIZE) < 0)
		panic("check_ptrace : munmap failed, errno = %d", errno);
	return ret;
}
Beispiel #13
0
void do_exec(int old_pid, int new_pid)
{
	unsigned long regs[FRAME_SIZE];
	int err;

	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
		tracer_panic("do_exec failed to attach proc - errno = %d",
			     errno);

	CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
	if (err < 0)
		tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
			     errno);

	if(ptrace_getregs(old_pid, regs) < 0)
		tracer_panic("do_exec failed to get registers - errno = %d",
			     errno);

	kill(old_pid, SIGKILL);

	if(ptrace_setregs(new_pid, regs) < 0)
		tracer_panic("do_exec failed to start new proc - errno = %d",
			     errno);
}
static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
			int fd)
{
	struct addr_change change;
	char *output;
	int n;

	change.what = op;
	memcpy(change.addr, addr, sizeof(change.addr));
	memcpy(change.netmask, netmask, sizeof(change.netmask));
	CATCH_EINTR(n = write(fd, &change, sizeof(change)));
	if (n != sizeof(change)) {
		printk(UM_KERN_ERR "etap_change - request failed, err = %d\n",
		       errno);
		return;
	}

	output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL);
	if (output == NULL)
		printk(UM_KERN_ERR "etap_change : Failed to allocate output "
		       "buffer\n");
	read_output(fd, output, UM_KERN_PAGE_SIZE);
	if (output != NULL) {
		printk("%s", output);
		kfree(output);
	}
}
Beispiel #15
0
void __init check_ptrace(void)
{
	void *stack;
	int pid, syscall, n, status;

	printk("Checking that ptrace can change system call numbers...");
	pid = start_ptraced_child(&stack);

	while(1){
		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
			panic("check_ptrace : ptrace failed, errno = %d", 
			      errno);
		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
		if(n < 0)
			panic("check_ptrace : wait failed, errno = %d", errno);
		if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
			panic("check_ptrace : expected SIGTRAP, "
			      "got status = %d", status);
		
		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
				 0);
		if(syscall == __NR_getpid){
			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
				   __NR_getppid);
			if(n < 0)
				panic("check_ptrace : failed to modify system "
				      "call, errno = %d", errno);
			break;
		}
	}
	stop_ptraced_child(pid, stack, 0, 1);
	printk("OK\n");
	check_sysemu();
}
Beispiel #16
0
/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
{
	int err, status;

	/* Mark this as a syscall */
	UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);

	if (!local_using_sysemu)
	{
		err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
		if(err < 0)
			panic("handle_trap - nullifying syscall failed errno = %d\n",
			      errno);

		err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
		if(err < 0)
			panic("handle_trap - continuing to end of syscall failed, "
			      "errno = %d\n", errno);

		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
		if((err < 0) || !WIFSTOPPED(status) ||
		   (WSTOPSIG(status) != SIGTRAP + 0x80))
			panic("handle_trap - failed to wait at end of syscall, "
			      "errno = %d, status = %d\n", errno, status);
	}

	handle_syscall(regs);
}
Beispiel #17
0
void do_exec(int old_pid, int new_pid)
{
	unsigned long regs[FRAME_SIZE];
	int err;

	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
		tracer_panic("do_exec failed to attach proc - errno = %d",
			     errno);

	CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
	if (err < 0)
		tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
			     errno);

	if(ptrace_getregs(old_pid, regs) < 0)
		tracer_panic("do_exec failed to get registers - errno = %d",
			     errno);

	os_kill_ptraced_process(old_pid, 0);

	if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
		tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);

	if(ptrace_setregs(new_pid, regs) < 0)
		tracer_panic("do_exec failed to start new proc - errno = %d",
			     errno);
}
Beispiel #18
0
void os_kill_ptraced_process(int pid, int reap_child)
{
	kill(pid, SIGKILL);
	ptrace(PTRACE_KILL, pid);
	ptrace(PTRACE_CONT, pid);
	if (reap_child)
		CATCH_EINTR(waitpid(pid, NULL, __WALL));
}
Beispiel #19
0
void userspace(union uml_pt_regs *regs)
{
	int err, status, op, pid = userspace_pid[0];
	int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/

	while(1){
		restore_registers(pid, regs);

		/* Now we set local_using_sysemu to be used for one loop */
		local_using_sysemu = get_using_sysemu();

		op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));

		err = ptrace(op, pid, 0, 0);
		if(err)
			panic("userspace - could not resume userspace process, "
			      "pid=%d, ptrace operation = %d, errno = %d\n",
			      op, errno);

		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
		if(err < 0)
			panic("userspace - waitpid failed, errno = %d\n", 
			      errno);

		regs->skas.is_user = 1;
		save_registers(pid, regs);
		UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */

		if(WIFSTOPPED(status)){
		  	switch(WSTOPSIG(status)){
			case SIGSEGV:
                                handle_segv(pid, regs);
				break;
			case SIGTRAP + 0x80:
			        handle_trap(pid, regs, local_using_sysemu);
				break;
			case SIGTRAP:
				relay_signal(SIGTRAP, regs);
				break;
			case SIGIO:
			case SIGVTALRM:
			case SIGILL:
			case SIGBUS:
			case SIGFPE:
			case SIGWINCH:
                                user_signal(WSTOPSIG(status), regs, pid);
				break;
			default:
			        printk("userspace - child stopped with signal "
				       "%d\n", WSTOPSIG(status));
			}
			interrupt_end();

			/* Avoid -ERESTARTSYS handling in host */
			PT_SYSCALL_NR(regs->skas.regs) = -1;
		}
	}
}
Beispiel #20
0
int raw(int fd)
{
	struct termios tt;
	int err;

	CATCH_EINTR(err = tcgetattr(fd, &tt));
	if(err < 0)
		return -errno;

	cfmakeraw(&tt);

	CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
	if(err < 0)
		return -errno;

	/* XXX tcsetattr could have applied only some changes
	 * (and cfmakeraw() is a set of changes) */
	return 0;
}
Beispiel #21
0
static int slip_tramp(char **argv, int fd)
{
	struct slip_pre_exec_data pe_data;
	char *output;
	int status, pid, fds[2], err, output_len;

	err = os_pipe(fds, 1, 0);
	if(err < 0){
		printk("slip_tramp : pipe failed, err = %d\n", -err);
		goto out;
	}

	err = 0;
	pe_data.stdin = fd;
	pe_data.stdout = fds[1];
	pe_data.close_me = fds[0];
	err = run_helper(slip_pre_exec, &pe_data, argv, NULL);
	if(err < 0)
		goto out_close;
	pid = err;

	output_len = page_size();
	output = um_kmalloc(output_len);
	if(output == NULL){
		printk("slip_tramp : failed to allocate output buffer\n");
		os_kill_process(pid, 1);
		err = -ENOMEM;
		goto out_free;
	}

	os_close_file(fds[1]);
	read_output(fds[0], output, output_len);
	printk("%s", output);

	CATCH_EINTR(err = waitpid(pid, &status, 0));
	if(err < 0)
		err = errno;
	else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
		printk("'%s' didn't exit with status 0\n", argv[0]);
		err = -EINVAL;
	}
	else err = 0;

	os_close_file(fds[0]);

out_free:
	kfree(output);
	return err;

out_close:
	os_close_file(fds[0]);
	os_close_file(fds[1]);
out:
	return err;
}
Beispiel #22
0
int helper_wait(int pid, int block)
{
	int ret;

	CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG));
	if(ret < 0){
		printk("helper_wait : waitpid failed, errno = %d\n", errno);
		return(-errno);
	}
	return(ret);
}
Beispiel #23
0
void userspace(union uml_pt_regs *regs)
{
	int err, status, op, pid = userspace_pid[0];

	restore_registers(regs);
		
	err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
	if(err)
		panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", 
		       errno);
	while(1){
		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
		if(err < 0)
			panic("userspace - waitpid failed, errno = %d\n", 
			      errno);

		regs->skas.is_user = 1;
		save_registers(regs);

		if(WIFSTOPPED(status)){
		  	switch(WSTOPSIG(status)){
			case SIGSEGV:
				handle_segv(pid);
				break;
			case SIGTRAP:
			        handle_trap(pid, regs);
				break;
			case SIGIO:
			case SIGVTALRM:
			case SIGILL:
			case SIGBUS:
			case SIGFPE:
			case SIGWINCH:
				user_signal(WSTOPSIG(status), regs);
				break;
			default:
			        printk("userspace - child stopped with signal "
				       "%d\n", WSTOPSIG(status));
			}
			interrupt_end();
		}

		restore_registers(regs);

		op = singlestepping_skas() ? PTRACE_SINGLESTEP : 
			PTRACE_SYSCALL;
		err = ptrace(op, pid, 0, 0);
		if(err)
			panic("userspace - PTRACE_SYSCALL failed, "
			      "errno = %d\n", errno);
	}
}
Beispiel #24
0
void kill_child_dead(int pid)
{
	kill(pid, SIGKILL);
	kill(pid, SIGCONT);
	do {
		int n;
		CATCH_EINTR(n = waitpid(pid, NULL, 0));
		if (n > 0)
			kill(pid, SIGCONT);
		else
			break;
	} while(1);
}
int net_recvfrom(int fd, void *buf, int len)
{
	int n;

	CATCH_EINTR(n = recvfrom(fd,  buf,  len, 0, NULL, NULL));
	if (n < 0) {
		if (errno == EAGAIN)
			return 0;
		return -errno;
	}
	else if (n == 0)
		return -ENOTCONN;
	return n;
}
int net_send(int fd, void *buf, int len)
{
	int n;

	CATCH_EINTR(n = send(fd, buf, len, 0));
	if (n < 0) {
		if (errno == EAGAIN)
			return 0;
		return -errno;
	}
	else if (n == 0)
		return -ENOTCONN;
	return n;
}
static int helper_child(void *arg)
{
	struct helper_data *data = arg;
	char **argv = data->argv;
	int err, ret;

	if (data->pre_exec != NULL)
		(*data->pre_exec)(data->pre_data);
	err = execvp_noalloc(data->buf, argv[0], argv);

	/* If the exec succeeds, we don't get here */
	CATCH_EINTR(ret = write(data->fd, &err, sizeof(err)));

	return 0;
}
int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
{
	int n;

	CATCH_EINTR(n = sendto(fd, buf, len, 0, (struct sockaddr *) to,
			       sock_len));
	if (n < 0) {
		if (errno == EAGAIN)
			return 0;
		return -errno;
	}
	else if (n == 0)
		return -ENOTCONN;
	return n;
}
static int etap_tramp(char *dev, char *gate, int control_me, 
		      int control_remote, int data_me, int data_remote)
{
	struct etap_pre_exec_data pe_data;
	int pid, status, err, n;
	char version_buf[sizeof("nnnnn\0")];
	char data_fd_buf[sizeof("nnnnnn\0")];
	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
	char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
			       data_fd_buf, gate_buf, NULL };
	char *nosetup_args[] = { "uml_net", version_buf, "ethertap", 
				 dev, data_fd_buf, NULL };
	char **args, c;

	sprintf(data_fd_buf, "%d", data_remote);
	sprintf(version_buf, "%d", UML_NET_VERSION);
	if(gate != NULL){
		strcpy(gate_buf, gate);
		args = setup_args;
	}
	else args = nosetup_args;

	err = 0;
	pe_data.control_remote = control_remote;
	pe_data.control_me = control_me;
	pe_data.data_me = data_me;
	pid = run_helper(etap_pre_exec, &pe_data, args, NULL);

	if(pid < 0) err = pid;
	os_close_file(data_remote);
	os_close_file(control_remote);
	n = os_read_file(control_me, &c, sizeof(c));
	if(n != sizeof(c)){
		printk("etap_tramp : read of status failed, err = %d\n", -n);
		return(-EINVAL);
	}
	if(c != 1){
		printk("etap_tramp : uml_net failed\n");
		err = -EINVAL;
		CATCH_EINTR(n = waitpid(pid, &status, 0));
		if(n < 0)
			err = -errno;
		else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
			printk("uml_net didn't exit with status 1\n");
	}
	return(err);
}
int helper_wait(int pid)
{
	int ret, status;
	int wflags = __WCLONE;

	CATCH_EINTR(ret = waitpid(pid, &status, wflags));
	if (ret < 0) {
		printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
		       "errno = %d\n", pid, errno);
		return -errno;
	} else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
		printk(UM_KERN_ERR "helper_wait : process %d exited with "
		       "status 0x%x\n", pid, status);
		return -ECHILD;
	} else
		return 0;
}