aboutsummaryrefslogtreecommitdiff
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.c1398
1 files changed, 0 insertions, 1398 deletions
diff --git a/gnu/usr.bin/rcs/lib/rcsutil.c b/gnu/usr.bin/rcs/lib/rcsutil.c
deleted file mode 100644
index e10afff6c20d..000000000000
--- a/gnu/usr.bin/rcs/lib/rcsutil.c
+++ /dev/null
@@ -1,1398 +0,0 @@
-/* RCS utility functions */
-
-/* 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.
-
-RCS is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-RCS is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-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,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-Report problems and direct all questions to:
-
- rcs-bugs@cs.purdue.edu
-
-*/
-
-
-
-
-/*
- * 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.
- *
- * Revision 5.9 1991/08/19 03:13:55 eggert
- * Add spawn() support. Explicate assumptions about getting invoker's name.
- * Standardize user-visible dates. Tune.
- *
- * Revision 5.8 1991/04/21 11:58:30 eggert
- * Plug setuid security hole.
- *
- * Revision 5.6 1991/02/26 17:48:39 eggert
- * Fix setuid bug. Use fread, fwrite more portably.
- * Support waitpid. Don't assume -1 is acceptable to W* macros.
- * strsave -> str_save (DG/UX name clash)
- *
- * Revision 5.5 1990/12/04 05:18:49 eggert
- * Don't output a blank line after a signal diagnostic.
- * Use -I for prompts and -q for diagnostics.
- *
- * Revision 5.4 1990/11/01 05:03:53 eggert
- * Remove unneeded setid check. Add awrite(), fremember().
- *
- * Revision 5.3 1990/10/06 00:16:45 eggert
- * Don't fread F if feof(F).
- *
- * Revision 5.2 1990/09/04 08:02:31 eggert
- * Store fread()'s result in an fread_type object.
- *
- * Revision 5.1 1990/08/29 07:14:07 eggert
- * Declare getpwuid() more carefully.
- *
- * Revision 5.0 1990/08/22 08:13:46 eggert
- * Add setuid support. Permit multiple locks per user.
- * Remove compile-time limits; use malloc instead.
- * Switch to GMT. Permit dates past 1999/12/31.
- * Add -V. Remove snooping. Ansify and Posixate.
- * Tune. Some USG hosts define NSIG but not sys_siglist.
- * Don't run /bin/sh if it's hopeless.
- * Don't leave garbage behind if the output is an empty pipe.
- * Clean up after SIGXCPU or SIGXFSZ. Print name of signal that caused cleanup.
- *
- * Revision 4.6 89/05/01 15:13:40 narten
- * changed copyright header to reflect current distribution rules
- *
- * Revision 4.5 88/11/08 16:01:02 narten
- * corrected use of varargs routines
- *
- * Revision 4.4 88/08/09 19:13:24 eggert
- * Check for memory exhaustion.
- * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
- * Use execv(), not system(); yield exit status like diff(1)'s.
- *
- * Revision 4.3 87/10/18 10:40:22 narten
- * Updating version numbers. Changes relative to 1.1 actually
- * relative to 4.1
- *
- * Revision 1.3 87/09/24 14:01:01 narten
- * Sources now pass through lint (if you ignore printf/sprintf/fprintf
- * warnings)
- *
- * Revision 1.2 87/03/27 14:22:43 jenkins
- * Port to suns
- *
- * Revision 4.1 83/05/10 15:53:13 wft
- * Added getcaller() and findlock().
- * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
- * (needed for background jobs in older shells). Added restoreints().
- * Removed printing of full RCS path from logcommand().
- *
- * Revision 3.8 83/02/15 15:41:49 wft
- * Added routine fastcopy() to copy remainder of a file in blocks.
- *
- * Revision 3.7 82/12/24 15:25:19 wft
- * added catchints(), ignoreints() for catching and ingnoring interrupts;
- * fixed catchsig().
- *
- * Revision 3.6 82/12/08 21:52:05 wft
- * Using DATEFORM to format dates.
- *
- * Revision 3.5 82/12/04 18:20:49 wft
- * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
- * lockedby-field.
- *
- * Revision 3.4 82/12/03 17:17:43 wft
- * Added check to addlock() ensuring only one lock per person.
- * Addlock also returns a pointer to the lock created. Deleted fancydate().
- *
- * Revision 3.3 82/11/27 12:24:37 wft
- * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
- * Introduced macro SNOOP so that snoop can be placed in directory other than
- * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
- *
- * Revision 3.2 82/10/18 21:15:11 wft
- * added function getfullRCSname().
- *
- * Revision 3.1 82/10/13 16:17:37 wft
- * Cleanup message is now suppressed in quiet mode.
- */
-
-
-
-
-#include "rcsbase.h"
-
-libId(utilId, "$FreeBSD$")
-
-#if !has_memcmp
- int
-memcmp(s1, s2, n)
- void const *s1, *s2;
- size_t n;
-{
- register unsigned char const
- *p1 = (unsigned char const*)s1,
- *p2 = (unsigned char const*)s2;
- register size_t i = n;
- register int r = 0;
- while (i-- && !(r = (*p1++ - *p2++)))
- ;
- return r;
-}
-#endif
-
-#if !has_memcpy
- void *
-memcpy(s1, s2, n)
- void *s1;
- void const *s2;
- size_t n;
-{
- register char *p1 = (char*)s1;
- register char const *p2 = (char const*)s2;
- while (n--)
- *p1++ = *p2++;
- return s1;
-}
-#endif
-
-#if RCS_lint
- malloc_type lintalloc;
-#endif
-
-/*
- * list of blocks allocated with ftestalloc()
- * These blocks can be freed by ffree when we're done with the current file.
- * We could put the free block inside struct alloclist, rather than a pointer
- * to the free block, but that would be less portable.
- */
-struct alloclist {
- malloc_type alloc;
- struct alloclist *nextalloc;
-};
-static struct alloclist *alloced;
-
-
- static malloc_type okalloc P((malloc_type));
- static malloc_type
-okalloc(p)
- malloc_type p;
-{
- if (!p)
- faterror("out of memory");
- return p;
-}
-
- malloc_type
-testalloc(size)
- size_t size;
-/* Allocate a block, testing that the allocation succeeded. */
-{
- return okalloc(malloc(size));
-}
-
- malloc_type
-testrealloc(ptr, size)
- malloc_type ptr;
- size_t size;
-/* Reallocate a block, testing that the allocation succeeded. */
-{
- return okalloc(realloc(ptr, size));
-}
-
- malloc_type
-fremember(ptr)
- malloc_type ptr;
-/* Remember PTR in 'alloced' so that it can be freed later. Yield PTR. */
-{
- register struct alloclist *q = talloc(struct alloclist);
- q->nextalloc = alloced;
- alloced = q;
- return q->alloc = ptr;
-}
-
- malloc_type
-ftestalloc(size)
- size_t size;
-/* Allocate a block, putting it in 'alloced' so it can be freed later. */
-{
- return fremember(testalloc(size));
-}
-
- void
-ffree()
-/* Free all blocks allocated with ftestalloc(). */
-{
- register struct alloclist *p, *q;
- for (p = alloced; p; p = q) {
- q = p->nextalloc;
- tfree(p->alloc);
- tfree(p);
- }
- alloced = 0;
-}
-
- void
-ffree1(f)
- register char const *f;
-/* Free the block f, which was allocated by ftestalloc. */
-{
- register struct alloclist *p, **a = &alloced;
-
- while ((p = *a)->alloc != f)
- a = &p->nextalloc;
- *a = p->nextalloc;
- tfree(p->alloc);
- tfree(p);
-}
-
- char *
-str_save(s)
- char const *s;
-/* Save s in permanently allocated storage. */
-{
- return strcpy(tnalloc(char, strlen(s)+1), s);
-}
-
- char *
-fstr_save(s)
- char const *s;
-/* Save s in storage that will be deallocated when we're done with this file. */
-{
- return strcpy(ftnalloc(char, strlen(s)+1), s);
-}
-
- char *
-cgetenv(name)
- char const *name;
-/* Like getenv(), but yield a copy; getenv() can overwrite old results. */
-{
- register char *p;
-
- return (p=getenv(name)) ? str_save(p) : p;
-}
-
- char const *
-getusername(suspicious)
- int suspicious;
-/* Get the caller's login name. Trust only getwpuid if SUSPICIOUS. */
-{
- static char *name;
-
- if (!name) {
- if (
- /* Prefer getenv() unless suspicious; it's much faster. */
-# if getlogin_is_secure
- (suspicious
- || (
- !(name = cgetenv("LOGNAME"))
- && !(name = cgetenv("USER"))
- ))
- && !(name = getlogin())
-# else
- suspicious
- || (
- !(name = cgetenv("LOGNAME"))
- && !(name = cgetenv("USER"))
- && !(name = getlogin())
- )
-# endif
- ) {
-#if has_getuid && has_getpwuid
- struct passwd const *pw = getpwuid(ruid());
- if (!pw)
- faterror("no password entry for userid %lu",
- (unsigned long)ruid()
- );
- name = pw->pw_name;
-#else
-#if has_setuid
- faterror("setuid not supported");
-#else
- faterror("Who are you? Please setenv LOGNAME.");
-#endif
-#endif
- }
- checksid(name);
- }
- return name;
-}
-
-
-
-
-#if has_signal
-
-/*
- * Signal handling
- *
- * Standard C places too many restrictions on signal handlers.
- * We obey as many of them as we can.
- * Posix places fewer restrictions, and we are Posix-compatible here.
- */
-
-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
-
-
-#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
-# define accessName ((char const *) 0)
-#endif
-
-
-#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
- case SIGPIPE: sname = "Broken pipe"; break;
-# endif
-# ifdef SIGQUIT
- case SIGQUIT: sname = "Quit"; break;
-# endif
-# ifdef SIGTERM
- case SIGTERM: sname = "Terminated"; break;
-# endif
-# ifdef SIGXCPU
- case SIGXCPU: sname = "Cputime limit exceeded"; break;
-# endif
-# ifdef SIGXFSZ
- case SIGXFSZ: sname = "Filesize limit exceeded"; break;
-# 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
-
-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
- }
-
- 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
-ignoreints()
-{
- ++holdlevel;
-}
-
- void
-restoreints()
-{
- if (!--holdlevel && heldsignal)
-# ifdef SA_SIGINFO
- VOID catchsigaction(heldsignal, heldsiginfo, (void *)0);
-# else
- VOID catchsig(heldsignal);
-# endif
-}
-
-
-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 handling");
- }
-
- static void
- setup_catchsig(sig, sigs)
- int const *sig;
- int sigs;
- {
- register int i, j;
- struct sigaction 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;
-# 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);
- }
- }
- }
- }
-
-#else
-#if has_sigblock
-
- static void
- setup_catchsig(sig, sigs)
- int const *sig;
- int sigs;
- {
- register int i;
- int mask;
-
- mask = 0;
- for (i=sigs; 0<=--i; )
- mask |= sigmask(sig[i]);
- mask = sigblock(mask);
- for (i=sigs; 0<=--i; )
- if (
- signal(sig[i], catchsig) == SIG_IGN &&
- signal(sig[i], SIG_IGN) != catchsig
- )
- faterror("signal catcher failure");
- VOID sigsetmask(mask);
- }
-
-#else
-
- static void
- setup_catchsig(sig, sigs)
- int const *sig;
- int sigs;
- {
- register i;
-
- for (i=sigs; 0<=--i; )
- if (
- signal(sig[i], SIG_IGN) != SIG_IGN &&
- signal(sig[i], catchsig) != SIG_IGN
- )
- faterror("signal catcher failure");
- }
-
-#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(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 */
-
-
- void
-fastcopy(inf,outf)
- register RILE *inf;
- FILE *outf;
-/* Function: copies the remainder of file inf to outf.
- */
-{
-#if large_memory
-# if maps_memory
- awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf);
- inf->ptr = inf->lim;
-# else
- for (;;) {
- awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf);
- inf->ptr = inf->readlim;
- if (inf->ptr == inf->lim)
- break;
- VOID Igetmore(inf);
- }
-# endif
-#else
- char buf[BUFSIZ*8];
- register fread_type rcount;
-
- /*now read the rest of the file in blocks*/
- while (!feof(inf)) {
- if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) {
- testIerror(inf);
- return;
- }
- awrite(buf, (size_t)rcount, outf);
- }
-#endif
-}
-
-#ifndef SSIZE_MAX
- /* This does not work in #ifs, but it's good enough for us. */
- /* Underestimating SSIZE_MAX may slow us down, but it won't break us. */
-# define SSIZE_MAX ((unsigned)-1 >> 1)
-#endif
-
- void
-awrite(buf, chars, f)
- char const *buf;
- size_t chars;
- FILE *f;
-{
- /* Posix 1003.1-1990 ssize_t hack */
- while (SSIZE_MAX < chars) {
- if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f) != SSIZE_MAX)
- Oerror();
- buf += SSIZE_MAX;
- chars -= SSIZE_MAX;
- }
-
- if (Fwrite(buf, sizeof(*buf), chars, f) != chars)
- 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;
-{
- if (old < 0 || old == new)
- return old;
-# ifdef F_DUPFD
- new = fcntl(old, F_DUPFD, new);
-# else
- new = dup2(old, new);
-# endif
- return close(old)==0 ? new : -1;
-}
-
- static int fdreopen P((int,char const*,int));
- static int
-fdreopen(fd, file, flags)
- int fd;
- char const *file;
- int flags;
-{
- int newfd;
- VOID close(fd);
- newfd =
-#if !open_can_creat
- flags&O_CREAT ? creat(file, S_IRUSR|S_IWUSR) :
-#endif
- open(file, flags, S_IRUSR|S_IWUSR);
- return movefd(newfd, fd);
-}
-
-#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 ((old != -1 && close(new) != 0) || (0 <= old && movefd(old,new) < 0))
- efaterror("spawn I/O redirection");
-}
-#endif
-
-
-#else /* !has_fork && !has_spawn */
-
- static void bufargcat P((struct buf*,int,char const*));
- static void
-bufargcat(b, c, s)
- register struct buf *b;
- int c;
- register char const *s;
-/* Append to B a copy of C, plus a quoted copy of S. */
-{
- register char *p;
- register char const *t;
- size_t bl, sl;
-
- for (t=s, sl=0; *t; )
- sl += 3*(*t++=='\'') + 1;
- bl = strlen(b->string);
- bufrealloc(b, bl + sl + 4);
- p = b->string + bl;
- *p++ = c;
- *p++ = '\'';
- while (*s) {
- if (*s == '\'') {
- *p++ = '\'';
- *p++ = '\\';
- *p++ = '\'';
- }
- *p++ = *s++;
- }
- *p++ = '\'';
- *p = 0;
-}
-
-#endif
-
-#if !has_spawn && has_fork
-/*
-* 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(infd, outname, args)
- int infd;
- char const *outname, **args;
-{
- 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;
- 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 (!(pid = vfork())) {
- 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);
- }
-
- 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)
- efaterror("fork");
-# if has_waitpid
- if (waitpid(pid, &wstatus, 0) < 0)
- efaterror("waitpid");
-# else
- {
- 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 = args + 1;
- bufscpy(&b, *p);
- while (*++p)
- bufargcat(&b, ' ', *p);
- 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)) {
- 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.
-* 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(int infd, char const *outname, ...)
-#else
- /*VARARGS2*/
-run(infd, outname, va_alist)
- int infd;
- char const *outname;
- va_dcl
-#endif
-{
- va_list ap;
- char const *rgargs[CARGSMAX];
- 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(infd, outname, rgargs);
-}
-
-
-int RCSversion;
-
- void
-setRCSversion(str)
- char const *str;
-{
- static int oldversion;
-
- register char const *s = str + 2;
-
- if (*s) {
- int v = VERSION_DEFAULT;
-
- if (oldversion)
- redefined('V');
- oldversion = true;
- v = 0;
- while (isdigit(*s))
- v = 10*v + *s++ - '0';
- if (*s)
- 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);
- }
-}
-
- int
-getRCSINIT(argc, argv, newargv)
- int argc;
- char **argv, ***newargv;
-{
- register char *p, *q, **pp;
- char const *ev;
- size_t n;
-
- if ((ev = cgetenv("RCSLOCALID")))
- setRCSLocalId(ev);
-
- if ((ev = cgetenv("RCSINCEXC")))
- setIncExc(ev);
-
- if (!(q = cgetenv("RCSINIT")))
- *newargv = argv;
- else {
- n = argc + 2;
- /*
- * Count spaces in RCSINIT to allocate a new arg vector.
- * This is an upper bound, but it's OK even if too large.
- */
- for (p = q; ; ) {
- switch (*p++) {
- default:
- continue;
-
- case ' ':
- case '\b': case '\f': case '\n':
- case '\r': case '\t': case '\v':
- n++;
- continue;
-
- case '\0':
- break;
- }
- break;
- }
- *newargv = pp = tnalloc(char*, n);
- *pp++ = *argv++; /* copy program name */
- for (p = q; ; ) {
- for (;;) {
- switch (*q) {
- case '\0':
- goto copyrest;
-
- case ' ':
- case '\b': case '\f': case '\n':
- case '\r': case '\t': case '\v':
- q++;
- continue;
- }
- break;
- }
- *pp++ = p;
- ++argc;
- for (;;) {
- switch ((*p++ = *q++)) {
- case '\0':
- goto copyrest;
-
- case '\\':
- if (!*q)
- goto copyrest;
- p[-1] = *q++;
- continue;
-
- default:
- continue;
-
- case ' ':
- case '\b': case '\f': case '\n':
- case '\r': case '\t': case '\v':
- break;
- }
- break;
- }
- p[-1] = '\0';
- }
- copyrest:
- while ((*pp++ = *argv++))
- continue;
- }
- return argc;
-}
-
-
-#define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i
-
-#if has_getuid
- uid_t ruid() { cacheid(getuid()); }
-#endif
-#if has_setuid
- uid_t euid() { cacheid(geteuid()); }
-#endif
-
-
-#if has_setuid
-
-/*
- * Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(),
- * because it lets us switch back and forth between arbitrary users.
- * If seteuid() doesn't work, we fall back on setuid(),
- * which works if saved setuid is supported,
- * unless the real or effective user is root.
- * This area is such a mess that we always check switches at runtime.
- */
-
- static void
-#if has_prototypes
-set_uid_to(uid_t u)
-#else
- set_uid_to(u) uid_t u;
-#endif
-/* Become user u. */
-{
- static int looping;
-
- if (euid() == ruid())
- return;
-#if (has_fork||has_spawn) && DIFF_ABSOLUTE
-# 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)
- return;
- looping = true;
- faterror("root setuid not supported" + (u?5:0));
- }
-}
-
-static int stick_with_euid;
-
- void
-/* Ignore all calls to seteid() and setrid(). */
-nosetid()
-{
- stick_with_euid = true;
-}
-
- void
-seteid()
-/* Become effective user. */
-{
- if (!stick_with_euid)
- set_uid_to(euid());
-}
-
- void
-setrid()
-/* Become real user. */
-{
- if (!stick_with_euid)
- set_uid_to(ruid());
-}
-#endif
-
- time_t
-now()
-{
- static time_t t;
- if (!t && time(&t) == -1)
- efaterror("time");
- return t;
-}