static void call_diff_flush_output (void) { cvs_flushout (); }
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; }
/* * Process each of the files in the list with the callback proc */ static int do_file_proc (Node *p, void *closure) { struct frame_and_file *frfile = (struct frame_and_file *)closure; struct file_info *finfo = frfile->finfo; int ret; Entnode *e; const char *mapped_name; const char *mapped_file_repository = NULL; if(!current_parsed_root->isremote) mapped_name = map_filename(finfo->virtual_repository, p->key, &mapped_file_repository); else mapped_name = xstrdup(p->key); finfo->file = p->key; finfo->mapped_file = mapped_name; char *ff = (char*)xmalloc (strlen (finfo->file) + strlen (finfo->update_dir) + 2); finfo->fullname = ff; ff[0] = '\0'; if (finfo->update_dir[0] != '\0') { strcat (ff, finfo->update_dir); strcat (ff, "/"); } strcat (ff, finfo->file); if (frfile->frame->dosrcs && mapped_file_repository) { finfo->rcs = RCS_parse (finfo->mapped_file, mapped_file_repository); /* OK, without W_LOCAL the error handling becomes relatively simple. The file names came from readdir() on the repository and so we know any ENOENT is an error (e.g. symlink pointing to nothing). Now, the logic could be simpler - since we got the name from readdir, we could just be calling RCS_parsercsfile. */ if (finfo->rcs == NULL && !(frfile->frame->which & W_LOCAL)) { error (0, 0, "could not read RCS file for %s", fn_root(finfo->fullname)); xfree (finfo->fullname); cvs_flushout (); return 0; } } else finfo->rcs = (RCSNode *) NULL; p = findnode_fn(finfo->entries,finfo->file); if(p) { const char *message; const char *v_type; e = (Entnode *)p->data; if (! verify_access(frfile->frame->permproc, finfo->repository, finfo->file, finfo->update_dir, e->tag, &message, &v_type)) { if(e->tag && !quiet && !(frfile->frame->which&W_QUIET)) error (0, 0, "User %s is unable to %s %s/%s on branch/tag %s",CVS_Username,v_type,finfo->update_dir,finfo->file,e->tag); else if(!quiet && !(frfile->frame->which&W_QUIET)) error (0, 0, "User %s is unable to %s %s/%s",CVS_Username,v_type,finfo->update_dir,finfo->file); if(message && !quiet && !(frfile->frame->which&W_QUIET)) error (0, 0, "%s", message); ret = 1; } else ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo); } else ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo); freercsnode(&finfo->rcs); xfree (finfo->fullname); xfree (mapped_name); xfree (mapped_file_repository); /* Allow the user to monitor progress with tail -f. Doing this once per file should be no big deal, but we don't want the performance hit of flushing on every line like previous versions of CVS. */ cvs_flushout (); return (ret); }