#include "cvs.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <process.h>
#include <errno.h>
#include <io.h>
#include <fcntl.h>
static char **run_argv;
static int run_argc;
static size_t run_arg_allocated;
void
run_arg_free_p (int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
free (argv[i]);
}
void
run_setup (const char *prog)
{
char *cp;
int i;
char *run_prog;
for (i = 0; i < run_argc; i++)
{
if (run_argv[i])
{
free (run_argv[i]);
run_argv[i] = (char *) 0;
}
}
run_argc = 0;
run_prog = xstrdup (prog);
for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
run_add_arg (cp);
free (run_prog);
}
static char *
quote (const char *s)
{
size_t s_len = 0;
char *copy = NULL;
char *scan = (char *) s;
while (*scan)
if ('"' == *scan++)
s_len += 2;
else
s_len++;
scan = copy = xmalloc(s_len + 3);
*scan++ = '"';
while (*s)
{
if ('"' == *s)
*scan++ = '\\';
*scan++ = *s++;
}
*scan++ = '"';
*scan++ = '\0';
return copy;
}
void
run_add_arg_p (int *iargc, size_t *iarg_allocated, char ***iargv,
const char *s)
{
if (*iargc >= *iarg_allocated)
{
*iarg_allocated += 50;
*iargv = xnrealloc (*iargv, *iarg_allocated, sizeof (char **));
}
if (s)
(*iargv)[(*iargc)++] = xstrdup (s);
else
(*iargv)[*iargc] = NULL;
}
void
run_add_arg (const char *s)
{
run_add_arg_p (&run_argc, &run_arg_allocated, &run_argv, s);
}
int
run_exec (const char *stin, const char *stout, const char *sterr, int flags)
{
int shin, shout, sherr;
int sain, saout, saerr;
int mode_out, mode_err;
int status = -1;
int rerrno = 0;
int rval = -1;
void (*old_sigint) (int);
if (trace)
{
(void) fprintf (stderr, "-> system(");
run_print (stderr);
(void) fprintf (stderr, ")\n");
}
fflush (stderr);
fflush (stdout);
if (noexec && (flags & RUN_REALLY) == 0)
return (0);
run_add_arg ((char *) 0);
shin = 0;
shout = 1;
sherr = 2;
mode_out = mode_err = O_WRONLY | O_CREAT;
mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
if (stin && (shin = open (stin, O_RDONLY)) == -1)
{
rerrno = errno;
error (0, errno, "cannot open %s for reading (prog %s)",
stin, run_argv[0]);
goto out0;
}
if (stout && (shout = open (stout, mode_out, 0666)) == -1)
{
rerrno = errno;
error (0, errno, "cannot open %s for writing (prog %s)",
stout, run_argv[0]);
goto out1;
}
if (sterr && (flags & RUN_COMBINED) == 0)
{
if ((sherr = open (sterr, mode_err, 0666)) == -1)
{
rerrno = errno;
error (0, errno, "cannot open %s for writing (prog %s)",
sterr, run_argv[0]);
goto out2;
}
}
sain = saout = saerr = -1;
sain = dup( 0);
saout = dup( 1);
saerr = dup( 2);
if (shin != 0)
{
(void) dup2 (shin, 0);
(void) close (shin);
}
if (shout != 1)
{
(void) dup2 (shout, 1);
(void) close (shout);
}
if (flags & RUN_COMBINED)
(void) dup2 (1, 2);
else if (sherr != 2)
{
(void) dup2 (sherr, 2);
(void) close (sherr);
}
old_sigint = signal (SIGINT, SIG_IGN);
rval = spawnvp ( P_WAIT, run_argv[0], run_argv);
signal (SIGINT, old_sigint);
if (sain != -1) {
(void) dup2( sain, 0);
(void) close( sain);
}
if (saout != -1) {
(void) dup2( saout, 1);
(void) close( saout);
}
if (saerr != -1) {
(void) dup2( saerr, 2);
(void) close( saerr);
}
fflush (stderr);
fflush (stdout);
if (rval == CONTROL_C_EXIT)
return 2;
else
return rval;
out2:
if (stout)
(void) close (shout);
out1:
if (stin)
(void) close (shin);
out0:
if (rerrno)
errno = rerrno;
return (status);
}
void
run_print (FILE *fp)
{
int i;
for (i = 0; i < run_argc; i++)
{
(void) fprintf (fp, "'%s'", run_argv[i]);
if (i != run_argc - 1)
(void) fprintf (fp, " ");
}
}
static char *
requote (const char *cmd)
{
char *requoted = xmalloc (strlen (cmd) + 1);
char *p = requoted;
strcpy (requoted, cmd);
while ((p = strchr (p, '\'')) != NULL)
{
*p++ = '"';
}
return requoted;
}
FILE *
run_popen (const char *cmd, const char *mode)
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> run_popen(%s,%s)\n",
(server_active) ? 'S' : ' ', cmd, mode);
#else
(void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode);
#endif
if (noexec)
return (NULL);
{
char *requoted = requote (cmd);
int old_stdin = dup (STDIN_FILENO);
int old_stdout = dup (STDOUT_FILENO);
int old_stderr = dup (STDERR_FILENO);
FILE *result = popen (requoted, mode);
dup2 (old_stdin, STDIN_FILENO);
dup2 (old_stdout, STDOUT_FILENO);
dup2 (old_stderr, STDERR_FILENO);
close (old_stdin);
close (old_stdout);
close (old_stderr);
free (requoted);
return result;
}
}
static HANDLE
inheritable (HANDLE in)
{
HANDLE copy;
HANDLE self = GetCurrentProcess ();
if (! DuplicateHandle (self, in, self, ©,
0, 1 ,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
return INVALID_HANDLE_VALUE;
return copy;
}
static void
init_sa (LPSECURITY_ATTRIBUTES lpsa, BOOL inherit)
{
lpsa->nLength = sizeof(*lpsa);
lpsa->bInheritHandle = inherit;
lpsa->lpSecurityDescriptor = NULL;
}
enum inherit_pipe { inherit_reading, inherit_writing };
static int
my_pipe (HANDLE *readwrite, enum inherit_pipe end)
{
HANDLE read, write;
SECURITY_ATTRIBUTES sa;
init_sa (&sa, 0);
if (! CreatePipe (&read, &write, &sa, 1 << 13))
{
errno = EMFILE;
return -1;
}
if (end == inherit_reading)
read = inheritable (read);
else
write = inheritable (write);
if (read == INVALID_HANDLE_VALUE
|| write == INVALID_HANDLE_VALUE)
{
CloseHandle (read);
CloseHandle (write);
errno = EMFILE;
return -1;
}
readwrite[0] = read;
readwrite[1] = write;
return 0;
}
static void
init_si (LPSTARTUPINFO lpsi)
{
memset (lpsi, 0, sizeof (*lpsi));
lpsi->cb = sizeof(*lpsi);
lpsi->lpReserved = NULL;
lpsi->lpTitle = NULL;
lpsi->lpReserved2 = NULL;
lpsi->cbReserved2 = 0;
lpsi->lpDesktop = NULL;
lpsi->dwFlags = 0;
}
static int
start_child (char *command, HANDLE in, HANDLE out)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL status;
init_si (&si);
si.hStdInput = in;
si.hStdOutput = out;
si.hStdError = (HANDLE) _get_osfhandle (2);
si.dwFlags = STARTF_USESTDHANDLES;
status = CreateProcess ((LPCTSTR) NULL,
(LPTSTR) command,
(LPSECURITY_ATTRIBUTES) NULL,
(LPSECURITY_ATTRIBUTES) NULL,
TRUE,
0,
(LPVOID) 0,
(LPCTSTR) 0,
&si,
&pi);
if (! status)
{
DWORD error_code = GetLastError ();
switch (error_code)
{
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
errno = ENOMEM; break;
case ERROR_BAD_EXE_FORMAT:
errno = ENOEXEC; break;
case ERROR_ACCESS_DENIED:
errno = EACCES; break;
case ERROR_NOT_READY:
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
default:
errno = ENOENT; break;
}
return (int) INVALID_HANDLE_VALUE;
}
return (int) pi.hProcess;
}
static char *
build_command (char *const *argv)
{
int len;
{
int i;
len = 0;
for (i = 0; argv[i]; i++)
{
char *p;
len += 2;
for (p = argv[i]; *p; p++)
{
if (*p == '"')
len += 2;
else
len++;
}
len++;
}
}
{
char *command = (char *) malloc (len + 10);
int i;
char *p;
if (! command)
{
errno = ENOMEM;
return command;
}
p = command;
*p = '\0';
for (i = 0; argv[i]; i++)
{
char *a;
*p++ = '"';
for (a = argv[i]; *a; a++)
{
if (*a == '"')
*p++ = '\\', *p++ = '"';
else
*p++ = *a;
}
*p++ = '"';
*p++ = ' ';
}
if (p > command)
p[-1] = '\0';
return command;
}
}
int
piped_child (char *const *argv, int *to, int *from, bool fix_stderr)
{
int child;
HANDLE pipein[2], pipeout[2];
char *command;
command = build_command (argv);
if (!command)
return -1;
if (my_pipe (pipein, inherit_reading) == -1
|| my_pipe (pipeout, inherit_writing) == -1)
return -1;
child = start_child (command, pipein[0], pipeout[1]);
free (command);
if (child == (int) INVALID_HANDLE_VALUE)
return -1;
CloseHandle (pipein[0]);
CloseHandle (pipeout[1]);
if ((*to = _open_osfhandle ((long) pipein[1], _O_BINARY)) == -1
|| (*from = _open_osfhandle ((long) pipeout[0], _O_BINARY)) == -1)
return -1;
return child;
}
int
filter_stream_through_program (int oldfd, int dir, char **prog, pid_t *pidp)
{
HANDLE pipe[2];
char *command;
int child;
HANDLE oldfd_handle;
HANDLE newfd_handle;
int newfd;
if ((oldfd_handle = (HANDLE) _get_osfhandle (oldfd)) < 0)
error (1, errno, "cannot _get_osfhandle");
if (dir)
{
if (my_pipe (pipe, inherit_writing) == -1)
error (1, errno, "cannot my_pipe");
if ((command = build_command (prog)) == NULL)
error (1, errno, "cannot build_command");
child = start_child (command, oldfd_handle, pipe[1]);
free (command);
if (child == (int) INVALID_HANDLE_VALUE)
error (1, errno, "cannot start_child");
close (oldfd);
CloseHandle (pipe[1]);
newfd_handle = pipe[0];
}
else
{
if (my_pipe (pipe, inherit_reading) == -1)
error (1, errno, "cannot my_pipe");
if ((command = build_command (prog)) == NULL)
error (1, errno, "cannot build_command");
child = start_child (command, pipe[0], oldfd_handle);
free (command);
if (child == (int) INVALID_HANDLE_VALUE)
error (1, errno, "cannot start_child");
close (oldfd);
CloseHandle (pipe[0]);
newfd_handle = pipe[1];
}
if ((newfd = _open_osfhandle ((long) newfd_handle, _O_BINARY)) == -1)
error (1, errno, "cannot _open_osfhandle");
if (pidp)
*pidp = child;
return newfd;
}
int
run_piped (int *tofdp, int *fromfdp)
{
run_add_arg (NULL);
return piped_child (run_argv, tofdp, fromfdp, false);
}
void
close_on_exec (int fd)
{
}