LCOV - code coverage report
Current view: top level - lib/util - sys_popen.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 47 71 66.2 %
Date: 2024-05-31 13:13:24 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        1650 : int sys_popenv(char * const argl[])
      43             : {
      44           0 :         int parent_end, child_end;
      45           0 :         int pipe_fds[2];
      46        1650 :         popen_list *entry = NULL;
      47        1650 :         const char *command = NULL;
      48           0 :         int ret;
      49             : 
      50        1650 :         if (argl == NULL) {
      51           0 :                 errno = EINVAL;
      52           0 :                 return -1;
      53             :         }
      54        1650 :         command = argl[0];
      55             : 
      56        1650 :         if (!*command) {
      57           0 :                 errno = EINVAL;
      58           0 :                 return -1;
      59             :         }
      60             : 
      61        1650 :         ret = pipe(pipe_fds);
      62        1650 :         if (ret < 0) {
      63           0 :                 DBG_ERR("error opening pipe: %s\n",
      64             :                           strerror(errno));
      65           0 :                 return -1;
      66             :         }
      67             : 
      68        1650 :         parent_end = pipe_fds[0];
      69        1650 :         child_end = pipe_fds[1];
      70             : 
      71        1650 :         entry = talloc_zero(NULL, popen_list);
      72        1650 :         if (entry == NULL) {
      73           0 :                 DBG_ERR("talloc failed\n");
      74           0 :                 goto err_exit;
      75             :         }
      76             : 
      77        1650 :         entry->child_pid = fork();
      78             : 
      79        3404 :         if (entry->child_pid == -1) {
      80           0 :                 DBG_ERR("fork failed: %s\n", strerror(errno));
      81           0 :                 goto err_exit;
      82             :         }
      83             : 
      84        3404 :         if (entry->child_pid == 0) {
      85             : 
      86             :                 /*
      87             :                  * Child !
      88             :                  */
      89             : 
      90        1754 :                 int child_std_end = STDOUT_FILENO;
      91           0 :                 popen_list *p;
      92             : 
      93        1754 :                 close(parent_end);
      94        1754 :                 if (child_end != child_std_end) {
      95        1754 :                         dup2 (child_end, child_std_end);
      96        1754 :                         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        4638 :                 for (p = popen_chain; p; p = p->next)
     106        2884 :                         close(p->fd);
     107             : 
     108        1754 :                 ret = execv(argl[0], argl);
     109        1754 :                 if (ret == -1) {
     110           0 :                         DBG_ERR("ERROR executing command "
     111             :                           "'%s': %s\n", command, strerror(errno));
     112             :                 }
     113        1754 :                 _exit (127);
     114             :         }
     115             : 
     116             :         /*
     117             :          * Parent.
     118             :          */
     119             : 
     120        1650 :         close (child_end);
     121             : 
     122             :         /* Link into popen_chain. */
     123        1650 :         entry->next = popen_chain;
     124        1650 :         popen_chain = entry;
     125        1650 :         entry->fd = parent_end;
     126             : 
     127        1650 :         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        1650 : int sys_pclose(int fd)
     142             : {
     143           0 :         int wstatus;
     144        1650 :         popen_list **ptr = &popen_chain;
     145        1650 :         popen_list *entry = NULL;
     146           0 :         pid_t wait_pid;
     147        1650 :         int status = -1;
     148             : 
     149             :         /* Unlink from popen_chain. */
     150        3190 :         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
     151        3190 :                 if ((*ptr)->fd == fd) {
     152        1650 :                         entry = *ptr;
     153        1650 :                         *ptr = (*ptr)->next;
     154        1650 :                         status = 0;
     155        1650 :                         break;
     156             :                 }
     157             :         }
     158             : 
     159        1650 :         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           0 :         do {
     169        1771 :                 wait_pid = waitpid (entry->child_pid, &wstatus, 0);
     170        1771 :         } while (wait_pid == -1 && errno == EINTR);
     171             : 
     172        1650 :         TALLOC_FREE(entry);
     173             : 
     174        1650 :         if (wait_pid == -1)
     175        1083 :                 return -1;
     176         567 :         return wstatus;
     177             : }

Generated by: LCOV version 1.14