Back to index

cell-binutils  2.17cvs20070401
pex-msdos.c
Go to the documentation of this file.
00001 /* Utilities to execute a program in a subprocess (possibly linked by pipes
00002    with other subprocesses), and wait for it.  Generic MSDOS specialization.
00003    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
00004    Free Software Foundation, Inc.
00005 
00006 This file is part of the libiberty library.
00007 Libiberty is free software; you can redistribute it and/or
00008 modify it under the terms of the GNU Library General Public
00009 License as published by the Free Software Foundation; either
00010 version 2 of the License, or (at your option) any later version.
00011 
00012 Libiberty is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 Library General Public License for more details.
00016 
00017 You should have received a copy of the GNU Library General Public
00018 License along with libiberty; see the file COPYING.LIB.  If not,
00019 write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00020 Boston, MA 02110-1301, USA.  */
00021 
00022 #include "pex-common.h"
00023 
00024 #include <stdio.h>
00025 #include <errno.h>
00026 #ifdef NEED_DECLARATION_ERRNO
00027 extern int errno;
00028 #endif
00029 #ifdef HAVE_STRING_H
00030 #include <string.h>
00031 #endif
00032 #ifdef HAVE_STDLIB_H
00033 #include <stdlib.h>
00034 #endif
00035 
00036 #include "safe-ctype.h"
00037 #include <process.h>
00038 
00039 /* The structure we keep in obj->sysdep.  */
00040 
00041 #define PEX_MSDOS_FILE_COUNT 3
00042 
00043 #define PEX_MSDOS_FD_OFFSET 10
00044 
00045 struct pex_msdos
00046 {
00047   /* An array of file names.  We refer to these using file descriptors
00048      of 10 + array index.  */
00049   const char *files[PEX_MSDOS_FILE_COUNT];
00050   /* Exit statuses of programs which have been run.  */
00051   int *statuses;
00052 };
00053 
00054 static int pex_msdos_open (struct pex_obj *, const char *, int);
00055 static int pex_msdos_open (struct pex_obj *, const char *, int);
00056 static int pex_msdos_fdindex (struct pex_msdos *, int);
00057 static long pex_msdos_exec_child (struct pex_obj *, int, const char *,
00058                               char * const *, char * const *,
00059                               int, int, int, int,
00060                               int, const char **, int *);
00061 static int pex_msdos_close (struct pex_obj *, int);
00062 static int pex_msdos_wait (struct pex_obj *, long, int *, struct pex_time *,
00063                         int, const char **, int *);
00064 static void pex_msdos_cleanup (struct pex_obj *);
00065 
00066 /* The list of functions we pass to the common routines.  */
00067 
00068 const struct pex_funcs funcs =
00069 {
00070   pex_msdos_open,
00071   pex_msdos_open,
00072   pex_msdos_exec_child,
00073   pex_msdos_close,
00074   pex_msdos_wait,
00075   NULL, /* pipe */
00076   NULL, /* fdopenr */
00077   NULL, /* fdopenw */
00078   pex_msdos_cleanup
00079 };
00080 
00081 /* Return a newly initialized pex_obj structure.  */
00082 
00083 struct pex_obj *
00084 pex_init (int flags, const char *pname, const char *tempbase)
00085 {
00086   struct pex_obj *ret;
00087   int i;
00088 
00089   /* MSDOS does not support pipes.  */
00090   flags &= ~ PEX_USE_PIPES;
00091 
00092   ret = pex_init_common (flags, pname, tempbase, funcs);
00093 
00094   ret->sysdep = XNEW (struct pex_msdos);
00095   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
00096     ret->files[i] = NULL;
00097   ret->statuses = NULL;
00098 
00099   return ret;
00100 }
00101 
00102 /* Open a file.  FIXME: We ignore the binary argument, since we have
00103    no way to handle it.  */
00104 
00105 static int
00106 pex_msdos_open (struct pex_obj *obj, const char *name,
00107               int binary ATTRIBUTE_UNUSED)
00108 {
00109   struct pex_msdos *ms;
00110   int i;
00111 
00112   ms = (struct pex_msdos *) obj->sysdep;
00113 
00114   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
00115     {
00116       if (ms->files[i] == NULL)
00117        {
00118          ms->files[i] = xstrdup (name);
00119          return i + PEX_MSDOS_FD_OFFSET;
00120        }
00121     }
00122 
00123   abort ();
00124 }
00125 
00126 /* Get the index into msdos->files associated with an open file
00127    descriptor.  */
00128 
00129 static int
00130 pex_msdos_fdindex (struct pex_msdos *ms, int fd)
00131 {
00132   fd -= PEX_MSDOS_FD_OFFSET;
00133   if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
00134     abort ();
00135   return fd;
00136 }
00137 
00138 
00139 /* Close a file.  */
00140 
00141 static int
00142 pex_msdos_close (struct pex_obj *obj, int fd)
00143 {
00144   struct pex_msdos *ms;
00145   int fdinex;
00146 
00147   ms = (struct pex_msdos *) obj->sysdep;
00148   fdindex = pe_msdos_fdindex (ms, fd);
00149   free (ms->files[fdindex]);
00150   ms->files[fdindex] = NULL;
00151 }
00152 
00153 /* Execute a child.  */
00154 
00155 static long
00156 pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
00157                     char * const * argv, char * const * env, int in, int out,
00158                     int toclose ATTRIBUTE_UNUSED,
00159                     int errdes ATTRIBUTE_UNUSED, const char **errmsg,
00160                     int *err)
00161 {
00162   struct pex_msdos *ms;
00163   char *temp_base;
00164   int temp_base_allocated;
00165   char *rf;
00166   int inindex;
00167   char *infile;
00168   int outindex;
00169   char *outfile;
00170   char *scmd;
00171   FILE *argfile;
00172   int i;
00173   int status;
00174 
00175   ms = (struct pex_msdos *) obj->sysdep;
00176 
00177   /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
00178      and PEX_STDERR_TO_STDOUT.  */
00179 
00180   temp_base = obj->temp_base;
00181   if (temp_base != NULL)
00182     temp_base_allocated = 0;
00183   else
00184     {
00185       temp_base = choose_temp_base ();
00186       temp_base_allocated = 1;
00187     }
00188 
00189   rf = concat (temp_base, ".gp", NULL);
00190 
00191   if (temp_base_allocated)
00192     free (temp_base);
00193 
00194   if (in == STDIN_FILE_NO)
00195     {
00196       inindex = -1;
00197       infile = "";
00198     }
00199   else
00200     {
00201       inindex = pex_msdos_fdindex (ms, in);
00202       infile = ms->files[inindex];
00203     }
00204 
00205   if (out == STDOUT_FILE_NO)
00206     {
00207       outindex = -1;
00208       outfile = "";
00209     }
00210   else
00211     {
00212       outindex = pex_msdos_fdindex (ms, out);
00213       outfile = ms->files[outindex];
00214     }
00215 
00216   scmd = XNEWVEC (char, strlen (program)
00217                 + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
00218                 + strlen (rf)
00219                 + strlen (infile)
00220                 + strlen (outfile)
00221                 + 10);
00222   sprintf (scmd, "%s%s @%s%s%s%s%s",
00223           program,
00224           (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
00225           rf,
00226           inindex != -1 ? " <" : "",
00227           infile,
00228           outindex != -1 ? " >" : "",
00229           outfile);
00230 
00231   argfile = fopen (rf, "w");
00232   if (argfile == NULL)
00233     {
00234       *err = errno;
00235       free (scmd);
00236       free (rf);
00237       *errmsg = "cannot open temporary command file";
00238       return -1;
00239     }
00240 
00241   for (i = 1; argv[i] != NULL; ++i)
00242     {
00243       char *p;
00244 
00245       for (p = argv[i]; *p != '\0'; ++p)
00246        {
00247          if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
00248            putc ('\\', argfile);
00249          putc (*p, argfile);
00250        }
00251       putc ('\n', argfile);
00252     }
00253 
00254   fclose (argfile);
00255 
00256   status = system (scmd);
00257 
00258   if (status == -1)
00259     {
00260       *err = errno;
00261       remove (rf);
00262       free (scmd);
00263       free (rf);
00264       *errmsg = "system";
00265       return -1;
00266     }
00267 
00268   remove (rf);
00269   free (scmd);
00270   free (rf);
00271 
00272   /* Save the exit status for later.  When we are called, obj->count
00273      is the number of children which have executed before this
00274      one.  */
00275   ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
00276   ms->statuses[obj->count] = status;
00277 
00278   return obj->count;
00279 }
00280 
00281 /* Wait for a child process to complete.  Actually the child process
00282    has already completed, and we just need to return the exit
00283    status.  */
00284 
00285 static int
00286 pex_msdos_wait (struct pex_obj *obj, long pid, int *status,
00287               struct pex_time *time, int done ATTRIBUTE_UNUSED,
00288               const char **errmsg ATTRIBUTE_UNUSED,
00289               int *err ATTRIBUTE_UNUSED)
00290 {
00291   struct pex_msdos *ms;
00292 
00293   ms = (struct pex_msdos *) obj->sysdep;
00294 
00295   if (time != NULL)
00296     memset (time, 0, sizeof *time);
00297 
00298   *status = ms->statuses[pid];
00299 
00300   return 0;
00301 }
00302 
00303 /* Clean up the pex_msdos structure.  */
00304 
00305 static void
00306 pex_msdos_cleanup (struct pex_obj  *obj)
00307 {
00308   struct pex_msdos *ms;
00309   int i;
00310 
00311   ms = (struct pex_msdos *) obj->sysdep;
00312   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
00313     if (msdos->files[i] != NULL)
00314       free (msdos->files[i]);
00315   if (msdos->statuses != NULL)
00316     free (msdos->statuses);
00317   free (msdos);
00318   obj->sysdep = NULL;
00319 }