Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
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     /* If the exec succeeds, we don't get here */
0037     CATCH_EINTR(ret = write(data->fd, &err, sizeof(err)));
0038 
0039     return 0;
0040 }
0041 
0042 /* Returns either the pid of the child process we run or -E* on failure. */
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      * Read the errno value from the child, if the exec failed, or get 0 if
0088      * the exec succeeded because the pipe fd was set as close-on-exec.
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 }