Home | History | Annotate | Line # | Download | only in libiberty
      1   1.1  christos /* Utilities to execute a program in a subprocess (possibly linked by pipes
      2   1.1  christos    with other subprocesses), and wait for it.  Generic MSDOS specialization.
      3  1.10  christos    Copyright (C) 1996-2024 Free Software Foundation, Inc.
      4   1.1  christos 
      5   1.1  christos This file is part of the libiberty library.
      6   1.1  christos Libiberty is free software; you can redistribute it and/or
      7   1.1  christos modify it under the terms of the GNU Library General Public
      8   1.1  christos License as published by the Free Software Foundation; either
      9   1.1  christos version 2 of the License, or (at your option) any later version.
     10   1.1  christos 
     11   1.1  christos Libiberty is distributed in the hope that it will be useful,
     12   1.1  christos but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   1.1  christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   1.1  christos Library General Public License for more details.
     15   1.1  christos 
     16   1.1  christos You should have received a copy of the GNU Library General Public
     17   1.1  christos License along with libiberty; see the file COPYING.LIB.  If not,
     18   1.1  christos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
     19   1.1  christos Boston, MA 02110-1301, USA.  */
     20   1.1  christos 
     21   1.1  christos #include "pex-common.h"
     22   1.1  christos 
     23   1.1  christos #include <stdio.h>
     24   1.1  christos #include <errno.h>
     25   1.1  christos #ifdef NEED_DECLARATION_ERRNO
     26   1.1  christos extern int errno;
     27   1.1  christos #endif
     28   1.1  christos #ifdef HAVE_STRING_H
     29   1.1  christos #include <string.h>
     30   1.1  christos #endif
     31   1.1  christos #ifdef HAVE_STDLIB_H
     32   1.1  christos #include <stdlib.h>
     33   1.1  christos #endif
     34   1.1  christos 
     35   1.1  christos #include "safe-ctype.h"
     36   1.1  christos #include <process.h>
     37   1.1  christos 
     38   1.1  christos /* The structure we keep in obj->sysdep.  */
     39   1.1  christos 
     40   1.1  christos #define PEX_MSDOS_FILE_COUNT 3
     41   1.1  christos 
     42   1.1  christos #define PEX_MSDOS_FD_OFFSET 10
     43   1.1  christos 
     44   1.1  christos struct pex_msdos
     45   1.1  christos {
     46   1.1  christos   /* An array of file names.  We refer to these using file descriptors
     47   1.1  christos      of 10 + array index.  */
     48   1.1  christos   const char *files[PEX_MSDOS_FILE_COUNT];
     49   1.1  christos   /* Exit statuses of programs which have been run.  */
     50   1.1  christos   int *statuses;
     51   1.1  christos };
     52   1.1  christos 
     53   1.1  christos static int pex_msdos_open (struct pex_obj *, const char *, int);
     54   1.1  christos static int pex_msdos_open (struct pex_obj *, const char *, int);
     55   1.1  christos static int pex_msdos_fdindex (struct pex_msdos *, int);
     56   1.1  christos static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *,
     57   1.1  christos 				  char * const *, char * const *,
     58   1.1  christos 				  int, int, int, int,
     59   1.1  christos 				  int, const char **, int *);
     60   1.1  christos static int pex_msdos_close (struct pex_obj *, int);
     61   1.1  christos static pid_t pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
     62   1.1  christos 			   int, const char **, int *);
     63   1.1  christos static void pex_msdos_cleanup (struct pex_obj *);
     64   1.1  christos 
     65   1.1  christos /* The list of functions we pass to the common routines.  */
     66   1.1  christos 
     67   1.1  christos const struct pex_funcs funcs =
     68   1.1  christos {
     69   1.1  christos   pex_msdos_open,
     70   1.1  christos   pex_msdos_open,
     71   1.1  christos   pex_msdos_exec_child,
     72   1.1  christos   pex_msdos_close,
     73   1.1  christos   pex_msdos_wait,
     74   1.1  christos   NULL, /* pipe */
     75   1.1  christos   NULL, /* fdopenr */
     76   1.1  christos   NULL, /* fdopenw */
     77   1.1  christos   pex_msdos_cleanup
     78   1.1  christos };
     79   1.1  christos 
     80   1.1  christos /* Return a newly initialized pex_obj structure.  */
     81   1.1  christos 
     82   1.1  christos struct pex_obj *
     83   1.1  christos pex_init (int flags, const char *pname, const char *tempbase)
     84   1.1  christos {
     85   1.1  christos   struct pex_obj *ret;
     86   1.1  christos   int i;
     87   1.1  christos 
     88   1.1  christos   /* MSDOS does not support pipes.  */
     89   1.1  christos   flags &= ~ PEX_USE_PIPES;
     90   1.1  christos 
     91   1.1  christos   ret = pex_init_common (flags, pname, tempbase, funcs);
     92   1.1  christos 
     93   1.1  christos   ret->sysdep = XNEW (struct pex_msdos);
     94   1.1  christos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
     95   1.1  christos     ret->files[i] = NULL;
     96   1.1  christos   ret->statuses = NULL;
     97   1.1  christos 
     98   1.1  christos   return ret;
     99   1.1  christos }
    100   1.1  christos 
    101   1.1  christos /* Open a file.  FIXME: We ignore the binary argument, since we have
    102   1.1  christos    no way to handle it.  */
    103   1.1  christos 
    104   1.1  christos static int
    105   1.1  christos pex_msdos_open (struct pex_obj *obj, const char *name,
    106   1.1  christos 		int binary ATTRIBUTE_UNUSED)
    107   1.1  christos {
    108   1.1  christos   struct pex_msdos *ms;
    109   1.1  christos   int i;
    110   1.1  christos 
    111   1.1  christos   ms = (struct pex_msdos *) obj->sysdep;
    112   1.1  christos 
    113   1.1  christos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
    114   1.1  christos     {
    115   1.1  christos       if (ms->files[i] == NULL)
    116   1.1  christos 	{
    117   1.1  christos 	  ms->files[i] = xstrdup (name);
    118   1.1  christos 	  return i + PEX_MSDOS_FD_OFFSET;
    119   1.1  christos 	}
    120   1.1  christos     }
    121   1.1  christos 
    122   1.1  christos   abort ();
    123   1.1  christos }
    124   1.1  christos 
    125   1.1  christos /* Get the index into msdos->files associated with an open file
    126   1.1  christos    descriptor.  */
    127   1.1  christos 
    128   1.1  christos static int
    129   1.1  christos pex_msdos_fdindex (struct pex_msdos *ms, int fd)
    130   1.1  christos {
    131   1.1  christos   fd -= PEX_MSDOS_FD_OFFSET;
    132   1.1  christos   if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
    133   1.1  christos     abort ();
    134   1.1  christos   return fd;
    135   1.1  christos }
    136   1.1  christos 
    137   1.1  christos 
    138   1.1  christos /* Close a file.  */
    139   1.1  christos 
    140   1.1  christos static int
    141   1.1  christos pex_msdos_close (struct pex_obj *obj, int fd)
    142   1.1  christos {
    143   1.1  christos   struct pex_msdos *ms;
    144   1.1  christos   int fdinex;
    145   1.1  christos 
    146   1.1  christos   ms = (struct pex_msdos *) obj->sysdep;
    147   1.1  christos   fdindex = pe_msdos_fdindex (ms, fd);
    148   1.1  christos   free (ms->files[fdindex]);
    149   1.1  christos   ms->files[fdindex] = NULL;
    150   1.1  christos }
    151   1.1  christos 
    152   1.1  christos /* Execute a child.  */
    153   1.1  christos 
    154   1.1  christos static pid_t
    155   1.1  christos pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
    156   1.1  christos 		      char * const * argv, char * const * env, int in, int out,
    157   1.1  christos 		      int toclose ATTRIBUTE_UNUSED,
    158   1.1  christos 		      int errdes ATTRIBUTE_UNUSED, const char **errmsg,
    159   1.1  christos 		      int *err)
    160   1.1  christos {
    161   1.1  christos   struct pex_msdos *ms;
    162   1.1  christos   char *temp_base;
    163   1.1  christos   int temp_base_allocated;
    164   1.1  christos   char *rf;
    165   1.1  christos   int inindex;
    166   1.1  christos   char *infile;
    167   1.1  christos   int outindex;
    168   1.1  christos   char *outfile;
    169   1.1  christos   char *scmd;
    170   1.1  christos   FILE *argfile;
    171   1.1  christos   int i;
    172   1.1  christos   int status;
    173   1.1  christos 
    174   1.1  christos   ms = (struct pex_msdos *) obj->sysdep;
    175   1.1  christos 
    176   1.1  christos   /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
    177   1.1  christos      and PEX_STDERR_TO_STDOUT.  */
    178   1.1  christos 
    179   1.1  christos   temp_base = obj->temp_base;
    180   1.1  christos   if (temp_base != NULL)
    181   1.1  christos     temp_base_allocated = 0;
    182   1.1  christos   else
    183   1.1  christos     {
    184   1.1  christos       temp_base = choose_temp_base ();
    185   1.1  christos       temp_base_allocated = 1;
    186   1.1  christos     }
    187   1.1  christos 
    188   1.1  christos   rf = concat (temp_base, ".gp", NULL);
    189   1.1  christos 
    190   1.1  christos   if (temp_base_allocated)
    191   1.1  christos     free (temp_base);
    192   1.1  christos 
    193   1.1  christos   if (in == STDIN_FILE_NO)
    194   1.1  christos     {
    195   1.1  christos       inindex = -1;
    196   1.1  christos       infile = "";
    197   1.1  christos     }
    198   1.1  christos   else
    199   1.1  christos     {
    200   1.1  christos       inindex = pex_msdos_fdindex (ms, in);
    201   1.1  christos       infile = ms->files[inindex];
    202   1.1  christos     }
    203   1.1  christos 
    204   1.1  christos   if (out == STDOUT_FILE_NO)
    205   1.1  christos     {
    206   1.1  christos       outindex = -1;
    207   1.1  christos       outfile = "";
    208   1.1  christos     }
    209   1.1  christos   else
    210   1.1  christos     {
    211   1.1  christos       outindex = pex_msdos_fdindex (ms, out);
    212   1.1  christos       outfile = ms->files[outindex];
    213   1.1  christos     }
    214   1.1  christos 
    215   1.1  christos   scmd = XNEWVEC (char, strlen (program)
    216   1.1  christos 		  + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
    217   1.1  christos 		  + strlen (rf)
    218   1.1  christos 		  + strlen (infile)
    219   1.1  christos 		  + strlen (outfile)
    220   1.1  christos 		  + 10);
    221   1.1  christos   sprintf (scmd, "%s%s @%s%s%s%s%s",
    222   1.1  christos 	   program,
    223   1.1  christos 	   (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
    224   1.1  christos 	   rf,
    225   1.1  christos 	   inindex != -1 ? " <" : "",
    226   1.1  christos 	   infile,
    227   1.1  christos 	   outindex != -1 ? " >" : "",
    228   1.1  christos 	   outfile);
    229   1.1  christos 
    230   1.1  christos   argfile = fopen (rf, "w");
    231   1.1  christos   if (argfile == NULL)
    232   1.1  christos     {
    233   1.1  christos       *err = errno;
    234   1.1  christos       free (scmd);
    235   1.1  christos       free (rf);
    236   1.1  christos       *errmsg = "cannot open temporary command file";
    237   1.1  christos       return (pid_t) -1;
    238   1.1  christos     }
    239   1.1  christos 
    240   1.1  christos   for (i = 1; argv[i] != NULL; ++i)
    241   1.1  christos     {
    242   1.1  christos       char *p;
    243   1.1  christos 
    244   1.1  christos       for (p = argv[i]; *p != '\0'; ++p)
    245   1.1  christos 	{
    246   1.1  christos 	  if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
    247   1.1  christos 	    putc ('\\', argfile);
    248   1.1  christos 	  putc (*p, argfile);
    249   1.1  christos 	}
    250   1.1  christos       putc ('\n', argfile);
    251   1.1  christos     }
    252   1.1  christos 
    253   1.1  christos   fclose (argfile);
    254   1.1  christos 
    255   1.1  christos   status = system (scmd);
    256   1.1  christos 
    257   1.1  christos   if (status == -1)
    258   1.1  christos     {
    259   1.1  christos       *err = errno;
    260   1.1  christos       remove (rf);
    261   1.1  christos       free (scmd);
    262   1.1  christos       free (rf);
    263   1.1  christos       *errmsg = "system";
    264   1.1  christos       return (pid_t) -1;
    265   1.1  christos     }
    266   1.1  christos 
    267   1.1  christos   remove (rf);
    268   1.1  christos   free (scmd);
    269   1.1  christos   free (rf);
    270   1.1  christos 
    271   1.1  christos   /* Save the exit status for later.  When we are called, obj->count
    272   1.1  christos      is the number of children which have executed before this
    273   1.1  christos      one.  */
    274   1.1  christos   ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
    275   1.1  christos   ms->statuses[obj->count] = status;
    276   1.1  christos 
    277   1.1  christos   return (pid_t) obj->count;
    278   1.1  christos }
    279   1.1  christos 
    280   1.1  christos /* Wait for a child process to complete.  Actually the child process
    281   1.1  christos    has already completed, and we just need to return the exit
    282   1.1  christos    status.  */
    283   1.1  christos 
    284   1.1  christos static pid_t
    285   1.1  christos pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status,
    286   1.1  christos 		struct pex_time *time, int done ATTRIBUTE_UNUSED,
    287   1.1  christos 		const char **errmsg ATTRIBUTE_UNUSED,
    288   1.1  christos 		int *err ATTRIBUTE_UNUSED)
    289   1.1  christos {
    290   1.1  christos   struct pex_msdos *ms;
    291   1.1  christos 
    292   1.1  christos   ms = (struct pex_msdos *) obj->sysdep;
    293   1.1  christos 
    294   1.1  christos   if (time != NULL)
    295   1.1  christos     memset (time, 0, sizeof *time);
    296   1.1  christos 
    297   1.1  christos   *status = ms->statuses[pid];
    298   1.1  christos 
    299   1.1  christos   return 0;
    300   1.1  christos }
    301   1.1  christos 
    302   1.1  christos /* Clean up the pex_msdos structure.  */
    303   1.1  christos 
    304   1.1  christos static void
    305   1.1  christos pex_msdos_cleanup (struct pex_obj  *obj)
    306   1.1  christos {
    307   1.1  christos   struct pex_msdos *ms;
    308   1.1  christos   int i;
    309   1.1  christos 
    310   1.1  christos   ms = (struct pex_msdos *) obj->sysdep;
    311   1.1  christos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
    312   1.1  christos     free (msdos->files[i]);
    313   1.1  christos   free (msdos->statuses);
    314   1.1  christos   free (msdos);
    315   1.1  christos   obj->sysdep = NULL;
    316   1.1  christos }
    317