113571821Stholo /* run.c --- routines for executing subprocesses under OS/2.
213571821Stholo
313571821Stholo This file is part of GNU CVS.
413571821Stholo
513571821Stholo GNU CVS is free software; you can redistribute it and/or modify it
613571821Stholo under the terms of the GNU General Public License as published by the
713571821Stholo Free Software Foundation; either version 2, or (at your option) any
813571821Stholo later version.
913571821Stholo
1013571821Stholo This program is distributed in the hope that it will be useful,
1113571821Stholo but WITHOUT ANY WARRANTY; without even the implied warranty of
1213571821Stholo MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13461cc63eStholo GNU General Public License for more details. */
1413571821Stholo
1513571821Stholo #include "cvs.h"
1613571821Stholo
17461cc63eStholo #include "os2inc.h"
18461cc63eStholo
1913571821Stholo #include <process.h>
2013571821Stholo
2113571821Stholo #include <stdio.h>
2213571821Stholo #include <stdlib.h>
2313571821Stholo #include <sys/types.h>
2413571821Stholo #include <sys/stat.h>
2513571821Stholo #include <string.h>
2613571821Stholo #include <fcntl.h>
2713571821Stholo #include <errno.h>
2813571821Stholo #include <io.h>
2913571821Stholo
3013571821Stholo #define STDIN 0
3113571821Stholo #define STDOUT 1
3213571821Stholo #define STDERR 2
3313571821Stholo
3413571821Stholo static void run_add_arg PROTO((const char *s));
3513571821Stholo static void run_init_prog PROTO((void));
3613571821Stholo
3713571821Stholo extern char *strtok ();
3813571821Stholo
3913571821Stholo /*
4013571821Stholo * To exec a program under CVS, first call run_setup() to setup any initial
4113571821Stholo * arguments. The options to run_setup are essentially like printf(). The
4213571821Stholo * arguments will be parsed into whitespace separated words and added to the
4313571821Stholo * global run_argv list.
4413571821Stholo *
4513571821Stholo * Then, optionally call run_arg() for each additional argument that you'd like
4613571821Stholo * to pass to the executed program.
4713571821Stholo *
4813571821Stholo * Finally, call run_exec() to execute the program with the specified
4913571821Stholo * arguments.
5013571821Stholo * The execvp() syscall will be used, so that the PATH is searched correctly.
5113571821Stholo * File redirections can be performed in the call to run_exec().
5213571821Stholo */
5313571821Stholo static char **run_argv;
5413571821Stholo static int run_argc;
5513571821Stholo static int run_argc_allocated;
5613571821Stholo
5713571821Stholo void
run_setup(const char * prog)58*2286d8edStholo run_setup (const char *prog)
5913571821Stholo {
6013571821Stholo char *cp;
6113571821Stholo int i;
6213571821Stholo
63*2286d8edStholo char *run_prog;
6413571821Stholo
6513571821Stholo /* clean out any malloc'ed values from run_argv */
6613571821Stholo for (i = 0; i < run_argc; i++)
6713571821Stholo {
6813571821Stholo if (run_argv[i])
6913571821Stholo {
7013571821Stholo free (run_argv[i]);
7113571821Stholo run_argv[i] = (char *) 0;
7213571821Stholo }
7313571821Stholo }
7413571821Stholo run_argc = 0;
7513571821Stholo
76*2286d8edStholo run_prog = xstrdup (prog);
7713571821Stholo
7813571821Stholo /* put each word into run_argv, allocating it as we go */
7913571821Stholo for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
8013571821Stholo run_add_arg (cp);
81*2286d8edStholo
82*2286d8edStholo free (run_prog)
8313571821Stholo }
8413571821Stholo
8513571821Stholo void
run_arg(s)8613571821Stholo run_arg (s)
8713571821Stholo const char *s;
8813571821Stholo {
8913571821Stholo run_add_arg (s);
9013571821Stholo }
9113571821Stholo
9213571821Stholo /* Return a malloc'd copy of s, with double quotes around it. */
9313571821Stholo static char *
quote(const char * s)9413571821Stholo quote (const char *s)
9513571821Stholo {
9613571821Stholo size_t s_len = strlen (s);
9713571821Stholo char *copy = xmalloc (s_len + 3);
9813571821Stholo char *scan = copy;
9913571821Stholo
10013571821Stholo *scan++ = '"';
10113571821Stholo strcpy (scan, s);
10213571821Stholo scan += s_len;
10313571821Stholo *scan++ = '"';
10413571821Stholo *scan++ = '\0';
10513571821Stholo
10613571821Stholo return copy;
10713571821Stholo }
10813571821Stholo
10913571821Stholo static void
run_add_arg(s)11013571821Stholo run_add_arg (s)
11113571821Stholo const char *s;
11213571821Stholo {
11313571821Stholo /* allocate more argv entries if we've run out */
11413571821Stholo if (run_argc >= run_argc_allocated)
11513571821Stholo {
11613571821Stholo run_argc_allocated += 50;
11713571821Stholo run_argv = (char **) xrealloc ((char *) run_argv,
11813571821Stholo run_argc_allocated * sizeof (char **));
11913571821Stholo }
12013571821Stholo
12113571821Stholo if (s)
12213571821Stholo {
12313571821Stholo run_argv[run_argc] = (run_argc ? quote (s) : xstrdup (s));
12413571821Stholo run_argc++;
12513571821Stholo }
12613571821Stholo else
12713571821Stholo /* not post-incremented on purpose! */
12813571821Stholo run_argv[run_argc] = (char *) 0;
12913571821Stholo }
13013571821Stholo
13113571821Stholo int
run_exec(stin,stout,sterr,flags)13213571821Stholo run_exec (stin, stout, sterr, flags)
13313571821Stholo char *stin;
13413571821Stholo char *stout;
13513571821Stholo char *sterr;
13613571821Stholo int flags;
13713571821Stholo {
13813571821Stholo int shin, shout, sherr;
13913571821Stholo int sain, saout, saerr; /* saved handles */
14013571821Stholo int mode_out, mode_err;
14113571821Stholo int status = -1;
14213571821Stholo int rerrno = 0;
14313571821Stholo int rval = -1;
14413571821Stholo void (*old_sigint) (int);
14513571821Stholo
14613571821Stholo if (trace) /* if in trace mode */
14713571821Stholo {
14813571821Stholo (void) fprintf (stderr, "-> system(");
14913571821Stholo run_print (stderr);
15013571821Stholo (void) fprintf (stderr, ")\n");
15113571821Stholo }
15213571821Stholo if (noexec && (flags & RUN_REALLY) == 0) /* if in noexec mode */
15313571821Stholo return (0);
15413571821Stholo
15513571821Stholo /*
15613571821Stholo * start the engine and take off
15713571821Stholo */
15813571821Stholo
15913571821Stholo /* make sure that we are null terminated, since we didn't calloc */
16013571821Stholo run_add_arg ((char *) 0);
16113571821Stholo
16213571821Stholo /* setup default file descriptor numbers */
16313571821Stholo shin = 0;
16413571821Stholo shout = 1;
16513571821Stholo sherr = 2;
16613571821Stholo
16713571821Stholo /* set the file modes for stdout and stderr */
16813571821Stholo mode_out = mode_err = O_WRONLY | O_CREAT;
16913571821Stholo mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
17013571821Stholo mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
17113571821Stholo
17213571821Stholo /* open the files as required, shXX are shadows of stdin... */
17313571821Stholo if (stin && (shin = open (stin, O_RDONLY)) == -1)
17413571821Stholo {
17513571821Stholo rerrno = errno;
17613571821Stholo error (0, errno, "cannot open %s for reading (prog %s)",
17713571821Stholo stin, run_argv[0]);
17813571821Stholo goto out0;
17913571821Stholo }
18013571821Stholo if (stout && (shout = open (stout, mode_out, 0666)) == -1)
18113571821Stholo {
18213571821Stholo rerrno = errno;
18313571821Stholo error (0, errno, "cannot open %s for writing (prog %s)",
18413571821Stholo stout, run_argv[0]);
18513571821Stholo goto out1;
18613571821Stholo }
18713571821Stholo if (sterr && (flags & RUN_COMBINED) == 0)
18813571821Stholo {
18913571821Stholo if ((sherr = open (sterr, mode_err, 0666)) == -1)
19013571821Stholo {
19113571821Stholo rerrno = errno;
19213571821Stholo error (0, errno, "cannot open %s for writing (prog %s)",
19313571821Stholo sterr, run_argv[0]);
19413571821Stholo goto out2;
19513571821Stholo }
19613571821Stholo }
19713571821Stholo /* now save the standard handles */
19813571821Stholo sain = saout = saerr = -1;
19913571821Stholo sain = dup( 0); /* dup stdin */
20013571821Stholo saout = dup( 1); /* dup stdout */
20113571821Stholo saerr = dup( 2); /* dup stderr */
20213571821Stholo
20313571821Stholo /* the new handles will be dup'd to the standard handles
20413571821Stholo * for the spawn.
20513571821Stholo */
20613571821Stholo
20713571821Stholo if (shin != 0)
20813571821Stholo {
20913571821Stholo (void) dup2 (shin, 0);
21013571821Stholo (void) close (shin);
21113571821Stholo }
21213571821Stholo if (shout != 1)
21313571821Stholo {
21413571821Stholo (void) dup2 (shout, 1);
21513571821Stholo (void) close (shout);
21613571821Stholo }
21713571821Stholo if (flags & RUN_COMBINED)
21813571821Stholo (void) dup2 (1, 2);
21913571821Stholo else if (sherr != 2)
22013571821Stholo {
22113571821Stholo (void) dup2 (sherr, 2);
22213571821Stholo (void) close (sherr);
22313571821Stholo }
22413571821Stholo
22513571821Stholo /* Ignore signals while we're running this. */
22613571821Stholo old_sigint = signal (SIGINT, SIG_IGN);
22713571821Stholo
22813571821Stholo /* dup'ing is done. try to run it now */
22913571821Stholo rval = spawnvp ( P_WAIT, run_argv[0], run_argv);
23013571821Stholo
23113571821Stholo /* Restore signal handling. */
23213571821Stholo signal (SIGINT, old_sigint);
23313571821Stholo
23413571821Stholo /* restore the original file handles */
23513571821Stholo if (sain != -1) {
23613571821Stholo (void) dup2( sain, 0); /* re-connect stdin */
23713571821Stholo (void) close( sain);
23813571821Stholo }
23913571821Stholo if (saout != -1) {
24013571821Stholo (void) dup2( saout, 1); /* re-connect stdout */
24113571821Stholo (void) close( saout);
24213571821Stholo }
24313571821Stholo if (saerr != -1) {
24413571821Stholo (void) dup2( saerr, 2); /* re-connect stderr */
24513571821Stholo (void) close( saerr);
24613571821Stholo }
24713571821Stholo
24813571821Stholo /* Recognize the return code for a failed subprocess. */
24913571821Stholo if (rval == -1)
25013571821Stholo return 2;
25113571821Stholo else
25213571821Stholo return rval; /* return child's exit status */
25313571821Stholo
25413571821Stholo /* error cases */
25513571821Stholo /* cleanup the open file descriptors */
25613571821Stholo out2:
25713571821Stholo if (stout)
25813571821Stholo (void) close (shout);
25913571821Stholo out1:
26013571821Stholo if (stin)
26113571821Stholo (void) close (shin);
26213571821Stholo
26313571821Stholo out0:
26413571821Stholo if (rerrno)
26513571821Stholo errno = rerrno;
26613571821Stholo return (status);
26713571821Stholo }
26813571821Stholo
26913571821Stholo
27013571821Stholo void
run_print(fp)27113571821Stholo run_print (fp)
27213571821Stholo FILE *fp;
27313571821Stholo {
27413571821Stholo int i;
27513571821Stholo
27613571821Stholo for (i = 0; i < run_argc; i++)
27713571821Stholo {
27813571821Stholo (void) fprintf (fp, "'%s'", run_argv[i]);
27913571821Stholo if (i != run_argc - 1)
28013571821Stholo (void) fprintf (fp, " ");
28113571821Stholo }
28213571821Stholo }
28313571821Stholo
28413571821Stholo static char *
requote(const char * cmd)28513571821Stholo requote (const char *cmd)
28613571821Stholo {
28713571821Stholo char *requoted = xmalloc (strlen (cmd) + 1);
28813571821Stholo char *p = requoted;
28913571821Stholo
29013571821Stholo strcpy (requoted, cmd);
29113571821Stholo while ((p = strchr (p, '\'')) != NULL)
29213571821Stholo {
29313571821Stholo *p++ = '"';
29413571821Stholo }
29513571821Stholo
29613571821Stholo return requoted;
29713571821Stholo }
29813571821Stholo
29913571821Stholo FILE *
run_popen(cmd,mode)300c26070a5Stholo run_popen (cmd, mode)
30113571821Stholo const char *cmd;
30213571821Stholo const char *mode;
30313571821Stholo {
30413571821Stholo if (trace)
30513571821Stholo #ifdef SERVER_SUPPORT
306c26070a5Stholo (void) fprintf (stderr, "%c-> run_popen(%s,%s)\n",
30713571821Stholo (server_active) ? 'S' : ' ', cmd, mode);
30813571821Stholo #else
309c26070a5Stholo (void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode);
31013571821Stholo #endif
31113571821Stholo
31213571821Stholo if (noexec)
31313571821Stholo return (NULL);
31413571821Stholo
31513571821Stholo /* If the command string uses single quotes, turn them into
31613571821Stholo double quotes. */
31713571821Stholo {
31813571821Stholo char *requoted = requote (cmd);
31913571821Stholo FILE *result = popen (requoted, mode);
32013571821Stholo free (requoted);
32113571821Stholo return result;
32213571821Stholo }
32313571821Stholo }
32413571821Stholo
32513571821Stholo
32613571821Stholo /* Running children with pipes connected to them. */
32713571821Stholo
32813571821Stholo /* Create a pipe. Set READWRITE[0] to its reading end, and
32913571821Stholo READWRITE[1] to its writing end. */
33013571821Stholo
33113571821Stholo static int
my_pipe(int * readwrite)33213571821Stholo my_pipe (int *readwrite)
33313571821Stholo {
33413571821Stholo fprintf (stderr,
33513571821Stholo "Error: my_pipe() is unimplemented.\n");
33613571821Stholo exit (1);
33713571821Stholo }
33813571821Stholo
33913571821Stholo
34013571821Stholo /* Create a child process running COMMAND with IN as its standard input,
34113571821Stholo and OUT as its standard output. Return a handle to the child, or
34213571821Stholo INVALID_HANDLE_VALUE. */
34313571821Stholo static int
start_child(char * command,int in,int out)34413571821Stholo start_child (char *command, int in, int out)
34513571821Stholo {
34613571821Stholo fprintf (stderr,
34713571821Stholo "Error: start_child() is unimplemented.\n");
34813571821Stholo exit (1);
34913571821Stholo }
35013571821Stholo
35113571821Stholo
35213571821Stholo /* Given an array of arguments that one might pass to spawnv,
35313571821Stholo construct a command line that one might pass to CreateProcess.
35413571821Stholo Try to quote things appropriately. */
35513571821Stholo static char *
build_command(char ** argv)35613571821Stholo build_command (char **argv)
35713571821Stholo {
35813571821Stholo int len;
35913571821Stholo
36013571821Stholo /* Compute the total length the command will have. */
36113571821Stholo {
36213571821Stholo int i;
36313571821Stholo
36413571821Stholo len = 0;
36513571821Stholo for (i = 0; argv[i]; i++)
36613571821Stholo {
36713571821Stholo char *p;
36813571821Stholo
36913571821Stholo len += 2; /* for the double quotes */
37013571821Stholo
37113571821Stholo for (p = argv[i]; *p; p++)
37213571821Stholo {
37313571821Stholo if (*p == '"')
37413571821Stholo len += 2;
37513571821Stholo else
37613571821Stholo len++;
37713571821Stholo }
37813571821Stholo }
37913571821Stholo len++; /* for the space or the '\0' */
38013571821Stholo }
38113571821Stholo
38213571821Stholo {
38313571821Stholo char *command = (char *) malloc (len);
38413571821Stholo int i;
38513571821Stholo char *p;
38613571821Stholo
38713571821Stholo if (! command)
38813571821Stholo {
38913571821Stholo errno = ENOMEM;
39013571821Stholo return command;
39113571821Stholo }
39213571821Stholo
39313571821Stholo p = command;
39413571821Stholo /* copy each element of argv to command, putting each command
39513571821Stholo in double quotes, and backslashing any quotes that appear
39613571821Stholo within an argument. */
39713571821Stholo for (i = 0; argv[i]; i++)
39813571821Stholo {
39913571821Stholo char *a;
40013571821Stholo *p++ = '"';
40113571821Stholo for (a = argv[i]; *a; a++)
40213571821Stholo {
40313571821Stholo if (*a == '"')
40413571821Stholo *p++ = '\\', *p++ = '"';
40513571821Stholo else
40613571821Stholo *p++ = *a;
40713571821Stholo }
40813571821Stholo *p++ = '"';
40913571821Stholo *p++ = ' ';
41013571821Stholo }
41113571821Stholo p[-1] = '\0';
41213571821Stholo
41313571821Stholo return command;
41413571821Stholo }
41513571821Stholo }
41613571821Stholo
41713571821Stholo
41813571821Stholo /* Create an asynchronous child process executing ARGV,
41913571821Stholo with its standard input and output connected to the
42013571821Stholo parent with pipes. Set *TO to the file descriptor on
42113571821Stholo which one writes data for the child; set *FROM to
42213571821Stholo the file descriptor from which one reads data from the child.
42313571821Stholo Return the handle of the child process (this is what
42413571821Stholo _cwait and waitpid expect). */
42513571821Stholo int
piped_child(char ** argv,int * to,int * from)42613571821Stholo piped_child (char **argv, int *to, int *from)
42713571821Stholo {
42813571821Stholo fprintf (stderr,
42913571821Stholo "Error: piped_child() is unimplemented.\n");
43013571821Stholo exit (1);
43113571821Stholo }
43213571821Stholo
43313571821Stholo /*
43413571821Stholo * dir = 0 : main proc writes to new proc, which writes to oldfd
43513571821Stholo * dir = 1 : main proc reads from new proc, which reads from oldfd
43613571821Stholo *
43713571821Stholo * If this returns at all, then it was successful and the return value
43813571821Stholo * is a file descriptor; else it errors and exits.
43913571821Stholo */
44013571821Stholo int
filter_stream_through_program(int oldfd,int dir,char ** prog,int * pidp)44113571821Stholo filter_stream_through_program (int oldfd, int dir,
44213571821Stholo char **prog, int *pidp)
44313571821Stholo {
44413571821Stholo int newfd; /* Gets set to one end of the pipe and returned. */
44513571821Stholo HFILE from, to;
44613571821Stholo HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp;
44713571821Stholo
44813571821Stholo if (DosCreatePipe (&from, &to, 4096))
44913571821Stholo return FALSE;
45013571821Stholo
45113571821Stholo /* Save std{in,out,err} */
45213571821Stholo DosDupHandle (STDIN, &Old0);
45313571821Stholo DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
45413571821Stholo DosDupHandle (STDOUT, &Old1);
45513571821Stholo DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
45613571821Stholo DosDupHandle (STDERR, &Old2);
45713571821Stholo DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
45813571821Stholo
45913571821Stholo /* Redirect std{in,out,err} */
46013571821Stholo if (dir) /* Who goes where? */
46113571821Stholo {
46213571821Stholo Tmp = STDIN;
46313571821Stholo DosDupHandle (oldfd, &Tmp);
46413571821Stholo Tmp = STDOUT;
46513571821Stholo DosDupHandle (to, &Tmp);
46613571821Stholo Tmp = STDERR;
46713571821Stholo DosDupHandle (to, &Tmp);
46813571821Stholo
46913571821Stholo newfd = from;
47013571821Stholo _setmode (newfd, O_BINARY);
47113571821Stholo
47213571821Stholo DosClose (oldfd);
47313571821Stholo DosClose (to);
47413571821Stholo DosSetFHState (from, OPEN_FLAGS_NOINHERIT);
47513571821Stholo }
47613571821Stholo else
47713571821Stholo {
47813571821Stholo Tmp = STDIN;
47913571821Stholo DosDupHandle (from, &Tmp);
48013571821Stholo Tmp = STDOUT;
48113571821Stholo DosDupHandle (oldfd, &Tmp);
48213571821Stholo Tmp = STDERR;
48313571821Stholo DosDupHandle (oldfd, &Tmp);
48413571821Stholo
48513571821Stholo newfd = to;
48613571821Stholo _setmode (newfd, O_BINARY);
48713571821Stholo
48813571821Stholo DosClose (oldfd);
48913571821Stholo DosClose (from);
49013571821Stholo DosSetFHState (to, OPEN_FLAGS_NOINHERIT);
49113571821Stholo }
49213571821Stholo
49313571821Stholo /* Spawn we now our hoary brood. */
49413571821Stholo *pidp = spawnvp (P_NOWAIT, prog[0], prog);
49513571821Stholo
49613571821Stholo /* Restore std{in,out,err} */
49713571821Stholo Tmp = STDIN;
49813571821Stholo DosDupHandle (Old0, &Tmp);
49913571821Stholo DosClose (Old0);
50013571821Stholo Tmp = STDOUT;
50113571821Stholo DosDupHandle (Old1, &Tmp);
50213571821Stholo DosClose (Old1);
50313571821Stholo Tmp = STDERR;
50413571821Stholo DosDupHandle (Old2, &Tmp);
50513571821Stholo DosClose (Old2);
50613571821Stholo
50713571821Stholo if(*pidp < 0)
50813571821Stholo {
50913571821Stholo DosClose (from);
51013571821Stholo DosClose (to);
51113571821Stholo error (1, 0, "error spawning %s", prog[0]);
51213571821Stholo }
51313571821Stholo
51413571821Stholo return newfd;
51513571821Stholo }
51613571821Stholo
51713571821Stholo
51813571821Stholo int
pipe(int * filedesc)51913571821Stholo pipe (int *filedesc)
52013571821Stholo {
52113571821Stholo /* todo: actually, we can use DosCreatePipe(). Fix this. */
52213571821Stholo fprintf (stderr,
52313571821Stholo "Error: pipe() should not have been called in client.\n");
52413571821Stholo exit (1);
52513571821Stholo }
52613571821Stholo
52713571821Stholo
52813571821Stholo void
close_on_exec(int fd)52913571821Stholo close_on_exec (int fd)
53013571821Stholo {
53113571821Stholo /* Just does nothing for now... */
53213571821Stholo
53313571821Stholo /* Actually, we probably *can* implement this one. Let's see... */
53413571821Stholo /* Nope. OS/2 has <fcntl.h>, but no fcntl() ! Wow. */
53513571821Stholo /* Well, I'll leave this stuff in for future reference. */
53613571821Stholo }
53713571821Stholo
53813571821Stholo
53913571821Stholo /* Actually, we #define sleep() in config.h now. */
54013571821Stholo #ifndef sleep
54113571821Stholo unsigned int
sleep(unsigned int seconds)54213571821Stholo sleep (unsigned int seconds)
54313571821Stholo {
54413571821Stholo /* I don't want to interfere with alarm signals, so I'm going to do
54513571821Stholo this the nasty way. */
54613571821Stholo
54713571821Stholo time_t base;
54813571821Stholo time_t tick;
54913571821Stholo int i;
55013571821Stholo
55113571821Stholo /* Init. */
55213571821Stholo time (&base);
55313571821Stholo time (&tick);
55413571821Stholo
55513571821Stholo /* Loop until time has passed. */
55613571821Stholo while (difftime (tick, base) < seconds)
55713571821Stholo {
55813571821Stholo /* This might be more civilized than calling time over and over
55913571821Stholo again. */
56013571821Stholo for (i = 0; i < 10000; i++)
56113571821Stholo ;
56213571821Stholo time (&tick);
56313571821Stholo }
56413571821Stholo
56513571821Stholo return 0;
56613571821Stholo }
56713571821Stholo #endif /* sleep */
568