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