home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / ntcode / gr564s / src / rcsutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  23.0 KB  |  1,111 lines

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