home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / RCS_SRC.ZIP / RCSUTIL.C < prev    next >
C/C++ Source or Header  |  1991-01-15  |  14KB  |  498 lines

  1. /*
  2.  *                     RCS utilities
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcsutil.c,v 4.6 89/05/01 15:13:40 narten Exp $ Purdue CS";
  6. #endif
  7.  
  8. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  9.    Distributed under license by the Free Software Foundation, Inc.
  10.  
  11. This file is part of RCS.
  12.  
  13. RCS is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Public License as published by
  15. the Free Software Foundation; either version 1, or (at your option)
  16. any later version.
  17.  
  18. RCS is distributed in the hope that it will be useful,
  19. but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. GNU General Public License for more details.
  22.  
  23. You should have received a copy of the GNU General Public License
  24. along with RCS; see the file COPYING.  If not, write to
  25. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  
  27. Report problems and direct all questions to:
  28.  
  29.     rcs-bugs@cs.purdue.edu
  30.  
  31. */
  32.  
  33.  
  34.  
  35.  
  36. /* $Log:    rcsutil.c,v $
  37.  * Revision 4.6  89/05/01  15:13:40  narten
  38.  * changed copyright header to reflect current distribution rules
  39.  * 
  40.  * Revision 4.5  88/11/08  16:01:02  narten
  41.  * corrected use of varargs routines
  42.  * 
  43.  * Revision 4.4  88/11/08  12:00:28  narten
  44.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  45.  * 
  46.  * Revision 4.4  88/08/09  19:13:24  eggert
  47.  * Check for memory exhaustion.
  48.  * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
  49.  * Use execv(), not system(); yield exit status like diff(1)'s.
  50.  * 
  51.  * Revision 4.3  87/10/18  10:40:22  narten
  52.  * Updating version numbers. Changes relative to 1.1 actually
  53.  * relative to 4.1
  54.  * 
  55.  * Revision 1.3  87/09/24  14:01:01  narten
  56.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  57.  * warnings)
  58.  * 
  59.  * Revision 1.2  87/03/27  14:22:43  jenkins
  60.  * Port to suns
  61.  * 
  62.  * Revision 1.1  84/01/23  14:50:43  kcs
  63.  * Initial revision
  64.  * 
  65.  * Revision 4.1  83/05/10  15:53:13  wft
  66.  * Added getcaller() and findlock().
  67.  * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
  68.  * (needed for background jobs in older shells). Added restoreints().
  69.  * Removed printing of full RCS path from logcommand().
  70.  * 
  71.  * Revision 3.8  83/02/15  15:41:49  wft
  72.  * Added routine fastcopy() to copy remainder of a file in blocks.
  73.  *
  74.  * Revision 3.7  82/12/24  15:25:19  wft
  75.  * added catchints(), ignoreints() for catching and ingnoring interrupts;
  76.  * fixed catchsig().
  77.  *
  78.  * Revision 3.6  82/12/08  21:52:05  wft
  79.  * Using DATEFORM to format dates.
  80.  *
  81.  * Revision 3.5  82/12/04  18:20:49  wft
  82.  * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
  83.  * lockedby-field.
  84.  *
  85.  * Revision 3.4  82/12/03  17:17:43  wft
  86.  * Added check to addlock() ensuring only one lock per person.
  87.  * Addlock also returns a pointer to the lock created. Deleted fancydate().
  88.  *
  89.  * Revision 3.3  82/11/27  12:24:37  wft
  90.  * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
  91.  * Introduced macro SNOOP so that snoop can be placed in directory other than
  92.  * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
  93.  *
  94.  * Revision 3.2  82/10/18  21:15:11  wft
  95.  * added function getfullRCSname().
  96.  *
  97.  * Revision 3.1  82/10/13  16:17:37  wft
  98.  * Cleanup message is now suppressed in quiet mode.
  99.  */
  100.  
  101.  
  102.  
  103.  
  104. #include <sys/types.h>
  105. #include <sys/stat.h>
  106. #include <signal.h>
  107. #include "rcsbase.h"
  108. #include <pwd.h>
  109. #include <varargs.h>
  110.  
  111. #if defined(USG) || defined(V4_2BSD)
  112. #include <fcntl.h>
  113. #endif
  114.  
  115. #ifndef V4_2BSD
  116. #define vfork fork
  117. #endif
  118.  
  119. extern char * bindex();
  120. extern FILE * finptr;
  121. extern char * RCSfilename;
  122. extern char * getlogin();
  123. extern struct passwd *getpwuid();
  124. extern char * malloc();
  125.  
  126.  
  127. char * talloc(size)
  128. unsigned size;
  129. {
  130.     char * p;
  131.     if (!(p = malloc(size))) {
  132.         faterror("out of memory");
  133.     }
  134.     return p;
  135. }
  136.  
  137.  
  138.  
  139. char * getcaller()
  140. /* Function: gets the callers login from his uid.
  141.  * If the uid is root, tries to get the true login with getlogin().
  142.  */
  143. {       char * name;
  144.     int uid;
  145.     uid=getuid();
  146.     if (uid==0) {
  147.         /* super user; try getlogin() to distinguish */
  148.         name = getlogin();
  149.         if (name!=nil && *name!='\0')
  150.             return name;
  151.     }
  152.     return(getpwuid(uid)->pw_name);
  153. }
  154.  
  155.  
  156.  
  157. struct hshentry * findlock(who,delete)
  158. char * who; int delete;
  159. /* Finds the first lock held by who and returns a pointer
  160.  * to the locked delta; also removes the lock if delete==true.
  161.  * Returns nil if there is no lock held by who.
  162.  */
  163. {
  164.         register struct lock * next, * trail;
  165.         struct lock dummy;
  166.  
  167.         dummy.nextlock=next=Locks;
  168.         trail = &dummy;
  169.         while (next!=nil) {
  170.                 if(strcmp(who,next->login)==0) break; /*found a lock*/
  171.                 trail=next;
  172.                 next=next->nextlock;
  173.         }
  174.         if (next!=nil) {
  175.         /* found one */
  176.         if (delete) {
  177.             /* delete it */
  178.             trail->nextlock=next->nextlock;
  179.             Locks=dummy.nextlock;
  180.             next->delta->lockedby=nil; /* reset locked-by */
  181.         }
  182.                 return next->delta;
  183.         } else  return nil;
  184. }
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192. struct lock * addlock(delta,who)
  193. struct hshentry * delta; char * who;
  194. /* Given a delta, addlock checks whether
  195.  * the delta is locked by somebody other than who.
  196.  * If so, an error message is printed, and false returned.
  197.  * If the delta is not reserved at all, a lock for it is added,
  198.  * and a pointer for the lock returned.
  199.  */
  200. {
  201.         struct lock * next;
  202.  
  203.         next=Locks;
  204.         while (next!=nil) {
  205.                 if (cmpnum(delta->num,next->delta->num)==0) {
  206.                         if (strcmp(who,next->login)==0)
  207.                                 return next;
  208.                                 /* lock exists already */
  209.                         else {
  210.                                 error("revision %s already locked by %s",
  211.                                       delta->num, next->login);
  212.                                 return false;
  213.                         }
  214.                 } else {
  215.                         if (strcmp(who,next->login)==0) {
  216.                                 error("you already locked %s; only one lock allowed per person.",
  217.                                        next->delta->num);
  218.                                 return false;
  219.                         } else {
  220.                                 next=next->nextlock;
  221.                         }
  222.                 }
  223.         }
  224.         /* not found; set up new lockblock */
  225.         next= (struct lock *) talloc(sizeof (struct lock));
  226.         delta->lockedby=next->login=who;
  227.         next->delta= delta;
  228.         next->nextlock=Locks;
  229.         Locks=next;
  230.         return next;
  231. }
  232.  
  233.  
  234.  
  235. int addsymbol(delta,name,rebind)
  236. struct hshentry * delta; char * name; int rebind;
  237. /* Function: adds a new symbolic name and associates it with node delta.
  238.  * If name already exists and rebind is true, the name is associated
  239.  * with the new delta; otherwise, an error message is printed and
  240.  * false returned. Returns true it successful.
  241.  */
  242. {       register struct assoc * next;
  243.         next=Symbols;
  244.         while (next!=nil) {
  245.                 if (strcmp(name,next->symbol)==0) {
  246.                         if (rebind) {
  247.                                 next->delta=delta;
  248.                                 return true;
  249.                         } else {
  250.                                 error("symbolic name %s already bound to %s",
  251.                                         name,next->delta->num);
  252.                                 return false;
  253.                         }
  254.                 } else  next = next->nextassoc;
  255.         }
  256.         /* not found; insert new pair. */
  257.         next = (struct assoc *) talloc(sizeof(struct assoc));
  258.         next->symbol=name;
  259.         next->delta=delta;
  260.         next->nextassoc=Symbols;
  261.         Symbols = next;
  262.         return true;
  263. }
  264.  
  265.  
  266.  
  267.  
  268. int checkaccesslist(who)
  269. char * who;
  270. /* function: Returns true if who is the superuser, the owner of the
  271.  * file, the access list is empty, or who is on the access list.
  272.  * Prints an error message and returns false otherwise.
  273.  */
  274. {
  275.         register struct access * next;
  276.         struct stat statbuf;
  277.  
  278.         if ((AccessList==nil) || (strcmp(who,"root")==0))
  279.                 return true;
  280.  
  281.         next=AccessList;
  282.         do {
  283.                 if (strcmp(who,next->login)==0)
  284.                         return true;
  285.                 next=next->nextaccess;
  286.         } while (next!=nil);
  287.  
  288.         VOID fstat(fileno(finptr),&statbuf);  /* get owner of file */
  289.         if (getuid() == statbuf.st_uid) return true;
  290.  
  291.         error("User %s not on the access list",who);
  292.         return false;
  293. }
  294.  
  295.  
  296. static SIGNAL_TYPE catchsig(s)
  297. {
  298.     ignoreints();
  299.         diagnose("\nRCS: cleaning up\n");
  300.         VOID cleanup();
  301.     exit(2);
  302. #ifdef lint
  303.     catchsig(s);
  304. #endif
  305. }
  306.  
  307. static sig[] = {SIGINT,SIGHUP,SIGQUIT,SIGPIPE,SIGTERM};
  308. #define SIGS (sizeof(sig)/sizeof(*sig))
  309. static SIGNAL_TYPE (*catcher[SIGS])();
  310.   
  311.   void catchints()
  312.   {
  313.     register i;
  314.     for (i=SIGS; 0<=--i; )
  315.         catcher[i]  =
  316.         signal(sig[i],SIG_IGN) == SIG_IGN  ?  SIG_IGN  :  catchsig;
  317.     restoreints();
  318.   }
  319.  
  320.   void ignoreints()
  321.   {
  322.     register i;
  323.     for (i=SIGS; 0<=--i; )
  324.         VOID signal(sig[i], SIG_IGN);
  325.   }
  326.  
  327. void restoreints()
  328. {
  329.     register i;
  330.     for (i=SIGS; 0<=--i; )
  331.         if (catcher[i] != SIG_IGN)
  332.             VOID signal(sig[i], catcher[i]);
  333. }
  334.  
  335. fastcopy(inf,outf)
  336. FILE * inf, * outf;
  337. /* Function: copies the remainder of file inf to outf. First copies the
  338.  * rest that is in the IO-buffer of inf character by character, and then
  339.  * copies the remainder in blocks.
  340.  */
  341. {       char buf[BUFSIZ];
  342.         register int rcount, wcount;
  343.  
  344.         /* write the rest of the buffer to outf */
  345.         while ((--inf->_cnt)>=0) {
  346.                 VOID putc(*inf->_ptr++&0377,outf);
  347.         }
  348.         if (fflush(outf) == EOF) {
  349.         writeerror();
  350.     }
  351.  
  352.         /*now read the rest of the file in blocks*/
  353.         while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) {
  354.                 wcount=write(fileno(outf),buf,rcount);
  355.                 if (wcount!=rcount) {
  356.                     writeerror();
  357.                 }
  358.         }
  359. }
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366. #ifdef SNOOPFILE
  367.  
  368. #include "time.h"
  369. extern struct tm* localtime();
  370. extern long time();
  371.  
  372. logcommand(commandname,delta, sequence,login)
  373. char* commandname; struct hshentry * delta, * sequence[];char * login;
  374. /* Function: start a process to write the file that
  375.  * logs the RCS command.
  376.  * Each line in the log file contains the following information:
  377.  * operation, revision(r), backward deltas applied(b), forward deltas applied(f),
  378.  * total deltas present(t), creation date of delta(d), date of operation(o),
  379.  * login of caller, RCS file name.
  380.  */
  381. {
  382.         char logline[200];
  383.         char curdate[datelength];
  384.     char *inoutargs[5];
  385.         register int i, backward, forward;
  386.         long clock;
  387.         struct tm * tm;
  388.  
  389.         clock=time((long *)0);
  390.         tm=localtime(&clock);
  391.  
  392.         VOID sprintf(curdate,DATEFORM,
  393.                 tm->tm_year, tm->tm_mon+1, tm->tm_mday,
  394.                 tm->tm_hour, tm->tm_min, tm->tm_sec);
  395.  
  396.         i= backward=forward=0;
  397.         while(sequence[i]!=nil) {  /* count deltas to be applied*/
  398.         if (countnumflds(sequence[i]->num) == 2)
  399.                 backward++;  /* reverse delta */
  400.         else    forward++;   /* branch delta  */
  401.         i++;
  402.         }
  403.     VOID sprintf(logline,"%s %10sr %3db %3df %3dt %sc %so %s %s",
  404.         commandname,delta->num,backward,forward,TotalDeltas,delta->date,
  405.         curdate,login,bindex(getfullRCSname(),'/'));
  406.     inoutargs[0] = nil;
  407.     inoutargs[1] = nil;
  408.     inoutargs[2] = SNOOP;
  409.     inoutargs[3] = logline;
  410.     inoutargs[4] = nil;
  411.     VOID run_back(inoutargs);
  412. }
  413. #endif
  414.  
  415.  
  416. static int fdreopen(fd, file, flags, mode)
  417.     char *file;
  418. {
  419.     int newfd;
  420.     VOID close(fd);
  421.     newfd = flags==-1 ? creat(file,mode) : open(file,flags,mode);
  422.     if (newfd < 0  ||  newfd == fd)
  423.         return newfd;
  424. #ifdef F_DUPFD
  425.     fd = fcntl(newfd, F_DUPFD, fd);
  426. #else
  427.     fd = dup2(newfd, fd);
  428. #endif
  429.     VOID close(newfd);
  430.     return fd;
  431. }
  432.  
  433. static void tryopen(fd,file,flags)
  434.     char *file;
  435. {
  436.     if (file  &&  fdreopen(fd,file,flags,0600) != fd) {
  437.         VOID write(fileno(stderr), file, strlen(file));
  438.         VOID write(fileno(stderr), ": cannot open\n", 14);
  439.         _exit(2);
  440.     }
  441. }
  442.  
  443. /*
  444. /* Run in the background a command specified by the strings in 'inoutargs'.
  445. /* inoutargs[0], if nonnil, is the name of the input file.
  446. /* inoutargs[1], if nonnil, is the name of the output file.
  447. /* inoutargs[2..] form the command to be run in the background.
  448. /*/
  449. static int run_back(inoutargs)
  450.     register char **inoutargs;
  451. {
  452.     int pid;
  453.     if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
  454.         return -1;
  455.     if (!(pid = vfork())) {
  456.         tryopen(fileno(stdin), inoutargs[0], 0);
  457.         tryopen(fileno(stdout), inoutargs[1], -1);
  458.         VOID execv(inoutargs[2], &inoutargs[2]);
  459.         inoutargs[1] = "/bin/sh";
  460.         VOID execv(inoutargs[1], &inoutargs[1]);
  461.         VOID write(fileno(stderr), "/bin/sh: not found\n", 19);
  462.         _exit(2);
  463.     }
  464.     return pid;
  465. }
  466.  
  467. #define CARGSMAX 20
  468. /*
  469. /* Run a command.
  470. /* The first two arguments are the input and output files (if nonnil);
  471. /* the rest specify the command and its arguments.
  472. /*/
  473. int run(va_alist)
  474.     va_dcl
  475. {
  476.     va_list ap;
  477.     int pid, wstatus, w;
  478.     char *rgargs[CARGSMAX];
  479.     register i = 0;
  480.     va_start(ap);
  481.     rgargs[0] = va_arg(ap, char *);
  482.     rgargs[1] = va_arg(ap, char *);
  483.     for (i =2; i< CARGSMAX; i++) {
  484.         rgargs[i] = va_arg(ap, char *);
  485.         if (rgargs[i] == NULL)
  486.         break;
  487.     }
  488.     va_end(ap);
  489.     pid = run_back(rgargs);
  490.     if (pid < 0)
  491.         return pid;
  492.     for (;;)
  493.         if ((w = wait(&wstatus)) < 0)
  494.             return w;
  495.         else if (w == pid)
  496.             return wstatus;
  497. }
  498.