LCOV - code coverage report
Current view: top level - arch/um/os-Linux - helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 77 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 4 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
       4             :  */
       5             : 
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : #include <unistd.h>
       9             : #include <errno.h>
      10             : #include <sched.h>
      11             : #include <linux/limits.h>
      12             : #include <sys/socket.h>
      13             : #include <sys/wait.h>
      14             : #include <kern_util.h>
      15             : #include <os.h>
      16             : #include <um_malloc.h>
      17             : 
      18             : struct helper_data {
      19             :         void (*pre_exec)(void*);
      20             :         void *pre_data;
      21             :         char **argv;
      22             :         int fd;
      23             :         char *buf;
      24             : };
      25             : 
      26           0 : static int helper_child(void *arg)
      27             : {
      28           0 :         struct helper_data *data = arg;
      29           0 :         char **argv = data->argv;
      30             :         int err, ret;
      31             : 
      32           0 :         if (data->pre_exec != NULL)
      33           0 :                 (*data->pre_exec)(data->pre_data);
      34           0 :         err = execvp_noalloc(data->buf, argv[0], argv);
      35             : 
      36             :         /* If the exec succeeds, we don't get here */
      37           0 :         CATCH_EINTR(ret = write(data->fd, &err, sizeof(err)));
      38             : 
      39           0 :         return 0;
      40             : }
      41             : 
      42             : /* Returns either the pid of the child process we run or -E* on failure. */
      43           0 : int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
      44             : {
      45             :         struct helper_data data;
      46             :         unsigned long stack, sp;
      47             :         int pid, fds[2], ret, n;
      48             : 
      49           0 :         stack = alloc_stack(0, __cant_sleep());
      50           0 :         if (stack == 0)
      51             :                 return -ENOMEM;
      52             : 
      53           0 :         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
      54           0 :         if (ret < 0) {
      55           0 :                 ret = -errno;
      56           0 :                 printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
      57             :                        errno);
      58           0 :                 goto out_free;
      59             :         }
      60             : 
      61           0 :         ret = os_set_exec_close(fds[1]);
      62           0 :         if (ret < 0) {
      63           0 :                 printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
      64             :                        "ret = %d\n", -ret);
      65           0 :                 goto out_close;
      66             :         }
      67             : 
      68           0 :         sp = stack + UM_KERN_PAGE_SIZE;
      69           0 :         data.pre_exec = pre_exec;
      70           0 :         data.pre_data = pre_data;
      71           0 :         data.argv = argv;
      72           0 :         data.fd = fds[1];
      73           0 :         data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
      74             :                                         uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
      75           0 :         pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
      76           0 :         if (pid < 0) {
      77           0 :                 ret = -errno;
      78           0 :                 printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
      79             :                        errno);
      80           0 :                 goto out_free2;
      81             :         }
      82             : 
      83           0 :         close(fds[1]);
      84           0 :         fds[1] = -1;
      85             : 
      86             :         /*
      87             :          * Read the errno value from the child, if the exec failed, or get 0 if
      88             :          * the exec succeeded because the pipe fd was set as close-on-exec.
      89             :          */
      90           0 :         n = read(fds[0], &ret, sizeof(ret));
      91           0 :         if (n == 0) {
      92           0 :                 ret = pid;
      93             :         } else {
      94           0 :                 if (n < 0) {
      95           0 :                         n = -errno;
      96           0 :                         printk(UM_KERN_ERR "run_helper : read on pipe failed, "
      97             :                                "ret = %d\n", -n);
      98           0 :                         ret = n;
      99             :                 }
     100           0 :                 CATCH_EINTR(waitpid(pid, NULL, __WALL));
     101             :         }
     102             : 
     103           0 :         if (ret < 0)
     104           0 :                 printk(UM_KERN_ERR "run_helper : failed to exec %s on host: %s\n",
     105             :                        argv[0], strerror(-ret));
     106             : 
     107             : out_free2:
     108           0 :         kfree(data.buf);
     109             : out_close:
     110           0 :         if (fds[1] != -1)
     111           0 :                 close(fds[1]);
     112           0 :         close(fds[0]);
     113             : out_free:
     114           0 :         free_stack(stack, 0);
     115           0 :         return ret;
     116             : }
     117             : 
     118           0 : int 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           0 :         stack = alloc_stack(0, __cant_sleep());
     125           0 :         if (stack == 0)
     126             :                 return -ENOMEM;
     127             : 
     128           0 :         sp = stack + UM_KERN_PAGE_SIZE;
     129           0 :         pid = clone(proc, (void *) sp, flags, arg);
     130           0 :         if (pid < 0) {
     131           0 :                 err = -errno;
     132           0 :                 printk(UM_KERN_ERR "run_helper_thread : clone failed, "
     133             :                        "errno = %d\n", errno);
     134           0 :                 return err;
     135             :         }
     136           0 :         if (stack_out == NULL) {
     137           0 :                 CATCH_EINTR(pid = waitpid(pid, &status, __WALL));
     138           0 :                 if (pid < 0) {
     139           0 :                         err = -errno;
     140           0 :                         printk(UM_KERN_ERR "run_helper_thread - wait failed, "
     141             :                                "errno = %d\n", errno);
     142           0 :                         pid = err;
     143             :                 }
     144           0 :                 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
     145           0 :                         printk(UM_KERN_ERR "run_helper_thread - thread "
     146             :                                "returned status 0x%x\n", status);
     147           0 :                 free_stack(stack, 0);
     148             :         } else
     149           0 :                 *stack_out = stack;
     150             :         return pid;
     151             : }
     152             : 
     153           0 : int helper_wait(int pid)
     154             : {
     155             :         int ret, status;
     156           0 :         int wflags = __WALL;
     157             : 
     158           0 :         CATCH_EINTR(ret = waitpid(pid, &status, wflags));
     159           0 :         if (ret < 0) {
     160           0 :                 printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
     161             :                        "errno = %d\n", pid, errno);
     162           0 :                 return -errno;
     163           0 :         } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
     164           0 :                 printk(UM_KERN_ERR "helper_wait : process %d exited with "
     165             :                        "status 0x%x\n", pid, status);
     166           0 :                 return -ECHILD;
     167             :         } else
     168             :                 return 0;
     169             : }

Generated by: LCOV version 1.14