1/* run.c --- routines for executing subprocesses. 2 3 This file is part of GNU CVS. 4 5 GNU CVS is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published by the 7 Free Software Foundation; either version 2, or (at your option) any 8 later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. */ 14 15#include "cvs.h" 16 17#ifndef HAVE_UNISTD_H 18extern int execvp PROTO((char *file, char **argv)); 19#endif 20 21static void run_add_arg PROTO((const char *s)); 22 23extern char *strtok (); 24 25/* 26 * To exec a program under CVS, first call run_setup() to setup initial 27 * arguments. The argument to run_setup will be parsed into whitespace 28 * separated words and added to the global run_argv list. 29 * 30 * Then, optionally call run_arg() for each additional argument that you'd like 31 * to pass to the executed program. 32 * 33 * Finally, call run_exec() to execute the program with the specified arguments. 34 * The execvp() syscall will be used, so that the PATH is searched correctly. 35 * File redirections can be performed in the call to run_exec(). 36 */ 37static char **run_argv; 38static int run_argc; 39static size_t run_argc_allocated; 40 41 42 43void 44run_arg_free_p (int argc, char **argv) 45{ 46 int i; 47 for (i = 0; i < argc; i++) 48 free (argv[i]); 49} 50 51 52 53/* VARARGS */ 54void 55run_setup (prog) 56 const char *prog; 57{ 58 char *cp; 59 char *run_prog; 60 61 /* clean out any malloc'ed values from run_argv */ 62 run_arg_free_p (run_argc, run_argv); 63 run_argc = 0; 64 65 run_prog = xstrdup (prog); 66 67 /* put each word into run_argv, allocating it as we go */ 68 for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t")) 69 run_add_arg (cp); 70 free (run_prog); 71} 72 73void 74run_arg (s) 75 const char *s; 76{ 77 run_add_arg (s); 78} 79 80 81 82void 83run_add_arg_p (iargc, iarg_allocated, iargv, s) 84 int *iargc; 85 size_t *iarg_allocated; 86 char ***iargv; 87 const char *s; 88{ 89 /* allocate more argv entries if we've run out */ 90 if (*iargc >= *iarg_allocated) 91 { 92 *iarg_allocated += 50; 93 *iargv = xrealloc (*iargv, *iarg_allocated * sizeof (char **)); 94 } 95 96 if (s) 97 (*iargv)[(*iargc)++] = xstrdup (s); 98 else 99 (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */ 100} 101 102 103 104static void 105run_add_arg (s) 106 const char *s; 107{ 108 run_add_arg_p (&run_argc, &run_argc_allocated, &run_argv, s); 109} 110 111 112 113int 114run_exec (stin, stout, sterr, flags) 115 const char *stin; 116 const char *stout; 117 const char *sterr; 118 int flags; 119{ 120 int shin, shout, sherr; 121 int mode_out, mode_err; 122 int status; 123 int rc = -1; 124 int rerrno = 0; 125 int pid, w; 126 127#ifdef POSIX_SIGNALS 128 sigset_t sigset_mask, sigset_omask; 129 struct sigaction act, iact, qact; 130 131#else 132#ifdef BSD_SIGNALS 133 int mask; 134 struct sigvec vec, ivec, qvec; 135 136#else 137 RETSIGTYPE (*istat) (), (*qstat) (); 138#endif 139#endif 140 141 if (trace) 142 { 143#ifdef SERVER_SUPPORT 144 cvs_outerr (server_active ? "S" : " ", 1); 145#endif 146 cvs_outerr ("-> system(", 0); 147 run_print (stderr); 148 cvs_outerr (")\n", 0); 149 } 150 if (noexec && (flags & RUN_REALLY) == 0) 151 return 0; 152 153 /* make sure that we are null terminated, since we didn't calloc */ 154 run_add_arg ((char *)0); 155 156 /* setup default file descriptor numbers */ 157 shin = 0; 158 shout = 1; 159 sherr = 2; 160 161 /* set the file modes for stdout and stderr */ 162 mode_out = mode_err = O_WRONLY | O_CREAT; 163 mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC); 164 mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC); 165 166 if (stin && (shin = open (stin, O_RDONLY)) == -1) 167 { 168 rerrno = errno; 169 error (0, errno, "cannot open %s for reading (prog %s)", 170 stin, run_argv[0]); 171 goto out0; 172 } 173 if (stout && (shout = open (stout, mode_out, 0666)) == -1) 174 { 175 rerrno = errno; 176 error (0, errno, "cannot open %s for writing (prog %s)", 177 stout, run_argv[0]); 178 goto out1; 179 } 180 if (sterr && (flags & RUN_COMBINED) == 0) 181 { 182 if ((sherr = open (sterr, mode_err, 0666)) == -1) 183 { 184 rerrno = errno; 185 error (0, errno, "cannot open %s for writing (prog %s)", 186 sterr, run_argv[0]); 187 goto out2; 188 } 189 } 190 191 /* Make sure we don't flush this twice, once in the subprocess. */ 192 cvs_flushout(); 193 cvs_flusherr(); 194 195 /* The output files, if any, are now created. Do the fork and dups. 196 197 We use vfork not so much for a performance boost (the 198 performance boost, if any, is modest on most modern unices), 199 but for the sake of systems without a memory management unit, 200 which find it difficult or impossible to implement fork at all 201 (e.g. Amiga). The other solution is spawn (see 202 windows-NT/run.c). */ 203 204#ifdef HAVE_VFORK 205 pid = vfork (); 206#else 207 pid = fork (); 208#endif 209 if (pid == 0) 210 { 211 if (shin != 0) 212 { 213 (void) dup2 (shin, 0); 214 (void) close (shin); 215 } 216 if (shout != 1) 217 { 218 (void) dup2 (shout, 1); 219 (void) close (shout); 220 } 221 if (flags & RUN_COMBINED) 222 (void) dup2 (1, 2); 223 else if (sherr != 2) 224 { 225 (void) dup2 (sherr, 2); 226 (void) close (sherr); 227 } 228 229#ifdef SETXID_SUPPORT 230 /* 231 ** This prevents a user from creating a privileged shell 232 ** from the text editor when the SETXID_SUPPORT option is selected. 233 */ 234 if (!strcmp (run_argv[0], Editor) && setegid (getgid ())) 235 { 236 error (0, errno, "cannot set egid to gid"); 237 _exit (127); 238 } 239#endif 240 241 /* dup'ing is done. try to run it now */ 242 (void) execvp (run_argv[0], run_argv); 243 error (0, errno, "cannot exec %s", run_argv[0]); 244 _exit (127); 245 } 246 else if (pid == -1) 247 { 248 rerrno = errno; 249 goto out; 250 } 251 252 /* the parent. Ignore some signals for now */ 253#ifdef POSIX_SIGNALS 254 if (flags & RUN_SIGIGNORE) 255 { 256 act.sa_handler = SIG_IGN; 257 (void) sigemptyset (&act.sa_mask); 258 act.sa_flags = 0; 259 (void) sigaction (SIGINT, &act, &iact); 260 (void) sigaction (SIGQUIT, &act, &qact); 261 } 262 else 263 { 264 (void) sigemptyset (&sigset_mask); 265 (void) sigaddset (&sigset_mask, SIGINT); 266 (void) sigaddset (&sigset_mask, SIGQUIT); 267 (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask); 268 } 269#else 270#ifdef BSD_SIGNALS 271 if (flags & RUN_SIGIGNORE) 272 { 273 memset ((char *)&vec, 0, sizeof (vec)); 274 vec.sv_handler = SIG_IGN; 275 (void) sigvec (SIGINT, &vec, &ivec); 276 (void) sigvec (SIGQUIT, &vec, &qvec); 277 } 278 else 279 mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT)); 280#else 281 istat = signal (SIGINT, SIG_IGN); 282 qstat = signal (SIGQUIT, SIG_IGN); 283#endif 284#endif 285 286 /* wait for our process to die and munge return status */ 287#ifdef POSIX_SIGNALS 288 while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) 289 ; 290#else 291 while ((w = wait (&status)) != pid) 292 { 293 if (w == -1 && errno != EINTR) 294 break; 295 } 296#endif 297 298 if (w == -1) 299 { 300 rc = -1; 301 rerrno = errno; 302 } 303#ifndef VMS /* status is return status */ 304 else if (WIFEXITED (status)) 305 rc = WEXITSTATUS (status); 306 else if (WIFSIGNALED (status)) 307 { 308 if (WTERMSIG (status) == SIGPIPE) 309 error (1, 0, "broken pipe"); 310 rc = 2; 311 } 312 else 313 rc = 1; 314#else /* VMS */ 315 rc = WEXITSTATUS (status); 316#endif /* VMS */ 317 318 /* restore the signals */ 319#ifdef POSIX_SIGNALS 320 if (flags & RUN_SIGIGNORE) 321 { 322 (void) sigaction (SIGINT, &iact, (struct sigaction *)NULL); 323 (void) sigaction (SIGQUIT, &qact, (struct sigaction *)NULL); 324 } 325 else 326 (void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *)NULL); 327#else 328#ifdef BSD_SIGNALS 329 if (flags & RUN_SIGIGNORE) 330 { 331 (void) sigvec (SIGINT, &ivec, (struct sigvec *)NULL); 332 (void) sigvec (SIGQUIT, &qvec, (struct sigvec *)NULL); 333 } 334 else 335 (void) sigsetmask (mask); 336#else 337 (void) signal (SIGINT, istat); 338 (void) signal (SIGQUIT, qstat); 339#endif 340#endif 341 342 /* cleanup the open file descriptors */ 343 out: 344 if (sterr) 345 (void) close (sherr); 346 else 347 /* ensure things are received by the parent in the correct order 348 * relative to the protocol pipe 349 */ 350 cvs_flusherr(); 351 out2: 352 if (stout) 353 (void) close (shout); 354 else 355 /* ensure things are received by the parent in the correct order 356 * relative to the protocol pipe 357 */ 358 cvs_flushout(); 359 out1: 360 if (stin) 361 (void) close (shin); 362 363 out0: 364 if (rerrno) 365 errno = rerrno; 366 return rc; 367} 368 369 370 371void 372run_print (fp) 373 FILE *fp; 374{ 375 int i; 376 void (*outfn) PROTO ((const char *, size_t)); 377 378 if (fp == stderr) 379 outfn = cvs_outerr; 380 else if (fp == stdout) 381 outfn = cvs_output; 382 else 383 { 384 error (1, 0, "internal error: bad argument to run_print"); 385 /* Solely to placate gcc -Wall. 386 FIXME: it'd be better to use a function named `fatal' that 387 is known never to return. Then kludges wouldn't be necessary. */ 388 outfn = NULL; 389 } 390 391 for (i = 0; i < run_argc; i++) 392 { 393 (*outfn) ("'", 1); 394 (*outfn) (run_argv[i], 0); 395 (*outfn) ("'", 1); 396 if (i != run_argc - 1) 397 (*outfn) (" ", 1); 398 } 399} 400 401/* Return value is NULL for error, or if noexec was set. If there was an 402 error, return NULL and I'm not sure whether errno was set (the Red Hat 403 Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec 404 case complicates this even aside from popen behavior). */ 405 406FILE * 407run_popen (cmd, mode) 408 const char *cmd; 409 const char *mode; 410{ 411 if (trace) 412 (void) fprintf (stderr, "%s-> run_popen(%s,%s)\n", 413 CLIENT_SERVER_STR, cmd, mode); 414 if (noexec) 415 return (NULL); 416 417 return (popen (cmd, mode)); 418} 419 420 421 422/* Work around an OpenSSH problem: it can put its standard file 423 descriptors into nonblocking mode, which will mess us up if we 424 share file descriptions with it. The simplest workaround is 425 to create an intervening process between OpenSSH and the 426 actual stderr. */ 427 428static void 429work_around_openssh_glitch (void) 430{ 431 pid_t pid; 432 int stderr_pipe[2]; 433 struct stat sb; 434 435 /* Do nothing unless stderr is a file that is affected by 436 nonblocking mode. */ 437 if (!(fstat (STDERR_FILENO, &sb) == 0 438 && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode) 439 || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode)))) 440 return; 441 442 if (pipe (stderr_pipe) < 0) 443 error (1, errno, "cannot create pipe"); 444 pid = fork (); 445 if (pid < 0) 446 error (1, errno, "cannot fork"); 447 if (pid != 0) 448 { 449 /* Still in child of original process. Act like "cat -u". */ 450 char buf[1 << 13]; 451 ssize_t inbytes; 452 pid_t w; 453 int status; 454 455 if (close (stderr_pipe[1]) < 0) 456 error (1, errno, "cannot close pipe"); 457 458 while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0) 459 { 460 size_t outbytes = 0; 461 462 if (inbytes < 0) 463 { 464 if (errno == EINTR) 465 continue; 466 error (1, errno, "reading from pipe"); 467 } 468 469 do 470 { 471 ssize_t w = write (STDERR_FILENO, 472 buf + outbytes, inbytes - outbytes); 473 if (w < 0) 474 { 475 if (errno == EINTR) 476 w = 0; 477 if (w < 0) 478 _exit (1); 479 } 480 outbytes += w; 481 } 482 while (inbytes != outbytes); 483 } 484 485 /* Done processing output from grandchild. Propagate 486 its exit status back to the parent. */ 487 while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) 488 continue; 489 if (w < 0) 490 error (1, errno, "waiting for child"); 491 if (!WIFEXITED (status)) 492 { 493 if (WIFSIGNALED (status)) 494 raise (WTERMSIG (status)); 495 error (1, errno, "child did not exit cleanly"); 496 } 497 _exit (WEXITSTATUS (status)); 498 } 499 500 /* Grandchild of original process. */ 501 if (close (stderr_pipe[0]) < 0) 502 error (1, errno, "cannot close pipe"); 503 504 if (stderr_pipe[1] != STDERR_FILENO) 505 { 506 if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0) 507 error (1, errno, "cannot dup2 pipe"); 508 if (close (stderr_pipe[1]) < 0) 509 error (1, errno, "cannot close pipe"); 510 } 511} 512 513 514 515int 516piped_child (command, tofdp, fromfdp, fix_stderr) 517 const char **command; 518 int *tofdp; 519 int *fromfdp; 520 int fix_stderr; 521{ 522 int pid; 523 int to_child_pipe[2]; 524 int from_child_pipe[2]; 525 526 if (pipe (to_child_pipe) < 0) 527 error (1, errno, "cannot create pipe"); 528 if (pipe (from_child_pipe) < 0) 529 error (1, errno, "cannot create pipe"); 530 531#ifdef USE_SETMODE_BINARY 532 setmode (to_child_pipe[0], O_BINARY); 533 setmode (to_child_pipe[1], O_BINARY); 534 setmode (from_child_pipe[0], O_BINARY); 535 setmode (from_child_pipe[1], O_BINARY); 536#endif 537 538 pid = fork (); 539 if (pid < 0) 540 error (1, errno, "cannot fork"); 541 if (pid == 0) 542 { 543 if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0) 544 error (1, errno, "cannot dup2 pipe"); 545 if (close (to_child_pipe[1]) < 0) 546 error (1, errno, "cannot close pipe"); 547 if (close (from_child_pipe[0]) < 0) 548 error (1, errno, "cannot close pipe"); 549 if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) 550 error (1, errno, "cannot dup2 pipe"); 551 552 if (fix_stderr) 553 work_around_openssh_glitch (); 554 555 /* Okay to cast out const below - execvp don't return nohow. */ 556 execvp ((char *)command[0], (char **)command); 557 error (1, errno, "cannot exec %s", command[0]); 558 } 559 if (close (to_child_pipe[0]) < 0) 560 error (1, errno, "cannot close pipe"); 561 if (close (from_child_pipe[1]) < 0) 562 error (1, errno, "cannot close pipe"); 563 564 *tofdp = to_child_pipe[1]; 565 *fromfdp = from_child_pipe[0]; 566 return pid; 567} 568 569 570void 571close_on_exec (fd) 572 int fd; 573{ 574#ifdef F_SETFD 575 if (fcntl (fd, F_SETFD, 1) == -1) 576 error (1, errno, "can't set close-on-exec flag on %d", fd); 577#endif 578} 579