LCOV - code coverage report
Current view: top level - lib/util - sys_popen.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 46 64 71.9 %
Date: 2021-09-23 10:06:22 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  *  Samba system utilities
       4             :  * Copyright (C) Jeremy Allison  2000
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "replace.h"
      21             : #include "system/wait.h"
      22             : #include "system/filesys.h"
      23             : #include <talloc.h>
      24             : #include "lib/util/sys_popen.h"
      25             : #include "lib/util/debug.h"
      26             : 
      27             : /**************************************************************************
      28             :  Wrapper for popen. Safer as it doesn't search a path.
      29             :  Modified from the glibc sources.
      30             :  modified by tridge to return a file descriptor. We must kick our FILE* habit
      31             : ****************************************************************************/
      32             : 
      33             : typedef struct _popen_list
      34             : {
      35             :         int fd;
      36             :         pid_t child_pid;
      37             :         struct _popen_list *next;
      38             : } popen_list;
      39             : 
      40             : static popen_list *popen_chain;
      41             : 
      42         760 : int sys_popenv(char * const argl[])
      43             : {
      44             :         int parent_end, child_end;
      45             :         int pipe_fds[2];
      46         760 :         popen_list *entry = NULL;
      47         760 :         const char *command = NULL;
      48             :         int ret;
      49             : 
      50         760 :         if (argl == NULL) {
      51           0 :                 errno = EINVAL;
      52           0 :                 return -1;
      53             :         }
      54         760 :         command = argl[0];
      55             : 
      56         760 :         if (!*command) {
      57           0 :                 errno = EINVAL;
      58           0 :                 return -1;
      59             :         }
      60             : 
      61         760 :         ret = pipe(pipe_fds);
      62         760 :         if (ret < 0) {
      63           0 :                 DBG_ERR("error opening pipe: %s\n",
      64             :                           strerror(errno));
      65           0 :                 return -1;
      66             :         }
      67             : 
      68         760 :         parent_end = pipe_fds[0];
      69         760 :         child_end = pipe_fds[1];
      70             : 
      71         760 :         entry = talloc_zero(NULL, popen_list);
      72         760 :         if (entry == NULL) {
      73           0 :                 DBG_ERR("talloc failed\n");
      74           0 :                 goto err_exit;
      75             :         }
      76             : 
      77         760 :         entry->child_pid = fork();
      78             : 
      79        1520 :         if (entry->child_pid == -1) {
      80           0 :                 DBG_ERR("fork failed: %s\n", strerror(errno));
      81           0 :                 goto err_exit;
      82             :         }
      83             : 
      84        1520 :         if (entry->child_pid == 0) {
      85             : 
      86             :                 /*
      87             :                  * Child !
      88             :                  */
      89             : 
      90         760 :                 int child_std_end = STDOUT_FILENO;
      91             :                 popen_list *p;
      92             : 
      93         760 :                 close(parent_end);
      94         760 :                 if (child_end != child_std_end) {
      95         760 :                         dup2 (child_end, child_std_end);
      96         760 :                         close (child_end);
      97             :                 }
      98             : 
      99             :                 /*
     100             :                  * POSIX.2:  "popen() shall ensure that any streams from previous
     101             :                  * popen() calls that remain open in the parent process are closed
     102             :                  * in the new child process."
     103             :                  */
     104             : 
     105         760 :                 for (p = popen_chain; p; p = p->next)
     106           0 :                         close(p->fd);
     107             : 
     108         760 :                 ret = execv(argl[0], argl);
     109         760 :                 if (ret == -1) {
     110           0 :                         DBG_ERR("ERROR executing command "
     111             :                           "'%s': %s\n", command, strerror(errno));
     112             :                 }
     113         760 :                 _exit (127);
     114             :         }
     115             : 
     116             :         /*
     117             :          * Parent.
     118             :          */
     119             : 
     120         760 :         close (child_end);
     121             : 
     122             :         /* Link into popen_chain. */
     123         760 :         entry->next = popen_chain;
     124         760 :         popen_chain = entry;
     125         760 :         entry->fd = parent_end;
     126             : 
     127         760 :         return entry->fd;
     128             : 
     129           0 : err_exit:
     130             : 
     131           0 :         TALLOC_FREE(entry);
     132           0 :         close(pipe_fds[0]);
     133           0 :         close(pipe_fds[1]);
     134           0 :         return -1;
     135             : }
     136             : 
     137             : /**************************************************************************
     138             :  Wrapper for pclose. Modified from the glibc sources.
     139             : ****************************************************************************/
     140             : 
     141         760 : int sys_pclose(int fd)
     142             : {
     143             :         int wstatus;
     144         760 :         popen_list **ptr = &popen_chain;
     145         760 :         popen_list *entry = NULL;
     146             :         pid_t wait_pid;
     147         760 :         int status = -1;
     148             : 
     149             :         /* Unlink from popen_chain. */
     150         760 :         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
     151         760 :                 if ((*ptr)->fd == fd) {
     152         760 :                         entry = *ptr;
     153         760 :                         *ptr = (*ptr)->next;
     154         760 :                         status = 0;
     155         760 :                         break;
     156             :                 }
     157             :         }
     158             : 
     159         760 :         if (status < 0 || close(entry->fd) < 0)
     160           0 :                 return -1;
     161             : 
     162             :         /*
     163             :          * As Samba is catching and eating child process
     164             :          * exits we don't really care about the child exit
     165             :          * code, a -1 with errno = ECHILD will do fine for us.
     166             :          */
     167             : 
     168             :         do {
     169         760 :                 wait_pid = waitpid (entry->child_pid, &wstatus, 0);
     170         760 :         } while (wait_pid == -1 && errno == EINTR);
     171             : 
     172         760 :         TALLOC_FREE(entry);
     173             : 
     174         760 :         if (wait_pid == -1)
     175         751 :                 return -1;
     176           9 :         return wstatus;
     177             : }

Generated by: LCOV version 1.13