linux/arch/um/os-Linux/helper.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include <stdio.h>
   7#include <stdlib.h>
   8#include <unistd.h>
   9#include <errno.h>
  10#include <sched.h>
  11#include <limits.h>
  12#include <sys/signal.h>
  13#include <sys/wait.h>
  14#include <sys/socket.h>
  15#include "user.h"
  16#include "kern_util.h"
  17#include "os.h"
  18#include "um_malloc.h"
  19#include "kern_constants.h"
  20
  21struct helper_data {
  22        void (*pre_exec)(void*);
  23        void *pre_data;
  24        char **argv;
  25        int fd;
  26        char *buf;
  27};
  28
  29static int helper_child(void *arg)
  30{
  31        struct helper_data *data = arg;
  32        char **argv = data->argv;
  33        int errval;
  34
  35        if (data->pre_exec != NULL)
  36                (*data->pre_exec)(data->pre_data);
  37        errval = execvp_noalloc(data->buf, argv[0], argv);
  38        printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0],
  39               -errval);
  40        write(data->fd, &errval, sizeof(errval));
  41        kill(os_getpid(), SIGKILL);
  42        return 0;
  43}
  44
  45/* Returns either the pid of the child process we run or -E* on failure.
  46 * XXX The alloc_stack here breaks if this is called in the tracing thread, so
  47 * we need to receive a preallocated stack (a local buffer is ok). */
  48int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
  49{
  50        struct helper_data data;
  51        unsigned long stack, sp;
  52        int pid, fds[2], ret, n;
  53
  54        stack = alloc_stack(0, __cant_sleep());
  55        if (stack == 0)
  56                return -ENOMEM;
  57
  58        ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
  59        if (ret < 0) {
  60                ret = -errno;
  61                printk("run_helper : pipe failed, errno = %d\n", errno);
  62                goto out_free;
  63        }
  64
  65        ret = os_set_exec_close(fds[1]);
  66        if (ret < 0) {
  67                printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n",
  68                       -ret);
  69                goto out_close;
  70        }
  71
  72        sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
  73        data.pre_exec = pre_exec;
  74        data.pre_data = pre_data;
  75        data.argv = argv;
  76        data.fd = fds[1];
  77        data.buf = __cant_sleep() ? kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
  78                                        kmalloc(PATH_MAX, UM_GFP_KERNEL);
  79        pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
  80        if (pid < 0) {
  81                ret = -errno;
  82                printk("run_helper : clone failed, errno = %d\n", errno);
  83                goto out_free2;
  84        }
  85
  86        close(fds[1]);
  87        fds[1] = -1;
  88
  89        /*
  90         * Read the errno value from the child, if the exec failed, or get 0 if
  91         * the exec succeeded because the pipe fd was set as close-on-exec.
  92         */
  93        n = read(fds[0], &ret, sizeof(ret));
  94        if (n == 0) {
  95                ret = pid;
  96        } else {
  97                if (n < 0) {
  98                        n = -errno;
  99                        printk("run_helper : read on pipe failed, ret = %d\n",
 100                               -n);
 101                        ret = n;
 102                        kill(pid, SIGKILL);
 103                }
 104                CATCH_EINTR(waitpid(pid, NULL, __WCLONE));
 105        }
 106
 107out_free2:
 108        kfree(data.buf);
 109out_close:
 110        if (fds[1] != -1)
 111                close(fds[1]);
 112        close(fds[0]);
 113out_free:
 114        free_stack(stack, 0);
 115        return ret;
 116}
 117
 118int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
 119                      unsigned long *stack_out)
 120{
 121        unsigned long stack, sp;
 122        int pid, status, err;
 123
 124        stack = alloc_stack(0, __cant_sleep());
 125        if (stack == 0)
 126                return -ENOMEM;
 127
 128        sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
 129        pid = clone(proc, (void *) sp, flags, arg);
 130        if (pid < 0) {
 131                err = -errno;
 132                printk("run_helper_thread : clone failed, errno = %d\n",
 133                       errno);
 134                return err;
 135        }
 136        if (stack_out == NULL) {
 137                CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE));
 138                if (pid < 0) {
 139                        err = -errno;
 140                        printk("run_helper_thread - wait failed, errno = %d\n",
 141                               errno);
 142                        pid = err;
 143                }
 144                if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
 145                        printk("run_helper_thread - thread returned status "
 146                               "0x%x\n", status);
 147                free_stack(stack, 0);
 148        } else
 149                *stack_out = stack;
 150        return pid;
 151}
 152
 153int helper_wait(int pid, int nohang, char *pname)
 154{
 155        int ret, status;
 156        int wflags = __WCLONE;
 157
 158        if (nohang)
 159                wflags |= WNOHANG;
 160
 161        if (!pname)
 162                pname = "helper_wait";
 163
 164        CATCH_EINTR(ret = waitpid(pid, &status, wflags));
 165        if (ret < 0) {
 166                printk(UM_KERN_ERR "%s : waitpid process %d failed, "
 167                       "errno = %d\n", pname, pid, errno);
 168                return -errno;
 169        } else if (nohang && ret == 0) {
 170                printk(UM_KERN_ERR "%s : process %d has not exited\n",
 171                       pname, pid);
 172                return -ECHILD;
 173        } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
 174                printk(UM_KERN_ERR "%s : process %d didn't exit with "
 175                       "status 0\n", pname, pid);
 176                return -ECHILD;
 177        } else
 178                return 0;
 179}
 180