diff options
Diffstat (limited to 'arch/um/os-Linux/helper.c')
| -rw-r--r-- | arch/um/os-Linux/helper.c | 181 |
1 files changed, 90 insertions, 91 deletions
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 36cc8475bcd..e3ee4a51ef6 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -1,165 +1,164 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sched.h> -#include <sys/signal.h> +#include <linux/limits.h> +#include <sys/socket.h> #include <sys/wait.h> -#include "user.h" -#include "kern_util.h" -#include "user_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> struct helper_data { void (*pre_exec)(void*); void *pre_data; char **argv; int fd; + char *buf; }; -/* Debugging aid, changed only from gdb */ -int helper_pause = 0; - -static void helper_hup(int sig) -{ -} - static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; - int errval; + int err, ret; - if(helper_pause){ - signal(SIGHUP, helper_hup); - pause(); - } - if(data->pre_exec != NULL) + if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); - execvp(argv[0], argv); - errval = errno; - printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); - os_write_file(data->fd, &errval, sizeof(errval)); - kill(os_getpid(), SIGKILL); - return(0); + 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; } -/* Returns either the pid of the child process we run or -E* on failure. - * XXX The alloc_stack here breaks if this is called in the tracing thread */ -int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, - unsigned long *stack_out) +/* Returns either the pid of the child process we run or -E* on failure. */ +int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) { struct helper_data data; unsigned long stack, sp; int pid, fds[2], ret, n; - if((stack_out != NULL) && (*stack_out != 0)) - stack = *stack_out; - else stack = alloc_stack(0, um_in_interrupt()); - if(stack == 0) - return(-ENOMEM); + stack = alloc_stack(0, __cant_sleep()); + if (stack == 0) + return -ENOMEM; - ret = os_pipe(fds, 1, 0); - if(ret < 0){ - printk("run_helper : pipe failed, ret = %d\n", -ret); + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + if (ret < 0) { + ret = -errno; + printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n", + errno); goto out_free; } - ret = os_set_exec_close(fds[1], 1); - if(ret < 0){ - printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n", - -ret); + ret = os_set_exec_close(fds[1]); + if (ret < 0) { + printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, " + "ret = %d\n", -ret); goto out_close; } - sp = stack + page_size() - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); data.pre_exec = pre_exec; data.pre_data = pre_data; data.argv = argv; data.fd = fds[1]; - pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); - if(pid < 0){ + data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : + uml_kmalloc(PATH_MAX, UM_GFP_KERNEL); + pid = clone(helper_child, (void *) sp, CLONE_VM, &data); + if (pid < 0) { ret = -errno; - printk("run_helper : clone failed, errno = %d\n", errno); - goto out_close; + printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n", + errno); + goto out_free2; } close(fds[1]); fds[1] = -1; - /*Read the errno value from the child.*/ - n = os_read_file(fds[0], &ret, sizeof(ret)); - if(n < 0){ - printk("run_helper : read on pipe failed, ret = %d\n", -n); - ret = n; - kill(pid, SIGKILL); - CATCH_EINTR(waitpid(pid, NULL, 0)); - } - else if(n != 0){ - CATCH_EINTR(n = waitpid(pid, NULL, 0)); - ret = -errno; - } else { + /* + * Read the errno value from the child, if the exec failed, or get 0 if + * the exec succeeded because the pipe fd was set as close-on-exec. + */ + n = read(fds[0], &ret, sizeof(ret)); + if (n == 0) { ret = pid; + } else { + if (n < 0) { + n = -errno; + printk(UM_KERN_ERR "run_helper : read on pipe failed, " + "ret = %d\n", -n); + ret = n; + } + CATCH_EINTR(waitpid(pid, NULL, __WCLONE)); } +out_free2: + kfree(data.buf); out_close: if (fds[1] != -1) close(fds[1]); close(fds[0]); out_free: - if(stack_out == NULL) - free_stack(stack, 0); - else *stack_out = stack; - return(ret); + free_stack(stack, 0); + return ret; } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, - unsigned long *stack_out, int stack_order) + unsigned long *stack_out) { unsigned long stack, sp; int pid, status, err; - stack = alloc_stack(stack_order, um_in_interrupt()); - if(stack == 0) return(-ENOMEM); + stack = alloc_stack(0, __cant_sleep()); + if (stack == 0) + return -ENOMEM; - sp = stack + (page_size() << stack_order) - sizeof(void *); - pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); - if(pid < 0){ + sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); + pid = clone(proc, (void *) sp, flags, arg); + if (pid < 0) { err = -errno; - printk("run_helper_thread : clone failed, errno = %d\n", - 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, 0)); - if(pid < 0){ + if (stack_out == NULL) { + CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE)); + if (pid < 0) { err = -errno; - printk("run_helper_thread - wait failed, errno = %d\n", - errno); + printk(UM_KERN_ERR "run_helper_thread - wait failed, " + "errno = %d\n", errno); pid = err; } - 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); + 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; } int helper_wait(int pid) { - int ret; - - CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); - if(ret < 0){ - ret = -errno; - printk("helper_wait : waitpid failed, errno = %d\n", errno); - } - return(ret); + 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; } |
