xref: /openbsd-src/gnu/usr.bin/cvs/windows-NT/run.c (revision 2286d8ed900f26153a3cd5227a124b1c0adce72f)
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
13461cc63eStholo    GNU General Public License for more details.  */
141e72d8d2Sderaadt 
151e72d8d2Sderaadt #include "cvs.h"
161e72d8d2Sderaadt 
171e72d8d2Sderaadt #define WIN32_LEAN_AND_MEAN
181e72d8d2Sderaadt #include <windows.h>
191e72d8d2Sderaadt #include <stdlib.h>
201e72d8d2Sderaadt #include <process.h>
211e72d8d2Sderaadt #include <errno.h>
221e72d8d2Sderaadt #include <io.h>
231e72d8d2Sderaadt #include <fcntl.h>
241e72d8d2Sderaadt 
251e72d8d2Sderaadt static void run_add_arg PROTO((const char *s));
261e72d8d2Sderaadt static void run_init_prog PROTO((void));
271e72d8d2Sderaadt 
281e72d8d2Sderaadt extern char *strtok ();
291e72d8d2Sderaadt 
301e72d8d2Sderaadt /*
311e72d8d2Sderaadt  * To exec a program under CVS, first call run_setup() to setup any initial
321e72d8d2Sderaadt  * arguments.  The options to run_setup are essentially like printf(). The
331e72d8d2Sderaadt  * arguments will be parsed into whitespace separated words and added to the
341e72d8d2Sderaadt  * global run_argv list.
351e72d8d2Sderaadt  *
361e72d8d2Sderaadt  * Then, optionally call run_arg() for each additional argument that you'd like
371e72d8d2Sderaadt  * to pass to the executed program.
381e72d8d2Sderaadt  *
391e72d8d2Sderaadt  * Finally, call run_exec() to execute the program with the specified arguments.
401e72d8d2Sderaadt  * The execvp() syscall will be used, so that the PATH is searched correctly.
411e72d8d2Sderaadt  * File redirections can be performed in the call to run_exec().
421e72d8d2Sderaadt  */
431e72d8d2Sderaadt static char **run_argv;
441e72d8d2Sderaadt static int run_argc;
451e72d8d2Sderaadt static int run_argc_allocated;
461e72d8d2Sderaadt 
471e72d8d2Sderaadt void
run_setup(const char * prog)48*2286d8edStholo run_setup (const char *prog)
491e72d8d2Sderaadt {
501e72d8d2Sderaadt     char *cp;
511e72d8d2Sderaadt     int i;
521e72d8d2Sderaadt 
53*2286d8edStholo     char *run_prog;
541e72d8d2Sderaadt 
551e72d8d2Sderaadt     /* clean out any malloc'ed values from run_argv */
561e72d8d2Sderaadt     for (i = 0; i < run_argc; i++)
571e72d8d2Sderaadt     {
581e72d8d2Sderaadt 	if (run_argv[i])
591e72d8d2Sderaadt 	{
601e72d8d2Sderaadt 	    free (run_argv[i]);
611e72d8d2Sderaadt 	    run_argv[i] = (char *) 0;
621e72d8d2Sderaadt 	}
631e72d8d2Sderaadt     }
641e72d8d2Sderaadt     run_argc = 0;
651e72d8d2Sderaadt 
66*2286d8edStholo     run_prog = xstrdup (prog);
671e72d8d2Sderaadt 
681e72d8d2Sderaadt     /* put each word into run_argv, allocating it as we go */
691e72d8d2Sderaadt     for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
701e72d8d2Sderaadt 	run_add_arg (cp);
71*2286d8edStholo 
72*2286d8edStholo     free (run_prog);
731e72d8d2Sderaadt }
741e72d8d2Sderaadt 
751e72d8d2Sderaadt void
run_arg(s)761e72d8d2Sderaadt run_arg (s)
771e72d8d2Sderaadt     const char *s;
781e72d8d2Sderaadt {
791e72d8d2Sderaadt     run_add_arg (s);
801e72d8d2Sderaadt }
811e72d8d2Sderaadt 
821e72d8d2Sderaadt /* Return a malloc'd copy of s, with double quotes around it.  */
831e72d8d2Sderaadt static char *
quote(const char * s)841e72d8d2Sderaadt quote (const char *s)
851e72d8d2Sderaadt {
86*2286d8edStholo     size_t s_len = 0;
87*2286d8edStholo     char *copy = NULL;
88*2286d8edStholo     char *scan = (char *) s;
891e72d8d2Sderaadt 
90*2286d8edStholo     /* scan string for extra quotes ... */
91*2286d8edStholo     while (*scan)
92*2286d8edStholo 	if ('"' == *scan++)
93*2286d8edStholo 	    s_len += 2;   /* one extra for the quote character */
94*2286d8edStholo 	else
95*2286d8edStholo 	    s_len++;
96*2286d8edStholo     /* allocate length + byte for ending zero + for double quotes around */
97*2286d8edStholo     scan = copy = xmalloc(s_len + 3);
981e72d8d2Sderaadt     *scan++ = '"';
99*2286d8edStholo     while (*s)
100*2286d8edStholo     {
101*2286d8edStholo 	if ('"' == *s)
102*2286d8edStholo 	    *scan++ = '\\';
103*2286d8edStholo 	*scan++ = *s++;
104*2286d8edStholo     }
105*2286d8edStholo     /* ending quote and closing zero */
1061e72d8d2Sderaadt     *scan++ = '"';
1071e72d8d2Sderaadt     *scan++ = '\0';
1081e72d8d2Sderaadt     return copy;
1091e72d8d2Sderaadt }
1101e72d8d2Sderaadt 
1111e72d8d2Sderaadt static void
run_add_arg(s)1121e72d8d2Sderaadt run_add_arg (s)
1131e72d8d2Sderaadt     const char *s;
1141e72d8d2Sderaadt {
1151e72d8d2Sderaadt     /* allocate more argv entries if we've run out */
1161e72d8d2Sderaadt     if (run_argc >= run_argc_allocated)
1171e72d8d2Sderaadt     {
1181e72d8d2Sderaadt 	run_argc_allocated += 50;
1191e72d8d2Sderaadt 	run_argv = (char **) xrealloc ((char *) run_argv,
1201e72d8d2Sderaadt 				     run_argc_allocated * sizeof (char **));
1211e72d8d2Sderaadt     }
1221e72d8d2Sderaadt 
1231e72d8d2Sderaadt     if (s)
1241e72d8d2Sderaadt     {
1251e72d8d2Sderaadt 	run_argv[run_argc] = (run_argc ? quote (s) : xstrdup (s));
1261e72d8d2Sderaadt 	run_argc++;
1271e72d8d2Sderaadt     }
1281e72d8d2Sderaadt     else
1291e72d8d2Sderaadt 	run_argv[run_argc] = (char *) 0;	/* not post-incremented on purpose! */
1301e72d8d2Sderaadt }
1311e72d8d2Sderaadt 
1321e72d8d2Sderaadt int
run_exec(stin,stout,sterr,flags)1331e72d8d2Sderaadt run_exec (stin, stout, sterr, flags)
134*2286d8edStholo     const char *stin;
135*2286d8edStholo     const char *stout;
136*2286d8edStholo     const char *sterr;
1371e72d8d2Sderaadt     int flags;
1381e72d8d2Sderaadt {
1391e72d8d2Sderaadt     int shin, shout, sherr;
1401e72d8d2Sderaadt     int sain, saout, saerr;	/* saved handles */
1411e72d8d2Sderaadt     int mode_out, mode_err;
1421e72d8d2Sderaadt     int status = -1;
1431e72d8d2Sderaadt     int rerrno = 0;
1441e72d8d2Sderaadt     int rval   = -1;
1451e72d8d2Sderaadt     void (*old_sigint) (int);
1461e72d8d2Sderaadt 
1471e72d8d2Sderaadt     if (trace)			/* if in trace mode */
1481e72d8d2Sderaadt     {
1491e72d8d2Sderaadt 	(void) fprintf (stderr, "-> system(");
1501e72d8d2Sderaadt 	run_print (stderr);
1511e72d8d2Sderaadt 	(void) fprintf (stderr, ")\n");
1521e72d8d2Sderaadt     }
15350bf276cStholo 
15450bf276cStholo     /* Flush standard output and standard error, or otherwise we end
15550bf276cStholo        up with strange interleavings of stuff called from CYGWIN
15650bf276cStholo        vs. CMD.  */
15750bf276cStholo 
15850bf276cStholo     fflush (stderr);
15950bf276cStholo     fflush (stdout);
16050bf276cStholo 
1611e72d8d2Sderaadt     if (noexec && (flags & RUN_REALLY) == 0) /* if in noexec mode */
1621e72d8d2Sderaadt 	return (0);
1631e72d8d2Sderaadt 
1641e72d8d2Sderaadt     /*
1651e72d8d2Sderaadt      * start the engine and take off
1661e72d8d2Sderaadt      */
1671e72d8d2Sderaadt 
1681e72d8d2Sderaadt     /* make sure that we are null terminated, since we didn't calloc */
1691e72d8d2Sderaadt     run_add_arg ((char *) 0);
1701e72d8d2Sderaadt 
1711e72d8d2Sderaadt     /* setup default file descriptor numbers */
1721e72d8d2Sderaadt     shin = 0;
1731e72d8d2Sderaadt     shout = 1;
1741e72d8d2Sderaadt     sherr = 2;
1751e72d8d2Sderaadt 
1761e72d8d2Sderaadt     /* set the file modes for stdout and stderr */
1771e72d8d2Sderaadt     mode_out = mode_err = O_WRONLY | O_CREAT;
1781e72d8d2Sderaadt     mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
1791e72d8d2Sderaadt     mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
1801e72d8d2Sderaadt 
1811e72d8d2Sderaadt     /* open the files as required, shXX are shadows of stdin... */
1821e72d8d2Sderaadt     if (stin && (shin = open (stin, O_RDONLY)) == -1)
1831e72d8d2Sderaadt     {
1841e72d8d2Sderaadt 	rerrno = errno;
1851e72d8d2Sderaadt 	error (0, errno, "cannot open %s for reading (prog %s)",
1861e72d8d2Sderaadt 	       stin, run_argv[0]);
1871e72d8d2Sderaadt 	goto out0;
1881e72d8d2Sderaadt     }
1891e72d8d2Sderaadt     if (stout && (shout = open (stout, mode_out, 0666)) == -1)
1901e72d8d2Sderaadt     {
1911e72d8d2Sderaadt 	rerrno = errno;
1921e72d8d2Sderaadt 	error (0, errno, "cannot open %s for writing (prog %s)",
1931e72d8d2Sderaadt 	       stout, run_argv[0]);
1941e72d8d2Sderaadt 	goto out1;
1951e72d8d2Sderaadt     }
1961e72d8d2Sderaadt     if (sterr && (flags & RUN_COMBINED) == 0)
1971e72d8d2Sderaadt     {
1981e72d8d2Sderaadt 	if ((sherr = open (sterr, mode_err, 0666)) == -1)
1991e72d8d2Sderaadt 	{
2001e72d8d2Sderaadt 	    rerrno = errno;
2011e72d8d2Sderaadt 	    error (0, errno, "cannot open %s for writing (prog %s)",
2021e72d8d2Sderaadt 		   sterr, run_argv[0]);
2031e72d8d2Sderaadt 	    goto out2;
2041e72d8d2Sderaadt 	}
2051e72d8d2Sderaadt     }
2061e72d8d2Sderaadt     /* now save the standard handles */
2071e72d8d2Sderaadt     sain = saout = saerr = -1;
2081e72d8d2Sderaadt     sain  = dup( 0); /* dup stdin  */
2091e72d8d2Sderaadt     saout = dup( 1); /* dup stdout */
2101e72d8d2Sderaadt     saerr = dup( 2); /* dup stderr */
2111e72d8d2Sderaadt 
2121e72d8d2Sderaadt     /* the new handles will be dup'd to the standard handles
2131e72d8d2Sderaadt      * for the spawn.
2141e72d8d2Sderaadt      */
2151e72d8d2Sderaadt 
2161e72d8d2Sderaadt     if (shin != 0)
2171e72d8d2Sderaadt       {
2181e72d8d2Sderaadt 	(void) dup2 (shin, 0);
2191e72d8d2Sderaadt 	(void) close (shin);
2201e72d8d2Sderaadt       }
2211e72d8d2Sderaadt     if (shout != 1)
2221e72d8d2Sderaadt       {
2231e72d8d2Sderaadt 	(void) dup2 (shout, 1);
2241e72d8d2Sderaadt 	(void) close (shout);
2251e72d8d2Sderaadt       }
2261e72d8d2Sderaadt     if (flags & RUN_COMBINED)
2271e72d8d2Sderaadt       (void) dup2 (1, 2);
2281e72d8d2Sderaadt     else if (sherr != 2)
2291e72d8d2Sderaadt       {
2301e72d8d2Sderaadt 	(void) dup2 (sherr, 2);
2311e72d8d2Sderaadt 	(void) close (sherr);
2321e72d8d2Sderaadt       }
2331e72d8d2Sderaadt 
2341e72d8d2Sderaadt     /* Ignore signals while we're running this.  */
2351e72d8d2Sderaadt     old_sigint = signal (SIGINT, SIG_IGN);
2361e72d8d2Sderaadt 
2371e72d8d2Sderaadt     /* dup'ing is done.  try to run it now */
2381e72d8d2Sderaadt     rval = spawnvp ( P_WAIT, run_argv[0], run_argv);
2391e72d8d2Sderaadt 
2401e72d8d2Sderaadt     /* Restore signal handling.  */
2411e72d8d2Sderaadt     signal (SIGINT, old_sigint);
2421e72d8d2Sderaadt 
2431e72d8d2Sderaadt     /* restore the original file handles   */
2441e72d8d2Sderaadt     if (sain  != -1) {
2451e72d8d2Sderaadt       (void) dup2( sain, 0);	/* re-connect stdin  */
2461e72d8d2Sderaadt       (void) close( sain);
2471e72d8d2Sderaadt     }
2481e72d8d2Sderaadt     if (saout != -1) {
2491e72d8d2Sderaadt       (void) dup2( saout, 1);	/* re-connect stdout */
2501e72d8d2Sderaadt       (void) close( saout);
2511e72d8d2Sderaadt     }
2521e72d8d2Sderaadt     if (saerr != -1) {
2531e72d8d2Sderaadt       (void) dup2( saerr, 2);	/* re-connect stderr */
2541e72d8d2Sderaadt       (void) close( saerr);
2551e72d8d2Sderaadt     }
2561e72d8d2Sderaadt 
25750bf276cStholo     /* Flush standard output and standard error, or otherwise we end
25850bf276cStholo        up with strange interleavings of stuff called from CYGWIN
25950bf276cStholo        vs. CMD.  */
26050bf276cStholo 
26150bf276cStholo     fflush (stderr);
26250bf276cStholo     fflush (stdout);
26350bf276cStholo 
2641e72d8d2Sderaadt     /* Recognize the return code for an interrupted subprocess.  */
2651e72d8d2Sderaadt     if (rval == CONTROL_C_EXIT)
2661e72d8d2Sderaadt         return 2;
2671e72d8d2Sderaadt     else
2681e72d8d2Sderaadt         return rval;		/* end, if all went coorect */
2691e72d8d2Sderaadt 
2701e72d8d2Sderaadt     /* error cases */
2711e72d8d2Sderaadt     /* cleanup the open file descriptors */
2721e72d8d2Sderaadt   out2:
2731e72d8d2Sderaadt     if (stout)
2741e72d8d2Sderaadt 	(void) close (shout);
2751e72d8d2Sderaadt   out1:
2761e72d8d2Sderaadt     if (stin)
2771e72d8d2Sderaadt 	(void) close (shin);
2781e72d8d2Sderaadt 
2791e72d8d2Sderaadt   out0:
2801e72d8d2Sderaadt     if (rerrno)
2811e72d8d2Sderaadt 	errno = rerrno;
2821e72d8d2Sderaadt     return (status);
2831e72d8d2Sderaadt }
2841e72d8d2Sderaadt 
2851e72d8d2Sderaadt void
run_print(fp)2861e72d8d2Sderaadt run_print (fp)
2871e72d8d2Sderaadt     FILE *fp;
2881e72d8d2Sderaadt {
2891e72d8d2Sderaadt     int i;
2901e72d8d2Sderaadt 
2911e72d8d2Sderaadt     for (i = 0; i < run_argc; i++)
2921e72d8d2Sderaadt     {
2931e72d8d2Sderaadt 	(void) fprintf (fp, "'%s'", run_argv[i]);
2941e72d8d2Sderaadt 	if (i != run_argc - 1)
2951e72d8d2Sderaadt 	    (void) fprintf (fp, " ");
2961e72d8d2Sderaadt     }
2971e72d8d2Sderaadt }
2981e72d8d2Sderaadt 
2991e72d8d2Sderaadt static char *
requote(const char * cmd)3001e72d8d2Sderaadt requote (const char *cmd)
3011e72d8d2Sderaadt {
3021e72d8d2Sderaadt     char *requoted = xmalloc (strlen (cmd) + 1);
3031e72d8d2Sderaadt     char *p = requoted;
3041e72d8d2Sderaadt 
3051e72d8d2Sderaadt     strcpy (requoted, cmd);
3061e72d8d2Sderaadt     while ((p = strchr (p, '\'')) != NULL)
3071e72d8d2Sderaadt     {
3081e72d8d2Sderaadt         *p++ = '"';
3091e72d8d2Sderaadt     }
3101e72d8d2Sderaadt 
3111e72d8d2Sderaadt     return requoted;
3121e72d8d2Sderaadt }
3131e72d8d2Sderaadt 
3141e72d8d2Sderaadt FILE *
run_popen(cmd,mode)315c26070a5Stholo run_popen (cmd, mode)
3161e72d8d2Sderaadt     const char *cmd;
3171e72d8d2Sderaadt     const char *mode;
3181e72d8d2Sderaadt {
3191e72d8d2Sderaadt     if (trace)
3201e72d8d2Sderaadt #ifdef SERVER_SUPPORT
321c26070a5Stholo 	(void) fprintf (stderr, "%c-> run_popen(%s,%s)\n",
3221e72d8d2Sderaadt 			(server_active) ? 'S' : ' ', cmd, mode);
3231e72d8d2Sderaadt #else
324c26070a5Stholo 	(void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode);
3251e72d8d2Sderaadt #endif
3261e72d8d2Sderaadt     if (noexec)
3271e72d8d2Sderaadt 	return (NULL);
3281e72d8d2Sderaadt 
3291e72d8d2Sderaadt     /* If the command string uses single quotes, turn them into
3301e72d8d2Sderaadt        double quotes.  */
3311e72d8d2Sderaadt     {
3321e72d8d2Sderaadt         char *requoted = requote (cmd);
333461cc63eStholo 	/* Save and restore our file descriptors to work around
334461cc63eStholo 	   apparent bugs in _popen.  We are perhaps better off using
335461cc63eStholo 	   the win32 functions instead of _popen.  */
336461cc63eStholo 	int old_stdin = dup (STDIN_FILENO);
337461cc63eStholo 	int old_stdout = dup (STDOUT_FILENO);
338461cc63eStholo 	int old_stderr = dup (STDERR_FILENO);
339461cc63eStholo 
3401e72d8d2Sderaadt 	FILE *result = popen (requoted, mode);
341461cc63eStholo 
342461cc63eStholo 	dup2 (old_stdin, STDIN_FILENO);
343461cc63eStholo 	dup2 (old_stdout, STDOUT_FILENO);
344461cc63eStholo 	dup2 (old_stderr, STDERR_FILENO);
345461cc63eStholo 	close (old_stdin);
346461cc63eStholo 	close (old_stdout);
347461cc63eStholo 	close (old_stderr);
348461cc63eStholo 
3491e72d8d2Sderaadt 	free (requoted);
3501e72d8d2Sderaadt 	return result;
3511e72d8d2Sderaadt     }
3521e72d8d2Sderaadt }
3531e72d8d2Sderaadt 
3541e72d8d2Sderaadt 
3551e72d8d2Sderaadt /* Running children with pipes connected to them.  */
3561e72d8d2Sderaadt 
3571e72d8d2Sderaadt /* It's kind of ridiculous the hoops we're jumping through to get
3581e72d8d2Sderaadt    this working.  _pipe and dup2 and _spawnmumble work just fine, except
3591e72d8d2Sderaadt    that the child inherits a file descriptor for the writing end of the
3601e72d8d2Sderaadt    pipe, and thus will never receive end-of-file on it.  If you know of
3611e72d8d2Sderaadt    a better way to implement the piped_child function, please let me know.
3621e72d8d2Sderaadt 
3631e72d8d2Sderaadt    You can apparently specify _O_NOINHERIT when you open a file, but there's
3641e72d8d2Sderaadt    apparently no fcntl function, so you can't change that bit on an existing
3651e72d8d2Sderaadt    file descriptor.  */
3661e72d8d2Sderaadt 
3671e72d8d2Sderaadt /* Given a handle, make an inheritable duplicate of it, and close
3681e72d8d2Sderaadt    the original.  */
3691e72d8d2Sderaadt static HANDLE
inheritable(HANDLE in)3701e72d8d2Sderaadt inheritable (HANDLE in)
3711e72d8d2Sderaadt {
3721e72d8d2Sderaadt     HANDLE copy;
3731e72d8d2Sderaadt     HANDLE self = GetCurrentProcess ();
3741e72d8d2Sderaadt 
3751e72d8d2Sderaadt     if (! DuplicateHandle (self, in, self, &copy,
3761e72d8d2Sderaadt 			   0, 1 /* fInherit */,
3771e72d8d2Sderaadt 			   DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
3781e72d8d2Sderaadt         return INVALID_HANDLE_VALUE;
3791e72d8d2Sderaadt 
3801e72d8d2Sderaadt     return copy;
3811e72d8d2Sderaadt }
3821e72d8d2Sderaadt 
3831e72d8d2Sderaadt 
3841e72d8d2Sderaadt /* Initialize the SECURITY_ATTRIBUTES structure *LPSA.  Set its
3851e72d8d2Sderaadt    bInheritHandle flag according to INHERIT.  */
3861e72d8d2Sderaadt static void
init_sa(LPSECURITY_ATTRIBUTES lpsa,BOOL inherit)3871e72d8d2Sderaadt init_sa (LPSECURITY_ATTRIBUTES lpsa, BOOL inherit)
3881e72d8d2Sderaadt {
3891e72d8d2Sderaadt   lpsa->nLength = sizeof(*lpsa);
3901e72d8d2Sderaadt   lpsa->bInheritHandle = inherit;
3911e72d8d2Sderaadt   lpsa->lpSecurityDescriptor = NULL;
3921e72d8d2Sderaadt }
3931e72d8d2Sderaadt 
3941e72d8d2Sderaadt 
3951e72d8d2Sderaadt enum inherit_pipe { inherit_reading, inherit_writing };
3961e72d8d2Sderaadt 
3971e72d8d2Sderaadt /* Create a pipe.  Set READWRITE[0] to its reading end, and
3981e72d8d2Sderaadt    READWRITE[1] to its writing end.  If END is inherit_reading,
3991e72d8d2Sderaadt    make the only the handle for the pipe's reading end inheritable.
4001e72d8d2Sderaadt    If END is inherit_writing, make only the handle for the pipe's
4011e72d8d2Sderaadt    writing end inheritable.  Return 0 if we succeed, -1 if we fail.
4021e72d8d2Sderaadt 
4031e72d8d2Sderaadt    Why does inheritability matter?  Consider the case of a
4041e72d8d2Sderaadt    pipe carrying data from the parent process to the child
4051e72d8d2Sderaadt    process.  The child wants to read data from the parent until
4061e72d8d2Sderaadt    it reaches the EOF.  Now, the only way to send an EOF on a pipe
4071e72d8d2Sderaadt    is to close all the handles to its writing end.  Obviously, the
4081e72d8d2Sderaadt    parent has a handle to the writing end when it creates the child.
4091e72d8d2Sderaadt    If the child inherits this handle, then it will never close it
4101e72d8d2Sderaadt    (the child has no idea it's inherited it), and will thus never
4111e72d8d2Sderaadt    receive an EOF on the pipe because it's holding a handle
4121e72d8d2Sderaadt    to it.
4131e72d8d2Sderaadt 
4141e72d8d2Sderaadt    In Unix, the child process closes the pipe ends before it execs.
4151e72d8d2Sderaadt    In Windows NT, you create the pipe with uninheritable handles, and then use
4161e72d8d2Sderaadt    DuplicateHandle to make the appropriate ends inheritable.  */
4171e72d8d2Sderaadt 
4181e72d8d2Sderaadt static int
my_pipe(HANDLE * readwrite,enum inherit_pipe end)4191e72d8d2Sderaadt my_pipe (HANDLE *readwrite, enum inherit_pipe end)
4201e72d8d2Sderaadt {
4211e72d8d2Sderaadt     HANDLE read, write;
4221e72d8d2Sderaadt     SECURITY_ATTRIBUTES sa;
4231e72d8d2Sderaadt 
4241e72d8d2Sderaadt     init_sa (&sa, 0);
4251e72d8d2Sderaadt     if (! CreatePipe (&read, &write, &sa, 1 << 13))
4261e72d8d2Sderaadt     {
4271e72d8d2Sderaadt         errno = EMFILE;
4281e72d8d2Sderaadt         return -1;
4291e72d8d2Sderaadt     }
4301e72d8d2Sderaadt     if (end == inherit_reading)
4311e72d8d2Sderaadt         read = inheritable (read);
4321e72d8d2Sderaadt     else
4331e72d8d2Sderaadt         write = inheritable (write);
4341e72d8d2Sderaadt 
4351e72d8d2Sderaadt     if (read == INVALID_HANDLE_VALUE
4361e72d8d2Sderaadt         || write == INVALID_HANDLE_VALUE)
4371e72d8d2Sderaadt     {
4381e72d8d2Sderaadt         CloseHandle (read);
4391e72d8d2Sderaadt 	CloseHandle (write);
4401e72d8d2Sderaadt 	errno = EMFILE;
4411e72d8d2Sderaadt 	return -1;
4421e72d8d2Sderaadt     }
4431e72d8d2Sderaadt 
4441e72d8d2Sderaadt     readwrite[0] = read;
4451e72d8d2Sderaadt     readwrite[1] = write;
4461e72d8d2Sderaadt 
4471e72d8d2Sderaadt     return 0;
4481e72d8d2Sderaadt }
4491e72d8d2Sderaadt 
4501e72d8d2Sderaadt 
4511e72d8d2Sderaadt /* Initialize the STARTUPINFO structure *LPSI.  */
4521e72d8d2Sderaadt static void
init_si(LPSTARTUPINFO lpsi)4531e72d8d2Sderaadt init_si (LPSTARTUPINFO lpsi)
4541e72d8d2Sderaadt {
4551e72d8d2Sderaadt   memset (lpsi, 0, sizeof (*lpsi));
4561e72d8d2Sderaadt   lpsi->cb = sizeof(*lpsi);
4571e72d8d2Sderaadt   lpsi->lpReserved = NULL;
4581e72d8d2Sderaadt   lpsi->lpTitle = NULL;
4591e72d8d2Sderaadt   lpsi->lpReserved2 = NULL;
4601e72d8d2Sderaadt   lpsi->cbReserved2 = 0;
4611e72d8d2Sderaadt   lpsi->lpDesktop = NULL;
4621e72d8d2Sderaadt   lpsi->dwFlags = 0;
4631e72d8d2Sderaadt }
4641e72d8d2Sderaadt 
4651e72d8d2Sderaadt 
4661e72d8d2Sderaadt /* Create a child process running COMMAND with IN as its standard input,
4671e72d8d2Sderaadt    and OUT as its standard output.  Return a handle to the child, or
4681e72d8d2Sderaadt    INVALID_HANDLE_VALUE.  */
4691e72d8d2Sderaadt static int
start_child(char * command,HANDLE in,HANDLE out)4701e72d8d2Sderaadt start_child (char *command, HANDLE in, HANDLE out)
4711e72d8d2Sderaadt {
4721e72d8d2Sderaadt   STARTUPINFO si;
4731e72d8d2Sderaadt   PROCESS_INFORMATION pi;
4741e72d8d2Sderaadt   BOOL status;
4751e72d8d2Sderaadt 
4761e72d8d2Sderaadt   /* The STARTUPINFO structure can specify handles to pass to the
4771e72d8d2Sderaadt      child as its standard input, output, and error.  */
4781e72d8d2Sderaadt   init_si (&si);
4791e72d8d2Sderaadt   si.hStdInput = in;
4801e72d8d2Sderaadt   si.hStdOutput = out;
4811e72d8d2Sderaadt   si.hStdError  = (HANDLE) _get_osfhandle (2);
4821e72d8d2Sderaadt   si.dwFlags = STARTF_USESTDHANDLES;
4831e72d8d2Sderaadt 
4841e72d8d2Sderaadt   status = CreateProcess ((LPCTSTR) NULL,
4851e72d8d2Sderaadt                           (LPTSTR) command,
4861e72d8d2Sderaadt 		          (LPSECURITY_ATTRIBUTES) NULL, /* lpsaProcess */
4871e72d8d2Sderaadt 		          (LPSECURITY_ATTRIBUTES) NULL, /* lpsaThread */
4881e72d8d2Sderaadt 		          TRUE, /* fInheritHandles */
4891e72d8d2Sderaadt 		          0,    /* fdwCreate */
4901e72d8d2Sderaadt 		          (LPVOID) 0, /* lpvEnvironment */
4911e72d8d2Sderaadt 		          (LPCTSTR) 0, /* lpszCurDir */
4921e72d8d2Sderaadt 		          &si,  /* lpsiStartInfo */
4931e72d8d2Sderaadt 		          &pi); /* lppiProcInfo */
4941e72d8d2Sderaadt 
4951e72d8d2Sderaadt   if (! status)
4961e72d8d2Sderaadt   {
4971e72d8d2Sderaadt       DWORD error_code = GetLastError ();
4981e72d8d2Sderaadt       switch (error_code)
4991e72d8d2Sderaadt       {
5001e72d8d2Sderaadt       case ERROR_NOT_ENOUGH_MEMORY:
5011e72d8d2Sderaadt       case ERROR_OUTOFMEMORY:
5021e72d8d2Sderaadt           errno = ENOMEM; break;
5031e72d8d2Sderaadt       case ERROR_BAD_EXE_FORMAT:
5041e72d8d2Sderaadt           errno = ENOEXEC; break;
5051e72d8d2Sderaadt       case ERROR_ACCESS_DENIED:
5061e72d8d2Sderaadt           errno = EACCES; break;
5071e72d8d2Sderaadt       case ERROR_NOT_READY:
5081e72d8d2Sderaadt       case ERROR_FILE_NOT_FOUND:
5091e72d8d2Sderaadt       case ERROR_PATH_NOT_FOUND:
5101e72d8d2Sderaadt       default:
5111e72d8d2Sderaadt           errno = ENOENT; break;
5121e72d8d2Sderaadt       }
5131e72d8d2Sderaadt       return (int) INVALID_HANDLE_VALUE;
5141e72d8d2Sderaadt   }
5151e72d8d2Sderaadt 
5161e72d8d2Sderaadt   /* The _spawn and _cwait functions in the C runtime library
5171e72d8d2Sderaadt      seem to operate on raw NT handles, not PID's.  Odd, but we'll
5181e72d8d2Sderaadt      deal.  */
5191e72d8d2Sderaadt   return (int) pi.hProcess;
5201e72d8d2Sderaadt }
5211e72d8d2Sderaadt 
5221e72d8d2Sderaadt 
5231e72d8d2Sderaadt /* Given an array of arguments that one might pass to spawnv,
5241e72d8d2Sderaadt    construct a command line that one might pass to CreateProcess.
5251e72d8d2Sderaadt    Try to quote things appropriately.  */
5261e72d8d2Sderaadt static char *
build_command(char ** argv)5271e72d8d2Sderaadt build_command (char **argv)
5281e72d8d2Sderaadt {
5291e72d8d2Sderaadt     int len;
5301e72d8d2Sderaadt 
5311e72d8d2Sderaadt     /* Compute the total length the command will have.  */
5321e72d8d2Sderaadt     {
5331e72d8d2Sderaadt         int i;
5341e72d8d2Sderaadt 
5351e72d8d2Sderaadt 	len = 0;
5361e72d8d2Sderaadt         for (i = 0; argv[i]; i++)
5371e72d8d2Sderaadt 	{
5381e72d8d2Sderaadt 	    char *p;
5391e72d8d2Sderaadt 
5401e72d8d2Sderaadt 	    len += 2;  /* for the double quotes */
5411e72d8d2Sderaadt 
5421e72d8d2Sderaadt 	    for (p = argv[i]; *p; p++)
5431e72d8d2Sderaadt 	    {
5441e72d8d2Sderaadt 	        if (*p == '"')
5451e72d8d2Sderaadt 		    len += 2;
5461e72d8d2Sderaadt 		else
5471e72d8d2Sderaadt 		    len++;
5481e72d8d2Sderaadt 	    }
5491e72d8d2Sderaadt 	    len++;  /* for the space or the '\0'  */
5501e72d8d2Sderaadt 	}
55113571821Stholo     }
5521e72d8d2Sderaadt 
5531e72d8d2Sderaadt     {
55413571821Stholo 	/* The + 10 is in case len is 0.  */
55513571821Stholo         char *command = (char *) malloc (len + 10);
5561e72d8d2Sderaadt 	int i;
5571e72d8d2Sderaadt 	char *p;
5581e72d8d2Sderaadt 
5591e72d8d2Sderaadt 	if (! command)
5601e72d8d2Sderaadt 	{
5611e72d8d2Sderaadt 	    errno = ENOMEM;
5621e72d8d2Sderaadt 	    return command;
5631e72d8d2Sderaadt 	}
5641e72d8d2Sderaadt 
5651e72d8d2Sderaadt 	p = command;
56613571821Stholo         *p = '\0';
5671e72d8d2Sderaadt 	/* copy each element of argv to command, putting each command
5681e72d8d2Sderaadt 	   in double quotes, and backslashing any quotes that appear
5691e72d8d2Sderaadt 	   within an argument.  */
5701e72d8d2Sderaadt 	for (i = 0; argv[i]; i++)
5711e72d8d2Sderaadt 	{
5721e72d8d2Sderaadt 	    char *a;
5731e72d8d2Sderaadt 	    *p++ = '"';
5741e72d8d2Sderaadt 	    for (a = argv[i]; *a; a++)
5751e72d8d2Sderaadt 	    {
5761e72d8d2Sderaadt 	        if (*a == '"')
5771e72d8d2Sderaadt 		    *p++ = '\\', *p++ = '"';
5781e72d8d2Sderaadt 		else
5791e72d8d2Sderaadt 		    *p++ = *a;
5801e72d8d2Sderaadt 	    }
5811e72d8d2Sderaadt 	    *p++ = '"';
5821e72d8d2Sderaadt 	    *p++ = ' ';
5831e72d8d2Sderaadt 	}
58413571821Stholo 	if (p > command)
5851e72d8d2Sderaadt 	    p[-1] = '\0';
5861e72d8d2Sderaadt 
5871e72d8d2Sderaadt         return command;
5881e72d8d2Sderaadt     }
5891e72d8d2Sderaadt }
5901e72d8d2Sderaadt 
5911e72d8d2Sderaadt 
5921e72d8d2Sderaadt /* Create an asynchronous child process executing ARGV,
5931e72d8d2Sderaadt    with its standard input and output connected to the
5941e72d8d2Sderaadt    parent with pipes.  Set *TO to the file descriptor on
5951e72d8d2Sderaadt    which one writes data for the child; set *FROM to
5961e72d8d2Sderaadt    the file descriptor from which one reads data from the child.
5971e72d8d2Sderaadt    Return the handle of the child process (this is what
5981e72d8d2Sderaadt    _cwait and waitpid expect).  */
5991e72d8d2Sderaadt int
piped_child(char ** argv,int * to,int * from)6001e72d8d2Sderaadt piped_child (char **argv, int *to, int *from)
6011e72d8d2Sderaadt {
6021e72d8d2Sderaadt   int child;
6031e72d8d2Sderaadt   HANDLE pipein[2], pipeout[2];
6041e72d8d2Sderaadt   char *command;
6051e72d8d2Sderaadt 
6061e72d8d2Sderaadt   /* Turn argv into a form acceptable to CreateProcess.  */
6071e72d8d2Sderaadt   command = build_command (argv);
6081e72d8d2Sderaadt   if (! command)
6091e72d8d2Sderaadt       return -1;
6101e72d8d2Sderaadt 
6111e72d8d2Sderaadt   /* Create pipes for communicating with child.  Arrange for
6121e72d8d2Sderaadt      the child not to inherit the ends it won't use.  */
6131e72d8d2Sderaadt   if (my_pipe (pipein, inherit_reading) == -1
6141e72d8d2Sderaadt       || my_pipe (pipeout, inherit_writing) == -1)
6151e72d8d2Sderaadt       return -1;
6161e72d8d2Sderaadt 
6171e72d8d2Sderaadt   child = start_child (command, pipein[0], pipeout[1]);
6181e72d8d2Sderaadt   free (command);
6191e72d8d2Sderaadt   if (child == (int) INVALID_HANDLE_VALUE)
6201e72d8d2Sderaadt       return -1;
6211e72d8d2Sderaadt 
6221e72d8d2Sderaadt   /* Close the pipe ends the parent doesn't use.  */
6231e72d8d2Sderaadt   CloseHandle (pipein[0]);
6241e72d8d2Sderaadt   CloseHandle (pipeout[1]);
6251e72d8d2Sderaadt 
6261e72d8d2Sderaadt   /* Given the pipe handles, turn them into file descriptors for
6271e72d8d2Sderaadt      use by the caller.  */
6281e72d8d2Sderaadt   if ((*to      = _open_osfhandle ((long) pipein[1],  _O_BINARY)) == -1
6291e72d8d2Sderaadt       || (*from = _open_osfhandle ((long) pipeout[0], _O_BINARY)) == -1)
6301e72d8d2Sderaadt       return -1;
6311e72d8d2Sderaadt 
6321e72d8d2Sderaadt   return child;
6331e72d8d2Sderaadt }
6341e72d8d2Sderaadt 
6351e72d8d2Sderaadt /*
6361e72d8d2Sderaadt  * dir = 0 : main proc writes to new proc, which writes to oldfd
6371e72d8d2Sderaadt  * dir = 1 : main proc reads from new proc, which reads from oldfd
63813571821Stholo  *
63913571821Stholo  * Returns: a file descriptor.  On failure (e.g., the exec fails),
64013571821Stholo  * then filter_stream_through_program() complains and dies.
6411e72d8d2Sderaadt  */
6421e72d8d2Sderaadt 
6431e72d8d2Sderaadt int
filter_stream_through_program(oldfd,dir,prog,pidp)6441e72d8d2Sderaadt filter_stream_through_program (oldfd, dir, prog, pidp)
6451e72d8d2Sderaadt      int oldfd, dir;
6461e72d8d2Sderaadt      char **prog;
6471e72d8d2Sderaadt      pid_t *pidp;
6481e72d8d2Sderaadt {
6491e72d8d2Sderaadt     HANDLE pipe[2];
6501e72d8d2Sderaadt     char *command;
6511e72d8d2Sderaadt     int child;
6521e72d8d2Sderaadt     HANDLE oldfd_handle;
6531e72d8d2Sderaadt     HANDLE newfd_handle;
6541e72d8d2Sderaadt     int newfd;
6551e72d8d2Sderaadt 
6561e72d8d2Sderaadt     /* Get the OS handle associated with oldfd, to be passed to the child.  */
6571e72d8d2Sderaadt     if ((oldfd_handle = (HANDLE) _get_osfhandle (oldfd)) < 0)
65813571821Stholo 	error (1, errno, "cannot _get_osfhandle");
6591e72d8d2Sderaadt 
6601e72d8d2Sderaadt     if (dir)
6611e72d8d2Sderaadt     {
6621e72d8d2Sderaadt         /* insert child before parent, pipe goes child->parent.  */
6631e72d8d2Sderaadt 	if (my_pipe (pipe, inherit_writing) == -1)
66413571821Stholo 	    error (1, errno, "cannot my_pipe");
6651e72d8d2Sderaadt 	if ((command = build_command (prog)) == NULL)
66613571821Stholo 	    error (1, errno, "cannot build_command");
6671e72d8d2Sderaadt 	child = start_child (command, oldfd_handle, pipe[1]);
6681e72d8d2Sderaadt 	free (command);
6691e72d8d2Sderaadt 	if (child == (int) INVALID_HANDLE_VALUE)
67013571821Stholo 	    error (1, errno, "cannot start_child");
6711e72d8d2Sderaadt 	close (oldfd);
6721e72d8d2Sderaadt 	CloseHandle (pipe[1]);
6731e72d8d2Sderaadt 	newfd_handle = pipe[0];
6741e72d8d2Sderaadt     }
6751e72d8d2Sderaadt     else
6761e72d8d2Sderaadt     {
6771e72d8d2Sderaadt         /* insert child after parent, pipe goes parent->child.  */
6781e72d8d2Sderaadt 	if (my_pipe (pipe, inherit_reading) == -1)
67913571821Stholo 	    error (1, errno, "cannot my_pipe");
6801e72d8d2Sderaadt 	if ((command = build_command (prog)) == NULL)
68113571821Stholo 	    error (1, errno, "cannot build_command");
6821e72d8d2Sderaadt 	child = start_child (command, pipe[0], oldfd_handle);
6831e72d8d2Sderaadt 	free (command);
6841e72d8d2Sderaadt 	if (child == (int) INVALID_HANDLE_VALUE)
68513571821Stholo 	    error (1, errno, "cannot start_child");
6861e72d8d2Sderaadt 	close (oldfd);
6871e72d8d2Sderaadt 	CloseHandle (pipe[0]);
6881e72d8d2Sderaadt 	newfd_handle = pipe[1];
6891e72d8d2Sderaadt     }
6901e72d8d2Sderaadt 
6911e72d8d2Sderaadt     if ((newfd = _open_osfhandle ((long) newfd_handle, _O_BINARY)) == -1)
69213571821Stholo         error (1, errno, "cannot _open_osfhandle");
6931e72d8d2Sderaadt 
69413571821Stholo     if (pidp)
6951e72d8d2Sderaadt 	*pidp = child;
6961e72d8d2Sderaadt     return newfd;
6971e72d8d2Sderaadt }
6981e72d8d2Sderaadt 
6991e72d8d2Sderaadt 
7001e72d8d2Sderaadt /* Arrange for the file descriptor FD to not be inherited by child
7011e72d8d2Sderaadt    processes.  At the moment, CVS uses this function only on pipes
7021e72d8d2Sderaadt    returned by piped_child, and our implementation of piped_child
7031e72d8d2Sderaadt    takes care of setting the file handles' inheritability, so this
7041e72d8d2Sderaadt    can be a no-op.  */
7051e72d8d2Sderaadt void
close_on_exec(int fd)7061e72d8d2Sderaadt close_on_exec (int fd)
7071e72d8d2Sderaadt {
7081e72d8d2Sderaadt }
709