home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs567s.zip / rcs / src / rcsutil.c < prev    next >
C/C++ Source or Header  |  1994-03-20  |  26KB  |  1,220 lines

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