diff options
Diffstat (limited to 'gnu/usr.bin/rcs/lib/rcsutil.c')
| -rw-r--r-- | gnu/usr.bin/rcs/lib/rcsutil.c | 832 |
1 files changed, 613 insertions, 219 deletions
diff --git a/gnu/usr.bin/rcs/lib/rcsutil.c b/gnu/usr.bin/rcs/lib/rcsutil.c index 55140c2e4793..122bdd70969e 100644 --- a/gnu/usr.bin/rcs/lib/rcsutil.c +++ b/gnu/usr.bin/rcs/lib/rcsutil.c @@ -1,9 +1,7 @@ -/* - * RCS utilities - */ +/* RCS utility functions */ -/* Copyright (C) 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991 by Paul Eggert +/* Copyright 1982, 1988, 1989 Walter Tichy + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert Distributed under license by the Free Software Foundation, Inc. This file is part of RCS. @@ -19,8 +17,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +along with RCS; see the file COPYING. +If not, write to the Free Software Foundation, +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Report problems and direct all questions to: @@ -31,9 +30,57 @@ Report problems and direct all questions to: -/* $Log: rcsutil.c,v $ - * Revision 1.1.1.1 1993/06/18 04:22:13 jkh - * Updated GNU utilities +/* + * Revision 5.20 1995/06/16 06:19:24 eggert + * (catchsig): Remove `return'. + * Update FSF address. + * + * Revision 5.19 1995/06/02 18:19:00 eggert + * (catchsigaction): New name for `catchsig', for sa_sigaction signature. + * Use nRCS even if !has_psiginfo, to remove unused variable warning. + * (setup_catchsig): Use sa_sigaction only if has_sa_sigaction. + * Use ENOTSUP only if defined. + * + * Revision 5.18 1995/06/01 16:23:43 eggert + * (catchsig, restoreints, setup_catchsig): Use SA_SIGINFO, not has_psiginfo, + * to determine whether to use SA_SIGINFO feature, + * but also check at runtime whether the feature works. + * (catchsig): If an mmap_signal occurs, report the affected file name. + * (unsupported_SA_SIGINFO, accessName): New variables. + * (setup_catchsig): If using SA_SIGINFO, use sa_sigaction, not sa_handler. + * If SA_SIGINFO fails, fall back on sa_handler method. + * + * (readAccessFilenameBuffer, dupSafer, fdSafer, fopenSafer): New functions. + * (concatenate): Remove. + * + * (runv): Work around bad_wait_if_SIGCHLD_ignored bug. + * Remove reference to OPEN_O_WORK. + * + * Revision 5.17 1994/03/20 04:52:58 eggert + * Specify subprocess input via file descriptor, not file name. + * Avoid messing with I/O buffers in the child process. + * Define dup in terms of F_DUPFD if it exists. + * Move setmtime to rcsedit.c. Remove lint. + * + * Revision 5.16 1993/11/09 17:40:15 eggert + * -V now prints version on stdout and exits. + * + * Revision 5.15 1993/11/03 17:42:27 eggert + * Use psiginfo and setreuid if available. Move date2str to maketime.c. + * + * Revision 5.14 1992/07/28 16:12:44 eggert + * Add -V. has_sigaction overrides sig_zaps_handler. Fix -M bug. + * Add mmap_signal, which minimizes signal handling for non-mmap hosts. + * + * Revision 5.13 1992/02/17 23:02:28 eggert + * Work around NFS mmap SIGBUS problem. Add -T support. + * + * Revision 5.12 1992/01/24 18:44:19 eggert + * Work around NFS mmap bug that leads to SIGBUS core dumps. lint -> RCS_lint + * + * Revision 5.11 1992/01/06 02:42:34 eggert + * O_BINARY -> OPEN_O_WORK + * while (E) ; -> while (E) continue; * * Revision 5.10 1991/10/07 17:32:46 eggert * Support piece tables even if !has_mmap. @@ -139,7 +186,7 @@ Report problems and direct all questions to: #include "rcsbase.h" -libId(utilId, "$Id: rcsutil.c,v 1.1.1.1 1993/06/18 04:22:13 jkh Exp $") +libId(utilId, "$Id: rcsutil.c,v 1.4 1995/10/29 22:06:32 peter Exp $") #if !has_memcmp int @@ -173,7 +220,7 @@ memcpy(s1, s2, n) } #endif -#if lint +#if RCS_lint malloc_type lintalloc; #endif @@ -190,6 +237,7 @@ struct alloclist { static struct alloclist *alloced; + static malloc_type okalloc P((malloc_type)); static malloc_type okalloc(p) malloc_type p; @@ -245,7 +293,7 @@ ffree() tfree(p->alloc); tfree(p); } - alloced = nil; + alloced = 0; } void @@ -300,16 +348,18 @@ getusername(suspicious) /* Prefer getenv() unless suspicious; it's much faster. */ # if getlogin_is_secure (suspicious - || - !(name = cgetenv("LOGNAME")) - && !(name = cgetenv("USER"))) + || ( + !(name = cgetenv("LOGNAME")) + && !(name = cgetenv("USER")) + )) && !(name = getlogin()) # else suspicious - || + || ( !(name = cgetenv("LOGNAME")) && !(name = cgetenv("USER")) && !(name = getlogin()) + ) # endif ) { #if has_getuid && has_getpwuid @@ -323,7 +373,7 @@ getusername(suspicious) #if has_setuid faterror("setuid not supported"); #else - faterror("Who are you? Please set LOGNAME."); + faterror("Who are you? Please setenv LOGNAME."); #endif #endif } @@ -346,65 +396,191 @@ getusername(suspicious) */ static sig_atomic_t volatile heldsignal, holdlevel; +#ifdef SA_SIGINFO + static int unsupported_SA_SIGINFO; + static siginfo_t bufsiginfo; + static siginfo_t *volatile heldsiginfo; +#endif - static signal_type -catchsig(s) - int s; -{ - char const *sname; - char buf[BUFSIZ]; -#if sig_zaps_handler - /* If a signal arrives before we reset the signal handler, we lose. */ - VOID signal(s, SIG_IGN); -#endif - if (holdlevel) { - heldsignal = s; - return; - } - ignoreints(); - setrid(); - if (!quietflag) { - sname = nil; -#if has_sys_siglist && defined(NSIG) - if ((unsigned)s < NSIG) { -# ifndef sys_siglist - extern char const *sys_siglist[]; -# endif - sname = sys_siglist[s]; - } +#if has_NFS && has_mmap && large_memory && mmap_signal + static char const *accessName; + + void + readAccessFilenameBuffer(filename, p) + char const *filename; + unsigned char const *p; + { + unsigned char volatile t; + accessName = filename; + t = *p; + accessName = 0; + } #else - switch (s) { -#ifdef SIGHUP - case SIGHUP: sname = "Hangup"; break; +# define accessName ((char const *) 0) #endif -#ifdef SIGINT + + +#if !has_psignal + +# define psignal my_psignal + static void my_psignal P((int,char const*)); + static void +my_psignal(sig, s) + int sig; + char const *s; +{ + char const *sname = "Unknown signal"; +# if has_sys_siglist && defined(NSIG) + if ((unsigned)sig < NSIG) + sname = sys_siglist[sig]; +# else + switch (sig) { +# ifdef SIGHUP + case SIGHUP: sname = "Hangup"; break; +# endif +# ifdef SIGINT case SIGINT: sname = "Interrupt"; break; -#endif -#ifdef SIGPIPE +# endif +# ifdef SIGPIPE case SIGPIPE: sname = "Broken pipe"; break; -#endif -#ifdef SIGQUIT +# endif +# ifdef SIGQUIT case SIGQUIT: sname = "Quit"; break; -#endif -#ifdef SIGTERM +# endif +# ifdef SIGTERM case SIGTERM: sname = "Terminated"; break; -#endif -#ifdef SIGXCPU +# endif +# ifdef SIGXCPU case SIGXCPU: sname = "Cputime limit exceeded"; break; -#endif -#ifdef SIGXFSZ +# endif +# ifdef SIGXFSZ case SIGXFSZ: sname = "Filesize limit exceeded"; break; -#endif +# endif +# if has_mmap && large_memory +# if defined(SIGBUS) && mmap_signal==SIGBUS + case SIGBUS: sname = "Bus error"; break; +# endif +# if defined(SIGSEGV) && mmap_signal==SIGSEGV + case SIGSEGV: sname = "Segmentation fault"; break; +# endif +# endif } +# endif + + /* Avoid calling sprintf etc., in case they're not reentrant. */ + { + char const *p; + char buf[BUFSIZ], *b = buf; + for (p = s; *p; *b++ = *p++) + continue; + *b++ = ':'; + *b++ = ' '; + for (p = sname; *p; *b++ = *p++) + continue; + *b++ = '\n'; + VOID write(STDERR_FILENO, buf, b - buf); + } +} #endif - if (sname) - VOID sprintf(buf, "\nRCS: %s. Cleaning up.\n", sname); - else - VOID sprintf(buf, "\nRCS: Signal %d. Cleaning up.\n", s); - VOID write(STDERR_FILENO, buf, strlen(buf)); + +static signal_type catchsig P((int)); +#ifdef SA_SIGINFO + static signal_type catchsigaction P((int,siginfo_t*,void*)); +#endif + + static signal_type +catchsig(s) + int s; +#ifdef SA_SIGINFO +{ + catchsigaction(s, (siginfo_t *)0, (void *)0); +} + static signal_type +catchsigaction(s, i, c) + int s; + siginfo_t *i; + void *c; +#endif +{ +# if sig_zaps_handler + /* If a signal arrives before we reset the handler, we lose. */ + VOID signal(s, SIG_IGN); +# endif + +# ifdef SA_SIGINFO + if (!unsupported_SA_SIGINFO) + i = 0; +# endif + + if (holdlevel) { + heldsignal = s; +# ifdef SA_SIGINFO + if (i) { + bufsiginfo = *i; + heldsiginfo = &bufsiginfo; + } +# endif + return; + } + + ignoreints(); + setrid(); + if (!quietflag) { + /* Avoid calling sprintf etc., in case they're not reentrant. */ + char const *p; + char buf[BUFSIZ], *b = buf; + + if ( ! ( +# if has_mmap && large_memory && mmap_signal + /* Check whether this signal was planned. */ + s == mmap_signal && accessName +# else + 0 +# endif + )) { + char const *nRCS = "\nRCS"; +# if defined(SA_SIGINFO) && has_si_errno && has_mmap && large_memory && mmap_signal + if (s == mmap_signal && i && i->si_errno) { + errno = i->si_errno; + perror(nRCS++); + } +# endif +# if defined(SA_SIGINFO) && has_psiginfo + if (i) + psiginfo(i, nRCS); + else + psignal(s, nRCS); +# else + psignal(s, nRCS); +# endif } - exiterr(); + + for (p = "RCS: "; *p; *b++ = *p++) + continue; +# if has_mmap && large_memory && mmap_signal + if (s == mmap_signal) { + p = accessName; + if (!p) + p = "Was a file changed by some other process? "; + else { + char const *p1; + for (p1 = p; *p1; p1++) + continue; + VOID write(STDERR_FILENO, buf, b - buf); + VOID write(STDERR_FILENO, p, p1 - p); + b = buf; + p = ": Permission denied. "; + } + while (*p) + *b++ = *p++; + } +# endif + for (p = "Cleaning up.\n"; *p; *b++ = *p++) + continue; + VOID write(STDERR_FILENO, buf, b - buf); + } + exiterr(); } void @@ -417,62 +593,62 @@ ignoreints() restoreints() { if (!--holdlevel && heldsignal) +# ifdef SA_SIGINFO + VOID catchsigaction(heldsignal, heldsiginfo, (void *)0); +# else VOID catchsig(heldsignal); +# endif } -static int const sig[] = { -#ifdef SIGHUP - SIGHUP, -#endif -#ifdef SIGINT - SIGINT, -#endif -#ifdef SIGPIPE - SIGPIPE, -#endif -#ifdef SIGQUIT - SIGQUIT, -#endif -#ifdef SIGTERM - SIGTERM, -#endif -#ifdef SIGXCPU - SIGXCPU, -#endif -#ifdef SIGXFSZ - SIGXFSZ, -#endif -}; -#define SIGS (sizeof(sig)/sizeof(*sig)) - +static void setup_catchsig P((int const*,int)); #if has_sigaction + static void check_sig P((int)); static void check_sig(r) int r; { if (r != 0) - efaterror("signal"); + efaterror("signal handling"); } static void - setup_catchsig() + setup_catchsig(sig, sigs) + int const *sig; + int sigs; { - register int i; - sigset_t blocked; + register int i, j; struct sigaction act; - check_sig(sigemptyset(&blocked)); - for (i=SIGS; 0<=--i; ) - check_sig(sigaddset(&blocked, sig[i])); - for (i=SIGS; 0<=--i; ) { - check_sig(sigaction(sig[i], (struct sigaction*)nil, &act)); + for (i=sigs; 0<=--i; ) { + check_sig(sigaction(sig[i], (struct sigaction*)0, &act)); if (act.sa_handler != SIG_IGN) { - act.sa_handler = catchsig; - act.sa_mask = blocked; - check_sig(sigaction(sig[i], &act, (struct sigaction*)nil)); + act.sa_handler = catchsig; +# ifdef SA_SIGINFO + if (!unsupported_SA_SIGINFO) { +# if has_sa_sigaction + act.sa_sigaction = catchsigaction; +# else + act.sa_handler = catchsigaction; +# endif + act.sa_flags |= SA_SIGINFO; + } +# endif + for (j=sigs; 0<=--j; ) + check_sig(sigaddset(&act.sa_mask, sig[j])); + if (sigaction(sig[i], &act, (struct sigaction*)0) != 0) { +# if defined(SA_SIGINFO) && defined(ENOTSUP) + if (errno == ENOTSUP && !unsupported_SA_SIGINFO) { + /* Turn off use of SA_SIGINFO and try again. */ + unsupported_SA_SIGINFO = 1; + i++; + continue; + } +# endif + check_sig(-1); + } } } } @@ -481,16 +657,18 @@ static int const sig[] = { #if has_sigblock static void - setup_catchsig() + setup_catchsig(sig, sigs) + int const *sig; + int sigs; { register int i; int mask; mask = 0; - for (i=SIGS; 0<=--i; ) + for (i=sigs; 0<=--i; ) mask |= sigmask(sig[i]); mask = sigblock(mask); - for (i=SIGS; 0<=--i; ) + for (i=sigs; 0<=--i; ) if ( signal(sig[i], catchsig) == SIG_IGN && signal(sig[i], SIG_IGN) != catchsig @@ -502,11 +680,13 @@ static int const sig[] = { #else static void - setup_catchsig() + setup_catchsig(sig, sigs) + int const *sig; + int sigs; { register i; - for (i=SIGS; 0<=--i; ) + for (i=sigs; 0<=--i; ) if ( signal(sig[i], SIG_IGN) != SIG_IGN && signal(sig[i], catchsig) != SIG_IGN @@ -517,16 +697,68 @@ static int const sig[] = { #endif #endif + +static int const regsigs[] = { +# ifdef SIGHUP + SIGHUP, +# endif +# ifdef SIGINT + SIGINT, +# endif +# ifdef SIGPIPE + SIGPIPE, +# endif +# ifdef SIGQUIT + SIGQUIT, +# endif +# ifdef SIGTERM + SIGTERM, +# endif +# ifdef SIGXCPU + SIGXCPU, +# endif +# ifdef SIGXFSZ + SIGXFSZ, +# endif +}; + void catchints() { static int catching_ints; if (!catching_ints) { - catching_ints = true; - setup_catchsig(); + catching_ints = true; + setup_catchsig(regsigs, (int) (sizeof(regsigs)/sizeof(*regsigs))); } } +#if has_mmap && large_memory && mmap_signal + + /* + * If you mmap an NFS file, and someone on another client removes the last + * link to that file, and you later reference an uncached part of that file, + * you'll get a SIGBUS or SIGSEGV (depending on the operating system). + * Catch the signal and report the problem to the user. + * Unfortunately, there's no portable way to differentiate between this + * problem and actual bugs in the program. + * This NFS problem is rare, thank goodness. + * + * This can also occur if someone truncates the file, even without NFS. + */ + + static int const mmapsigs[] = { mmap_signal }; + + void + catchmmapints() + { + static int catching_mmap_ints; + if (!catching_mmap_ints) { + catching_mmap_ints = true; + setup_catchsig(mmapsigs, (int)(sizeof(mmapsigs)/sizeof(*mmapsigs))); + } + } +#endif + #endif /* has_signal */ @@ -538,7 +770,7 @@ fastcopy(inf,outf) */ { #if large_memory -# if has_mmap +# if maps_memory awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf); inf->ptr = inf->lim; # else @@ -589,10 +821,81 @@ awrite(buf, chars, f) Oerror(); } +/* dup a file descriptor; the result must not be stdin, stdout, or stderr. */ + static int dupSafer P((int)); + static int +dupSafer(fd) + int fd; +{ +# ifdef F_DUPFD + return fcntl(fd, F_DUPFD, STDERR_FILENO + 1); +# else + int e, f, i, used = 0; + while (STDIN_FILENO <= (f = dup(fd)) && f <= STDERR_FILENO) + used |= 1<<f; + e = errno; + for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) + if (used & (1<<i)) + VOID close(i); + errno = e; + return f; +# endif +} +/* Renumber a file descriptor so that it's not stdin, stdout, or stderr. */ + int +fdSafer(fd) + int fd; +{ + if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) { + int f = dupSafer(fd); + int e = errno; + VOID close(fd); + errno = e; + fd = f; + } + return fd; +} +/* Like fopen, except the result is never stdin, stdout, or stderr. */ + FILE * +fopenSafer(filename, type) + char const *filename; + char const *type; +{ + FILE *stream = fopen(filename, type); + if (stream) { + int fd = fileno(stream); + if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) { + int f = dupSafer(fd); + if (f < 0) { + int e = errno; + VOID fclose(stream); + errno = e; + return 0; + } + if (fclose(stream) != 0) { + int e = errno; + VOID close(f); + errno = e; + return 0; + } + stream = fdopen(f, type); + } + } + return stream; +} +#ifdef F_DUPFD +# undef dup +# define dup(fd) fcntl(fd, F_DUPFD, 0) +#endif + + +#if has_fork || has_spawn + + static int movefd P((int,int)); static int movefd(old, new) int old, new; @@ -607,6 +910,7 @@ movefd(old, new) return close(old)==0 ? new : -1; } + static int fdreopen P((int,char const*,int)); static int fdreopen(fd, file, flags) int fd; @@ -623,38 +927,26 @@ fdreopen(fd, file, flags) return movefd(newfd, fd); } -#if !has_spawn - static void -tryopen(fd,file,flags) - int fd, flags; - char const *file; -{ - if (file && fdreopen(fd,file,flags) != fd) - efaterror(file); -} -#else - static int -tryopen(fd,file,flags) - int fd, flags; - char const *file; -{ - int newfd = -1; - if (file && ((newfd=dup(fd)) < 0 || fdreopen(fd,file,flags) != fd)) - efaterror(file); - return newfd; -} +#if has_spawn + static void redirect P((int,int)); static void redirect(old, new) int old, new; +/* +* Move file descriptor OLD to NEW. +* If OLD is -1, do nothing. +* If OLD is -2, just close NEW. +*/ { - if (0 <= old && (close(new) != 0 || movefd(old,new) < 0)) + if ((old != -1 && close(new) != 0) || (0 <= old && movefd(old,new) < 0)) efaterror("spawn I/O redirection"); } #endif +#else /* !has_fork && !has_spawn */ -#if !has_fork && !has_spawn + static void bufargcat P((struct buf*,int,char const*)); static void bufargcat(b, c, s) register struct buf *b; @@ -684,53 +976,145 @@ bufargcat(b, c, s) *p++ = '\''; *p = 0; } + #endif +#if !has_spawn && has_fork /* -* Run a command specified by the strings in 'inoutargs'. -* inoutargs[0], if nonnil, is the name of the input file. -* inoutargs[1], if nonnil, is the name of the output file. -* inoutargs[2..] form the command to be run. +* Output the string S to stderr, without touching any I/O buffers. +* This is useful if you are a child process, whose buffers are usually wrong. +* Exit immediately if the write does not completely succeed. +*/ +static void write_stderr P((char const *)); + static void +write_stderr(s) + char const *s; +{ + size_t slen = strlen(s); + if (write(STDERR_FILENO, s, slen) != slen) + _exit(EXIT_TROUBLE); +} +#endif + +/* +* Run a command. +* infd, if not -1, is the input file descriptor. +* outname, if nonzero, is the name of the output file. +* args[1..] form the command to be run; args[0] might be modified. */ int -runv(inoutargs) - char const **inoutargs; +runv(infd, outname, args) + int infd; + char const *outname, **args; { - register char const **p; int wstatus; +#if bad_wait_if_SIGCHLD_ignored + static int fixed_SIGCHLD; + if (!fixed_SIGCHLD) { + fixed_SIGCHLD = true; +# ifndef SIGCHLD +# define SIGCHLD SIGCLD +# endif + VOID signal(SIGCHLD, SIG_DFL); + } +#endif + oflush(); eflush(); { #if has_spawn int in, out; - p = inoutargs; - in = tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY); - out = tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY); - wstatus = spawn_RCS(0, *p, (char*const*)p); - if (wstatus == -1 && errno == ENOEXEC) { - *--p = RCS_SHELL; - wstatus = spawnv(0, *p, (char*const*)p); + char const *file; + + in = -1; + if (infd != -1 && infd != STDIN_FILENO) { + if ((in = dup(STDIN_FILENO)) < 0) { + if (errno != EBADF) + efaterror("spawn input setup"); + in = -2; + } else { +# ifdef F_DUPFD + if (close(STDIN_FILENO) != 0) + efaterror("spawn input close"); +# endif + } + if ( +# ifdef F_DUPFD + fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO +# else + dup2(infd, STDIN_FILENO) != STDIN_FILENO +# endif + ) + efaterror("spawn input redirection"); } + + out = -1; + if (outname) { + if ((out = dup(STDOUT_FILENO)) < 0) { + if (errno != EBADF) + efaterror("spawn output setup"); + out = -2; + } + if (fdreopen( + STDOUT_FILENO, outname, + O_CREAT | O_TRUNC | O_WRONLY + ) < 0) + efaterror(outname); + } + + wstatus = spawn_RCS(0, args[1], (char**)(args + 1)); +# ifdef RCS_SHELL + if (wstatus == -1 && errno == ENOEXEC) { + args[0] = RCS_SHELL; + wstatus = spawnv(0, args[0], (char**)args); + } +# endif redirect(in, STDIN_FILENO); redirect(out, STDOUT_FILENO); #else #if has_fork pid_t pid; -# if !has_waitpid - pid_t w; -# endif if (!(pid = vfork())) { - p = inoutargs; - tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY); - tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY); - VOID exec_RCS(*p, (char*const*)p); - if (errno == ENOEXEC) { - *--p = RCS_SHELL; - VOID execv(*p, (char*const*)p); + char const *notfound; + if (infd != -1 && infd != STDIN_FILENO && ( +# ifdef F_DUPFD + (VOID close(STDIN_FILENO), + fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO) +# else + dup2(infd, STDIN_FILENO) != STDIN_FILENO +# endif + )) { + /* Avoid perror since it may misuse buffers. */ + write_stderr(args[1]); + write_stderr(": I/O redirection failed\n"); + _exit(EXIT_TROUBLE); } - VOID write(STDERR_FILENO, *p, strlen(*p)); - VOID write(STDERR_FILENO, ": not found\n", 12); + + if (outname) + if (fdreopen( + STDOUT_FILENO, outname, + O_CREAT | O_TRUNC | O_WRONLY + ) < 0) { + /* Avoid perror since it may misuse buffers. */ + write_stderr(args[1]); + write_stderr(": "); + write_stderr(outname); + write_stderr(": cannot create\n"); + _exit(EXIT_TROUBLE); + } + VOID exec_RCS(args[1], (char**)(args + 1)); + notfound = args[1]; +# ifdef RCS_SHELL + if (errno == ENOEXEC) { + args[0] = notfound = RCS_SHELL; + VOID execv(args[0], (char**)args); + } +# endif + + /* Avoid perror since it may misuse buffers. */ + write_stderr(notfound); + write_stderr(": not found\n"); _exit(EXIT_TROUBLE); } if (pid < 0) @@ -739,83 +1123,71 @@ runv(inoutargs) if (waitpid(pid, &wstatus, 0) < 0) efaterror("waitpid"); # else - do { - if ((w = wait(&wstatus)) < 0) - efaterror("wait"); - } while (w != pid); + { + pid_t w; + do { + if ((w = wait(&wstatus)) < 0) + efaterror("wait"); + } while (w != pid); + } # endif #else static struct buf b; + char const *p; /* Use system(). On many hosts system() discards signals. Yuck! */ - p = inoutargs+2; + p = args + 1; bufscpy(&b, *p); while (*++p) bufargcat(&b, ' ', *p); - if (inoutargs[0]) - bufargcat(&b, '<', inoutargs[0]); - if (inoutargs[1]) - bufargcat(&b, '>', inoutargs[1]); + if (infd != -1 && infd != STDIN_FILENO) { + char redirection[32]; + VOID sprintf(redirection, "<&%d", infd); + bufscat(&b, redirection); + } + if (outname) + bufargcat(&b, '>', outname); wstatus = system(b.string); #endif #endif } - if (!WIFEXITED(wstatus)) - faterror("%s failed", inoutargs[2]); + if (!WIFEXITED(wstatus)) { + if (WIFSIGNALED(wstatus)) { + psignal(WTERMSIG(wstatus), args[1]); + fatcleanup(1); + } + faterror("%s failed for unknown reason", args[1]); + } return WEXITSTATUS(wstatus); } #define CARGSMAX 20 /* * Run a command. -* The first two arguments are the input and output files (if nonnil); -* the rest specify the command and its arguments. +* infd, if not -1, is the input file descriptor. +* outname, if nonzero, is the name of the output file. +* The remaining arguments specify the command and its arguments. */ int #if has_prototypes -run(char const *infile, char const *outfile, ...) +run(int infd, char const *outname, ...) #else /*VARARGS2*/ -run(infile, outfile, va_alist) - char const *infile; - char const *outfile; +run(infd, outname, va_alist) + int infd; + char const *outname; va_dcl #endif { va_list ap; char const *rgargs[CARGSMAX]; - register i = 0; - rgargs[0] = infile; - rgargs[1] = outfile; - vararg_start(ap, outfile); - for (i = 2; (rgargs[i++] = va_arg(ap, char const*)); ) + register int i; + vararg_start(ap, outname); + for (i = 1; (rgargs[i++] = va_arg(ap, char const*)); ) if (CARGSMAX <= i) faterror("too many command arguments"); va_end(ap); - return runv(rgargs); -} - - - char const * -date2str(date, datebuf) - char const date[datesize]; - char datebuf[datesize]; -/* -* Format a user-readable form of the RCS format DATE into the buffer DATEBUF. -* Yield DATEBUF. -*/ -{ - register char const *p = date; - - while (*p++ != '.') - ; - VOID sprintf(datebuf, - "19%.*s/%.2s/%.2s %.2s:%.2s:%s" + - (date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2), - (int)(p-date-1), date, - p, p+3, p+6, p+9, p+12 - ); - return datebuf; + return runv(infd, outname, rgargs); } @@ -828,23 +1200,28 @@ setRCSversion(str) static int oldversion; register char const *s = str + 2; - int v = VERSION_DEFAULT; - - if (oldversion) - redefined('V'); - oldversion = true; if (*s) { + int v = VERSION_DEFAULT; + + if (oldversion) + redefined('V'); + oldversion = true; v = 0; while (isdigit(*s)) v = 10*v + *s++ - '0'; if (*s) - faterror("%s isn't a number", str); - if (v < VERSION_min || VERSION_max < v) - faterror("%s out of range %d..%d", str, VERSION_min, VERSION_max); + error("%s isn't a number", str); + else if (v < VERSION_min || VERSION_max < v) + error("%s out of range %d..%d", + str, VERSION_min, VERSION_max + ); + + RCSversion = VERSION(v); + } else { + printf("RCS version %s\n", RCS_version_string); + exit(0); } - - RCSversion = VERSION(v); } int @@ -853,7 +1230,7 @@ getRCSINIT(argc, argv, newargv) char **argv, ***newargv; { register char *p, *q, **pp; - unsigned n; + size_t n; if (!(q = cgetenv("RCSINIT"))) *newargv = argv; @@ -922,7 +1299,7 @@ getRCSINIT(argc, argv, newargv) } copyrest: while ((*pp++ = *argv++)) - ; + continue; } return argc; } @@ -950,8 +1327,11 @@ getRCSINIT(argc, argv, newargv) */ static void -set_uid_to(u) - uid_t u; +#if has_prototypes +set_uid_to(uid_t u) +#else + set_uid_to(u) uid_t u; +#endif /* Become user u. */ { static int looping; @@ -959,8 +1339,13 @@ set_uid_to(u) if (euid() == ruid()) return; #if (has_fork||has_spawn) && DIFF_ABSOLUTE - if (seteuid(u) != 0) - efaterror("setuid"); +# if has_setreuid + if (setreuid(u==euid() ? ruid() : euid(), u) != 0) + efaterror("setuid"); +# else + if (seteuid(u) != 0) + efaterror("setuid"); +# endif #endif if (geteuid() != u) { if (looping) @@ -995,3 +1380,12 @@ setrid() set_uid_to(ruid()); } #endif + + time_t +now() +{ + static time_t t; + if (!t && time(&t) == -1) + efaterror("time"); + return t; +} |
