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, ©,
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