xref: /openbsd-src/gnu/usr.bin/cvs/windows-NT/run.c (revision c26070a5a87b8b908afc23542b77914040a7b4e9)
11e72d8d2Sderaadt /* run.c --- routines for executing subprocesses under Windows NT.
21e72d8d2Sderaadt 
31e72d8d2Sderaadt    This file is part of GNU CVS.
41e72d8d2Sderaadt 
51e72d8d2Sderaadt    GNU CVS is free software; you can redistribute it and/or modify it
61e72d8d2Sderaadt    under the terms of the GNU General Public License as published by the
71e72d8d2Sderaadt    Free Software Foundation; either version 2, or (at your option) any
81e72d8d2Sderaadt    later version.
91e72d8d2Sderaadt 
101e72d8d2Sderaadt    This program is distributed in the hope that it will be useful,
111e72d8d2Sderaadt    but WITHOUT ANY WARRANTY; without even the implied warranty of
121e72d8d2Sderaadt    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
131e72d8d2Sderaadt    GNU General Public License for more details.
141e72d8d2Sderaadt 
151e72d8d2Sderaadt    You should have received a copy of the GNU General Public License
161e72d8d2Sderaadt    along with this program; if not, write to the Free Software
171e72d8d2Sderaadt    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
181e72d8d2Sderaadt 
191e72d8d2Sderaadt #include "cvs.h"
201e72d8d2Sderaadt 
211e72d8d2Sderaadt #define WIN32_LEAN_AND_MEAN
221e72d8d2Sderaadt #include <windows.h>
231e72d8d2Sderaadt #include <stdlib.h>
241e72d8d2Sderaadt #include <process.h>
251e72d8d2Sderaadt #include <errno.h>
261e72d8d2Sderaadt #include <io.h>
271e72d8d2Sderaadt #include <fcntl.h>
281e72d8d2Sderaadt 
291e72d8d2Sderaadt #ifdef HAVE_VPRINTF
301e72d8d2Sderaadt #if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
311e72d8d2Sderaadt #include <stdarg.h>
321e72d8d2Sderaadt #define VA_START(args, lastarg) va_start(args, lastarg)
331e72d8d2Sderaadt #else
341e72d8d2Sderaadt #include <varargs.h>
351e72d8d2Sderaadt #define VA_START(args, lastarg) va_start(args)
361e72d8d2Sderaadt #endif
371e72d8d2Sderaadt #else
381e72d8d2Sderaadt #define va_alist a1, a2, a3, a4, a5, a6, a7, a8
391e72d8d2Sderaadt #define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
401e72d8d2Sderaadt #endif
411e72d8d2Sderaadt 
421e72d8d2Sderaadt static void run_add_arg PROTO((const char *s));
431e72d8d2Sderaadt static void run_init_prog PROTO((void));
441e72d8d2Sderaadt 
451e72d8d2Sderaadt extern char *strtok ();
461e72d8d2Sderaadt 
471e72d8d2Sderaadt /*
481e72d8d2Sderaadt  * To exec a program under CVS, first call run_setup() to setup any initial
491e72d8d2Sderaadt  * arguments.  The options to run_setup are essentially like printf(). The
501e72d8d2Sderaadt  * arguments will be parsed into whitespace separated words and added to the
511e72d8d2Sderaadt  * global run_argv list.
521e72d8d2Sderaadt  *
531e72d8d2Sderaadt  * Then, optionally call run_arg() for each additional argument that you'd like
541e72d8d2Sderaadt  * to pass to the executed program.
551e72d8d2Sderaadt  *
561e72d8d2Sderaadt  * Finally, call run_exec() to execute the program with the specified arguments.
571e72d8d2Sderaadt  * The execvp() syscall will be used, so that the PATH is searched correctly.
581e72d8d2Sderaadt  * File redirections can be performed in the call to run_exec().
591e72d8d2Sderaadt  */
601e72d8d2Sderaadt static char *run_prog;
611e72d8d2Sderaadt static char **run_argv;
621e72d8d2Sderaadt static int run_argc;
631e72d8d2Sderaadt static int run_argc_allocated;
641e72d8d2Sderaadt 
651e72d8d2Sderaadt /* VARARGS */
661e72d8d2Sderaadt #if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__))
671e72d8d2Sderaadt void
681e72d8d2Sderaadt run_setup (const char *fmt,...)
691e72d8d2Sderaadt #else
701e72d8d2Sderaadt void
711e72d8d2Sderaadt run_setup (fmt, va_alist)
721e72d8d2Sderaadt     char *fmt;
731e72d8d2Sderaadt     va_dcl
741e72d8d2Sderaadt #endif
751e72d8d2Sderaadt {
761e72d8d2Sderaadt #ifdef HAVE_VPRINTF
771e72d8d2Sderaadt     va_list args;
781e72d8d2Sderaadt #endif
791e72d8d2Sderaadt     char *cp;
801e72d8d2Sderaadt     int i;
811e72d8d2Sderaadt 
821e72d8d2Sderaadt     run_init_prog ();
831e72d8d2Sderaadt 
841e72d8d2Sderaadt     /* clean out any malloc'ed values from run_argv */
851e72d8d2Sderaadt     for (i = 0; i < run_argc; i++)
861e72d8d2Sderaadt     {
871e72d8d2Sderaadt 	if (run_argv[i])
881e72d8d2Sderaadt 	{
891e72d8d2Sderaadt 	    free (run_argv[i]);
901e72d8d2Sderaadt 	    run_argv[i] = (char *) 0;
911e72d8d2Sderaadt 	}
921e72d8d2Sderaadt     }
931e72d8d2Sderaadt     run_argc = 0;
941e72d8d2Sderaadt 
951e72d8d2Sderaadt     /* process the varargs into run_prog */
961e72d8d2Sderaadt #ifdef HAVE_VPRINTF
971e72d8d2Sderaadt     VA_START (args, fmt);
981e72d8d2Sderaadt     (void) vsprintf (run_prog, fmt, args);
991e72d8d2Sderaadt     va_end (args);
1001e72d8d2Sderaadt #else
1011e72d8d2Sderaadt     (void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
1021e72d8d2Sderaadt #endif
1031e72d8d2Sderaadt 
1041e72d8d2Sderaadt     /* put each word into run_argv, allocating it as we go */
1051e72d8d2Sderaadt     for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
1061e72d8d2Sderaadt 	run_add_arg (cp);
1071e72d8d2Sderaadt }
1081e72d8d2Sderaadt 
1091e72d8d2Sderaadt void
1101e72d8d2Sderaadt run_arg (s)
1111e72d8d2Sderaadt     const char *s;
1121e72d8d2Sderaadt {
1131e72d8d2Sderaadt     run_add_arg (s);
1141e72d8d2Sderaadt }
1151e72d8d2Sderaadt 
1161e72d8d2Sderaadt /* VARARGS */
1171e72d8d2Sderaadt #if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__))
1181e72d8d2Sderaadt void
1191e72d8d2Sderaadt run_args (const char *fmt,...)
1201e72d8d2Sderaadt #else
1211e72d8d2Sderaadt void
1221e72d8d2Sderaadt run_args (fmt, va_alist)
1231e72d8d2Sderaadt     char *fmt;
1241e72d8d2Sderaadt     va_dcl
1251e72d8d2Sderaadt #endif
1261e72d8d2Sderaadt {
1271e72d8d2Sderaadt #ifdef HAVE_VPRINTF
1281e72d8d2Sderaadt     va_list args;
1291e72d8d2Sderaadt #endif
1301e72d8d2Sderaadt 
1311e72d8d2Sderaadt     run_init_prog ();
1321e72d8d2Sderaadt 
1331e72d8d2Sderaadt     /* process the varargs into run_prog */
1341e72d8d2Sderaadt #ifdef HAVE_VPRINTF
1351e72d8d2Sderaadt     VA_START (args, fmt);
1361e72d8d2Sderaadt     (void) vsprintf (run_prog, fmt, args);
1371e72d8d2Sderaadt     va_end (args);
1381e72d8d2Sderaadt #else
1391e72d8d2Sderaadt     (void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
1401e72d8d2Sderaadt #endif
1411e72d8d2Sderaadt 
1421e72d8d2Sderaadt     /* and add the (single) argument to the run_argv list */
1431e72d8d2Sderaadt     run_add_arg (run_prog);
1441e72d8d2Sderaadt }
1451e72d8d2Sderaadt 
1461e72d8d2Sderaadt /* Return a malloc'd copy of s, with double quotes around it.  */
1471e72d8d2Sderaadt static char *
1481e72d8d2Sderaadt quote (const char *s)
1491e72d8d2Sderaadt {
1501e72d8d2Sderaadt     size_t s_len = strlen (s);
1511e72d8d2Sderaadt     char *copy = xmalloc (s_len + 3);
1521e72d8d2Sderaadt     char *scan = copy;
1531e72d8d2Sderaadt 
1541e72d8d2Sderaadt     *scan++ = '"';
1551e72d8d2Sderaadt     strcpy (scan, s);
1561e72d8d2Sderaadt     scan += s_len;
1571e72d8d2Sderaadt     *scan++ = '"';
1581e72d8d2Sderaadt     *scan++ = '\0';
1591e72d8d2Sderaadt 
1601e72d8d2Sderaadt     return copy;
1611e72d8d2Sderaadt }
1621e72d8d2Sderaadt 
1631e72d8d2Sderaadt static void
1641e72d8d2Sderaadt run_add_arg (s)
1651e72d8d2Sderaadt     const char *s;
1661e72d8d2Sderaadt {
1671e72d8d2Sderaadt     /* allocate more argv entries if we've run out */
1681e72d8d2Sderaadt     if (run_argc >= run_argc_allocated)
1691e72d8d2Sderaadt     {
1701e72d8d2Sderaadt 	run_argc_allocated += 50;
1711e72d8d2Sderaadt 	run_argv = (char **) xrealloc ((char *) run_argv,
1721e72d8d2Sderaadt 				     run_argc_allocated * sizeof (char **));
1731e72d8d2Sderaadt     }
1741e72d8d2Sderaadt 
1751e72d8d2Sderaadt     if (s)
1761e72d8d2Sderaadt     {
1771e72d8d2Sderaadt 	run_argv[run_argc] = (run_argc ? quote (s) : xstrdup (s));
1781e72d8d2Sderaadt 	run_argc++;
1791e72d8d2Sderaadt     }
1801e72d8d2Sderaadt     else
1811e72d8d2Sderaadt 	run_argv[run_argc] = (char *) 0;	/* not post-incremented on purpose! */
1821e72d8d2Sderaadt }
1831e72d8d2Sderaadt 
1841e72d8d2Sderaadt static void
1851e72d8d2Sderaadt run_init_prog ()
1861e72d8d2Sderaadt {
1871e72d8d2Sderaadt     /* make sure that run_prog is allocated once */
1881e72d8d2Sderaadt     if (run_prog == (char *) 0)
1891e72d8d2Sderaadt 	run_prog = xmalloc (10 * 1024);	/* 10K of args for _setup and _arg */
1901e72d8d2Sderaadt }
1911e72d8d2Sderaadt 
1921e72d8d2Sderaadt 
1931e72d8d2Sderaadt int
1941e72d8d2Sderaadt run_exec (stin, stout, sterr, flags)
1951e72d8d2Sderaadt     char *stin;
1961e72d8d2Sderaadt     char *stout;
1971e72d8d2Sderaadt     char *sterr;
1981e72d8d2Sderaadt     int flags;
1991e72d8d2Sderaadt {
2001e72d8d2Sderaadt     int shin, shout, sherr;
2011e72d8d2Sderaadt     int sain, saout, saerr;	/* saved handles */
2021e72d8d2Sderaadt     int mode_out, mode_err;
2031e72d8d2Sderaadt     int status = -1;
2041e72d8d2Sderaadt     int rerrno = 0;
2051e72d8d2Sderaadt     int rval   = -1;
2061e72d8d2Sderaadt     void (*old_sigint) (int);
2071e72d8d2Sderaadt 
2081e72d8d2Sderaadt     if (trace)			/* if in trace mode */
2091e72d8d2Sderaadt     {
2101e72d8d2Sderaadt 	(void) fprintf (stderr, "-> system(");
2111e72d8d2Sderaadt 	run_print (stderr);
2121e72d8d2Sderaadt 	(void) fprintf (stderr, ")\n");
2131e72d8d2Sderaadt     }
2141e72d8d2Sderaadt     if (noexec && (flags & RUN_REALLY) == 0) /* if in noexec mode */
2151e72d8d2Sderaadt 	return (0);
2161e72d8d2Sderaadt 
2171e72d8d2Sderaadt     /*
2181e72d8d2Sderaadt      * start the engine and take off
2191e72d8d2Sderaadt      */
2201e72d8d2Sderaadt 
2211e72d8d2Sderaadt     /* make sure that we are null terminated, since we didn't calloc */
2221e72d8d2Sderaadt     run_add_arg ((char *) 0);
2231e72d8d2Sderaadt 
2241e72d8d2Sderaadt     /* setup default file descriptor numbers */
2251e72d8d2Sderaadt     shin = 0;
2261e72d8d2Sderaadt     shout = 1;
2271e72d8d2Sderaadt     sherr = 2;
2281e72d8d2Sderaadt 
2291e72d8d2Sderaadt     /* set the file modes for stdout and stderr */
2301e72d8d2Sderaadt     mode_out = mode_err = O_WRONLY | O_CREAT;
2311e72d8d2Sderaadt     mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
2321e72d8d2Sderaadt     mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
2331e72d8d2Sderaadt 
2341e72d8d2Sderaadt     /* open the files as required, shXX are shadows of stdin... */
2351e72d8d2Sderaadt     if (stin && (shin = open (stin, O_RDONLY)) == -1)
2361e72d8d2Sderaadt     {
2371e72d8d2Sderaadt 	rerrno = errno;
2381e72d8d2Sderaadt 	error (0, errno, "cannot open %s for reading (prog %s)",
2391e72d8d2Sderaadt 	       stin, run_argv[0]);
2401e72d8d2Sderaadt 	goto out0;
2411e72d8d2Sderaadt     }
2421e72d8d2Sderaadt     if (stout && (shout = open (stout, mode_out, 0666)) == -1)
2431e72d8d2Sderaadt     {
2441e72d8d2Sderaadt 	rerrno = errno;
2451e72d8d2Sderaadt 	error (0, errno, "cannot open %s for writing (prog %s)",
2461e72d8d2Sderaadt 	       stout, run_argv[0]);
2471e72d8d2Sderaadt 	goto out1;
2481e72d8d2Sderaadt     }
2491e72d8d2Sderaadt     if (sterr && (flags & RUN_COMBINED) == 0)
2501e72d8d2Sderaadt     {
2511e72d8d2Sderaadt 	if ((sherr = open (sterr, mode_err, 0666)) == -1)
2521e72d8d2Sderaadt 	{
2531e72d8d2Sderaadt 	    rerrno = errno;
2541e72d8d2Sderaadt 	    error (0, errno, "cannot open %s for writing (prog %s)",
2551e72d8d2Sderaadt 		   sterr, run_argv[0]);
2561e72d8d2Sderaadt 	    goto out2;
2571e72d8d2Sderaadt 	}
2581e72d8d2Sderaadt     }
2591e72d8d2Sderaadt     /* now save the standard handles */
2601e72d8d2Sderaadt     sain = saout = saerr = -1;
2611e72d8d2Sderaadt     sain  = dup( 0); /* dup stdin  */
2621e72d8d2Sderaadt     saout = dup( 1); /* dup stdout */
2631e72d8d2Sderaadt     saerr = dup( 2); /* dup stderr */
2641e72d8d2Sderaadt 
2651e72d8d2Sderaadt     /* the new handles will be dup'd to the standard handles
2661e72d8d2Sderaadt      * for the spawn.
2671e72d8d2Sderaadt      */
2681e72d8d2Sderaadt 
2691e72d8d2Sderaadt     if (shin != 0)
2701e72d8d2Sderaadt       {
2711e72d8d2Sderaadt 	(void) dup2 (shin, 0);
2721e72d8d2Sderaadt 	(void) close (shin);
2731e72d8d2Sderaadt       }
2741e72d8d2Sderaadt     if (shout != 1)
2751e72d8d2Sderaadt       {
2761e72d8d2Sderaadt 	(void) dup2 (shout, 1);
2771e72d8d2Sderaadt 	(void) close (shout);
2781e72d8d2Sderaadt       }
2791e72d8d2Sderaadt     if (flags & RUN_COMBINED)
2801e72d8d2Sderaadt       (void) dup2 (1, 2);
2811e72d8d2Sderaadt     else if (sherr != 2)
2821e72d8d2Sderaadt       {
2831e72d8d2Sderaadt 	(void) dup2 (sherr, 2);
2841e72d8d2Sderaadt 	(void) close (sherr);
2851e72d8d2Sderaadt       }
2861e72d8d2Sderaadt 
2871e72d8d2Sderaadt     /* Ignore signals while we're running this.  */
2881e72d8d2Sderaadt     old_sigint = signal (SIGINT, SIG_IGN);
2891e72d8d2Sderaadt 
2901e72d8d2Sderaadt     /* dup'ing is done.  try to run it now */
2911e72d8d2Sderaadt     rval = spawnvp ( P_WAIT, run_argv[0], run_argv);
2921e72d8d2Sderaadt 
2931e72d8d2Sderaadt     /* Restore signal handling.  */
2941e72d8d2Sderaadt     signal (SIGINT, old_sigint);
2951e72d8d2Sderaadt 
2961e72d8d2Sderaadt     /* restore the original file handles   */
2971e72d8d2Sderaadt     if (sain  != -1) {
2981e72d8d2Sderaadt       (void) dup2( sain, 0);	/* re-connect stdin  */
2991e72d8d2Sderaadt       (void) close( sain);
3001e72d8d2Sderaadt     }
3011e72d8d2Sderaadt     if (saout != -1) {
3021e72d8d2Sderaadt       (void) dup2( saout, 1);	/* re-connect stdout */
3031e72d8d2Sderaadt       (void) close( saout);
3041e72d8d2Sderaadt     }
3051e72d8d2Sderaadt     if (saerr != -1) {
3061e72d8d2Sderaadt       (void) dup2( saerr, 2);	/* re-connect stderr */
3071e72d8d2Sderaadt       (void) close( saerr);
3081e72d8d2Sderaadt     }
3091e72d8d2Sderaadt 
3101e72d8d2Sderaadt     /* Recognize the return code for an interrupted subprocess.  */
3111e72d8d2Sderaadt     if (rval == CONTROL_C_EXIT)
3121e72d8d2Sderaadt         return 2;
3131e72d8d2Sderaadt     else
3141e72d8d2Sderaadt         return rval;		/* end, if all went coorect */
3151e72d8d2Sderaadt 
3161e72d8d2Sderaadt     /* error cases */
3171e72d8d2Sderaadt     /* cleanup the open file descriptors */
3181e72d8d2Sderaadt   out2:
3191e72d8d2Sderaadt     if (stout)
3201e72d8d2Sderaadt 	(void) close (shout);
3211e72d8d2Sderaadt   out1:
3221e72d8d2Sderaadt     if (stin)
3231e72d8d2Sderaadt 	(void) close (shin);
3241e72d8d2Sderaadt 
3251e72d8d2Sderaadt   out0:
3261e72d8d2Sderaadt     if (rerrno)
3271e72d8d2Sderaadt 	errno = rerrno;
3281e72d8d2Sderaadt     return (status);
3291e72d8d2Sderaadt }
3301e72d8d2Sderaadt 
3311e72d8d2Sderaadt 
3321e72d8d2Sderaadt void
3331e72d8d2Sderaadt run_print (fp)
3341e72d8d2Sderaadt     FILE *fp;
3351e72d8d2Sderaadt {
3361e72d8d2Sderaadt     int i;
3371e72d8d2Sderaadt 
3381e72d8d2Sderaadt     for (i = 0; i < run_argc; i++)
3391e72d8d2Sderaadt     {
3401e72d8d2Sderaadt 	(void) fprintf (fp, "'%s'", run_argv[i]);
3411e72d8d2Sderaadt 	if (i != run_argc - 1)
3421e72d8d2Sderaadt 	    (void) fprintf (fp, " ");
3431e72d8d2Sderaadt     }
3441e72d8d2Sderaadt }
3451e72d8d2Sderaadt 
3461e72d8d2Sderaadt static char *
3471e72d8d2Sderaadt requote (const char *cmd)
3481e72d8d2Sderaadt {
3491e72d8d2Sderaadt     char *requoted = xmalloc (strlen (cmd) + 1);
3501e72d8d2Sderaadt     char *p = requoted;
3511e72d8d2Sderaadt 
3521e72d8d2Sderaadt     strcpy (requoted, cmd);
3531e72d8d2Sderaadt     while ((p = strchr (p, '\'')) != NULL)
3541e72d8d2Sderaadt     {
3551e72d8d2Sderaadt         *p++ = '"';
3561e72d8d2Sderaadt     }
3571e72d8d2Sderaadt 
3581e72d8d2Sderaadt     return requoted;
3591e72d8d2Sderaadt }
3601e72d8d2Sderaadt 
3611e72d8d2Sderaadt FILE *
362*c26070a5Stholo run_popen (cmd, mode)
3631e72d8d2Sderaadt     const char *cmd;
3641e72d8d2Sderaadt     const char *mode;
3651e72d8d2Sderaadt {
3661e72d8d2Sderaadt     if (trace)
3671e72d8d2Sderaadt #ifdef SERVER_SUPPORT
368*c26070a5Stholo 	(void) fprintf (stderr, "%c-> run_popen(%s,%s)\n",
3691e72d8d2Sderaadt 			(server_active) ? 'S' : ' ', cmd, mode);
3701e72d8d2Sderaadt #else
371*c26070a5Stholo 	(void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode);
3721e72d8d2Sderaadt #endif
3731e72d8d2Sderaadt     if (noexec)
3741e72d8d2Sderaadt 	return (NULL);
3751e72d8d2Sderaadt 
3761e72d8d2Sderaadt     /* If the command string uses single quotes, turn them into
3771e72d8d2Sderaadt        double quotes.  */
3781e72d8d2Sderaadt     {
3791e72d8d2Sderaadt         char *requoted = requote (cmd);
3801e72d8d2Sderaadt 	FILE *result = popen (requoted, mode);
3811e72d8d2Sderaadt 	free (requoted);
3821e72d8d2Sderaadt 	return result;
3831e72d8d2Sderaadt     }
3841e72d8d2Sderaadt }
3851e72d8d2Sderaadt 
3861e72d8d2Sderaadt 
3871e72d8d2Sderaadt /* Running children with pipes connected to them.  */
3881e72d8d2Sderaadt 
3891e72d8d2Sderaadt /* It's kind of ridiculous the hoops we're jumping through to get
3901e72d8d2Sderaadt    this working.  _pipe and dup2 and _spawnmumble work just fine, except
3911e72d8d2Sderaadt    that the child inherits a file descriptor for the writing end of the
3921e72d8d2Sderaadt    pipe, and thus will never receive end-of-file on it.  If you know of
3931e72d8d2Sderaadt    a better way to implement the piped_child function, please let me know.
3941e72d8d2Sderaadt 
3951e72d8d2Sderaadt    You can apparently specify _O_NOINHERIT when you open a file, but there's
3961e72d8d2Sderaadt    apparently no fcntl function, so you can't change that bit on an existing
3971e72d8d2Sderaadt    file descriptor.  */
3981e72d8d2Sderaadt 
3991e72d8d2Sderaadt /* Given a handle, make an inheritable duplicate of it, and close
4001e72d8d2Sderaadt    the original.  */
4011e72d8d2Sderaadt static HANDLE
4021e72d8d2Sderaadt inheritable (HANDLE in)
4031e72d8d2Sderaadt {
4041e72d8d2Sderaadt     HANDLE copy;
4051e72d8d2Sderaadt     HANDLE self = GetCurrentProcess ();
4061e72d8d2Sderaadt 
4071e72d8d2Sderaadt     if (! DuplicateHandle (self, in, self, &copy,
4081e72d8d2Sderaadt 			   0, 1 /* fInherit */,
4091e72d8d2Sderaadt 			   DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
4101e72d8d2Sderaadt         return INVALID_HANDLE_VALUE;
4111e72d8d2Sderaadt 
4121e72d8d2Sderaadt     return copy;
4131e72d8d2Sderaadt }
4141e72d8d2Sderaadt 
4151e72d8d2Sderaadt 
4161e72d8d2Sderaadt /* Initialize the SECURITY_ATTRIBUTES structure *LPSA.  Set its
4171e72d8d2Sderaadt    bInheritHandle flag according to INHERIT.  */
4181e72d8d2Sderaadt static void
4191e72d8d2Sderaadt init_sa (LPSECURITY_ATTRIBUTES lpsa, BOOL inherit)
4201e72d8d2Sderaadt {
4211e72d8d2Sderaadt   lpsa->nLength = sizeof(*lpsa);
4221e72d8d2Sderaadt   lpsa->bInheritHandle = inherit;
4231e72d8d2Sderaadt   lpsa->lpSecurityDescriptor = NULL;
4241e72d8d2Sderaadt }
4251e72d8d2Sderaadt 
4261e72d8d2Sderaadt 
4271e72d8d2Sderaadt enum inherit_pipe { inherit_reading, inherit_writing };
4281e72d8d2Sderaadt 
4291e72d8d2Sderaadt /* Create a pipe.  Set READWRITE[0] to its reading end, and
4301e72d8d2Sderaadt    READWRITE[1] to its writing end.  If END is inherit_reading,
4311e72d8d2Sderaadt    make the only the handle for the pipe's reading end inheritable.
4321e72d8d2Sderaadt    If END is inherit_writing, make only the handle for the pipe's
4331e72d8d2Sderaadt    writing end inheritable.  Return 0 if we succeed, -1 if we fail.
4341e72d8d2Sderaadt 
4351e72d8d2Sderaadt    Why does inheritability matter?  Consider the case of a
4361e72d8d2Sderaadt    pipe carrying data from the parent process to the child
4371e72d8d2Sderaadt    process.  The child wants to read data from the parent until
4381e72d8d2Sderaadt    it reaches the EOF.  Now, the only way to send an EOF on a pipe
4391e72d8d2Sderaadt    is to close all the handles to its writing end.  Obviously, the
4401e72d8d2Sderaadt    parent has a handle to the writing end when it creates the child.
4411e72d8d2Sderaadt    If the child inherits this handle, then it will never close it
4421e72d8d2Sderaadt    (the child has no idea it's inherited it), and will thus never
4431e72d8d2Sderaadt    receive an EOF on the pipe because it's holding a handle
4441e72d8d2Sderaadt    to it.
4451e72d8d2Sderaadt 
4461e72d8d2Sderaadt    In Unix, the child process closes the pipe ends before it execs.
4471e72d8d2Sderaadt    In Windows NT, you create the pipe with uninheritable handles, and then use
4481e72d8d2Sderaadt    DuplicateHandle to make the appropriate ends inheritable.  */
4491e72d8d2Sderaadt 
4501e72d8d2Sderaadt static int
4511e72d8d2Sderaadt my_pipe (HANDLE *readwrite, enum inherit_pipe end)
4521e72d8d2Sderaadt {
4531e72d8d2Sderaadt     HANDLE read, write;
4541e72d8d2Sderaadt     SECURITY_ATTRIBUTES sa;
4551e72d8d2Sderaadt 
4561e72d8d2Sderaadt     init_sa (&sa, 0);
4571e72d8d2Sderaadt     if (! CreatePipe (&read, &write, &sa, 1 << 13))
4581e72d8d2Sderaadt     {
4591e72d8d2Sderaadt         errno = EMFILE;
4601e72d8d2Sderaadt         return -1;
4611e72d8d2Sderaadt     }
4621e72d8d2Sderaadt     if (end == inherit_reading)
4631e72d8d2Sderaadt         read = inheritable (read);
4641e72d8d2Sderaadt     else
4651e72d8d2Sderaadt         write = inheritable (write);
4661e72d8d2Sderaadt 
4671e72d8d2Sderaadt     if (read == INVALID_HANDLE_VALUE
4681e72d8d2Sderaadt         || write == INVALID_HANDLE_VALUE)
4691e72d8d2Sderaadt     {
4701e72d8d2Sderaadt         CloseHandle (read);
4711e72d8d2Sderaadt 	CloseHandle (write);
4721e72d8d2Sderaadt 	errno = EMFILE;
4731e72d8d2Sderaadt 	return -1;
4741e72d8d2Sderaadt     }
4751e72d8d2Sderaadt 
4761e72d8d2Sderaadt     readwrite[0] = read;
4771e72d8d2Sderaadt     readwrite[1] = write;
4781e72d8d2Sderaadt 
4791e72d8d2Sderaadt     return 0;
4801e72d8d2Sderaadt }
4811e72d8d2Sderaadt 
4821e72d8d2Sderaadt 
4831e72d8d2Sderaadt /* Initialize the STARTUPINFO structure *LPSI.  */
4841e72d8d2Sderaadt static void
4851e72d8d2Sderaadt init_si (LPSTARTUPINFO lpsi)
4861e72d8d2Sderaadt {
4871e72d8d2Sderaadt   memset (lpsi, 0, sizeof (*lpsi));
4881e72d8d2Sderaadt   lpsi->cb = sizeof(*lpsi);
4891e72d8d2Sderaadt   lpsi->lpReserved = NULL;
4901e72d8d2Sderaadt   lpsi->lpTitle = NULL;
4911e72d8d2Sderaadt   lpsi->lpReserved2 = NULL;
4921e72d8d2Sderaadt   lpsi->cbReserved2 = 0;
4931e72d8d2Sderaadt   lpsi->lpDesktop = NULL;
4941e72d8d2Sderaadt   lpsi->dwFlags = 0;
4951e72d8d2Sderaadt }
4961e72d8d2Sderaadt 
4971e72d8d2Sderaadt 
4981e72d8d2Sderaadt /* Create a child process running COMMAND with IN as its standard input,
4991e72d8d2Sderaadt    and OUT as its standard output.  Return a handle to the child, or
5001e72d8d2Sderaadt    INVALID_HANDLE_VALUE.  */
5011e72d8d2Sderaadt static int
5021e72d8d2Sderaadt start_child (char *command, HANDLE in, HANDLE out)
5031e72d8d2Sderaadt {
5041e72d8d2Sderaadt   STARTUPINFO si;
5051e72d8d2Sderaadt   PROCESS_INFORMATION pi;
5061e72d8d2Sderaadt   BOOL status;
5071e72d8d2Sderaadt 
5081e72d8d2Sderaadt   /* The STARTUPINFO structure can specify handles to pass to the
5091e72d8d2Sderaadt      child as its standard input, output, and error.  */
5101e72d8d2Sderaadt   init_si (&si);
5111e72d8d2Sderaadt   si.hStdInput = in;
5121e72d8d2Sderaadt   si.hStdOutput = out;
5131e72d8d2Sderaadt   si.hStdError  = (HANDLE) _get_osfhandle (2);
5141e72d8d2Sderaadt   si.dwFlags = STARTF_USESTDHANDLES;
5151e72d8d2Sderaadt 
5161e72d8d2Sderaadt   status = CreateProcess ((LPCTSTR) NULL,
5171e72d8d2Sderaadt                           (LPTSTR) command,
5181e72d8d2Sderaadt 		          (LPSECURITY_ATTRIBUTES) NULL, /* lpsaProcess */
5191e72d8d2Sderaadt 		          (LPSECURITY_ATTRIBUTES) NULL, /* lpsaThread */
5201e72d8d2Sderaadt 		          TRUE, /* fInheritHandles */
5211e72d8d2Sderaadt 		          0,    /* fdwCreate */
5221e72d8d2Sderaadt 		          (LPVOID) 0, /* lpvEnvironment */
5231e72d8d2Sderaadt 		          (LPCTSTR) 0, /* lpszCurDir */
5241e72d8d2Sderaadt 		          &si,  /* lpsiStartInfo */
5251e72d8d2Sderaadt 		          &pi); /* lppiProcInfo */
5261e72d8d2Sderaadt 
5271e72d8d2Sderaadt   if (! status)
5281e72d8d2Sderaadt   {
5291e72d8d2Sderaadt       DWORD error_code = GetLastError ();
5301e72d8d2Sderaadt       switch (error_code)
5311e72d8d2Sderaadt       {
5321e72d8d2Sderaadt       case ERROR_NOT_ENOUGH_MEMORY:
5331e72d8d2Sderaadt       case ERROR_OUTOFMEMORY:
5341e72d8d2Sderaadt           errno = ENOMEM; break;
5351e72d8d2Sderaadt       case ERROR_BAD_EXE_FORMAT:
5361e72d8d2Sderaadt           errno = ENOEXEC; break;
5371e72d8d2Sderaadt       case ERROR_ACCESS_DENIED:
5381e72d8d2Sderaadt           errno = EACCES; break;
5391e72d8d2Sderaadt       case ERROR_NOT_READY:
5401e72d8d2Sderaadt       case ERROR_FILE_NOT_FOUND:
5411e72d8d2Sderaadt       case ERROR_PATH_NOT_FOUND:
5421e72d8d2Sderaadt       default:
5431e72d8d2Sderaadt           errno = ENOENT; break;
5441e72d8d2Sderaadt       }
5451e72d8d2Sderaadt       return (int) INVALID_HANDLE_VALUE;
5461e72d8d2Sderaadt   }
5471e72d8d2Sderaadt 
5481e72d8d2Sderaadt   /* The _spawn and _cwait functions in the C runtime library
5491e72d8d2Sderaadt      seem to operate on raw NT handles, not PID's.  Odd, but we'll
5501e72d8d2Sderaadt      deal.  */
5511e72d8d2Sderaadt   return (int) pi.hProcess;
5521e72d8d2Sderaadt }
5531e72d8d2Sderaadt 
5541e72d8d2Sderaadt 
5551e72d8d2Sderaadt /* Given an array of arguments that one might pass to spawnv,
5561e72d8d2Sderaadt    construct a command line that one might pass to CreateProcess.
5571e72d8d2Sderaadt    Try to quote things appropriately.  */
5581e72d8d2Sderaadt static char *
5591e72d8d2Sderaadt build_command (char **argv)
5601e72d8d2Sderaadt {
5611e72d8d2Sderaadt     int len;
5621e72d8d2Sderaadt 
5631e72d8d2Sderaadt     /* Compute the total length the command will have.  */
5641e72d8d2Sderaadt     {
5651e72d8d2Sderaadt         int i;
5661e72d8d2Sderaadt 
5671e72d8d2Sderaadt 	len = 0;
5681e72d8d2Sderaadt         for (i = 0; argv[i]; i++)
5691e72d8d2Sderaadt 	{
5701e72d8d2Sderaadt 	    char *p;
5711e72d8d2Sderaadt 
5721e72d8d2Sderaadt 	    len += 2;  /* for the double quotes */
5731e72d8d2Sderaadt 
5741e72d8d2Sderaadt 	    for (p = argv[i]; *p; p++)
5751e72d8d2Sderaadt 	    {
5761e72d8d2Sderaadt 	        if (*p == '"')
5771e72d8d2Sderaadt 		    len += 2;
5781e72d8d2Sderaadt 		else
5791e72d8d2Sderaadt 		    len++;
5801e72d8d2Sderaadt 	    }
5811e72d8d2Sderaadt 	    len++;  /* for the space or the '\0'  */
5821e72d8d2Sderaadt 	}
58313571821Stholo     }
5841e72d8d2Sderaadt 
5851e72d8d2Sderaadt     {
58613571821Stholo 	/* The + 10 is in case len is 0.  */
58713571821Stholo         char *command = (char *) malloc (len + 10);
5881e72d8d2Sderaadt 	int i;
5891e72d8d2Sderaadt 	char *p;
5901e72d8d2Sderaadt 
5911e72d8d2Sderaadt 	if (! command)
5921e72d8d2Sderaadt 	{
5931e72d8d2Sderaadt 	    errno = ENOMEM;
5941e72d8d2Sderaadt 	    return command;
5951e72d8d2Sderaadt 	}
5961e72d8d2Sderaadt 
5971e72d8d2Sderaadt 	p = command;
59813571821Stholo         *p = '\0';
5991e72d8d2Sderaadt 	/* copy each element of argv to command, putting each command
6001e72d8d2Sderaadt 	   in double quotes, and backslashing any quotes that appear
6011e72d8d2Sderaadt 	   within an argument.  */
6021e72d8d2Sderaadt 	for (i = 0; argv[i]; i++)
6031e72d8d2Sderaadt 	{
6041e72d8d2Sderaadt 	    char *a;
6051e72d8d2Sderaadt 	    *p++ = '"';
6061e72d8d2Sderaadt 	    for (a = argv[i]; *a; a++)
6071e72d8d2Sderaadt 	    {
6081e72d8d2Sderaadt 	        if (*a == '"')
6091e72d8d2Sderaadt 		    *p++ = '\\', *p++ = '"';
6101e72d8d2Sderaadt 		else
6111e72d8d2Sderaadt 		    *p++ = *a;
6121e72d8d2Sderaadt 	    }
6131e72d8d2Sderaadt 	    *p++ = '"';
6141e72d8d2Sderaadt 	    *p++ = ' ';
6151e72d8d2Sderaadt 	}
61613571821Stholo 	if (p > command)
6171e72d8d2Sderaadt 	    p[-1] = '\0';
6181e72d8d2Sderaadt 
6191e72d8d2Sderaadt         return command;
6201e72d8d2Sderaadt     }
6211e72d8d2Sderaadt }
6221e72d8d2Sderaadt 
6231e72d8d2Sderaadt 
6241e72d8d2Sderaadt /* Create an asynchronous child process executing ARGV,
6251e72d8d2Sderaadt    with its standard input and output connected to the
6261e72d8d2Sderaadt    parent with pipes.  Set *TO to the file descriptor on
6271e72d8d2Sderaadt    which one writes data for the child; set *FROM to
6281e72d8d2Sderaadt    the file descriptor from which one reads data from the child.
6291e72d8d2Sderaadt    Return the handle of the child process (this is what
6301e72d8d2Sderaadt    _cwait and waitpid expect).  */
6311e72d8d2Sderaadt int
6321e72d8d2Sderaadt piped_child (char **argv, int *to, int *from)
6331e72d8d2Sderaadt {
6341e72d8d2Sderaadt   int child;
6351e72d8d2Sderaadt   HANDLE pipein[2], pipeout[2];
6361e72d8d2Sderaadt   char *command;
6371e72d8d2Sderaadt 
6381e72d8d2Sderaadt   /* Turn argv into a form acceptable to CreateProcess.  */
6391e72d8d2Sderaadt   command = build_command (argv);
6401e72d8d2Sderaadt   if (! command)
6411e72d8d2Sderaadt       return -1;
6421e72d8d2Sderaadt 
6431e72d8d2Sderaadt   /* Create pipes for communicating with child.  Arrange for
6441e72d8d2Sderaadt      the child not to inherit the ends it won't use.  */
6451e72d8d2Sderaadt   if (my_pipe (pipein, inherit_reading) == -1
6461e72d8d2Sderaadt       || my_pipe (pipeout, inherit_writing) == -1)
6471e72d8d2Sderaadt       return -1;
6481e72d8d2Sderaadt 
6491e72d8d2Sderaadt   child = start_child (command, pipein[0], pipeout[1]);
6501e72d8d2Sderaadt   free (command);
6511e72d8d2Sderaadt   if (child == (int) INVALID_HANDLE_VALUE)
6521e72d8d2Sderaadt       return -1;
6531e72d8d2Sderaadt 
6541e72d8d2Sderaadt   /* Close the pipe ends the parent doesn't use.  */
6551e72d8d2Sderaadt   CloseHandle (pipein[0]);
6561e72d8d2Sderaadt   CloseHandle (pipeout[1]);
6571e72d8d2Sderaadt 
6581e72d8d2Sderaadt   /* Given the pipe handles, turn them into file descriptors for
6591e72d8d2Sderaadt      use by the caller.  */
6601e72d8d2Sderaadt   if ((*to      = _open_osfhandle ((long) pipein[1],  _O_BINARY)) == -1
6611e72d8d2Sderaadt       || (*from = _open_osfhandle ((long) pipeout[0], _O_BINARY)) == -1)
6621e72d8d2Sderaadt       return -1;
6631e72d8d2Sderaadt 
6641e72d8d2Sderaadt   return child;
6651e72d8d2Sderaadt }
6661e72d8d2Sderaadt 
6671e72d8d2Sderaadt /*
6681e72d8d2Sderaadt  * dir = 0 : main proc writes to new proc, which writes to oldfd
6691e72d8d2Sderaadt  * dir = 1 : main proc reads from new proc, which reads from oldfd
67013571821Stholo  *
67113571821Stholo  * Returns: a file descriptor.  On failure (e.g., the exec fails),
67213571821Stholo  * then filter_stream_through_program() complains and dies.
6731e72d8d2Sderaadt  */
6741e72d8d2Sderaadt 
6751e72d8d2Sderaadt int
6761e72d8d2Sderaadt filter_stream_through_program (oldfd, dir, prog, pidp)
6771e72d8d2Sderaadt      int oldfd, dir;
6781e72d8d2Sderaadt      char **prog;
6791e72d8d2Sderaadt      pid_t *pidp;
6801e72d8d2Sderaadt {
6811e72d8d2Sderaadt     HANDLE pipe[2];
6821e72d8d2Sderaadt     char *command;
6831e72d8d2Sderaadt     int child;
6841e72d8d2Sderaadt     HANDLE oldfd_handle;
6851e72d8d2Sderaadt     HANDLE newfd_handle;
6861e72d8d2Sderaadt     int newfd;
6871e72d8d2Sderaadt 
6881e72d8d2Sderaadt     /* Get the OS handle associated with oldfd, to be passed to the child.  */
6891e72d8d2Sderaadt     if ((oldfd_handle = (HANDLE) _get_osfhandle (oldfd)) < 0)
69013571821Stholo 	error (1, errno, "cannot _get_osfhandle");
6911e72d8d2Sderaadt 
6921e72d8d2Sderaadt     if (dir)
6931e72d8d2Sderaadt     {
6941e72d8d2Sderaadt         /* insert child before parent, pipe goes child->parent.  */
6951e72d8d2Sderaadt 	if (my_pipe (pipe, inherit_writing) == -1)
69613571821Stholo 	    error (1, errno, "cannot my_pipe");
6971e72d8d2Sderaadt 	if ((command = build_command (prog)) == NULL)
69813571821Stholo 	    error (1, errno, "cannot build_command");
6991e72d8d2Sderaadt 	child = start_child (command, oldfd_handle, pipe[1]);
7001e72d8d2Sderaadt 	free (command);
7011e72d8d2Sderaadt 	if (child == (int) INVALID_HANDLE_VALUE)
70213571821Stholo 	    error (1, errno, "cannot start_child");
7031e72d8d2Sderaadt 	close (oldfd);
7041e72d8d2Sderaadt 	CloseHandle (pipe[1]);
7051e72d8d2Sderaadt 	newfd_handle = pipe[0];
7061e72d8d2Sderaadt     }
7071e72d8d2Sderaadt     else
7081e72d8d2Sderaadt     {
7091e72d8d2Sderaadt         /* insert child after parent, pipe goes parent->child.  */
7101e72d8d2Sderaadt 	if (my_pipe (pipe, inherit_reading) == -1)
71113571821Stholo 	    error (1, errno, "cannot my_pipe");
7121e72d8d2Sderaadt 	if ((command = build_command (prog)) == NULL)
71313571821Stholo 	    error (1, errno, "cannot build_command");
7141e72d8d2Sderaadt 	child = start_child (command, pipe[0], oldfd_handle);
7151e72d8d2Sderaadt 	free (command);
7161e72d8d2Sderaadt 	if (child == (int) INVALID_HANDLE_VALUE)
71713571821Stholo 	    error (1, errno, "cannot start_child");
7181e72d8d2Sderaadt 	close (oldfd);
7191e72d8d2Sderaadt 	CloseHandle (pipe[0]);
7201e72d8d2Sderaadt 	newfd_handle = pipe[1];
7211e72d8d2Sderaadt     }
7221e72d8d2Sderaadt 
7231e72d8d2Sderaadt     if ((newfd = _open_osfhandle ((long) newfd_handle, _O_BINARY)) == -1)
72413571821Stholo         error (1, errno, "cannot _open_osfhandle");
7251e72d8d2Sderaadt 
72613571821Stholo     if (pidp)
7271e72d8d2Sderaadt 	*pidp = child;
7281e72d8d2Sderaadt     return newfd;
7291e72d8d2Sderaadt }
7301e72d8d2Sderaadt 
7311e72d8d2Sderaadt 
7321e72d8d2Sderaadt /* Arrange for the file descriptor FD to not be inherited by child
7331e72d8d2Sderaadt    processes.  At the moment, CVS uses this function only on pipes
7341e72d8d2Sderaadt    returned by piped_child, and our implementation of piped_child
7351e72d8d2Sderaadt    takes care of setting the file handles' inheritability, so this
7361e72d8d2Sderaadt    can be a no-op.  */
7371e72d8d2Sderaadt void
7381e72d8d2Sderaadt close_on_exec (int fd)
7391e72d8d2Sderaadt {
7401e72d8d2Sderaadt }
741