xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/pex-msdos.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
198b9484cSchristos /* Utilities to execute a program in a subprocess (possibly linked by pipes
298b9484cSchristos    with other subprocesses), and wait for it.  Generic MSDOS specialization.
3*5173eb0aSchristos    Copyright (C) 1996-2024 Free Software Foundation, Inc.
498b9484cSchristos 
598b9484cSchristos This file is part of the libiberty library.
698b9484cSchristos Libiberty is free software; you can redistribute it and/or
798b9484cSchristos modify it under the terms of the GNU Library General Public
898b9484cSchristos License as published by the Free Software Foundation; either
998b9484cSchristos version 2 of the License, or (at your option) any later version.
1098b9484cSchristos 
1198b9484cSchristos Libiberty is distributed in the hope that it will be useful,
1298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1498b9484cSchristos Library General Public License for more details.
1598b9484cSchristos 
1698b9484cSchristos You should have received a copy of the GNU Library General Public
1798b9484cSchristos License along with libiberty; see the file COPYING.LIB.  If not,
1898b9484cSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
1998b9484cSchristos Boston, MA 02110-1301, USA.  */
2098b9484cSchristos 
2198b9484cSchristos #include "pex-common.h"
2298b9484cSchristos 
2398b9484cSchristos #include <stdio.h>
2498b9484cSchristos #include <errno.h>
2598b9484cSchristos #ifdef NEED_DECLARATION_ERRNO
2698b9484cSchristos extern int errno;
2798b9484cSchristos #endif
2898b9484cSchristos #ifdef HAVE_STRING_H
2998b9484cSchristos #include <string.h>
3098b9484cSchristos #endif
3198b9484cSchristos #ifdef HAVE_STDLIB_H
3298b9484cSchristos #include <stdlib.h>
3398b9484cSchristos #endif
3498b9484cSchristos 
3598b9484cSchristos #include "safe-ctype.h"
3698b9484cSchristos #include <process.h>
3798b9484cSchristos 
3898b9484cSchristos /* The structure we keep in obj->sysdep.  */
3998b9484cSchristos 
4098b9484cSchristos #define PEX_MSDOS_FILE_COUNT 3
4198b9484cSchristos 
4298b9484cSchristos #define PEX_MSDOS_FD_OFFSET 10
4398b9484cSchristos 
4498b9484cSchristos struct pex_msdos
4598b9484cSchristos {
4698b9484cSchristos   /* An array of file names.  We refer to these using file descriptors
4798b9484cSchristos      of 10 + array index.  */
4898b9484cSchristos   const char *files[PEX_MSDOS_FILE_COUNT];
4998b9484cSchristos   /* Exit statuses of programs which have been run.  */
5098b9484cSchristos   int *statuses;
5198b9484cSchristos };
5298b9484cSchristos 
5398b9484cSchristos static int pex_msdos_open (struct pex_obj *, const char *, int);
5498b9484cSchristos static int pex_msdos_open (struct pex_obj *, const char *, int);
5598b9484cSchristos static int pex_msdos_fdindex (struct pex_msdos *, int);
5698b9484cSchristos static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *,
5798b9484cSchristos 				  char * const *, char * const *,
5898b9484cSchristos 				  int, int, int, int,
5998b9484cSchristos 				  int, const char **, int *);
6098b9484cSchristos static int pex_msdos_close (struct pex_obj *, int);
6198b9484cSchristos static pid_t pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
6298b9484cSchristos 			   int, const char **, int *);
6398b9484cSchristos static void pex_msdos_cleanup (struct pex_obj *);
6498b9484cSchristos 
6598b9484cSchristos /* The list of functions we pass to the common routines.  */
6698b9484cSchristos 
6798b9484cSchristos const struct pex_funcs funcs =
6898b9484cSchristos {
6998b9484cSchristos   pex_msdos_open,
7098b9484cSchristos   pex_msdos_open,
7198b9484cSchristos   pex_msdos_exec_child,
7298b9484cSchristos   pex_msdos_close,
7398b9484cSchristos   pex_msdos_wait,
7498b9484cSchristos   NULL, /* pipe */
7598b9484cSchristos   NULL, /* fdopenr */
7698b9484cSchristos   NULL, /* fdopenw */
7798b9484cSchristos   pex_msdos_cleanup
7898b9484cSchristos };
7998b9484cSchristos 
8098b9484cSchristos /* Return a newly initialized pex_obj structure.  */
8198b9484cSchristos 
8298b9484cSchristos struct pex_obj *
8398b9484cSchristos pex_init (int flags, const char *pname, const char *tempbase)
8498b9484cSchristos {
8598b9484cSchristos   struct pex_obj *ret;
8698b9484cSchristos   int i;
8798b9484cSchristos 
8898b9484cSchristos   /* MSDOS does not support pipes.  */
8998b9484cSchristos   flags &= ~ PEX_USE_PIPES;
9098b9484cSchristos 
9198b9484cSchristos   ret = pex_init_common (flags, pname, tempbase, funcs);
9298b9484cSchristos 
9398b9484cSchristos   ret->sysdep = XNEW (struct pex_msdos);
9498b9484cSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
9598b9484cSchristos     ret->files[i] = NULL;
9698b9484cSchristos   ret->statuses = NULL;
9798b9484cSchristos 
9898b9484cSchristos   return ret;
9998b9484cSchristos }
10098b9484cSchristos 
10198b9484cSchristos /* Open a file.  FIXME: We ignore the binary argument, since we have
10298b9484cSchristos    no way to handle it.  */
10398b9484cSchristos 
10498b9484cSchristos static int
10598b9484cSchristos pex_msdos_open (struct pex_obj *obj, const char *name,
10698b9484cSchristos 		int binary ATTRIBUTE_UNUSED)
10798b9484cSchristos {
10898b9484cSchristos   struct pex_msdos *ms;
10998b9484cSchristos   int i;
11098b9484cSchristos 
11198b9484cSchristos   ms = (struct pex_msdos *) obj->sysdep;
11298b9484cSchristos 
11398b9484cSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
11498b9484cSchristos     {
11598b9484cSchristos       if (ms->files[i] == NULL)
11698b9484cSchristos 	{
11798b9484cSchristos 	  ms->files[i] = xstrdup (name);
11898b9484cSchristos 	  return i + PEX_MSDOS_FD_OFFSET;
11998b9484cSchristos 	}
12098b9484cSchristos     }
12198b9484cSchristos 
12298b9484cSchristos   abort ();
12398b9484cSchristos }
12498b9484cSchristos 
12598b9484cSchristos /* Get the index into msdos->files associated with an open file
12698b9484cSchristos    descriptor.  */
12798b9484cSchristos 
12898b9484cSchristos static int
12998b9484cSchristos pex_msdos_fdindex (struct pex_msdos *ms, int fd)
13098b9484cSchristos {
13198b9484cSchristos   fd -= PEX_MSDOS_FD_OFFSET;
13298b9484cSchristos   if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
13398b9484cSchristos     abort ();
13498b9484cSchristos   return fd;
13598b9484cSchristos }
13698b9484cSchristos 
13798b9484cSchristos 
13898b9484cSchristos /* Close a file.  */
13998b9484cSchristos 
14098b9484cSchristos static int
14198b9484cSchristos pex_msdos_close (struct pex_obj *obj, int fd)
14298b9484cSchristos {
14398b9484cSchristos   struct pex_msdos *ms;
14498b9484cSchristos   int fdinex;
14598b9484cSchristos 
14698b9484cSchristos   ms = (struct pex_msdos *) obj->sysdep;
14798b9484cSchristos   fdindex = pe_msdos_fdindex (ms, fd);
14898b9484cSchristos   free (ms->files[fdindex]);
14998b9484cSchristos   ms->files[fdindex] = NULL;
15098b9484cSchristos }
15198b9484cSchristos 
15298b9484cSchristos /* Execute a child.  */
15398b9484cSchristos 
15498b9484cSchristos static pid_t
15598b9484cSchristos pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
15698b9484cSchristos 		      char * const * argv, char * const * env, int in, int out,
15798b9484cSchristos 		      int toclose ATTRIBUTE_UNUSED,
15898b9484cSchristos 		      int errdes ATTRIBUTE_UNUSED, const char **errmsg,
15998b9484cSchristos 		      int *err)
16098b9484cSchristos {
16198b9484cSchristos   struct pex_msdos *ms;
16298b9484cSchristos   char *temp_base;
16398b9484cSchristos   int temp_base_allocated;
16498b9484cSchristos   char *rf;
16598b9484cSchristos   int inindex;
16698b9484cSchristos   char *infile;
16798b9484cSchristos   int outindex;
16898b9484cSchristos   char *outfile;
16998b9484cSchristos   char *scmd;
17098b9484cSchristos   FILE *argfile;
17198b9484cSchristos   int i;
17298b9484cSchristos   int status;
17398b9484cSchristos 
17498b9484cSchristos   ms = (struct pex_msdos *) obj->sysdep;
17598b9484cSchristos 
17698b9484cSchristos   /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
17798b9484cSchristos      and PEX_STDERR_TO_STDOUT.  */
17898b9484cSchristos 
17998b9484cSchristos   temp_base = obj->temp_base;
18098b9484cSchristos   if (temp_base != NULL)
18198b9484cSchristos     temp_base_allocated = 0;
18298b9484cSchristos   else
18398b9484cSchristos     {
18498b9484cSchristos       temp_base = choose_temp_base ();
18598b9484cSchristos       temp_base_allocated = 1;
18698b9484cSchristos     }
18798b9484cSchristos 
18898b9484cSchristos   rf = concat (temp_base, ".gp", NULL);
18998b9484cSchristos 
19098b9484cSchristos   if (temp_base_allocated)
19198b9484cSchristos     free (temp_base);
19298b9484cSchristos 
19398b9484cSchristos   if (in == STDIN_FILE_NO)
19498b9484cSchristos     {
19598b9484cSchristos       inindex = -1;
19698b9484cSchristos       infile = "";
19798b9484cSchristos     }
19898b9484cSchristos   else
19998b9484cSchristos     {
20098b9484cSchristos       inindex = pex_msdos_fdindex (ms, in);
20198b9484cSchristos       infile = ms->files[inindex];
20298b9484cSchristos     }
20398b9484cSchristos 
20498b9484cSchristos   if (out == STDOUT_FILE_NO)
20598b9484cSchristos     {
20698b9484cSchristos       outindex = -1;
20798b9484cSchristos       outfile = "";
20898b9484cSchristos     }
20998b9484cSchristos   else
21098b9484cSchristos     {
21198b9484cSchristos       outindex = pex_msdos_fdindex (ms, out);
21298b9484cSchristos       outfile = ms->files[outindex];
21398b9484cSchristos     }
21498b9484cSchristos 
21598b9484cSchristos   scmd = XNEWVEC (char, strlen (program)
21698b9484cSchristos 		  + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
21798b9484cSchristos 		  + strlen (rf)
21898b9484cSchristos 		  + strlen (infile)
21998b9484cSchristos 		  + strlen (outfile)
22098b9484cSchristos 		  + 10);
22198b9484cSchristos   sprintf (scmd, "%s%s @%s%s%s%s%s",
22298b9484cSchristos 	   program,
22398b9484cSchristos 	   (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
22498b9484cSchristos 	   rf,
22598b9484cSchristos 	   inindex != -1 ? " <" : "",
22698b9484cSchristos 	   infile,
22798b9484cSchristos 	   outindex != -1 ? " >" : "",
22898b9484cSchristos 	   outfile);
22998b9484cSchristos 
23098b9484cSchristos   argfile = fopen (rf, "w");
23198b9484cSchristos   if (argfile == NULL)
23298b9484cSchristos     {
23398b9484cSchristos       *err = errno;
23498b9484cSchristos       free (scmd);
23598b9484cSchristos       free (rf);
23698b9484cSchristos       *errmsg = "cannot open temporary command file";
23798b9484cSchristos       return (pid_t) -1;
23898b9484cSchristos     }
23998b9484cSchristos 
24098b9484cSchristos   for (i = 1; argv[i] != NULL; ++i)
24198b9484cSchristos     {
24298b9484cSchristos       char *p;
24398b9484cSchristos 
24498b9484cSchristos       for (p = argv[i]; *p != '\0'; ++p)
24598b9484cSchristos 	{
24698b9484cSchristos 	  if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
24798b9484cSchristos 	    putc ('\\', argfile);
24898b9484cSchristos 	  putc (*p, argfile);
24998b9484cSchristos 	}
25098b9484cSchristos       putc ('\n', argfile);
25198b9484cSchristos     }
25298b9484cSchristos 
25398b9484cSchristos   fclose (argfile);
25498b9484cSchristos 
25598b9484cSchristos   status = system (scmd);
25698b9484cSchristos 
25798b9484cSchristos   if (status == -1)
25898b9484cSchristos     {
25998b9484cSchristos       *err = errno;
26098b9484cSchristos       remove (rf);
26198b9484cSchristos       free (scmd);
26298b9484cSchristos       free (rf);
26398b9484cSchristos       *errmsg = "system";
26498b9484cSchristos       return (pid_t) -1;
26598b9484cSchristos     }
26698b9484cSchristos 
26798b9484cSchristos   remove (rf);
26898b9484cSchristos   free (scmd);
26998b9484cSchristos   free (rf);
27098b9484cSchristos 
27198b9484cSchristos   /* Save the exit status for later.  When we are called, obj->count
27298b9484cSchristos      is the number of children which have executed before this
27398b9484cSchristos      one.  */
27498b9484cSchristos   ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
27598b9484cSchristos   ms->statuses[obj->count] = status;
27698b9484cSchristos 
27798b9484cSchristos   return (pid_t) obj->count;
27898b9484cSchristos }
27998b9484cSchristos 
28098b9484cSchristos /* Wait for a child process to complete.  Actually the child process
28198b9484cSchristos    has already completed, and we just need to return the exit
28298b9484cSchristos    status.  */
28398b9484cSchristos 
28498b9484cSchristos static pid_t
28598b9484cSchristos pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status,
28698b9484cSchristos 		struct pex_time *time, int done ATTRIBUTE_UNUSED,
28798b9484cSchristos 		const char **errmsg ATTRIBUTE_UNUSED,
28898b9484cSchristos 		int *err ATTRIBUTE_UNUSED)
28998b9484cSchristos {
29098b9484cSchristos   struct pex_msdos *ms;
29198b9484cSchristos 
29298b9484cSchristos   ms = (struct pex_msdos *) obj->sysdep;
29398b9484cSchristos 
29498b9484cSchristos   if (time != NULL)
29598b9484cSchristos     memset (time, 0, sizeof *time);
29698b9484cSchristos 
29798b9484cSchristos   *status = ms->statuses[pid];
29898b9484cSchristos 
29998b9484cSchristos   return 0;
30098b9484cSchristos }
30198b9484cSchristos 
30298b9484cSchristos /* Clean up the pex_msdos structure.  */
30398b9484cSchristos 
30498b9484cSchristos static void
30598b9484cSchristos pex_msdos_cleanup (struct pex_obj  *obj)
30698b9484cSchristos {
30798b9484cSchristos   struct pex_msdos *ms;
30898b9484cSchristos   int i;
30998b9484cSchristos 
31098b9484cSchristos   ms = (struct pex_msdos *) obj->sysdep;
31198b9484cSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
31298b9484cSchristos     free (msdos->files[i]);
31398b9484cSchristos   free (msdos->statuses);
31498b9484cSchristos   free (msdos);
31598b9484cSchristos   obj->sysdep = NULL;
31698b9484cSchristos }
317