(root)/
glibc-2.38/
libio/
oldiopopen.c
       1  /* Copyright (C) 1998-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  #define _IO_USE_OLD_IO_FILE
      28  #include "libioP.h"
      29  #include <signal.h>
      30  #include <unistd.h>
      31  #include <stdlib.h>
      32  #include <unistd.h>
      33  #include <sys/types.h>
      34  #include <sys/wait.h>
      35  
      36  #include <shlib-compat.h>
      37  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
      38  
      39  struct _IO_proc_file
      40  {
      41    struct _IO_FILE_complete_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 *old_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  FILE *
      61  attribute_compat_text_section
      62  _IO_old_proc_open (FILE *fp, const char *command, const char *mode)
      63  {
      64    volatile int read_or_write;
      65    volatile int parent_end, child_end;
      66    int pipe_fds[2];
      67    pid_t child_pid;
      68    if (_IO_file_is_open (fp))
      69      return NULL;
      70    if (__pipe (pipe_fds) < 0)
      71      return NULL;
      72    if (mode[0] == 'r' && mode[1] == '\0')
      73      {
      74        parent_end = pipe_fds[0];
      75        child_end = pipe_fds[1];
      76        read_or_write = _IO_NO_WRITES;
      77      }
      78    else if (mode[0] == 'w' && mode[1] == '\0')
      79      {
      80        parent_end = pipe_fds[1];
      81        child_end = pipe_fds[0];
      82        read_or_write = _IO_NO_READS;
      83      }
      84    else
      85      {
      86        __close (pipe_fds[0]);
      87        __close (pipe_fds[1]);
      88        __set_errno (EINVAL);
      89        return NULL;
      90      }
      91    ((_IO_proc_file *) fp)->pid = child_pid = __fork ();
      92    if (child_pid == 0)
      93      {
      94        int child_std_end = mode[0] == 'r' ? 1 : 0;
      95        struct _IO_proc_file *p;
      96  
      97        __close (parent_end);
      98        if (child_end != child_std_end)
      99  	{
     100  	  __dup2 (child_end, child_std_end);
     101  	  __close (child_end);
     102  	}
     103        /* POSIX.2:  "popen() shall ensure that any streams from previous
     104           popen() calls that remain open in the parent process are closed
     105  	 in the new child process." */
     106        for (p = old_proc_file_chain; p; p = p->next)
     107  	__close (_IO_fileno ((FILE *) p));
     108  
     109        execl ("/bin/sh", "sh", "-c", command, (char *) 0);
     110        _exit (127);
     111      }
     112    __close (child_end);
     113    if (child_pid < 0)
     114      {
     115        __close (parent_end);
     116        return NULL;
     117      }
     118    _IO_fileno (fp) = parent_end;
     119  
     120    /* Link into old_proc_file_chain. */
     121  #ifdef _IO_MTSAFE_IO
     122    _IO_cleanup_region_start_noarg (unlock);
     123    _IO_lock_lock (proc_file_chain_lock);
     124  #endif
     125    ((_IO_proc_file *) fp)->next = old_proc_file_chain;
     126    old_proc_file_chain = (_IO_proc_file *) fp;
     127  #ifdef _IO_MTSAFE_IO
     128    _IO_lock_unlock (proc_file_chain_lock);
     129    _IO_cleanup_region_end (0);
     130  #endif
     131  
     132    _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
     133    return fp;
     134  }
     135  
     136  FILE *
     137  attribute_compat_text_section
     138  _IO_old_popen (const char *command, const char *mode)
     139  {
     140    struct locked_FILE
     141    {
     142      struct _IO_proc_file fpx;
     143  #ifdef _IO_MTSAFE_IO
     144      _IO_lock_t lock;
     145  #endif
     146    } *new_f;
     147    FILE *fp;
     148  
     149    new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
     150    if (new_f == NULL)
     151      return NULL;
     152  #ifdef _IO_MTSAFE_IO
     153    new_f->fpx.file.file._file._lock = &new_f->lock;
     154  #endif
     155    fp = &new_f->fpx.file.file._file;
     156    _IO_old_init (fp, 0);
     157    _IO_JUMPS_FILE_plus (&new_f->fpx.file) = &_IO_old_proc_jumps;
     158    _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fpx.file);
     159    if (_IO_old_proc_open (fp, command, mode) != NULL)
     160      return fp;
     161    _IO_un_link ((struct _IO_FILE_plus *) &new_f->fpx.file);
     162    free (new_f);
     163    return NULL;
     164  }
     165  
     166  int
     167  attribute_compat_text_section
     168  _IO_old_proc_close (FILE *fp)
     169  {
     170    /* This is not name-space clean. FIXME! */
     171    int wstatus;
     172    _IO_proc_file **ptr = &old_proc_file_chain;
     173    pid_t wait_pid;
     174    int status = -1;
     175  
     176    /* Unlink from old_proc_file_chain. */
     177  #ifdef _IO_MTSAFE_IO
     178    _IO_cleanup_region_start_noarg (unlock);
     179    _IO_lock_lock (proc_file_chain_lock);
     180  #endif
     181    for ( ; *ptr != NULL; ptr = &(*ptr)->next)
     182      {
     183        if (*ptr == (_IO_proc_file *) fp)
     184  	{
     185  	  *ptr = (*ptr)->next;
     186  	  status = 0;
     187  	  break;
     188  	}
     189      }
     190  #ifdef _IO_MTSAFE_IO
     191    _IO_lock_unlock (proc_file_chain_lock);
     192    _IO_cleanup_region_end (0);
     193  #endif
     194  
     195    if (status < 0 || __close (_IO_fileno(fp)) < 0)
     196      return -1;
     197    /* POSIX.2 Rationale:  "Some historical implementations either block
     198       or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
     199       for the child process to terminate.  Since this behavior is not
     200       described in POSIX.2, such implementations are not conforming." */
     201    do
     202      {
     203        wait_pid = __waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
     204      }
     205    while (wait_pid == -1 && errno == EINTR);
     206    if (wait_pid == -1)
     207      return -1;
     208    return wstatus;
     209  }
     210  
     211  strong_alias (_IO_old_popen, __old_popen)
     212  compat_symbol (libc, _IO_old_popen, _IO_popen, GLIBC_2_0);
     213  compat_symbol (libc, __old_popen, popen, GLIBC_2_0);
     214  compat_symbol (libc, _IO_old_proc_open, _IO_proc_open, GLIBC_2_0);
     215  compat_symbol (libc, _IO_old_proc_close, _IO_proc_close, GLIBC_2_0);
     216  
     217  #endif