home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs57pc3.zip / rcs / src / rcsutil.c < prev    next >
C/C++ Source or Header  |  1995-06-16  |  30KB  |  1,393 lines

  1. /* RCS utility functions */
  2.  
  3. /* Copyright 1982, 1988, 1989 Walter Tichy
  4.    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
  5.    Distributed under license by the Free Software Foundation, Inc.
  6.  
  7. This file is part of RCS.
  8.  
  9. RCS is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2, or (at your option)
  12. any later version.
  13.  
  14. RCS is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with RCS; see the file COPYING.
  21. If not, write to the Free Software Foundation,
  22. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23.  
  24. Report problems and direct all questions to:
  25.  
  26.     rcs-bugs@cs.purdue.edu
  27.  
  28. */
  29.  
  30.  
  31.  
  32.  
  33. /*
  34.  * $Log: rcsutil.c,v $
  35.  * Revision 5.20  1995/06/16 06:19:24  eggert
  36.  * (catchsig): Remove `return'.
  37.  * Update FSF address.
  38.  *
  39.  * Revision 5.19  1995/06/02 18:19:00  eggert
  40.  * (catchsigaction): New name for `catchsig', for sa_sigaction signature.
  41.  * Use nRCS even if !has_psiginfo, to remove unused variable warning.
  42.  * (setup_catchsig): Use sa_sigaction only if has_sa_sigaction.
  43.  * Use ENOTSUP only if defined.
  44.  *
  45.  * Revision 5.18  1995/06/01 16:23:43  eggert
  46.  * (catchsig, restoreints, setup_catchsig): Use SA_SIGINFO, not has_psiginfo,
  47.  * to determine whether to use SA_SIGINFO feature,
  48.  * but also check at runtime whether the feature works.
  49.  * (catchsig): If an mmap_signal occurs, report the affected file name.
  50.  * (unsupported_SA_SIGINFO, accessName): New variables.
  51.  * (setup_catchsig): If using SA_SIGINFO, use sa_sigaction, not sa_handler.
  52.  * If SA_SIGINFO fails, fall back on sa_handler method.
  53.  *
  54.  * (readAccessFilenameBuffer, dupSafer, fdSafer, fopenSafer): New functions.
  55.  * (concatenate): Remove.
  56.  *
  57.  * (runv): Work around bad_wait_if_SIGCHLD_ignored bug.
  58.  * Remove reference to OPEN_O_WORK.
  59.  *
  60.  * Revision 5.17  1994/03/20 04:52:58  eggert
  61.  * Specify subprocess input via file descriptor, not file name.
  62.  * Avoid messing with I/O buffers in the child process.
  63.  * Define dup in terms of F_DUPFD if it exists.
  64.  * Move setmtime to rcsedit.c.  Remove lint.
  65.  *
  66.  * Revision 5.16  1993/11/09 17:40:15  eggert
  67.  * -V now prints version on stdout and exits.
  68.  *
  69.  * Revision 5.15  1993/11/03 17:42:27  eggert
  70.  * Use psiginfo and setreuid if available.  Move date2str to maketime.c.
  71.  *
  72.  * Revision 5.14  1992/07/28  16:12:44  eggert
  73.  * Add -V.  has_sigaction overrides sig_zaps_handler.  Fix -M bug.
  74.  * Add mmap_signal, which minimizes signal handling for non-mmap hosts.
  75.  *
  76.  * Revision 5.13  1992/02/17  23:02:28  eggert
  77.  * Work around NFS mmap SIGBUS problem.  Add -T support.
  78.  *
  79.  * Revision 5.12  1992/01/24  18:44:19  eggert
  80.  * Work around NFS mmap bug that leads to SIGBUS core dumps.  lint -> RCS_lint
  81.  *
  82.  * Revision 5.11  1992/01/06  02:42:34  eggert
  83.  * O_BINARY -> OPEN_O_WORK
  84.  * while (E) ; -> while (E) continue;
  85.  *
  86.  * Revision 5.10  1991/10/07  17:32:46  eggert
  87.  * Support piece tables even if !has_mmap.
  88.  *
  89.  * Revision 5.9  1991/08/19  03:13:55  eggert
  90.  * Add spawn() support.  Explicate assumptions about getting invoker's name.
  91.  * Standardize user-visible dates.  Tune.
  92.  *
  93.  * Revision 5.8  1991/04/21  11:58:30  eggert
  94.  * Plug setuid security hole.
  95.  *
  96.  * Revision 5.6  1991/02/26  17:48:39  eggert
  97.  * Fix setuid bug.  Use fread, fwrite more portably.
  98.  * Support waitpid.  Don't assume -1 is acceptable to W* macros.
  99.  * strsave -> str_save (DG/UX name clash)
  100.  *
  101.  * Revision 5.5  1990/12/04  05:18:49  eggert
  102.  * Don't output a blank line after a signal diagnostic.
  103.  * Use -I for prompts and -q for diagnostics.
  104.  *
  105.  * Revision 5.4  1990/11/01  05:03:53  eggert
  106.  * Remove unneeded setid check.  Add awrite(), fremember().
  107.  *
  108.  * Revision 5.3  1990/10/06  00:16:45  eggert
  109.  * Don't fread F if feof(F).
  110.  *
  111.  * Revision 5.2  1990/09/04  08:02:31  eggert
  112.  * Store fread()'s result in an fread_type object.
  113.  *
  114.  * Revision 5.1  1990/08/29  07:14:07  eggert
  115.  * Declare getpwuid() more carefully.
  116.  *
  117.  * Revision 5.0  1990/08/22  08:13:46  eggert
  118.  * Add setuid support.  Permit multiple locks per user.
  119.  * Remove compile-time limits; use malloc instead.
  120.  * Switch to GMT.  Permit dates past 1999/12/31.
  121.  * Add -V.  Remove snooping.  Ansify and Posixate.
  122.  * Tune.  Some USG hosts define NSIG but not sys_siglist.
  123.  * Don't run /bin/sh if it's hopeless.
  124.  * Don't leave garbage behind if the output is an empty pipe.
  125.  * Clean up after SIGXCPU or SIGXFSZ.  Print name of signal that caused cleanup.
  126.  *
  127.  * Revision 4.6  89/05/01  15:13:40  narten
  128.  * changed copyright header to reflect current distribution rules
  129.  * 
  130.  * Revision 4.5  88/11/08  16:01:02  narten
  131.  * corrected use of varargs routines
  132.  * 
  133.  * Revision 4.4  88/08/09  19:13:24  eggert
  134.  * Check for memory exhaustion.
  135.  * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
  136.  * Use execv(), not system(); yield exit status like diff(1)'s.
  137.  * 
  138.  * Revision 4.3  87/10/18  10:40:22  narten
  139.  * Updating version numbers. Changes relative to 1.1 actually
  140.  * relative to 4.1
  141.  * 
  142.  * Revision 1.3  87/09/24  14:01:01  narten
  143.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  144.  * warnings)
  145.  * 
  146.  * Revision 1.2  87/03/27  14:22:43  jenkins
  147.  * Port to suns
  148.  * 
  149.  * Revision 4.1  83/05/10  15:53:13  wft
  150.  * Added getcaller() and findlock().
  151.  * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
  152.  * (needed for background jobs in older shells). Added restoreints().
  153.  * Removed printing of full RCS path from logcommand().
  154.  * 
  155.  * Revision 3.8  83/02/15  15:41:49  wft
  156.  * Added routine fastcopy() to copy remainder of a file in blocks.
  157.  *
  158.  * Revision 3.7  82/12/24  15:25:19  wft
  159.  * added catchints(), ignoreints() for catching and ingnoring interrupts;
  160.  * fixed catchsig().
  161.  *
  162.  * Revision 3.6  82/12/08  21:52:05  wft
  163.  * Using DATEFORM to format dates.
  164.  *
  165.  * Revision 3.5  82/12/04  18:20:49  wft
  166.  * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
  167.  * lockedby-field.
  168.  *
  169.  * Revision 3.4  82/12/03  17:17:43  wft
  170.  * Added check to addlock() ensuring only one lock per person.
  171.  * Addlock also returns a pointer to the lock created. Deleted fancydate().
  172.  *
  173.  * Revision 3.3  82/11/27  12:24:37  wft
  174.  * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
  175.  * Introduced macro SNOOP so that snoop can be placed in directory other than
  176.  * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
  177.  *
  178.  * Revision 3.2  82/10/18  21:15:11  wft
  179.  * added function getfullRCSname().
  180.  *
  181.  * Revision 3.1  82/10/13  16:17:37  wft
  182.  * Cleanup message is now suppressed in quiet mode.
  183.  */
  184.  
  185.  
  186.  
  187.  
  188. #include "rcsbase.h"
  189.  
  190. libId(utilId, "$Id: rcsutil.c,v 5.20 1995/06/16 06:19:24 eggert Exp $")
  191.  
  192. #if !has_memcmp
  193.     int
  194. memcmp(s1, s2, n)
  195.     void const *s1, *s2;
  196.     size_t n;
  197. {
  198.     register unsigned char const
  199.         *p1 = (unsigned char const*)s1,
  200.         *p2 = (unsigned char const*)s2;
  201.     register size_t i = n;
  202.     register int r = 0;
  203.     while (i--  &&  !(r = (*p1++ - *p2++)))
  204.         ;
  205.     return r;
  206. }
  207. #endif
  208.  
  209. #if !has_memcpy
  210.     void *
  211. memcpy(s1, s2, n)
  212.     void *s1;
  213.     void const *s2;
  214.     size_t n;
  215. {
  216.     register char *p1 = (char*)s1;
  217.     register char const *p2 = (char const*)s2;
  218.     while (n--)
  219.         *p1++ = *p2++;
  220.     return s1;
  221. }
  222. #endif
  223.  
  224. #if RCS_lint
  225.     malloc_type lintalloc;
  226. #endif
  227.  
  228. /*
  229.  * list of blocks allocated with ftestalloc()
  230.  * These blocks can be freed by ffree when we're done with the current file.
  231.  * We could put the free block inside struct alloclist, rather than a pointer
  232.  * to the free block, but that would be less portable.
  233.  */
  234. struct alloclist {
  235.     malloc_type alloc;
  236.     struct alloclist *nextalloc;
  237. };
  238. static struct alloclist *alloced;
  239.  
  240.  
  241.     static malloc_type okalloc P((malloc_type));
  242.     static malloc_type
  243. okalloc(p)
  244.     malloc_type p;
  245. {
  246.     if (!p)
  247.         faterror("out of memory");
  248.     return p;
  249. }
  250.  
  251.     malloc_type
  252. testalloc(size)
  253.     size_t size;
  254. /* Allocate a block, testing that the allocation succeeded.  */
  255. {
  256.     return okalloc(malloc(size));
  257. }
  258.  
  259.     malloc_type
  260. testrealloc(ptr, size)
  261.     malloc_type ptr;
  262.     size_t size;
  263. /* Reallocate a block, testing that the allocation succeeded.  */
  264. {
  265.     return okalloc(realloc(ptr, size));
  266. }
  267.  
  268.     malloc_type
  269. fremember(ptr)
  270.     malloc_type ptr;
  271. /* Remember PTR in 'alloced' so that it can be freed later.  Yield PTR.  */
  272. {
  273.     register struct alloclist *q = talloc(struct alloclist);
  274.     q->nextalloc = alloced;
  275.     alloced = q;
  276.     return q->alloc = ptr;
  277. }
  278.  
  279.     malloc_type
  280. ftestalloc(size)
  281.     size_t size;
  282. /* Allocate a block, putting it in 'alloced' so it can be freed later. */
  283. {
  284.     return fremember(testalloc(size));
  285. }
  286.  
  287.     void
  288. ffree()
  289. /* Free all blocks allocated with ftestalloc().  */
  290. {
  291.     register struct alloclist *p, *q;
  292.     for (p = alloced;  p;  p = q) {
  293.         q = p->nextalloc;
  294.         tfree(p->alloc);
  295.         tfree(p);
  296.     }
  297.     alloced = 0;
  298. }
  299.  
  300.     void
  301. ffree1(f)
  302.     register char const *f;
  303. /* Free the block f, which was allocated by ftestalloc.  */
  304. {
  305.     register struct alloclist *p, **a = &alloced;
  306.  
  307.     while ((p = *a)->alloc  !=  f)
  308.         a = &p->nextalloc;
  309.     *a = p->nextalloc;
  310.     tfree(p->alloc);
  311.     tfree(p);
  312. }
  313.  
  314.     char *
  315. str_save(s)
  316.     char const *s;
  317. /* Save s in permanently allocated storage. */
  318. {
  319.     return strcpy(tnalloc(char, strlen(s)+1), s);
  320. }
  321.  
  322.     char *
  323. fstr_save(s)
  324.     char const *s;
  325. /* Save s in storage that will be deallocated when we're done with this file. */
  326. {
  327.     return strcpy(ftnalloc(char, strlen(s)+1), s);
  328. }
  329.  
  330.     char *
  331. cgetenv(name)
  332.     char const *name;
  333. /* Like getenv(), but yield a copy; getenv() can overwrite old results. */
  334. {
  335.     register char *p;
  336.  
  337.     return (p=getenv(name)) ? str_save(p) : p;
  338. }
  339.  
  340.     char const *
  341. getusername(suspicious)
  342.     int suspicious;
  343. /* Get the caller's login name.  Trust only getwpuid if SUSPICIOUS.  */
  344. {
  345.     static char *name;
  346.  
  347.     if (!name) {
  348.         if (
  349.             /* Prefer getenv() unless suspicious; it's much faster.  */
  350. #            if getlogin_is_secure
  351.                 (suspicious
  352.                 || (
  353.                     !(name = cgetenv("LOGNAME"))
  354.                 &&  !(name = cgetenv("USER"))
  355.                 ))
  356.             &&  !(name = getlogin())
  357. #            else
  358.             suspicious
  359.             || (
  360.                 !(name = cgetenv("LOGNAME"))
  361.                 &&  !(name = cgetenv("USER"))
  362.                 &&  !(name = getlogin())
  363.             )
  364. #            endif
  365.         ) {
  366. #if has_getuid && has_getpwuid
  367.             struct passwd const *pw = getpwuid(ruid());
  368.             if (!pw)
  369.                 faterror("no password entry for userid %lu",
  370.                      (unsigned long)ruid()
  371.                 );
  372.             name = pw->pw_name;
  373. #else
  374. #if has_setuid
  375.             faterror("setuid not supported");
  376. #else
  377.             faterror("Who are you?  Please setenv LOGNAME.");
  378. #endif
  379. #endif
  380.         }
  381.         checksid(name);
  382.     }
  383.     return name;
  384. }
  385.  
  386.  
  387.  
  388.  
  389. #if has_signal
  390.  
  391. /*
  392.  *     Signal handling
  393.  *
  394.  * Standard C places too many restrictions on signal handlers.
  395.  * We obey as many of them as we can.
  396.  * Posix places fewer restrictions, and we are Posix-compatible here.
  397.  */
  398.  
  399. static sig_atomic_t volatile heldsignal, holdlevel;
  400. #ifdef SA_SIGINFO
  401.     static int unsupported_SA_SIGINFO;
  402.     static siginfo_t bufsiginfo;
  403.     static siginfo_t *volatile heldsiginfo;
  404. #endif
  405.  
  406.  
  407. #if has_NFS && has_mmap && large_memory && mmap_signal
  408.     static char const *accessName;
  409.  
  410.       void
  411.     readAccessFilenameBuffer(filename, p)
  412.     char const *filename;
  413.     unsigned char const *p;
  414.     {
  415.     unsigned char volatile t;
  416.     accessName = filename;
  417.     t = *p;
  418.     accessName = 0;
  419.     }
  420. #else
  421. #   define accessName ((char const *) 0)
  422. #endif
  423.  
  424.  
  425. #if !has_psignal
  426.  
  427. # define psignal my_psignal
  428.     static void my_psignal P((int,char const*));
  429.     static void
  430. my_psignal(sig, s)
  431.     int sig;
  432.     char const *s;
  433. {
  434.     char const *sname = "Unknown signal";
  435. #    if has_sys_siglist && defined(NSIG)
  436.         if ((unsigned)sig < NSIG)
  437.         sname = sys_siglist[sig];
  438. #    else
  439.         switch (sig) {
  440. #           ifdef SIGHUP
  441.         case SIGHUP:    sname = "Hangup";  break;
  442. #           endif
  443. #           ifdef SIGINT
  444.         case SIGINT:    sname = "Interrupt";  break;
  445. #           endif
  446. #           ifdef SIGPIPE
  447.         case SIGPIPE:    sname = "Broken pipe";  break;
  448. #           endif
  449. #           ifdef SIGQUIT
  450.         case SIGQUIT:    sname = "Quit";  break;
  451. #           endif
  452. #           ifdef SIGTERM
  453.         case SIGTERM:    sname = "Terminated";  break;
  454. #           endif
  455. #           ifdef SIGXCPU
  456.         case SIGXCPU:    sname = "Cputime limit exceeded";  break;
  457. #           endif
  458. #           ifdef SIGXFSZ
  459.         case SIGXFSZ:    sname = "Filesize limit exceeded";  break;
  460. #           endif
  461. #          if has_mmap && large_memory
  462. #           if defined(SIGBUS) && mmap_signal==SIGBUS
  463.         case SIGBUS:    sname = "Bus error";  break;
  464. #           endif
  465. #           if defined(SIGSEGV) && mmap_signal==SIGSEGV
  466.         case SIGSEGV:    sname = "Segmentation fault";  break;
  467. #           endif
  468. #          endif
  469.         }
  470. #    endif
  471.  
  472.     /* Avoid calling sprintf etc., in case they're not reentrant.  */
  473.     {
  474.         char const *p;
  475.         char buf[BUFSIZ], *b = buf;
  476.         for (p = s;  *p;  *b++ = *p++)
  477.         continue;
  478.         *b++ = ':';
  479.         *b++ = ' ';
  480.         for (p = sname;  *p;  *b++ = *p++)
  481.         continue;
  482.         *b++ = '\n';
  483.         VOID write(STDERR_FILENO, buf, b - buf);
  484.     }
  485. }
  486. #endif
  487.  
  488. static signal_type catchsig P((int));
  489. #ifdef SA_SIGINFO
  490.     static signal_type catchsigaction P((int,siginfo_t*,void*));
  491. #endif
  492.  
  493.     static signal_type
  494. catchsig(s)
  495.     int s;
  496. #ifdef SA_SIGINFO
  497. {
  498.     catchsigaction(s, (siginfo_t *)0, (void *)0);
  499. }
  500.     static signal_type
  501. catchsigaction(s, i, c)
  502.     int s;
  503.     siginfo_t *i;
  504.     void *c;
  505. #endif
  506. {
  507. #   if sig_zaps_handler
  508.     /* If a signal arrives before we reset the handler, we lose. */
  509.     VOID signal(s, SIG_IGN);
  510. #   endif
  511.  
  512. #   ifdef SA_SIGINFO
  513.     if (!unsupported_SA_SIGINFO)
  514.         i = 0;
  515. #   endif
  516.  
  517.     if (holdlevel) {
  518.     heldsignal = s;
  519. #    ifdef SA_SIGINFO
  520.         if (i) {
  521.         bufsiginfo = *i;
  522.         heldsiginfo = &bufsiginfo;
  523.         }
  524. #    endif
  525.     return;
  526.     }
  527.  
  528.     ignoreints();
  529.     setrid();
  530.     if (!quietflag) {
  531.     /* Avoid calling sprintf etc., in case they're not reentrant.  */
  532.     char const *p;
  533.     char buf[BUFSIZ], *b = buf;
  534.  
  535.     if ( !    (
  536. #        if has_mmap && large_memory && mmap_signal
  537.             /* Check whether this signal was planned.  */
  538.             s == mmap_signal && accessName
  539. #        else
  540.             0
  541. #        endif
  542.     )) {
  543.         char const *nRCS = "\nRCS";
  544. #        if defined(SA_SIGINFO) && has_si_errno && has_mmap && large_memory && mmap_signal
  545.         if (s == mmap_signal  &&  i  &&  i->si_errno) {
  546.             errno = i->si_errno;
  547.             perror(nRCS++);
  548.         }
  549. #        endif
  550. #        if defined(SA_SIGINFO) && has_psiginfo
  551.         if (i)
  552.             psiginfo(i, nRCS);
  553.         else
  554.             psignal(s, nRCS);
  555. #        else
  556.         psignal(s, nRCS);
  557. #        endif
  558.     }
  559.  
  560.     for (p = "RCS: ";  *p;  *b++ = *p++)
  561.         continue;
  562. #    if has_mmap && large_memory && mmap_signal
  563.         if (s == mmap_signal) {
  564.         p = accessName;
  565.         if (!p)
  566.             p = "Was a file changed by some other process?  ";
  567.         else {
  568.             char const *p1;
  569.             for (p1 = p;  *p1;  p1++)
  570.             continue;
  571.             VOID write(STDERR_FILENO, buf, b - buf);
  572.             VOID write(STDERR_FILENO, p, p1 - p);
  573.             b = buf;
  574.             p = ": Permission denied.  ";
  575.         }
  576.         while (*p)
  577.             *b++ = *p++;
  578.         }
  579. #    endif
  580.     for (p = "Cleaning up.\n";  *p;  *b++ = *p++)
  581.         continue;
  582.     VOID write(STDERR_FILENO, buf, b - buf);
  583.     }
  584.     exiterr();
  585. }
  586.  
  587.     void
  588. ignoreints()
  589. {
  590.     ++holdlevel;
  591. }
  592.  
  593.     void
  594. restoreints()
  595. {
  596.     if (!--holdlevel && heldsignal)
  597. #        ifdef SA_SIGINFO
  598.         VOID catchsigaction(heldsignal, heldsiginfo, (void *)0);
  599. #        else
  600.         VOID catchsig(heldsignal);
  601. #        endif
  602. }
  603.  
  604.  
  605. static void setup_catchsig P((int const*,int));
  606.  
  607. #if has_sigaction
  608.  
  609.     static void check_sig P((int));
  610.     static void
  611.   check_sig(r)
  612.     int r;
  613.   {
  614.     if (r != 0)
  615.         efaterror("signal handling");
  616.   }
  617.  
  618.     static void
  619.   setup_catchsig(sig, sigs)
  620.     int const *sig;
  621.     int sigs;
  622.   {
  623.     register int i, j;
  624.     struct sigaction act;
  625.  
  626.     for (i=sigs; 0<=--i; ) {
  627.         check_sig(sigaction(sig[i], (struct sigaction*)0, &act));
  628.         if (act.sa_handler != SIG_IGN) {
  629.         act.sa_handler = catchsig;
  630. #        ifdef SA_SIGINFO
  631.             if (!unsupported_SA_SIGINFO) {
  632. #            if has_sa_sigaction
  633.                 act.sa_sigaction = catchsigaction;
  634. #            else
  635.                 act.sa_handler = catchsigaction;
  636. #            endif
  637.             act.sa_flags |= SA_SIGINFO;
  638.             }
  639. #        endif
  640.         for (j=sigs; 0<=--j; )
  641.             check_sig(sigaddset(&act.sa_mask, sig[j]));
  642.         if (sigaction(sig[i], &act, (struct sigaction*)0) != 0) {
  643. #            if defined(SA_SIGINFO) && defined(ENOTSUP)
  644.             if (errno == ENOTSUP  &&  !unsupported_SA_SIGINFO) {
  645.                 /* Turn off use of SA_SIGINFO and try again.  */
  646.                 unsupported_SA_SIGINFO = 1;
  647.                 i++;
  648.                 continue;
  649.             }
  650. #            endif
  651.             check_sig(-1);
  652.         }
  653.         }
  654.     }
  655.   }
  656.  
  657. #else
  658. #if has_sigblock
  659.  
  660.     static void
  661.   setup_catchsig(sig, sigs)
  662.     int const *sig;
  663.     int sigs;
  664.   {
  665.     register int i;
  666.     int mask;
  667.  
  668.     mask = 0;
  669.     for (i=sigs; 0<=--i; )
  670.         mask |= sigmask(sig[i]);
  671.     mask = sigblock(mask);
  672.     for (i=sigs; 0<=--i; )
  673.         if (
  674.             signal(sig[i], catchsig) == SIG_IGN  &&
  675.             signal(sig[i], SIG_IGN) != catchsig
  676.         )
  677.             faterror("signal catcher failure");
  678.     VOID sigsetmask(mask);
  679.   }
  680.  
  681. #else
  682.  
  683.     static void
  684.   setup_catchsig(sig, sigs)
  685.     int const *sig;
  686.     int sigs;
  687.   {
  688.     register i;
  689.  
  690.     for (i=sigs; 0<=--i; )
  691.         if (
  692.             signal(sig[i], SIG_IGN) != SIG_IGN  &&
  693.             signal(sig[i], catchsig) != SIG_IGN
  694.         )
  695.             faterror("signal catcher failure");
  696.   }
  697.  
  698. #endif
  699. #endif
  700.  
  701.  
  702. static int const regsigs[] = {
  703. # ifdef SIGHUP
  704.     SIGHUP,
  705. # endif
  706. # ifdef SIGINT
  707.     SIGINT,
  708. # endif
  709. # ifdef SIGPIPE
  710.     SIGPIPE,
  711. # endif
  712. # ifdef SIGQUIT
  713.     SIGQUIT,
  714. # endif
  715. # ifdef SIGTERM
  716.     SIGTERM,
  717. # endif
  718. # ifdef SIGXCPU
  719.     SIGXCPU,
  720. # endif
  721. # ifdef SIGXFSZ
  722.     SIGXFSZ,
  723. # endif
  724. };
  725.  
  726.     void
  727. catchints()
  728. {
  729.     static int catching_ints;
  730.     if (!catching_ints) {
  731.         catching_ints = true;
  732.         setup_catchsig(regsigs, (int) (sizeof(regsigs)/sizeof(*regsigs)));
  733.     }
  734. }
  735.  
  736. #if has_mmap && large_memory && mmap_signal
  737.  
  738.     /*
  739.     * If you mmap an NFS file, and someone on another client removes the last
  740.     * link to that file, and you later reference an uncached part of that file,
  741.     * you'll get a SIGBUS or SIGSEGV (depending on the operating system).
  742.     * Catch the signal and report the problem to the user.
  743.     * Unfortunately, there's no portable way to differentiate between this
  744.     * problem and actual bugs in the program.
  745.     * This NFS problem is rare, thank goodness.
  746.     *
  747.     * This can also occur if someone truncates the file, even without NFS.
  748.     */
  749.  
  750.     static int const mmapsigs[] = { mmap_signal };
  751.  
  752.         void
  753.     catchmmapints()
  754.     {
  755.     static int catching_mmap_ints;
  756.     if (!catching_mmap_ints) {
  757.         catching_mmap_ints = true;
  758.         setup_catchsig(mmapsigs, (int)(sizeof(mmapsigs)/sizeof(*mmapsigs)));
  759.     }
  760.     }
  761. #endif
  762.  
  763. #endif /* has_signal */
  764.  
  765.  
  766.     void
  767. fastcopy(inf,outf)
  768.     register RILE *inf;
  769.     FILE *outf;
  770. /* Function: copies the remainder of file inf to outf.
  771.  */
  772. {
  773. #if large_memory
  774. #    if maps_memory
  775.         awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf);
  776.         inf->ptr = inf->lim;
  777. #    else
  778.         for (;;) {
  779.         awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf);
  780.         inf->ptr = inf->readlim;
  781.         if (inf->ptr == inf->lim)
  782.             break;
  783.         VOID Igetmore(inf);
  784.         }
  785. #    endif
  786. #else
  787.     char buf[BUFSIZ*8];
  788.     register fread_type rcount;
  789.  
  790.         /*now read the rest of the file in blocks*/
  791.     while (!feof(inf)) {
  792.         if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) {
  793.             testIerror(inf);
  794.             return;
  795.         }
  796.         awrite(buf, (size_t)rcount, outf);
  797.         }
  798. #endif
  799. }
  800.  
  801. #ifndef SSIZE_MAX
  802.  /* This does not work in #ifs, but it's good enough for us.  */
  803.  /* Underestimating SSIZE_MAX may slow us down, but it won't break us.  */
  804. #    define SSIZE_MAX ((unsigned)-1 >> 1)
  805. #endif
  806.  
  807.     void
  808. awrite(buf, chars, f)
  809.     char const *buf;
  810.     size_t chars;
  811.     FILE *f;
  812. {
  813.     /* Posix 1003.1-1990 ssize_t hack */
  814.     while (SSIZE_MAX < chars) {
  815.         if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f)  !=  SSIZE_MAX)
  816.             Oerror();
  817.         buf += SSIZE_MAX;
  818.         chars -= SSIZE_MAX;
  819.     }
  820.  
  821.     if (Fwrite(buf, sizeof(*buf), chars, f)  !=  chars)
  822.         Oerror();
  823. }
  824.  
  825. /* dup a file descriptor; the result must not be stdin, stdout, or stderr.  */
  826.     static int dupSafer P((int));
  827.     static int
  828. dupSafer(fd)
  829.     int fd;
  830. {
  831. #    ifdef F_DUPFD
  832.         return fcntl(fd, F_DUPFD, STDERR_FILENO + 1);
  833. #    else
  834.         int e, f, i, used = 0;
  835.         while (STDIN_FILENO <= (f = dup(fd))  &&  f <= STDERR_FILENO)
  836.             used |= 1<<f;
  837.         e = errno;
  838.         for (i = STDIN_FILENO;  i <= STDERR_FILENO;  i++)
  839.             if (used & (1<<i))
  840.                 VOID close(i);
  841.         errno = e;
  842.         return f;
  843. #    endif
  844. }
  845.  
  846. /* Renumber a file descriptor so that it's not stdin, stdout, or stderr.  */
  847.     int
  848. fdSafer(fd)
  849.     int fd;
  850. {
  851.     if (STDIN_FILENO <= fd  &&  fd <= STDERR_FILENO) {
  852.         int f = dupSafer(fd);
  853.         int e = errno;
  854.         VOID close(fd);
  855.         errno = e;
  856.         fd = f;
  857.     }
  858.     return fd;
  859. }
  860.  
  861. /* Like fopen, except the result is never stdin, stdout, or stderr.  */
  862.     FILE *
  863. fopenSafer(filename, type)
  864.     char const *filename;
  865.     char const *type;
  866. {
  867.     FILE *stream = fopen(filename, type);
  868.     if (stream) {
  869.         int fd = fileno(stream);
  870.         if (STDIN_FILENO <= fd  &&  fd <= STDERR_FILENO) {
  871.             int f = dupSafer(fd);
  872.             if (f < 0) {
  873.                 int e = errno;
  874.                 VOID fclose(stream);
  875.                 errno = e;
  876.                 return 0;
  877.             }
  878.             if (fclose(stream) != 0) {
  879.                 int e = errno;
  880.                 VOID close(f);
  881.                 errno = e;
  882.                 return 0;
  883.             }
  884.             stream = fdopen(f, type);
  885.         }
  886.     }
  887.     return stream;
  888. }
  889.  
  890.  
  891. #ifdef F_DUPFD
  892. #    undef dup
  893. #    define dup(fd) fcntl(fd, F_DUPFD, 0)
  894. #endif
  895.  
  896.  
  897. #if has_fork || has_spawn
  898.  
  899.     static int movefd P((int,int));
  900.     static int
  901. movefd(old, new)
  902.     int old, new;
  903. {
  904.     if (old < 0  ||  old == new)
  905.         return old;
  906. #    ifdef F_DUPFD
  907.         new = fcntl(old, F_DUPFD, new);
  908. #    else
  909.         new = dup2(old, new);
  910. #    endif
  911.     return close(old)==0 ? new : -1;
  912. }
  913.  
  914.     static int fdreopen P((int,char const*,int));
  915.     static int
  916. fdreopen(fd, file, flags)
  917.     int fd;
  918.     char const *file;
  919.     int flags;
  920. {
  921.     int newfd;
  922.     VOID close(fd);
  923.     newfd =
  924. #if !open_can_creat
  925.         flags&O_CREAT ? creat(file, S_IRUSR|S_IWUSR) :
  926. #endif
  927.         open(file, flags, S_IRUSR|S_IWUSR);
  928.     return movefd(newfd, fd);
  929. }
  930.  
  931. #if has_spawn
  932.     static void redirect P((int,int));
  933.     static void
  934. redirect(old, new)
  935.     int old, new;
  936. /*
  937. * Move file descriptor OLD to NEW.
  938. * If OLD is -1, do nothing.
  939. * If OLD is -2, just close NEW.
  940. */
  941. {
  942.     if ((old != -1 && close(new) != 0) || (0 <= old && movefd(old,new) < 0))
  943.         efaterror("spawn I/O redirection");
  944. }
  945. #endif
  946.  
  947.  
  948. #else /* !has_fork && !has_spawn */
  949.  
  950.     static void bufargcat P((struct buf*,int,char const*));
  951.     static void
  952. bufargcat(b, c, s)
  953.     register struct buf *b;
  954.     int c;
  955.     register char const *s;
  956. /* Append to B a copy of C, plus a quoted copy of S.  */
  957. {
  958.     register char *p;
  959.     register char const *t;
  960.     size_t bl, sl;
  961.  
  962.     for (t=s, sl=0;  *t;  )
  963.         sl  +=  3*(*t++=='\'') + 1;
  964.     bl = strlen(b->string);
  965.     bufrealloc(b, bl + sl + 4);
  966.     p = b->string + bl;
  967.     *p++ = c;
  968.     *p++ = '\'';
  969.     while (*s) {
  970.         if (*s == '\'') {
  971.             *p++ = '\'';
  972.             *p++ = '\\';
  973.             *p++ = '\'';
  974.         }
  975.         *p++ = *s++;
  976.     }
  977.     *p++ = '\'';
  978.     *p = 0;
  979. }
  980.  
  981. #endif
  982.  
  983. #if !has_spawn && has_fork
  984. /*
  985. * Output the string S to stderr, without touching any I/O buffers.
  986. * This is useful if you are a child process, whose buffers are usually wrong.
  987. * Exit immediately if the write does not completely succeed.
  988. */
  989. static void write_stderr P((char const *));
  990.     static void
  991. write_stderr(s)
  992.     char const *s;
  993. {
  994.     size_t slen = strlen(s);
  995.     if (write(STDERR_FILENO, s, slen) != slen)
  996.         _exit(EXIT_TROUBLE);
  997. }
  998. #endif
  999.  
  1000. /*
  1001. * Run a command.
  1002. * infd, if not -1, is the input file descriptor.
  1003. * outname, if nonzero, is the name of the output file.
  1004. * args[1..] form the command to be run; args[0] might be modified.
  1005. */
  1006.     int
  1007. runv(infd, outname, args)
  1008.     int infd;
  1009.     char const *outname, **args;
  1010. {
  1011.     int wstatus;
  1012.  
  1013. #if bad_wait_if_SIGCHLD_ignored
  1014.     static int fixed_SIGCHLD;
  1015.     if (!fixed_SIGCHLD) {
  1016.         fixed_SIGCHLD = true;
  1017. #        ifndef SIGCHLD
  1018. #        define SIGCHLD SIGCLD
  1019. #        endif
  1020.         VOID signal(SIGCHLD, SIG_DFL);
  1021.     }
  1022. #endif
  1023.  
  1024.     oflush();
  1025.     eflush();
  1026.     {
  1027. #if has_spawn
  1028.     int in, out;
  1029.     char const *file;
  1030.  
  1031.     in = -1;
  1032.     if (infd != -1  &&  infd != STDIN_FILENO) {
  1033.         if ((in = dup(STDIN_FILENO)) < 0) {
  1034.         if (errno != EBADF)
  1035.             efaterror("spawn input setup");
  1036.         in = -2;
  1037.         } else {
  1038. #        ifdef F_DUPFD
  1039.             if (close(STDIN_FILENO) != 0)
  1040.             efaterror("spawn input close");
  1041. #        endif
  1042.         }
  1043.         if (
  1044. #        ifdef F_DUPFD
  1045.             fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO
  1046. #        else
  1047.             dup2(infd, STDIN_FILENO) != STDIN_FILENO
  1048. #        endif
  1049.         )
  1050.         efaterror("spawn input redirection");
  1051.     }
  1052.  
  1053.     out = -1;
  1054.     if (outname) {
  1055.         if ((out = dup(STDOUT_FILENO)) < 0) {
  1056.         if (errno != EBADF)
  1057.             efaterror("spawn output setup");
  1058.         out = -2;
  1059.         }
  1060.         if (fdreopen(
  1061.         STDOUT_FILENO, outname,
  1062.         O_CREAT | O_TRUNC | O_WRONLY
  1063.         ) < 0)
  1064.         efaterror(outname);
  1065.     }
  1066.  
  1067.     wstatus = spawn_RCS(0, args[1], (char**)(args + 1));
  1068. #    ifdef RCS_SHELL
  1069.         if (wstatus == -1  &&  errno == ENOEXEC) {
  1070.         args[0] = RCS_SHELL;
  1071.         wstatus = spawnv(0, args[0], (char**)args);
  1072.         }
  1073. #    endif
  1074.     redirect(in, STDIN_FILENO);
  1075.     redirect(out, STDOUT_FILENO);
  1076. #else
  1077. #if has_fork
  1078.     pid_t pid;
  1079.     if (!(pid = vfork())) {
  1080.         char const *notfound;
  1081.         if (infd != -1  &&  infd != STDIN_FILENO  &&  (
  1082. #            ifdef F_DUPFD
  1083.             (VOID close(STDIN_FILENO),
  1084.             fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO)
  1085. #            else
  1086.             dup2(infd, STDIN_FILENO) != STDIN_FILENO
  1087. #            endif
  1088.         )) {
  1089.             /* Avoid perror since it may misuse buffers.  */
  1090.             write_stderr(args[1]);
  1091.             write_stderr(": I/O redirection failed\n");
  1092.             _exit(EXIT_TROUBLE);
  1093.         }
  1094.  
  1095.         if (outname)
  1096.             if (fdreopen(
  1097.             STDOUT_FILENO, outname,
  1098.             O_CREAT | O_TRUNC | O_WRONLY
  1099.             ) < 0) {
  1100.             /* Avoid perror since it may misuse buffers.  */
  1101.             write_stderr(args[1]);
  1102.             write_stderr(": ");
  1103.             write_stderr(outname);
  1104.             write_stderr(": cannot create\n");
  1105.             _exit(EXIT_TROUBLE);
  1106.             }
  1107.         VOID exec_RCS(args[1], (char**)(args + 1));
  1108.         notfound = args[1];
  1109. #        ifdef RCS_SHELL
  1110.             if (errno == ENOEXEC) {
  1111.             args[0] = notfound = RCS_SHELL;
  1112.             VOID execv(args[0], (char**)args);
  1113.             }
  1114. #        endif
  1115.  
  1116.         /* Avoid perror since it may misuse buffers.  */
  1117.         write_stderr(notfound);
  1118.         write_stderr(": not found\n");
  1119.         _exit(EXIT_TROUBLE);
  1120.     }
  1121.     if (pid < 0)
  1122.         efaterror("fork");
  1123. #    if has_waitpid
  1124.         if (waitpid(pid, &wstatus, 0) < 0)
  1125.             efaterror("waitpid");
  1126. #    else
  1127.         {
  1128.             pid_t w;
  1129.             do {
  1130.                 if ((w = wait(&wstatus)) < 0)
  1131.                     efaterror("wait");
  1132.             } while (w != pid);
  1133.         }
  1134. #    endif
  1135. #else
  1136.     static struct buf b;
  1137.     char const *p;
  1138.  
  1139.     /* Use system().  On many hosts system() discards signals.  Yuck!  */
  1140.     p = args + 1;
  1141.     bufscpy(&b, *p);
  1142.     while (*++p)
  1143.         bufargcat(&b, ' ', *p);
  1144.     if (infd != -1  &&  infd != STDIN_FILENO) {
  1145.         char redirection[32];
  1146.         VOID sprintf(redirection, "<&%d", infd);
  1147.         bufscat(&b, redirection);
  1148.     }
  1149.     if (outname)
  1150.         bufargcat(&b, '>', outname);
  1151.     wstatus = system(b.string);
  1152. #endif
  1153. #endif
  1154.     }
  1155.     if (!WIFEXITED(wstatus)) {
  1156.         if (WIFSIGNALED(wstatus)) {
  1157.             psignal(WTERMSIG(wstatus), args[1]);
  1158.             fatcleanup(1);
  1159.         }
  1160.         faterror("%s failed for unknown reason", args[1]);
  1161.     }
  1162.     return WEXITSTATUS(wstatus);
  1163. }
  1164.  
  1165. #define CARGSMAX 20
  1166. /*
  1167. * Run a command.
  1168. * infd, if not -1, is the input file descriptor.
  1169. * outname, if nonzero, is the name of the output file.
  1170. * The remaining arguments specify the command and its arguments.
  1171. */
  1172.     int
  1173. #if has_prototypes
  1174. run(int infd, char const *outname, ...)
  1175. #else
  1176.     /*VARARGS2*/
  1177. run(infd, outname, va_alist)
  1178.     int infd;
  1179.     char const *outname;
  1180.     va_dcl
  1181. #endif
  1182. {
  1183.     va_list ap;
  1184.     char const *rgargs[CARGSMAX];
  1185.     register int i;
  1186.     vararg_start(ap, outname);
  1187.     for (i = 1;  (rgargs[i++] = va_arg(ap, char const*));  )
  1188.         if (CARGSMAX <= i)
  1189.             faterror("too many command arguments");
  1190.     va_end(ap);
  1191.     return runv(infd, outname, rgargs);
  1192. }
  1193.  
  1194.  
  1195. int RCSversion;
  1196.  
  1197.     void
  1198. setRCSversion(str)
  1199.     char const *str;
  1200. {
  1201.     static int oldversion;
  1202.  
  1203.     register char const *s = str + 2;
  1204.  
  1205.     if (*s) {
  1206.         int v = VERSION_DEFAULT;
  1207.  
  1208.         if (oldversion)
  1209.             redefined('V');
  1210.         oldversion = true;
  1211.         v = 0;
  1212.         while (isdigit(*s))
  1213.             v  =  10*v + *s++ - '0';
  1214.         if (*s)
  1215.             error("%s isn't a number", str);
  1216.         else if (v < VERSION_min  ||  VERSION_max < v)
  1217.             error("%s out of range %d..%d",
  1218.                 str, VERSION_min, VERSION_max
  1219.             );
  1220.  
  1221.         RCSversion = VERSION(v);
  1222.     } else {
  1223.         printf("RCS version %s\n", RCS_version_string);
  1224.         exit(0);
  1225.     }
  1226. }
  1227.  
  1228.     int
  1229. getRCSINIT(argc, argv, newargv)
  1230.     int argc;
  1231.     char **argv, ***newargv;
  1232. {
  1233.     register char *p, *q, **pp;
  1234.     size_t n;
  1235.  
  1236.     if (!(q = cgetenv("RCSINIT")))
  1237.         *newargv = argv;
  1238.     else {
  1239.         n = argc + 2;
  1240.         /*
  1241.          * Count spaces in RCSINIT to allocate a new arg vector.
  1242.          * This is an upper bound, but it's OK even if too large.
  1243.          */
  1244.         for (p = q;  ;  ) {
  1245.             switch (*p++) {
  1246.                 default:
  1247.                 continue;
  1248.  
  1249.                 case ' ':
  1250.                 case '\b': case '\f': case '\n':
  1251.                 case '\r': case '\t': case '\v':
  1252.                 n++;
  1253.                 continue;
  1254.  
  1255.                 case '\0':
  1256.                 break;
  1257.             }
  1258.             break;
  1259.         }
  1260.         *newargv = pp = tnalloc(char*, n);
  1261.         *pp++ = *argv++; /* copy program name */
  1262.         for (p = q;  ;  ) {
  1263.             for (;;) {
  1264.                 switch (*q) {
  1265.                     case '\0':
  1266.                     goto copyrest;
  1267.  
  1268.                     case ' ':
  1269.                     case '\b': case '\f': case '\n':
  1270.                     case '\r': case '\t': case '\v':
  1271.                     q++;
  1272.                     continue;
  1273.                 }
  1274.                 break;
  1275.             }
  1276.             *pp++ = p;
  1277.             ++argc;
  1278.             for (;;) {
  1279.                 switch ((*p++ = *q++)) {
  1280.                     case '\0':
  1281.                     goto copyrest;
  1282.  
  1283.                     case '\\':
  1284.                     if (!*q)
  1285.                         goto copyrest;
  1286.                     p[-1] = *q++;
  1287.                     continue;
  1288.  
  1289.                     default:
  1290.                     continue;
  1291.  
  1292.                     case ' ':
  1293.                     case '\b': case '\f': case '\n':
  1294.                     case '\r': case '\t': case '\v':
  1295.                     break;
  1296.                 }
  1297.                 break;
  1298.             }
  1299.             p[-1] = '\0';
  1300.         }
  1301.         copyrest:
  1302.         while ((*pp++ = *argv++))
  1303.             continue;
  1304.     }
  1305.     return argc;
  1306. }
  1307.  
  1308.  
  1309. #define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i
  1310.  
  1311. #if has_getuid
  1312.     uid_t ruid() { cacheid(getuid()); }
  1313. #endif
  1314. #if has_setuid
  1315.     uid_t euid() { cacheid(geteuid()); }
  1316. #endif
  1317.  
  1318.  
  1319. #if has_setuid
  1320.  
  1321. /*
  1322.  * Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(),
  1323.  * because it lets us switch back and forth between arbitrary users.
  1324.  * If seteuid() doesn't work, we fall back on setuid(),
  1325.  * which works if saved setuid is supported,
  1326.  * unless the real or effective user is root.
  1327.  * This area is such a mess that we always check switches at runtime.
  1328.  */
  1329.  
  1330.     static void
  1331. #if has_prototypes
  1332. set_uid_to(uid_t u)
  1333. #else
  1334.  set_uid_to(u) uid_t u;
  1335. #endif
  1336. /* Become user u.  */
  1337. {
  1338.     static int looping;
  1339.  
  1340.     if (euid() == ruid())
  1341.         return;
  1342. #if (has_fork||has_spawn) && DIFF_ABSOLUTE
  1343. #    if has_setreuid
  1344.         if (setreuid(u==euid() ? ruid() : euid(), u) != 0)
  1345.             efaterror("setuid");
  1346. #    else
  1347.         if (seteuid(u) != 0)
  1348.             efaterror("setuid");
  1349. #    endif
  1350. #endif
  1351.     if (geteuid() != u) {
  1352.         if (looping)
  1353.             return;
  1354.         looping = true;
  1355.         faterror("root setuid not supported" + (u?5:0));
  1356.     }
  1357. }
  1358.  
  1359. static int stick_with_euid;
  1360.  
  1361.     void
  1362. /* Ignore all calls to seteid() and setrid().  */
  1363. nosetid()
  1364. {
  1365.     stick_with_euid = true;
  1366. }
  1367.  
  1368.     void
  1369. seteid()
  1370. /* Become effective user.  */
  1371. {
  1372.     if (!stick_with_euid)
  1373.         set_uid_to(euid());
  1374. }
  1375.  
  1376.     void
  1377. setrid()
  1378. /* Become real user.  */
  1379. {
  1380.     if (!stick_with_euid)
  1381.         set_uid_to(ruid());
  1382. }
  1383. #endif
  1384.  
  1385.     time_t
  1386. now()
  1387. {
  1388.     static time_t t;
  1389.     if (!t  &&  time(&t) == -1)
  1390.         efaterror("time");
  1391.     return t;
  1392. }
  1393.