summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/rcs/lib/rcsutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/rcs/lib/rcsutil.c')
-rw-r--r--gnu/usr.bin/rcs/lib/rcsutil.c832
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;
+}