0001
0002
0003
0004
0005
0006 #include <stdlib.h>
0007 #include <string.h>
0008 #include <unistd.h>
0009 #include <errno.h>
0010 #include <sched.h>
0011 #include <linux/limits.h>
0012 #include <sys/socket.h>
0013 #include <sys/wait.h>
0014 #include <kern_util.h>
0015 #include <os.h>
0016 #include <um_malloc.h>
0017
0018 struct helper_data {
0019 void (*pre_exec)(void*);
0020 void *pre_data;
0021 char **argv;
0022 int fd;
0023 char *buf;
0024 };
0025
0026 static int helper_child(void *arg)
0027 {
0028 struct helper_data *data = arg;
0029 char **argv = data->argv;
0030 int err, ret;
0031
0032 if (data->pre_exec != NULL)
0033 (*data->pre_exec)(data->pre_data);
0034 err = execvp_noalloc(data->buf, argv[0], argv);
0035
0036
0037 CATCH_EINTR(ret = write(data->fd, &err, sizeof(err)));
0038
0039 return 0;
0040 }
0041
0042
0043 int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
0044 {
0045 struct helper_data data;
0046 unsigned long stack, sp;
0047 int pid, fds[2], ret, n;
0048
0049 stack = alloc_stack(0, __cant_sleep());
0050 if (stack == 0)
0051 return -ENOMEM;
0052
0053 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
0054 if (ret < 0) {
0055 ret = -errno;
0056 printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
0057 errno);
0058 goto out_free;
0059 }
0060
0061 ret = os_set_exec_close(fds[1]);
0062 if (ret < 0) {
0063 printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
0064 "ret = %d\n", -ret);
0065 goto out_close;
0066 }
0067
0068 sp = stack + UM_KERN_PAGE_SIZE;
0069 data.pre_exec = pre_exec;
0070 data.pre_data = pre_data;
0071 data.argv = argv;
0072 data.fd = fds[1];
0073 data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
0074 uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
0075 pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
0076 if (pid < 0) {
0077 ret = -errno;
0078 printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
0079 errno);
0080 goto out_free2;
0081 }
0082
0083 close(fds[1]);
0084 fds[1] = -1;
0085
0086
0087
0088
0089
0090 n = read(fds[0], &ret, sizeof(ret));
0091 if (n == 0) {
0092 ret = pid;
0093 } else {
0094 if (n < 0) {
0095 n = -errno;
0096 printk(UM_KERN_ERR "run_helper : read on pipe failed, "
0097 "ret = %d\n", -n);
0098 ret = n;
0099 }
0100 CATCH_EINTR(waitpid(pid, NULL, __WALL));
0101 }
0102
0103 if (ret < 0)
0104 printk(UM_KERN_ERR "run_helper : failed to exec %s on host: %s\n",
0105 argv[0], strerror(-ret));
0106
0107 out_free2:
0108 kfree(data.buf);
0109 out_close:
0110 if (fds[1] != -1)
0111 close(fds[1]);
0112 close(fds[0]);
0113 out_free:
0114 free_stack(stack, 0);
0115 return ret;
0116 }
0117
0118 int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
0119 unsigned long *stack_out)
0120 {
0121 unsigned long stack, sp;
0122 int pid, status, err;
0123
0124 stack = alloc_stack(0, __cant_sleep());
0125 if (stack == 0)
0126 return -ENOMEM;
0127
0128 sp = stack + UM_KERN_PAGE_SIZE;
0129 pid = clone(proc, (void *) sp, flags, arg);
0130 if (pid < 0) {
0131 err = -errno;
0132 printk(UM_KERN_ERR "run_helper_thread : clone failed, "
0133 "errno = %d\n", errno);
0134 return err;
0135 }
0136 if (stack_out == NULL) {
0137 CATCH_EINTR(pid = waitpid(pid, &status, __WALL));
0138 if (pid < 0) {
0139 err = -errno;
0140 printk(UM_KERN_ERR "run_helper_thread - wait failed, "
0141 "errno = %d\n", errno);
0142 pid = err;
0143 }
0144 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
0145 printk(UM_KERN_ERR "run_helper_thread - thread "
0146 "returned status 0x%x\n", status);
0147 free_stack(stack, 0);
0148 } else
0149 *stack_out = stack;
0150 return pid;
0151 }
0152
0153 int helper_wait(int pid)
0154 {
0155 int ret, status;
0156 int wflags = __WALL;
0157
0158 CATCH_EINTR(ret = waitpid(pid, &status, wflags));
0159 if (ret < 0) {
0160 printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
0161 "errno = %d\n", pid, errno);
0162 return -errno;
0163 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
0164 printk(UM_KERN_ERR "helper_wait : process %d exited with "
0165 "status 0x%x\n", pid, status);
0166 return -ECHILD;
0167 } else
0168 return 0;
0169 }