(root)/
glibc-2.38/
libio/
iopopen.c
       1  /* Copyright (C) 1993-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.
      17  
      18     As a special exception, if you link the code in this file with
      19     files compiled with a GNU compiler to produce an executable,
      20     that does not cause the resulting executable to be covered by
      21     the GNU Lesser General Public License.  This exception does not
      22     however invalidate any other reasons why the executable file
      23     might be covered by the GNU Lesser General Public License.
      24     This exception applies to code released by its copyright holders
      25     in files containing the exception.  */
      26  
      27  #include "libioP.h"
      28  #include <fcntl.h>
      29  #include <signal.h>
      30  #include <unistd.h>
      31  #include <stdlib.h>
      32  #include <shlib-compat.h>
      33  #include <not-cancel.h>
      34  #include <sys/types.h>
      35  #include <sys/wait.h>
      36  #include <spawn.h>
      37  #include <paths.h>
      38  
      39  struct _IO_proc_file
      40  {
      41    struct _IO_FILE_plus file;
      42    /* Following fields must match those in class procbuf (procbuf.h) */
      43    pid_t pid;
      44    struct _IO_proc_file *next;
      45  };
      46  typedef struct _IO_proc_file _IO_proc_file;
      47  
      48  static struct _IO_proc_file *proc_file_chain;
      49  
      50  #ifdef _IO_MTSAFE_IO
      51  static _IO_lock_t proc_file_chain_lock = _IO_lock_initializer;
      52  
      53  static void
      54  unlock (void *not_used)
      55  {
      56    _IO_lock_unlock (proc_file_chain_lock);
      57  }
      58  #endif
      59  
      60  /* POSIX states popen shall ensure that any streams from previous popen()
      61     calls that remain open in the parent process should be closed in the new
      62     child process.
      63     To avoid a race-condition between checking which file descriptors need to
      64     be close (by transversing the proc_file_chain list) and the insertion of a
      65     new one after a successful posix_spawn this function should be called
      66     with proc_file_chain_lock acquired.  */
      67  static int
      68  spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command,
      69  	       int do_cloexec, int pipe_fds[2], int parent_end, int child_end,
      70  	       int child_pipe_fd)
      71  {
      72    int err = 0;
      73  
      74    for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next)
      75      {
      76        int fd = _IO_fileno ((FILE *) p);
      77  
      78        /* If any stream from previous popen() calls has fileno
      79  	 child_pipe_fd, it has been already closed by the adddup2 action
      80  	 above.  */
      81        if (fd != child_pipe_fd)
      82  	{
      83  	  err = __posix_spawn_file_actions_addclose (fa, fd);
      84  	  if (err != 0)
      85  	    return err;
      86  	}
      87      }
      88  
      89    err = __posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0,
      90  		       (char *const[]){ (char*) "sh", (char*) "-c", (char*) "--",
      91  		       (char *) command, NULL }, __environ);
      92    if (err != 0)
      93      return err;
      94  
      95    __close_nocancel (pipe_fds[child_end]);
      96  
      97    if (!do_cloexec)
      98      /* Undo the effects of the pipe2 call which set the
      99         close-on-exec flag.  */
     100      __fcntl (pipe_fds[parent_end], F_SETFD, 0);
     101  
     102    _IO_fileno (fp) = pipe_fds[parent_end];
     103  
     104    ((_IO_proc_file *) fp)->next = proc_file_chain;
     105    proc_file_chain = (_IO_proc_file *) fp;
     106  
     107    return 0;
     108  }
     109  
     110  FILE *
     111  _IO_new_proc_open (FILE *fp, const char *command, const char *mode)
     112  {
     113    int read_or_write;
     114    /* These are indexes for pipe_fds.  */
     115    int parent_end, child_end;
     116    int pipe_fds[2];
     117    int child_pipe_fd;
     118    int err;
     119  
     120    int do_read = 0;
     121    int do_write = 0;
     122    int do_cloexec = 0;
     123    while (*mode != '\0')
     124      switch (*mode++)
     125        {
     126        case 'r':
     127  	do_read = 1;
     128  	break;
     129        case 'w':
     130  	do_write = 1;
     131  	break;
     132        case 'e':
     133  	do_cloexec = 1;
     134  	break;
     135        default:
     136        errout:
     137  	__set_errno (EINVAL);
     138  	return NULL;
     139        }
     140  
     141    if ((do_read ^ do_write) == 0)
     142      goto errout;
     143  
     144    if (_IO_file_is_open (fp))
     145      return NULL;
     146  
     147    /* Atomically set the O_CLOEXEC flag for the pipe end used by the
     148       child process (to avoid leaking the file descriptor in case of a
     149       concurrent fork).  This is later reverted in the child process.
     150       When popen returns, the parent pipe end can be O_CLOEXEC or not,
     151       depending on the 'e' open mode, but there is only one flag which
     152       controls both descriptors.  The parent end is adjusted below,
     153       after creating the child process.  (In the child process, the
     154       parent end should be closed on execve, so O_CLOEXEC remains set
     155       there.)  */
     156    if (__pipe2 (pipe_fds, O_CLOEXEC) < 0)
     157      return NULL;
     158  
     159    if (do_read)
     160      {
     161        parent_end = 0;
     162        child_end = 1;
     163        read_or_write = _IO_NO_WRITES;
     164        child_pipe_fd = 1;
     165      }
     166    else
     167      {
     168        parent_end = 1;
     169        child_end = 0;
     170        read_or_write = _IO_NO_READS;
     171        child_pipe_fd = 0;
     172      }
     173  
     174    posix_spawn_file_actions_t fa;
     175    /* posix_spawn_file_actions_init does not fail.  */
     176    __posix_spawn_file_actions_init (&fa);
     177  
     178    /* The descriptor is already the one the child will use.  In this case
     179       it must be moved to another one otherwise, there is no safe way to
     180       remove the close-on-exec flag in the child without creating a FD leak
     181       race in the parent.  */
     182    if (pipe_fds[child_end] == child_pipe_fd)
     183      {
     184        int tmp = __fcntl (child_pipe_fd, F_DUPFD_CLOEXEC, 0);
     185        if (tmp < 0)
     186  	goto spawn_failure;
     187        __close_nocancel (pipe_fds[child_end]);
     188        pipe_fds[child_end] = tmp;
     189      }
     190  
     191    err = __posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end],
     192  					    child_pipe_fd);
     193    if (err != 0)
     194      goto spawn_failure;
     195  
     196  #ifdef _IO_MTSAFE_IO
     197    _IO_cleanup_region_start_noarg (unlock);
     198    _IO_lock_lock (proc_file_chain_lock);
     199  #endif
     200    err = spawn_process (&fa, fp, command, do_cloexec, pipe_fds, parent_end,
     201  		       child_end, child_pipe_fd);
     202  #ifdef _IO_MTSAFE_IO
     203    _IO_lock_unlock (proc_file_chain_lock);
     204    _IO_cleanup_region_end (0);
     205  #endif
     206  
     207    __posix_spawn_file_actions_destroy (&fa);
     208  
     209    if (err != 0)
     210      {
     211        __set_errno (err);
     212      spawn_failure:
     213        __close_nocancel (pipe_fds[child_end]);
     214        __close_nocancel (pipe_fds[parent_end]);
     215        return NULL;
     216      }
     217  
     218    _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
     219    return fp;
     220  }
     221  
     222  FILE *
     223  _IO_new_popen (const char *command, const char *mode)
     224  {
     225    struct locked_FILE
     226    {
     227      struct _IO_proc_file fpx;
     228  #ifdef _IO_MTSAFE_IO
     229      _IO_lock_t lock;
     230  #endif
     231    } *new_f;
     232    FILE *fp;
     233  
     234    new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
     235    if (new_f == NULL)
     236      return NULL;
     237  #ifdef _IO_MTSAFE_IO
     238    new_f->fpx.file.file._lock = &new_f->lock;
     239  #endif
     240    fp = &new_f->fpx.file.file;
     241    _IO_init_internal (fp, 0);
     242    _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps;
     243    _IO_new_file_init_internal (&new_f->fpx.file);
     244    if (_IO_new_proc_open (fp, command, mode) != NULL)
     245      return (FILE *) &new_f->fpx.file;
     246    _IO_un_link (&new_f->fpx.file);
     247    free (new_f);
     248    return NULL;
     249  }
     250  
     251  int
     252  _IO_new_proc_close (FILE *fp)
     253  {
     254    /* This is not name-space clean. FIXME! */
     255    int wstatus;
     256    _IO_proc_file **ptr = &proc_file_chain;
     257    pid_t wait_pid;
     258    int status = -1;
     259  
     260    /* Unlink from proc_file_chain. */
     261  #ifdef _IO_MTSAFE_IO
     262    _IO_cleanup_region_start_noarg (unlock);
     263    _IO_lock_lock (proc_file_chain_lock);
     264  #endif
     265    for ( ; *ptr != NULL; ptr = &(*ptr)->next)
     266      {
     267        if (*ptr == (_IO_proc_file *) fp)
     268  	{
     269  	  *ptr = (*ptr)->next;
     270  	  status = 0;
     271  	  break;
     272  	}
     273      }
     274  #ifdef _IO_MTSAFE_IO
     275    _IO_lock_unlock (proc_file_chain_lock);
     276    _IO_cleanup_region_end (0);
     277  #endif
     278  
     279    if (status < 0 || __close_nocancel (_IO_fileno(fp)) < 0)
     280      return -1;
     281    /* POSIX.2 Rationale:  "Some historical implementations either block
     282       or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
     283       for the child process to terminate.  Since this behavior is not
     284       described in POSIX.2, such implementations are not conforming." */
     285    do
     286      {
     287        int state;
     288        __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
     289        wait_pid = __waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
     290        __pthread_setcancelstate (state, NULL);
     291      }
     292    while (wait_pid == -1 && errno == EINTR);
     293    if (wait_pid == -1)
     294      return -1;
     295    return wstatus;
     296  }
     297  
     298  strong_alias (_IO_new_popen, __new_popen)
     299  versioned_symbol (libc, _IO_new_popen, _IO_popen, GLIBC_2_1);
     300  versioned_symbol (libc, __new_popen, popen, GLIBC_2_1);
     301  versioned_symbol (libc, _IO_new_proc_open, _IO_proc_open, GLIBC_2_1);
     302  versioned_symbol (libc, _IO_new_proc_close, _IO_proc_close, GLIBC_2_1);