diff options
author | peter <peter@FreeBSD.org> | 1995-10-28 21:50:58 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1995-10-28 21:50:58 +0000 |
commit | 822bceb624e3740412b90941feb1158d82f50edc (patch) | |
tree | 5072ccf03f140b698e07703cd04f14e6e4d75591 /gnu/usr.bin/rcs/lib/rcsutil.c | |
parent | 9d7e3d8dc0cccad8e42e4822ffa52ee28b6f7d2f (diff) | |
download | FreeBSD-src-822bceb624e3740412b90941feb1158d82f50edc.zip FreeBSD-src-822bceb624e3740412b90941feb1158d82f50edc.tar.gz |
First part of import conflict merge from rcs-5.7 import.
All those $Log$ entries, combined with the whitespace changes are a real
pain.
I'm committing this now, before it's completely finished to get it compiling
and working again ASAP. Some of the FreeBSD specific features are not working
in this commit yet (mainly rlog stuff and $FreeBSD$ support)
Diffstat (limited to 'gnu/usr.bin/rcs/lib/rcsutil.c')
-rw-r--r-- | gnu/usr.bin/rcs/lib/rcsutil.c | 833 |
1 files changed, 614 insertions, 219 deletions
diff --git a/gnu/usr.bin/rcs/lib/rcsutil.c b/gnu/usr.bin/rcs/lib/rcsutil.c index 55140c2..1177592 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,58 @@ 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 +/* + * $Log: rcsutil.c,v $ + * 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 +187,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 5.20 1995/06/16 06:19:24 eggert Exp $") #if !has_memcmp int @@ -173,7 +221,7 @@ memcpy(s1, s2, n) } #endif -#if lint +#if RCS_lint malloc_type lintalloc; #endif @@ -190,6 +238,7 @@ struct alloclist { static struct alloclist *alloced; + static malloc_type okalloc P((malloc_type)); static malloc_type okalloc(p) malloc_type p; @@ -245,7 +294,7 @@ ffree() tfree(p->alloc); tfree(p); } - alloced = nil; + alloced = 0; } void @@ -300,16 +349,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 +374,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 +397,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 +594,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 +658,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 +681,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 +698,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 +771,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 +822,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 +911,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 +928,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 +977,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 +1124,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 +1201,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 +1231,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 +1300,7 @@ getRCSINIT(argc, argv, newargv) } copyrest: while ((*pp++ = *argv++)) - ; + continue; } return argc; } @@ -950,8 +1328,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 +1340,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 +1381,12 @@ setrid() set_uid_to(ruid()); } #endif + + time_t +now() +{ + static time_t t; + if (!t && time(&t) == -1) + efaterror("time"); + return t; +} |