int run_exec (const char *stin, const char *stout, const char *sterr, int flags) { int shin, shout, sherr; int mode_out, mode_err; int status; int rc = -1; int rerrno = 0; int pid, w; #ifdef POSIX_SIGNALS sigset_t sigset_mask, sigset_omask; struct sigaction act, iact, qact; #else #ifdef BSD_SIGNALS int mask; struct sigvec vec, ivec, qvec; #else RETSIGTYPE (*istat) (), (*qstat) (); #endif #endif if (trace) { cvs_outerr ( #ifdef SERVER_SUPPORT server_active ? "S" : #endif " ", 1); cvs_outerr (" -> system (", 0); run_print (stderr); cvs_outerr (")\n", 0); } if (noexec && (flags & RUN_REALLY) == 0) return 0; /* make sure that we are null terminated, since we didn't calloc */ run_add_arg (NULL); /* setup default file descriptor numbers */ shin = 0; shout = 1; sherr = 2; /* set the file modes for stdout and stderr */ 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; } } /* Make sure we don't flush this twice, once in the subprocess. */ cvs_flushout(); cvs_flusherr(); /* The output files, if any, are now created. Do the fork and dups. We use vfork not so much for a performance boost (the performance boost, if any, is modest on most modern unices), but for the sake of systems without a memory management unit, which find it difficult or impossible to implement fork at all (e.g. Amiga). The other solution is spawn (see windows-NT/run.c). */ #ifdef HAVE_VFORK pid = vfork (); #else pid = fork (); #endif if (pid == 0) { #ifdef SETXID_SUPPORT if (flags & RUN_UNSETXID) { (void) setgid (getgid ()); (void) setuid (getuid ()); } #endif 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); } #ifdef SETXID_SUPPORT /* ** This prevents a user from creating a privileged shell ** from the text editor when the SETXID_SUPPORT option is selected. */ if (!strcmp (run_argv[0], Editor) && setegid (getgid ())) { error (0, errno, "cannot set egid to gid"); _exit (127); } #endif /* dup'ing is done. try to run it now */ (void) execvp (run_argv[0], run_argv); error (0, errno, "cannot exec %s", run_argv[0]); _exit (127); } else if (pid == -1) { rerrno = errno; goto out; } /* the parent. Ignore some signals for now */ #ifdef POSIX_SIGNALS if (flags & RUN_SIGIGNORE) { act.sa_handler = SIG_IGN; (void) sigemptyset (&act.sa_mask); act.sa_flags = 0; (void) sigaction (SIGINT, &act, &iact); (void) sigaction (SIGQUIT, &act, &qact); } else { (void) sigemptyset (&sigset_mask); (void) sigaddset (&sigset_mask, SIGINT); (void) sigaddset (&sigset_mask, SIGQUIT); (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask); } #else #ifdef BSD_SIGNALS if (flags & RUN_SIGIGNORE) { memset (&vec, 0, sizeof vec); vec.sv_handler = SIG_IGN; (void) sigvec (SIGINT, &vec, &ivec); (void) sigvec (SIGQUIT, &vec, &qvec); } else mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT)); #else istat = signal (SIGINT, SIG_IGN); qstat = signal (SIGQUIT, SIG_IGN); #endif #endif /* wait for our process to die and munge return status */ #ifdef POSIX_SIGNALS while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) ; #else while ((w = wait (&status)) != pid) { if (w == -1 && errno != EINTR) break; } #endif if (w == -1) { rc = -1; rerrno = errno; } #ifndef VMS /* status is return status */ else if (WIFEXITED (status)) rc = WEXITSTATUS (status); else if (WIFSIGNALED (status)) { if (WTERMSIG (status) == SIGPIPE) error (1, 0, "broken pipe"); rc = 2; } else rc = 1; #else /* VMS */ rc = WEXITSTATUS (status); #endif /* VMS */ /* restore the signals */ #ifdef POSIX_SIGNALS if (flags & RUN_SIGIGNORE) { (void) sigaction (SIGINT, &iact, NULL); (void) sigaction (SIGQUIT, &qact, NULL); } else (void) sigprocmask (SIG_SETMASK, &sigset_omask, NULL); #else #ifdef BSD_SIGNALS if (flags & RUN_SIGIGNORE) { (void) sigvec (SIGINT, &ivec, NULL); (void) sigvec (SIGQUIT, &qvec, NULL); } else (void) sigsetmask (mask); #else (void) signal (SIGINT, istat); (void) signal (SIGQUIT, qstat); #endif #endif /* cleanup the open file descriptors */ out: if (sterr) (void) close (sherr); else /* ensure things are received by the parent in the correct order * relative to the protocol pipe */ cvs_flusherr(); out2: if (stout) (void) close (shout); else /* ensure things are received by the parent in the correct order * relative to the protocol pipe */ cvs_flushout(); out1: if (stin) (void) close (shin); out0: if (rerrno) errno = rerrno; return rc; }
int RCS_merge (RCSNode *rcs, const char *path, const char *workfile, const char *options, const char *rev1, const char *rev2) { char *xrev1, *xrev2; char *tmp1, *tmp2; char *diffout = NULL; int retval; if (options != NULL && options[0] != '\0') assert (options[0] == '-' && options[1] == 'k'); cvs_output ("RCS file: ", 0); cvs_output (rcs->print_path, 0); cvs_output ("\n", 1); /* Calculate numeric revision numbers from rev1 and rev2 (may be symbolic). FIXME - No they can't. Both calls to RCS_merge are passing in numeric revisions. */ xrev1 = RCS_gettag (rcs, rev1, 0, NULL); xrev2 = RCS_gettag (rcs, rev2, 0, NULL); assert (xrev1 && xrev2); /* Check out chosen revisions. The error message when RCS_checkout fails is not very informative -- it is taken verbatim from RCS 5.7, and relies on RCS_checkout saying something intelligent upon failure. */ cvs_output ("retrieving revision ", 0); cvs_output (xrev1, 0); cvs_output ("\n", 1); tmp1 = cvs_temp_name(); if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL)) { cvs_outerr ("rcsmerge: co failed\n", 0); exit (EXIT_FAILURE); } cvs_output ("retrieving revision ", 0); cvs_output (xrev2, 0); cvs_output ("\n", 1); tmp2 = cvs_temp_name(); if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL)) { cvs_outerr ("rcsmerge: co failed\n", 0); exit (EXIT_FAILURE); } /* Merge changes. */ cvs_output ("Merging differences between ", 0); cvs_output (xrev1, 0); cvs_output (" and ", 0); cvs_output (xrev2, 0); cvs_output (" into ", 0); cvs_output (workfile, 0); cvs_output ("\n", 1); /* Remember that the first word in the `call_diff_setup' string is used now only for diagnostic messages -- CVS no longer forks to run diff3. */ diffout = cvs_temp_name(); call_diff_setup ("diff3", 0, NULL); call_diff_add_arg ("-E"); call_diff_add_arg ("-am"); call_diff_add_arg ("-L"); call_diff_add_arg (workfile); call_diff_add_arg ("-L"); call_diff_add_arg (xrev1); call_diff_add_arg ("-L"); call_diff_add_arg (xrev2); call_diff_add_arg ("--"); call_diff_add_arg (workfile); call_diff_add_arg (tmp1); call_diff_add_arg (tmp2); retval = call_diff3 (diffout); if (retval == 1) cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0); else if (retval == 2) exit (EXIT_FAILURE); if (diffout) copy_file (diffout, workfile); /* Clean up. */ { int save_noexec = noexec; noexec = 0; if (unlink_file (tmp1) < 0) { if (!existence_error (errno)) error (0, errno, "cannot remove temp file %s", tmp1); } free (tmp1); if (unlink_file (tmp2) < 0) { if (!existence_error (errno)) error (0, errno, "cannot remove temp file %s", tmp2); } free (tmp2); if (diffout) { if (unlink_file (diffout) < 0) { if (!existence_error (errno)) error (0, errno, "cannot remove temp file %s", diffout); } free (diffout); } free (xrev1); free (xrev2); noexec = save_noexec; } return retval; }