117721Speter/* run.c --- routines for executing subprocesses. 217721Speter 317721Speter This file is part of GNU CVS. 417721Speter 517721Speter GNU CVS is free software; you can redistribute it and/or modify it 617721Speter under the terms of the GNU General Public License as published by the 717721Speter Free Software Foundation; either version 2, or (at your option) any 817721Speter later version. 917721Speter 1017721Speter This program is distributed in the hope that it will be useful, 1117721Speter but WITHOUT ANY WARRANTY; without even the implied warranty of 1217721Speter MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1325839Speter GNU General Public License for more details. */ 1417721Speter 1517721Speter#include "cvs.h" 1617721Speter 1732785Speter#ifndef HAVE_UNISTD_H 1832785Speterextern int execvp PROTO((char *file, char **argv)); 1917721Speter#endif 2017721Speter 2117721Speterstatic void run_add_arg PROTO((const char *s)); 2217721Speter 2317721Speterextern char *strtok (); 2417721Speter 2517721Speter/* 2632785Speter * To exec a program under CVS, first call run_setup() to setup initial 2732785Speter * arguments. The argument to run_setup will be parsed into whitespace 2832785Speter * separated words and added to the global run_argv list. 2917721Speter * 3017721Speter * Then, optionally call run_arg() for each additional argument that you'd like 3117721Speter * to pass to the executed program. 3217721Speter * 3317721Speter * Finally, call run_exec() to execute the program with the specified arguments. 3417721Speter * The execvp() syscall will be used, so that the PATH is searched correctly. 3517721Speter * File redirections can be performed in the call to run_exec(). 3617721Speter */ 3717721Speterstatic char **run_argv; 3817721Speterstatic int run_argc; 39175261Sobrienstatic size_t run_argc_allocated; 4017721Speter 41175261Sobrien 42175261Sobrien 43175261Sobrienvoid 44175261Sobrienrun_arg_free_p (int argc, char **argv) 45175261Sobrien{ 46175261Sobrien int i; 47175261Sobrien for (i = 0; i < argc; i++) 48175261Sobrien free (argv[i]); 49175261Sobrien} 50175261Sobrien 51175261Sobrien 52175261Sobrien 5317721Speter/* VARARGS */ 5417721Spetervoid 5532785Speterrun_setup (prog) 5632785Speter const char *prog; 5717721Speter{ 5817721Speter char *cp; 5925839Speter char *run_prog; 6017721Speter 6117721Speter /* clean out any malloc'ed values from run_argv */ 62175261Sobrien run_arg_free_p (run_argc, run_argv); 6317721Speter run_argc = 0; 6417721Speter 6532785Speter run_prog = xstrdup (prog); 6617721Speter 6717721Speter /* put each word into run_argv, allocating it as we go */ 6817721Speter for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t")) 6917721Speter run_add_arg (cp); 7025839Speter free (run_prog); 7117721Speter} 7217721Speter 7317721Spetervoid 7417721Speterrun_arg (s) 7517721Speter const char *s; 7617721Speter{ 7717721Speter run_add_arg (s); 7817721Speter} 7917721Speter 80175261Sobrien 81175261Sobrien 82175261Sobrienvoid 83175261Sobrienrun_add_arg_p (iargc, iarg_allocated, iargv, s) 84175261Sobrien int *iargc; 85175261Sobrien size_t *iarg_allocated; 86175261Sobrien char ***iargv; 8717721Speter const char *s; 8817721Speter{ 8917721Speter /* allocate more argv entries if we've run out */ 90175261Sobrien if (*iargc >= *iarg_allocated) 9117721Speter { 92175261Sobrien *iarg_allocated += 50; 93175261Sobrien *iargv = xrealloc (*iargv, *iarg_allocated * sizeof (char **)); 9417721Speter } 9517721Speter 9617721Speter if (s) 97175261Sobrien (*iargv)[(*iargc)++] = xstrdup (s); 9817721Speter else 99175261Sobrien (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */ 10017721Speter} 10117721Speter 102128266Speter 103128266Speter 104175261Sobrienstatic void 105175261Sobrienrun_add_arg (s) 106175261Sobrien const char *s; 107175261Sobrien{ 108175261Sobrien run_add_arg_p (&run_argc, &run_argc_allocated, &run_argv, s); 109175261Sobrien} 110175261Sobrien 111175261Sobrien 112175261Sobrien 11317721Speterint 11417721Speterrun_exec (stin, stout, sterr, flags) 11532785Speter const char *stin; 11632785Speter const char *stout; 11732785Speter const char *sterr; 11817721Speter int flags; 11917721Speter{ 12017721Speter int shin, shout, sherr; 12117721Speter int mode_out, mode_err; 12217721Speter int status; 12317721Speter int rc = -1; 12417721Speter int rerrno = 0; 12517721Speter int pid, w; 12617721Speter 12717721Speter#ifdef POSIX_SIGNALS 12817721Speter sigset_t sigset_mask, sigset_omask; 12917721Speter struct sigaction act, iact, qact; 13017721Speter 13117721Speter#else 13217721Speter#ifdef BSD_SIGNALS 13317721Speter int mask; 13417721Speter struct sigvec vec, ivec, qvec; 13517721Speter 13617721Speter#else 13717721Speter RETSIGTYPE (*istat) (), (*qstat) (); 13817721Speter#endif 13917721Speter#endif 14017721Speter 14117721Speter if (trace) 14217721Speter { 14317721Speter#ifdef SERVER_SUPPORT 14425839Speter cvs_outerr (server_active ? "S" : " ", 1); 14517721Speter#endif 14625839Speter cvs_outerr ("-> system(", 0); 14717721Speter run_print (stderr); 14825839Speter cvs_outerr (")\n", 0); 14917721Speter } 15017721Speter if (noexec && (flags & RUN_REALLY) == 0) 151128266Speter return 0; 15217721Speter 15317721Speter /* make sure that we are null terminated, since we didn't calloc */ 154128266Speter run_add_arg ((char *)0); 15517721Speter 15617721Speter /* setup default file descriptor numbers */ 15717721Speter shin = 0; 15817721Speter shout = 1; 15917721Speter sherr = 2; 16017721Speter 16117721Speter /* set the file modes for stdout and stderr */ 16217721Speter mode_out = mode_err = O_WRONLY | O_CREAT; 16317721Speter mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC); 16417721Speter mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC); 16517721Speter 16617721Speter if (stin && (shin = open (stin, O_RDONLY)) == -1) 16717721Speter { 16817721Speter rerrno = errno; 16917721Speter error (0, errno, "cannot open %s for reading (prog %s)", 17017721Speter stin, run_argv[0]); 17117721Speter goto out0; 17217721Speter } 17317721Speter if (stout && (shout = open (stout, mode_out, 0666)) == -1) 17417721Speter { 17517721Speter rerrno = errno; 17617721Speter error (0, errno, "cannot open %s for writing (prog %s)", 17717721Speter stout, run_argv[0]); 17817721Speter goto out1; 17917721Speter } 18017721Speter if (sterr && (flags & RUN_COMBINED) == 0) 18117721Speter { 18217721Speter if ((sherr = open (sterr, mode_err, 0666)) == -1) 18317721Speter { 18417721Speter rerrno = errno; 18517721Speter error (0, errno, "cannot open %s for writing (prog %s)", 18617721Speter sterr, run_argv[0]); 18717721Speter goto out2; 18817721Speter } 18917721Speter } 19017721Speter 19117721Speter /* Make sure we don't flush this twice, once in the subprocess. */ 192128266Speter cvs_flushout(); 193128266Speter cvs_flusherr(); 19417721Speter 19525839Speter /* The output files, if any, are now created. Do the fork and dups. 19625839Speter 19754427Speter We use vfork not so much for a performance boost (the 19854427Speter performance boost, if any, is modest on most modern unices), 19954427Speter but for the sake of systems without a memory management unit, 20054427Speter which find it difficult or impossible to implement fork at all 20154427Speter (e.g. Amiga). The other solution is spawn (see 20225839Speter windows-NT/run.c). */ 20325839Speter 20417721Speter#ifdef HAVE_VFORK 20517721Speter pid = vfork (); 20617721Speter#else 20717721Speter pid = fork (); 20817721Speter#endif 20917721Speter if (pid == 0) 21017721Speter { 21117721Speter if (shin != 0) 21217721Speter { 21317721Speter (void) dup2 (shin, 0); 21417721Speter (void) close (shin); 21517721Speter } 21617721Speter if (shout != 1) 21717721Speter { 21817721Speter (void) dup2 (shout, 1); 21917721Speter (void) close (shout); 22017721Speter } 22117721Speter if (flags & RUN_COMBINED) 22217721Speter (void) dup2 (1, 2); 22317721Speter else if (sherr != 2) 22417721Speter { 22517721Speter (void) dup2 (sherr, 2); 22617721Speter (void) close (sherr); 22717721Speter } 22817721Speter 22966525Speter#ifdef SETXID_SUPPORT 23066525Speter /* 23166525Speter ** This prevents a user from creating a privileged shell 23266525Speter ** from the text editor when the SETXID_SUPPORT option is selected. 23366525Speter */ 23466525Speter if (!strcmp (run_argv[0], Editor) && setegid (getgid ())) 23566525Speter { 23666525Speter error (0, errno, "cannot set egid to gid"); 23766525Speter _exit (127); 23866525Speter } 23966525Speter#endif 24066525Speter 24117721Speter /* dup'ing is done. try to run it now */ 24217721Speter (void) execvp (run_argv[0], run_argv); 24317721Speter error (0, errno, "cannot exec %s", run_argv[0]); 24417721Speter _exit (127); 24517721Speter } 24617721Speter else if (pid == -1) 24717721Speter { 24817721Speter rerrno = errno; 24917721Speter goto out; 25017721Speter } 25117721Speter 25217721Speter /* the parent. Ignore some signals for now */ 25317721Speter#ifdef POSIX_SIGNALS 25417721Speter if (flags & RUN_SIGIGNORE) 25517721Speter { 25617721Speter act.sa_handler = SIG_IGN; 25717721Speter (void) sigemptyset (&act.sa_mask); 25817721Speter act.sa_flags = 0; 25917721Speter (void) sigaction (SIGINT, &act, &iact); 26017721Speter (void) sigaction (SIGQUIT, &act, &qact); 26117721Speter } 26217721Speter else 26317721Speter { 26417721Speter (void) sigemptyset (&sigset_mask); 26517721Speter (void) sigaddset (&sigset_mask, SIGINT); 26617721Speter (void) sigaddset (&sigset_mask, SIGQUIT); 26717721Speter (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask); 26817721Speter } 26917721Speter#else 27017721Speter#ifdef BSD_SIGNALS 27117721Speter if (flags & RUN_SIGIGNORE) 27217721Speter { 273128266Speter memset ((char *)&vec, 0, sizeof (vec)); 27417721Speter vec.sv_handler = SIG_IGN; 27517721Speter (void) sigvec (SIGINT, &vec, &ivec); 27617721Speter (void) sigvec (SIGQUIT, &vec, &qvec); 27717721Speter } 27817721Speter else 27917721Speter mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT)); 28017721Speter#else 28117721Speter istat = signal (SIGINT, SIG_IGN); 28217721Speter qstat = signal (SIGQUIT, SIG_IGN); 28317721Speter#endif 28417721Speter#endif 28517721Speter 28617721Speter /* wait for our process to die and munge return status */ 28717721Speter#ifdef POSIX_SIGNALS 28817721Speter while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) 28917721Speter ; 29017721Speter#else 29117721Speter while ((w = wait (&status)) != pid) 29217721Speter { 29317721Speter if (w == -1 && errno != EINTR) 29417721Speter break; 29517721Speter } 29617721Speter#endif 29717721Speter 29817721Speter if (w == -1) 29917721Speter { 30017721Speter rc = -1; 30117721Speter rerrno = errno; 30217721Speter } 30317721Speter#ifndef VMS /* status is return status */ 30417721Speter else if (WIFEXITED (status)) 30517721Speter rc = WEXITSTATUS (status); 30617721Speter else if (WIFSIGNALED (status)) 30717721Speter { 30817721Speter if (WTERMSIG (status) == SIGPIPE) 30917721Speter error (1, 0, "broken pipe"); 31017721Speter rc = 2; 31117721Speter } 31217721Speter else 31317721Speter rc = 1; 31417721Speter#else /* VMS */ 31517721Speter rc = WEXITSTATUS (status); 31617721Speter#endif /* VMS */ 31717721Speter 31817721Speter /* restore the signals */ 31917721Speter#ifdef POSIX_SIGNALS 32017721Speter if (flags & RUN_SIGIGNORE) 32117721Speter { 322128266Speter (void) sigaction (SIGINT, &iact, (struct sigaction *)NULL); 323128266Speter (void) sigaction (SIGQUIT, &qact, (struct sigaction *)NULL); 32417721Speter } 32517721Speter else 326128266Speter (void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *)NULL); 32717721Speter#else 32817721Speter#ifdef BSD_SIGNALS 32917721Speter if (flags & RUN_SIGIGNORE) 33017721Speter { 331128266Speter (void) sigvec (SIGINT, &ivec, (struct sigvec *)NULL); 332128266Speter (void) sigvec (SIGQUIT, &qvec, (struct sigvec *)NULL); 33317721Speter } 33417721Speter else 33517721Speter (void) sigsetmask (mask); 33617721Speter#else 33717721Speter (void) signal (SIGINT, istat); 33817721Speter (void) signal (SIGQUIT, qstat); 33917721Speter#endif 34017721Speter#endif 34117721Speter 34217721Speter /* cleanup the open file descriptors */ 34317721Speter out: 34417721Speter if (sterr) 34517721Speter (void) close (sherr); 34681404Speter else 34781404Speter /* ensure things are received by the parent in the correct order 34881404Speter * relative to the protocol pipe 34981404Speter */ 35081404Speter cvs_flusherr(); 35117721Speter out2: 35217721Speter if (stout) 35317721Speter (void) close (shout); 35481404Speter else 35581404Speter /* ensure things are received by the parent in the correct order 35681404Speter * relative to the protocol pipe 35781404Speter */ 35881404Speter cvs_flushout(); 35917721Speter out1: 36017721Speter if (stin) 36117721Speter (void) close (shin); 36217721Speter 36317721Speter out0: 36417721Speter if (rerrno) 36517721Speter errno = rerrno; 366128266Speter return rc; 36717721Speter} 36817721Speter 369128266Speter 370128266Speter 37117721Spetervoid 37217721Speterrun_print (fp) 37317721Speter FILE *fp; 37417721Speter{ 37517721Speter int i; 37625839Speter void (*outfn) PROTO ((const char *, size_t)); 37717721Speter 37825839Speter if (fp == stderr) 37925839Speter outfn = cvs_outerr; 38025839Speter else if (fp == stdout) 38125839Speter outfn = cvs_output; 38225839Speter else 38332785Speter { 38425839Speter error (1, 0, "internal error: bad argument to run_print"); 38532785Speter /* Solely to placate gcc -Wall. 38632785Speter FIXME: it'd be better to use a function named `fatal' that 38732785Speter is known never to return. Then kludges wouldn't be necessary. */ 38832785Speter outfn = NULL; 38932785Speter } 39025839Speter 39117721Speter for (i = 0; i < run_argc; i++) 39217721Speter { 39325839Speter (*outfn) ("'", 1); 39425839Speter (*outfn) (run_argv[i], 0); 39525839Speter (*outfn) ("'", 1); 39617721Speter if (i != run_argc - 1) 39725839Speter (*outfn) (" ", 1); 39817721Speter } 39917721Speter} 40017721Speter 40132785Speter/* Return value is NULL for error, or if noexec was set. If there was an 40232785Speter error, return NULL and I'm not sure whether errno was set (the Red Hat 40332785Speter Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec 40432785Speter case complicates this even aside from popen behavior). */ 40532785Speter 40617721SpeterFILE * 40717721Speterrun_popen (cmd, mode) 40817721Speter const char *cmd; 40917721Speter const char *mode; 41017721Speter{ 41117721Speter if (trace) 41254427Speter (void) fprintf (stderr, "%s-> run_popen(%s,%s)\n", 41354427Speter CLIENT_SERVER_STR, cmd, mode); 41417721Speter if (noexec) 41517721Speter return (NULL); 41617721Speter 41717721Speter return (popen (cmd, mode)); 41817721Speter} 41917721Speter 420175261Sobrien 421175261Sobrien 422175261Sobrien/* Work around an OpenSSH problem: it can put its standard file 423175261Sobrien descriptors into nonblocking mode, which will mess us up if we 424175261Sobrien share file descriptions with it. The simplest workaround is 425175261Sobrien to create an intervening process between OpenSSH and the 426175261Sobrien actual stderr. */ 427175261Sobrien 428175261Sobrienstatic void 429175261Sobrienwork_around_openssh_glitch (void) 430175261Sobrien{ 431175261Sobrien pid_t pid; 432175261Sobrien int stderr_pipe[2]; 433175261Sobrien struct stat sb; 434175261Sobrien 435175261Sobrien /* Do nothing unless stderr is a file that is affected by 436175261Sobrien nonblocking mode. */ 437175261Sobrien if (!(fstat (STDERR_FILENO, &sb) == 0 438175261Sobrien && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode) 439175261Sobrien || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode)))) 440175261Sobrien return; 441175261Sobrien 442175261Sobrien if (pipe (stderr_pipe) < 0) 443175261Sobrien error (1, errno, "cannot create pipe"); 444175261Sobrien pid = fork (); 445175261Sobrien if (pid < 0) 446175261Sobrien error (1, errno, "cannot fork"); 447175261Sobrien if (pid != 0) 448175261Sobrien { 449175261Sobrien /* Still in child of original process. Act like "cat -u". */ 450175261Sobrien char buf[1 << 13]; 451175261Sobrien ssize_t inbytes; 452175261Sobrien pid_t w; 453175261Sobrien int status; 454175261Sobrien 455175261Sobrien if (close (stderr_pipe[1]) < 0) 456175261Sobrien error (1, errno, "cannot close pipe"); 457175261Sobrien 458175261Sobrien while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0) 459175261Sobrien { 460175261Sobrien size_t outbytes = 0; 461175261Sobrien 462175261Sobrien if (inbytes < 0) 463175261Sobrien { 464175261Sobrien if (errno == EINTR) 465175261Sobrien continue; 466175261Sobrien error (1, errno, "reading from pipe"); 467175261Sobrien } 468175261Sobrien 469175261Sobrien do 470175261Sobrien { 471175261Sobrien ssize_t w = write (STDERR_FILENO, 472175261Sobrien buf + outbytes, inbytes - outbytes); 473175261Sobrien if (w < 0) 474175261Sobrien { 475175261Sobrien if (errno == EINTR) 476175261Sobrien w = 0; 477175261Sobrien if (w < 0) 478175261Sobrien _exit (1); 479175261Sobrien } 480175261Sobrien outbytes += w; 481175261Sobrien } 482175261Sobrien while (inbytes != outbytes); 483175261Sobrien } 484175261Sobrien 485175261Sobrien /* Done processing output from grandchild. Propagate 486175261Sobrien its exit status back to the parent. */ 487175261Sobrien while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) 488175261Sobrien continue; 489175261Sobrien if (w < 0) 490175261Sobrien error (1, errno, "waiting for child"); 491175261Sobrien if (!WIFEXITED (status)) 492175261Sobrien { 493175261Sobrien if (WIFSIGNALED (status)) 494175261Sobrien raise (WTERMSIG (status)); 495175261Sobrien error (1, errno, "child did not exit cleanly"); 496175261Sobrien } 497175261Sobrien _exit (WEXITSTATUS (status)); 498175261Sobrien } 499175261Sobrien 500175261Sobrien /* Grandchild of original process. */ 501175261Sobrien if (close (stderr_pipe[0]) < 0) 502175261Sobrien error (1, errno, "cannot close pipe"); 503175261Sobrien 504175261Sobrien if (stderr_pipe[1] != STDERR_FILENO) 505175261Sobrien { 506175261Sobrien if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0) 507175261Sobrien error (1, errno, "cannot dup2 pipe"); 508175261Sobrien if (close (stderr_pipe[1]) < 0) 509175261Sobrien error (1, errno, "cannot close pipe"); 510175261Sobrien } 511175261Sobrien} 512175261Sobrien 513175261Sobrien 514175261Sobrien 51517721Speterint 516175261Sobrienpiped_child (command, tofdp, fromfdp, fix_stderr) 517128266Speter const char **command; 51817721Speter int *tofdp; 51917721Speter int *fromfdp; 520175261Sobrien int fix_stderr; 52117721Speter{ 52217721Speter int pid; 52317721Speter int to_child_pipe[2]; 52417721Speter int from_child_pipe[2]; 52517721Speter 52617721Speter if (pipe (to_child_pipe) < 0) 52717721Speter error (1, errno, "cannot create pipe"); 52817721Speter if (pipe (from_child_pipe) < 0) 52917721Speter error (1, errno, "cannot create pipe"); 53017721Speter 53126801Speter#ifdef USE_SETMODE_BINARY 53226801Speter setmode (to_child_pipe[0], O_BINARY); 53326801Speter setmode (to_child_pipe[1], O_BINARY); 53426801Speter setmode (from_child_pipe[0], O_BINARY); 53526801Speter setmode (from_child_pipe[1], O_BINARY); 53626801Speter#endif 53726801Speter 53817721Speter pid = fork (); 53917721Speter if (pid < 0) 54017721Speter error (1, errno, "cannot fork"); 54117721Speter if (pid == 0) 54217721Speter { 54317721Speter if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0) 54454427Speter error (1, errno, "cannot dup2 pipe"); 54517721Speter if (close (to_child_pipe[1]) < 0) 54654427Speter error (1, errno, "cannot close pipe"); 54717721Speter if (close (from_child_pipe[0]) < 0) 54854427Speter error (1, errno, "cannot close pipe"); 54917721Speter if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) 55054427Speter error (1, errno, "cannot dup2 pipe"); 55117721Speter 552175261Sobrien if (fix_stderr) 553175261Sobrien work_around_openssh_glitch (); 554175261Sobrien 555175261Sobrien /* Okay to cast out const below - execvp don't return nohow. */ 556128266Speter execvp ((char *)command[0], (char **)command); 55754427Speter error (1, errno, "cannot exec %s", command[0]); 55817721Speter } 55917721Speter if (close (to_child_pipe[0]) < 0) 56054427Speter error (1, errno, "cannot close pipe"); 56117721Speter if (close (from_child_pipe[1]) < 0) 56254427Speter error (1, errno, "cannot close pipe"); 56317721Speter 56417721Speter *tofdp = to_child_pipe[1]; 56517721Speter *fromfdp = from_child_pipe[0]; 56617721Speter return pid; 56717721Speter} 56817721Speter 56917721Speter 57017721Spetervoid 57117721Speterclose_on_exec (fd) 57217721Speter int fd; 57317721Speter{ 57481404Speter#ifdef F_SETFD 575128266Speter if (fcntl (fd, F_SETFD, 1) == -1) 57654427Speter error (1, errno, "can't set close-on-exec flag on %d", fd); 57717721Speter#endif 57817721Speter} 579