(root)/
gcc-13.2.0/
libiberty/
pex-common.c
       1  /* Common code for executing a program in a sub-process.
       2     Copyright (C) 2005-2023 Free Software Foundation, Inc.
       3     Written by Ian Lance Taylor <ian@airs.com>.
       4  
       5  This file is part of the libiberty library.
       6  Libiberty is free software; you can redistribute it and/or
       7  modify it under the terms of the GNU Library General Public
       8  License as published by the Free Software Foundation; either
       9  version 2 of the License, or (at your option) any later version.
      10  
      11  Libiberty 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 GNU
      14  Library General Public License for more details.
      15  
      16  You should have received a copy of the GNU Library General Public
      17  License along with libiberty; see the file COPYING.LIB.  If not,
      18  write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
      19  Boston, MA 02110-1301, USA.  */
      20  
      21  #include "config.h"
      22  #include "libiberty.h"
      23  #include "pex-common.h"
      24  
      25  #include <stdio.h>
      26  #include <errno.h>
      27  #ifdef NEED_DECLARATION_ERRNO
      28  extern int errno;
      29  #endif
      30  #ifdef HAVE_STDLIB_H
      31  #include <stdlib.h>
      32  #endif
      33  #ifdef HAVE_STRING_H
      34  #include <string.h>
      35  #endif
      36  #ifdef HAVE_UNISTD_H
      37  #include <unistd.h>
      38  #endif
      39  
      40  extern int mkstemps (char *, int);
      41  
      42  /* This file contains subroutines for the program execution routines
      43     (pex_init, pex_run, etc.).  This file is compiled on all
      44     systems.  */
      45  
      46  static void pex_add_remove (struct pex_obj *, const char *, int);
      47  static int pex_get_status_and_time (struct pex_obj *, int, const char **,
      48  				    int *);
      49  
      50  /* Initialize a pex_obj structure.  */
      51  
      52  struct pex_obj *
      53  pex_init_common (int flags, const char *pname, const char *tempbase,
      54  		 const struct pex_funcs *funcs)
      55  {
      56    struct pex_obj *obj;
      57  
      58    obj = XNEW (struct pex_obj);
      59    obj->flags = flags;
      60    obj->pname = pname;
      61    obj->tempbase = tempbase;
      62    obj->next_input = STDIN_FILE_NO;
      63    obj->next_input_name = NULL;
      64    obj->next_input_name_allocated = 0;
      65    obj->stderr_pipe = -1;
      66    obj->count = 0;
      67    obj->children = NULL;
      68    obj->status = NULL;
      69    obj->time = NULL;
      70    obj->number_waited = 0;
      71    obj->input_file = NULL;
      72    obj->read_output = NULL;
      73    obj->read_err = NULL;
      74    obj->remove_count = 0;
      75    obj->remove = NULL;
      76    obj->funcs = funcs;
      77    obj->sysdep = NULL;
      78    return obj;
      79  }
      80  
      81  /* Add a file to be removed when we are done.  */
      82  
      83  static void
      84  pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
      85  {
      86    char *add;
      87  
      88    ++obj->remove_count;
      89    obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
      90    if (allocated)
      91      add = (char *) name;
      92    else
      93      add = xstrdup (name);
      94    obj->remove[obj->remove_count - 1] = add;
      95  }
      96  
      97  /* Generate a temporary file name based on OBJ, FLAGS, and NAME.
      98     Return NULL if we were unable to reserve a temporary filename.
      99  
     100     If non-NULL, the result is either allocated with malloc, or the
     101     same pointer as NAME.  */
     102  static char *
     103  temp_file (struct pex_obj *obj, int flags, char *name)
     104  {
     105    if (name == NULL)
     106      {
     107        if (obj->tempbase == NULL)
     108          {
     109            name = make_temp_file (NULL);
     110          }
     111        else
     112          {
     113            int len = strlen (obj->tempbase);
     114            int out;
     115  
     116            if (len >= 6
     117                && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
     118              name = xstrdup (obj->tempbase);
     119            else
     120              name = concat (obj->tempbase, "XXXXXX", NULL);
     121  
     122            out = mkstemps (name, 0);
     123            if (out < 0)
     124              {
     125                free (name);
     126                return NULL;
     127              }
     128  
     129            /* This isn't obj->funcs->close because we got the
     130               descriptor from mkstemps, not from a function in
     131               obj->funcs.  Calling close here is just like what
     132               make_temp_file does.  */
     133            close (out);
     134          }
     135      }
     136    else if ((flags & PEX_SUFFIX) != 0)
     137      {
     138        if (obj->tempbase == NULL)
     139          name = make_temp_file (name);
     140        else
     141          name = concat (obj->tempbase, name, NULL);
     142      }
     143  
     144    return name;
     145  }
     146  
     147  
     148  /* As for pex_run (), but permits the environment for the child process
     149     to be specified. */
     150  
     151  const char *
     152  pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
     153         	                char * const * argv, char * const * env,
     154                          const char *orig_outname, const char *errname,
     155                    	int *err)
     156  {
     157    const char *errmsg;
     158    int in, out, errdes;
     159    char *outname;
     160    int outname_allocated;
     161    int p[2];
     162    int toclose;
     163    pid_t pid;
     164  
     165    in = -1;
     166    out = -1;
     167    errdes = -1;
     168    outname = (char *) orig_outname;
     169    outname_allocated = 0;
     170  
     171    /* If the user called pex_input_file, close the file now.  */
     172    if (obj->input_file)
     173      {
     174        if (fclose (obj->input_file) == EOF)
     175          {
     176            errmsg = "closing pipeline input file";
     177            goto error_exit;
     178          }
     179        obj->input_file = NULL;
     180      }
     181  
     182    /* Set IN.  */
     183  
     184    if (obj->next_input_name != NULL)
     185      {
     186        /* We have to make sure that the previous process has completed
     187  	 before we try to read the file.  */
     188        if (!pex_get_status_and_time (obj, 0, &errmsg, err))
     189  	goto error_exit;
     190  
     191        in = obj->funcs->open_read (obj, obj->next_input_name,
     192  				  (flags & PEX_BINARY_INPUT) != 0);
     193        if (in < 0)
     194  	{
     195  	  *err = errno;
     196  	  errmsg = "open temporary file";
     197  	  goto error_exit;
     198  	}
     199        if (obj->next_input_name_allocated)
     200  	{
     201  	  free (obj->next_input_name);
     202  	  obj->next_input_name_allocated = 0;
     203  	}
     204        obj->next_input_name = NULL;
     205      }
     206    else
     207      {
     208        in = obj->next_input;
     209        if (in < 0)
     210  	{
     211  	  *err = 0;
     212  	  errmsg = "pipeline already complete";
     213  	  goto error_exit;
     214  	}
     215      }
     216  
     217    /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME.  */
     218  
     219    if ((flags & PEX_LAST) != 0)
     220      {
     221        if (outname == NULL)
     222  	out = STDOUT_FILE_NO;
     223        else if ((flags & PEX_SUFFIX) != 0)
     224  	{
     225  	  outname = concat (obj->tempbase, outname, NULL);
     226  	  outname_allocated = 1;
     227  	}
     228        obj->next_input = -1;
     229      }
     230    else if ((obj->flags & PEX_USE_PIPES) == 0)
     231      {
     232        outname = temp_file (obj, flags, outname);
     233        if (! outname)
     234          {
     235            *err = 0;
     236            errmsg = "could not create temporary file";
     237            goto error_exit;
     238          }
     239  
     240        if (outname != orig_outname)
     241          outname_allocated = 1;
     242  
     243        if ((obj->flags & PEX_SAVE_TEMPS) == 0)
     244  	{
     245  	  pex_add_remove (obj, outname, outname_allocated);
     246  	  outname_allocated = 0;
     247  	}
     248  
     249        /* Hand off ownership of outname to the next stage.  */
     250        obj->next_input_name = outname;
     251        obj->next_input_name_allocated = outname_allocated;
     252        outname_allocated = 0;
     253      }
     254    else
     255      {
     256        if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
     257  	{
     258  	  *err = errno;
     259  	  errmsg = "pipe";
     260  	  goto error_exit;
     261  	}
     262  
     263        out = p[WRITE_PORT];
     264        obj->next_input = p[READ_PORT];
     265      }
     266  
     267    if (out < 0)
     268      {
     269        out = obj->funcs->open_write (obj, outname,
     270  				    (flags & PEX_BINARY_OUTPUT) != 0,
     271  				    (flags & PEX_STDOUT_APPEND) != 0);
     272        if (out < 0)
     273  	{
     274  	  *err = errno;
     275  	  errmsg = "open temporary output file";
     276  	  goto error_exit;
     277  	}
     278      }
     279  
     280    if (outname_allocated)
     281      {
     282        free (outname);
     283        outname_allocated = 0;
     284      }
     285  
     286    /* Set ERRDES.  */
     287  
     288    if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
     289      {
     290        *err = 0;
     291        errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
     292        goto error_exit;
     293      }
     294  
     295    if (obj->stderr_pipe != -1)
     296      {
     297        *err = 0;
     298        errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
     299        goto error_exit;
     300      }
     301  
     302    if (errname == NULL)
     303      {
     304        if (flags & PEX_STDERR_TO_PIPE)
     305  	{
     306  	  if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
     307  	    {
     308  	      *err = errno;
     309  	      errmsg = "pipe";
     310  	      goto error_exit;
     311  	    }
     312  	  
     313  	  errdes = p[WRITE_PORT];
     314  	  obj->stderr_pipe = p[READ_PORT];	  
     315  	}
     316        else
     317  	{
     318  	  errdes = STDERR_FILE_NO;
     319  	}
     320      }
     321    else
     322      {
     323        errdes = obj->funcs->open_write (obj, errname,
     324  				       (flags & PEX_BINARY_ERROR) != 0,
     325  				       (flags & PEX_STDERR_APPEND) != 0);
     326        if (errdes < 0)
     327  	{
     328  	  *err = errno;
     329  	  errmsg = "open error file";
     330  	  goto error_exit;
     331  	}
     332      }
     333  
     334    /* If we are using pipes, the child process has to close the next
     335       input pipe.  */
     336  
     337    if ((obj->flags & PEX_USE_PIPES) == 0)
     338      toclose = -1;
     339    else
     340      toclose = obj->next_input;
     341  
     342    /* Run the program.  */
     343  
     344    pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
     345  				in, out, errdes, toclose, &errmsg, err);
     346    if (pid < 0)
     347      goto error_exit;
     348  
     349    ++obj->count;
     350    obj->children = XRESIZEVEC (pid_t, obj->children, obj->count);
     351    obj->children[obj->count - 1] = pid;
     352  
     353    return NULL;
     354  
     355   error_exit:
     356    if (in >= 0 && in != STDIN_FILE_NO)
     357      obj->funcs->close (obj, in);
     358    if (out >= 0 && out != STDOUT_FILE_NO)
     359      obj->funcs->close (obj, out);
     360    if (errdes >= 0 && errdes != STDERR_FILE_NO)
     361      obj->funcs->close (obj, errdes);
     362    if (outname_allocated)
     363      free (outname);
     364    return errmsg;
     365  }
     366  
     367  /* Run a program.  */
     368  
     369  const char *
     370  pex_run (struct pex_obj *obj, int flags, const char *executable,
     371         	 char * const * argv, const char *orig_outname, const char *errname,
     372           int *err)
     373  {
     374    return pex_run_in_environment (obj, flags, executable, argv, NULL,
     375  				 orig_outname, errname, err);
     376  }
     377  
     378  /* Return a FILE pointer for a temporary file to fill with input for
     379     the pipeline.  */
     380  FILE *
     381  pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
     382  {
     383    char *name = (char *) in_name;
     384    FILE *f;
     385  
     386    /* This must be called before the first pipeline stage is run, and
     387       there must not have been any other input selected.  */
     388    if (obj->count != 0
     389        || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
     390        || obj->next_input_name)
     391      {
     392        errno = EINVAL;
     393        return NULL;
     394      }
     395  
     396    name = temp_file (obj, flags, name);
     397    if (! name)
     398      return NULL;
     399  
     400    f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
     401    if (! f)
     402      {
     403        free (name);
     404        return NULL;
     405      }
     406  
     407    obj->input_file = f;
     408    obj->next_input_name = name;
     409    obj->next_input_name_allocated = (name != in_name);
     410  
     411    return f;
     412  }
     413  
     414  /* Return a stream for a pipe connected to the standard input of the
     415     first stage of the pipeline.  */
     416  FILE *
     417  pex_input_pipe (struct pex_obj *obj, int binary)
     418  {
     419    int p[2];
     420    FILE *f;
     421  
     422    /* You must call pex_input_pipe before the first pex_run or pex_one.  */
     423    if (obj->count > 0)
     424      goto usage_error;
     425  
     426    /* You must be using pipes.  Implementations that don't support
     427       pipes clear this flag before calling pex_init_common.  */
     428    if (! (obj->flags & PEX_USE_PIPES))
     429      goto usage_error;
     430  
     431    /* If we have somehow already selected other input, that's a
     432       mistake.  */
     433    if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
     434        || obj->next_input_name)
     435      goto usage_error;
     436  
     437    if (obj->funcs->pipe (obj, p, binary != 0) < 0)
     438      return NULL;
     439  
     440    f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
     441    if (! f)
     442      {
     443        int saved_errno = errno;
     444        obj->funcs->close (obj, p[READ_PORT]);
     445        obj->funcs->close (obj, p[WRITE_PORT]);
     446        errno = saved_errno;
     447        return NULL;
     448      }
     449  
     450    obj->next_input = p[READ_PORT];
     451  
     452    return f;
     453  
     454   usage_error:
     455    errno = EINVAL;
     456    return NULL;
     457  }
     458  
     459  /* Return a FILE pointer for the output of the last program
     460     executed.  */
     461  
     462  FILE *
     463  pex_read_output (struct pex_obj *obj, int binary)
     464  {
     465    if (obj->next_input_name != NULL)
     466      {
     467        const char *errmsg;
     468        int err;
     469  
     470        /* We have to make sure that the process has completed before we
     471  	 try to read the file.  */
     472        if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
     473  	{
     474  	  errno = err;
     475  	  return NULL;
     476  	}
     477  
     478        obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
     479  
     480        if (obj->next_input_name_allocated)
     481  	{
     482  	  free (obj->next_input_name);
     483  	  obj->next_input_name_allocated = 0;
     484  	}
     485        obj->next_input_name = NULL;
     486      }
     487    else
     488      {
     489        int o;
     490  
     491        o = obj->next_input;
     492        if (o < 0 || o == STDIN_FILE_NO)
     493  	return NULL;
     494        obj->read_output = obj->funcs->fdopenr (obj, o, binary);
     495        obj->next_input = -1;
     496      }
     497  
     498    return obj->read_output;
     499  }
     500  
     501  FILE *
     502  pex_read_err (struct pex_obj *obj, int binary)
     503  {
     504    int o;
     505    
     506    o = obj->stderr_pipe;
     507    if (o < 0 || o == STDIN_FILE_NO)
     508      return NULL;
     509    obj->read_err = obj->funcs->fdopenr (obj, o, binary);
     510    obj->stderr_pipe = -1;
     511    return obj->read_err;    
     512  }
     513  
     514  /* Get the exit status and, if requested, the resource time for all
     515     the child processes.  Return 0 on failure, 1 on success.  */
     516  
     517  static int
     518  pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
     519  			 int *err)
     520  {
     521    int ret;
     522    int i;
     523  
     524    if (obj->number_waited == obj->count)
     525      return 1;
     526  
     527    obj->status = XRESIZEVEC (int, obj->status, obj->count);
     528    if ((obj->flags & PEX_RECORD_TIMES) != 0)
     529      obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
     530  
     531    ret = 1;
     532    for (i = obj->number_waited; i < obj->count; ++i)
     533      {
     534        if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
     535  			    obj->time == NULL ? NULL : &obj->time[i],
     536  			    done, errmsg, err) < 0)
     537  	ret = 0;
     538      }
     539    obj->number_waited = i;
     540  
     541    return ret;
     542  }
     543  
     544  /* Get exit status of executed programs.  */
     545  
     546  int
     547  pex_get_status (struct pex_obj *obj, int count, int *vector)
     548  {
     549    if (obj->status == NULL)
     550      {
     551        const char *errmsg;
     552        int err;
     553  
     554        if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
     555  	return 0;
     556      }
     557  
     558    if (count > obj->count)
     559      {
     560        memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
     561        count = obj->count;
     562      }
     563  
     564    memcpy (vector, obj->status, count * sizeof (int));
     565  
     566    return 1;
     567  }
     568  
     569  /* Get process times of executed programs.  */
     570  
     571  int
     572  pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
     573  {
     574    if (obj->status == NULL)
     575      {
     576        const char *errmsg;
     577        int err;
     578  
     579        if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
     580  	return 0;
     581      }
     582  
     583    if (obj->time == NULL)
     584      return 0;
     585  
     586    if (count > obj->count)
     587      {
     588        memset (vector + obj->count, 0,
     589  	      (count - obj->count) * sizeof (struct pex_time));
     590        count = obj->count;
     591      }
     592  
     593    memcpy (vector, obj->time, count * sizeof (struct pex_time));
     594  
     595    return 1;
     596  }
     597  
     598  /* Free a pex_obj structure.  */
     599  
     600  void
     601  pex_free (struct pex_obj *obj)
     602  {
     603    /* Close pipe file descriptors corresponding to child's stdout and
     604       stderr so that the child does not hang trying to output something
     605       while we're waiting for it.  */
     606    if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
     607      obj->funcs->close (obj, obj->next_input);
     608    if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO)
     609      obj->funcs->close (obj, obj->stderr_pipe);
     610    if (obj->read_output != NULL)
     611      fclose (obj->read_output);
     612    if (obj->read_err != NULL)
     613      fclose (obj->read_err);
     614  
     615    /* If the caller forgot to wait for the children, we do it here, to
     616       avoid zombies.  */
     617    if (obj->status == NULL)
     618      {
     619        const char *errmsg;
     620        int err;
     621  
     622        obj->flags &= ~ PEX_RECORD_TIMES;
     623        pex_get_status_and_time (obj, 1, &errmsg, &err);
     624      }
     625  
     626    if (obj->next_input_name_allocated)
     627      free (obj->next_input_name);
     628    free (obj->children);
     629    free (obj->status);
     630    free (obj->time);
     631  
     632    if (obj->remove_count > 0)
     633      {
     634        int i;
     635  
     636        for (i = 0; i < obj->remove_count; ++i)
     637  	{
     638  	  remove (obj->remove[i]);
     639  	  free (obj->remove[i]);
     640  	}
     641        free (obj->remove);
     642      }
     643  
     644    if (obj->funcs->cleanup != NULL)
     645      obj->funcs->cleanup (obj);
     646  
     647    free (obj);
     648  }