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