home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / rcs4 / source / rcsutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-08  |  16.4 KB  |  622 lines

  1. /*
  2.  *                     RCS utilities
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcsutil.c 5.6 91/03/08 14:23:13 ROOT_DOS 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 $
  37.  * Revision 5.6  91/03/08  14:23:13  ROOT_DOS
  38.  * Save stdout & stdin file handles before redirecting, restore after
  39.  * 
  40.  * Revision 5.5  91/02/07  13:50:56  ROOT_DOS
  41.  * getcaller() always used to return NULL ! (misplaced ';')
  42.  * 
  43.  * Revision 5.4  90/07/16  21:40:37  lfk
  44.  * checked in with -k by ROOT_DOS at 91.02.07.11.45.45.
  45.  * 
  46.  * Revision 5.4  90/07/16  21:40:37  lfk
  47.  * checkin for release compilation
  48.  * 
  49.  * Revision 5.3  90/07/15  18:06:08  lfk
  50.  * changed signals around so that
  51.  * they actually allow you to abort an RCS command
  52.  * 
  53.  * Revision 5.2  90/07/15  11:35:32  ROOT_DOS
  54.  * DOS version of RCS 4.0 checked in for MODS
  55.  * by lfk@athena.mit.edu
  56.  * Also update to MSC 6.0
  57.  * 
  58.  * revision 5.2 koya 90/01/25 00:37:14
  59.  * Modified the codes related to Child processes and Signals.
  60.  * 
  61.  * revision 5.1 koya 90/01/24 10:40:36
  62.  * Initial revision
  63.  * 
  64.  * Revision 4.6  89/05/01  15:13:40  narten
  65.  * changed copyright header to reflect current distribution rules
  66.  * 
  67.  * Revision 4.5  88/11/08  16:01:02  narten
  68.  * corrected use of varargs routines
  69.  * 
  70.  * Revision 4.4  88/11/08  12:00:28  narten
  71.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  72.  * 
  73.  * Revision 4.4  88/08/09  19:13:24  eggert
  74.  * Check for memory exhaustion.
  75.  * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
  76.  * Use execv(), not system(); yield exit status like diff(1)'s.
  77.  * 
  78.  * Revision 4.3  87/10/18  10:40:22  narten
  79.  * Updating version numbers. Changes relative to 1.1 actually
  80.  * relative to 4.1
  81.  * 
  82.  * Revision 1.3  87/09/24  14:01:01  narten
  83.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  84.  * warnings)
  85.  * 
  86.  * Revision 1.2  87/03/27  14:22:43  jenkins
  87.  * Port to suns
  88.  * 
  89.  * Revision 1.1  84/01/23  14:50:43  kcs
  90.  * Initial revision
  91.  * 
  92.  * Revision 4.1  83/05/10  15:53:13  wft
  93.  * Added getcaller() and findlock().
  94.  * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
  95.  * (needed for background jobs in older shells). Added restoreints().
  96.  * Removed printing of full RCS path from logcommand().
  97.  * 
  98.  * Revision 3.8  83/02/15  15:41:49  wft
  99.  * Added routine fastcopy() to copy remainder of a file in blocks.
  100.  *
  101.  * Revision 3.7  82/12/24  15:25:19  wft
  102.  * added catchints(), ignoreints() for catching and ingnoring interrupts;
  103.  * fixed catchsig().
  104.  *
  105.  * Revision 3.6  82/12/08  21:52:05  wft
  106.  * Using DATEFORM to format dates.
  107.  *
  108.  * Revision 3.5  82/12/04  18:20:49  wft
  109.  * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
  110.  * lockedby-field.
  111.  *
  112.  * Revision 3.4  82/12/03  17:17:43  wft
  113.  * Added check to addlock() ensuring only one lock per person.
  114.  * Addlock also returns a pointer to the lock created. Deleted fancydate().
  115.  *
  116.  * Revision 3.3  82/11/27  12:24:37  wft
  117.  * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
  118.  * Introduced macro SNOOP so that snoop can be placed in directory other than
  119.  * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
  120.  *
  121.  * Revision 3.2  82/10/18  21:15:11  wft
  122.  * added function getfullRCSname().
  123.  *
  124.  * Revision 3.1  82/10/13  16:17:37  wft
  125.  * Cleanup message is now suppressed in quiet mode.
  126.  */
  127.  
  128.  
  129.  
  130.  
  131. #include <sys/types.h>
  132. #include <sys/stat.h>
  133. #include <signal.h>
  134. #include "rcsbase.h"
  135. #ifndef MSDOS
  136. #include <pwd.h>
  137. #endif /* NOT MSDOS */
  138. #include <varargs.h>
  139.  
  140. #if defined(USG) || defined(V4_2BSD)
  141. #include <fcntl.h>
  142. #endif
  143.  
  144. #ifndef MSDOS
  145. #ifndef V4_2BSD
  146. #define vfork fork
  147. #endif
  148. #endif /* NOT MSDOS */
  149.  
  150. extern char * bindex();
  151. extern FILE * finptr;
  152. extern char * RCSfilename;
  153. #ifndef MSDOS
  154. extern char * getlogin();
  155. extern struct passwd *getpwuid();
  156. #endif /* NOT MSDOS */
  157. extern char * malloc();
  158.  
  159.  
  160. char * talloc(size)
  161. unsigned size;
  162. {
  163.     char * p;
  164.     if (!(p = malloc(size))) {
  165.         faterror("out of memory");
  166.     }
  167.     return p;
  168. }
  169.  
  170. #ifdef MSDOS
  171. char * getenv( char * var );
  172. #endif
  173.  
  174. char * getcaller()
  175. /* Function: gets the callers login from his uid.
  176.  * If the uid is root, tries to get the true login with getlogin().
  177.  */
  178. {
  179.     char *name = "ROOT_DOS";
  180.     char *tmpname;
  181. #ifdef MSDOS
  182. #    ifndef MKS
  183.     if ((tmpname = getenv("USR")) != NULL)
  184. #    else
  185.     if ((tmpname = getenv("LOGNAME")) != NULL)
  186. #    endif
  187.         name = tmpname;
  188.     return name;
  189. #else
  190.     int uid;
  191.     uid=getuid();
  192.     if (uid==0) {
  193.         /* super user; try getlogin() to distinguish */
  194.         name = getlogin();
  195.         if (name!=nil && *name!='\0')
  196.             return name;
  197.     }
  198.     return(getpwuid(uid)->pw_name);
  199. #endif /* MSDOS */
  200. }
  201.  
  202.  
  203.  
  204. struct hshentry * findlock(who,delete)
  205. char * who; int delete;
  206. /* Finds the first lock held by who and returns a pointer
  207.  * to the locked delta; also removes the lock if delete==true.
  208.  * Returns nil if there is no lock held by who.
  209.  */
  210. {
  211.         register struct lock * next, * trail;
  212.         struct lock dummy;
  213.  
  214.         dummy.nextlock=next=Locks;
  215.         trail = &dummy;
  216.         while (next!=nil) {
  217.                 if(strcmp(who,next->login)==0) break; /*found a lock*/
  218.                 trail=next;
  219.                 next=next->nextlock;
  220.         }
  221.         if (next!=nil) {
  222.         /* found one */
  223.         if (delete) {
  224.             /* delete it */
  225.             trail->nextlock=next->nextlock;
  226.             Locks=dummy.nextlock;
  227.             next->delta->lockedby=nil; /* reset locked-by */
  228.         }
  229.                 return next->delta;
  230.         } else  return nil;
  231. }
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239. struct lock * addlock(delta,who)
  240. struct hshentry * delta; char * who;
  241. /* Given a delta, addlock checks whether
  242.  * the delta is locked by somebody other than who.
  243.  * If so, an error message is printed, and false returned.
  244.  * If the delta is not reserved at all, a lock for it is added,
  245.  * and a pointer for the lock returned.
  246.  */
  247. {
  248.         struct lock * next;
  249.  
  250.         next=Locks;
  251.         while (next!=nil) {
  252.                 if (cmpnum(delta->num,next->delta->num)==0) {
  253.                         if (strcmp(who,next->login)==0)
  254.                                 return next;
  255.                                 /* lock exists already */
  256.                         else {
  257.                                 error("revision %s already locked by %s",
  258.                                       delta->num, next->login);
  259.                                 return false;
  260.                         }
  261.                 } else {
  262.                         if (strcmp(who,next->login)==0) {
  263.                                 error("you already locked %s; only one lock allowed per person.",
  264.                                        next->delta->num);
  265.                                 return false;
  266.                         } else {
  267.                                 next=next->nextlock;
  268.                         }
  269.                 }
  270.         }
  271.         /* not found; set up new lockblock */
  272.         next= (struct lock *) talloc(sizeof (struct lock));
  273.         delta->lockedby=next->login=who;
  274.         next->delta= delta;
  275.         next->nextlock=Locks;
  276.         Locks=next;
  277.         return next;
  278. }
  279.  
  280.  
  281.  
  282. int addsymbol(delta,name,rebind)
  283. struct hshentry * delta; char * name; int rebind;
  284. /* Function: adds a new symbolic name and associates it with node delta.
  285.  * If name already exists and rebind is true, the name is associated
  286.  * with the new delta; otherwise, an error message is printed and
  287.  * false returned. Returns true it successful.
  288.  */
  289. {       register struct assoc * next;
  290.         next=Symbols;
  291.         while (next!=nil) {
  292.                 if (strcmp(name,next->symbol)==0) {
  293.                         if (rebind) {
  294.                                 next->delta=delta;
  295.                                 return true;
  296.                         } else {
  297.                                 error("symbolic name %s already bound to %s",
  298.                                         name,next->delta->num);
  299.                                 return false;
  300.                         }
  301.                 } else  next = next->nextassoc;
  302.         }
  303.         /* not found; insert new pair. */
  304.         next = (struct assoc *) talloc(sizeof(struct assoc));
  305.         next->symbol=name;
  306.         next->delta=delta;
  307.         next->nextassoc=Symbols;
  308.         Symbols = next;
  309.         return true;
  310. }
  311.  
  312.  
  313.  
  314.  
  315. int checkaccesslist(who)
  316. char * who;
  317. /* function: Returns true if who is the superuser, the owner of the
  318.  * file, the access list is empty, or who is on the access list.
  319.  * Prints an error message and returns false otherwise.
  320.  */
  321. {
  322.         register struct access * next;
  323.         struct stat statbuf;
  324.  
  325. #ifdef MSDOS
  326.         if ((AccessList==nil) || (strcmp(who,"ROOT_DOS")==0))
  327. #else
  328.         if ((AccessList==nil) || (strcmp(who,"root")==0))
  329. #endif /* MSDOS */
  330.                 return true;
  331.  
  332.         next=AccessList;
  333.         do {
  334.                 if (strcmp(who,next->login)==0)
  335.                         return true;
  336.                 next=next->nextaccess;
  337.         } while (next!=nil);
  338.  
  339. #ifdef MSDOS
  340. #else
  341.         VOID fstat(fileno(finptr),&statbuf);  /* get owner of file */
  342.         if (getuid() == statbuf.st_uid) return true;
  343. #endif /* MSDOS */
  344.  
  345.         error("User %s not on the access list",who);
  346.         return false;
  347. }
  348.  
  349. /* In MSDOS, we have a few signals.     */
  350. /* So, we set signal handlar for only SIGINT. lfk     */
  351.  
  352. #ifdef MSDOS
  353. void catchsig(void)
  354. #else
  355. static SIGNAL_TYPE catchsig(s)
  356. #endif /* MSDOS */
  357. {
  358.     ignoreints();
  359.         diagnose("\nRCS: cleaning up\n");
  360.         VOID cleanup();
  361.     exit(2);
  362. #ifdef lint
  363.     catchsig(s);
  364. #endif
  365. }
  366.  
  367. #ifndef MSDOS
  368. static sig[] = {SIGINT,SIGHUP,SIGQUIT,SIGPIPE,SIGTERM};
  369. #define SIGS (sizeof(sig)/sizeof(*sig))
  370. static SIGNAL_TYPE (*catcher[SIGS])();
  371. #endif /* NOT MSDOS */
  372.   void catchints()
  373.   {
  374. #ifdef MSDOS
  375.     signal(SIGINT, catchsig); /* lfk fixed this so Ctrl-C halts processing */
  376.     restoreints();
  377. #else
  378.     register i;
  379.     for (i=SIGS; 0<=--i; )
  380.         catcher[i]  =
  381.         signal(sig[i],SIG_IGN) == SIG_IGN  ?  SIG_IGN  :  catchsig;
  382.     restoreints();
  383. #endif /* MSDOS */
  384.   }
  385.  
  386.   void ignoreints()
  387.   {
  388. #ifdef MSDOS
  389.     VOID signal(SIGINT, SIG_IGN);
  390. #else
  391.     register i;
  392.     for (i=SIGS; 0<=--i; )
  393.         VOID signal(sig[i], SIG_IGN);
  394. #endif /* MSDOS */
  395.   }
  396.  
  397. void restoreints()
  398. {
  399. #ifdef MSDOS
  400.     VOID signal(SIGINT, catchsig);
  401. #else
  402.     register i;
  403.     for (i=SIGS; 0<=--i; )
  404.         if (catcher[i] != SIG_IGN)
  405.             VOID signal(sig[i], catcher[i]);
  406. #endif /* MSDOS */
  407. }
  408.  
  409. fastcopy(inf,outf)
  410. FILE * inf, * outf;
  411. /* Function: copies the remainder of file inf to outf. First copies the
  412.  * rest that is in the IO-buffer of inf character by character, and then
  413.  * copies the remainder in blocks.
  414.  */
  415. {       char buf[BUFSIZ];
  416.         register int rcount, wcount;
  417.  
  418.         /* write the rest of the buffer to outf */
  419.         while ((--inf->_cnt)>=0) {
  420.                 VOID putc(*inf->_ptr++&0377,outf);
  421.         }
  422.         if (fflush(outf) == EOF) {
  423.         writeerror();
  424.     }
  425.  
  426.         /*now read the rest of the file in blocks*/
  427.         while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) {
  428.                 wcount=write(fileno(outf),buf,rcount);
  429.                 if (wcount!=rcount) {
  430.                     writeerror();
  431.                 }
  432.         }
  433. }
  434.  
  435.  
  436. #ifdef SNOOPFILE
  437.  
  438. #include "time.h"
  439. extern struct tm* localtime();
  440. extern long time();
  441.  
  442. logcommand(commandname,delta, sequence,login)
  443. char* commandname; struct hshentry * delta, * sequence[];char * login;
  444. /* Function: start a process to write the file that
  445.  * logs the RCS command.
  446.  * Each line in the log file contains the following information:
  447.  * operation, revision(r), backward deltas applied(b), forward deltas applied(f),
  448.  * total deltas present(t), creation date of delta(d), date of operation(o),
  449.  * login of caller, RCS file name.
  450.  */
  451. {
  452.         char logline[200];
  453.         char curdate[datelength];
  454.     char *inoutargs[5];
  455.         register int i, backward, forward;
  456.         long clock;
  457.         struct tm * tm;
  458.  
  459.         clock=time((long *)0);
  460.         tm=localtime(&clock);
  461.  
  462.         VOID sprintf(curdate,DATEFORM,
  463.                 tm->tm_year, tm->tm_mon+1, tm->tm_mday,
  464.                 tm->tm_hour, tm->tm_min, tm->tm_sec);
  465.  
  466.         i= backward=forward=0;
  467.         while(sequence[i]!=nil) {  /* count deltas to be applied*/
  468.         if (countnumflds(sequence[i]->num) == 2)
  469.                 backward++;  /* reverse delta */
  470.         else    forward++;   /* branch delta  */
  471.         i++;
  472.         }
  473.     VOID sprintf(logline,"%s %10sr %3db %3df %3dt %sc %so %s %s",
  474.         commandname,delta->num,backward,forward,TotalDeltas,delta->date,
  475.         curdate,login,bindex(getfullRCSname(),'/'));
  476.     inoutargs[0] = nil;
  477.     inoutargs[1] = nil;
  478.     inoutargs[2] = SNOOP;
  479.     inoutargs[3] = logline;
  480.     inoutargs[4] = nil;
  481.     VOID run_back(inoutargs);
  482. }
  483. #endif
  484.  
  485.  
  486. static int fdreopen(fd, file, flags, mode)
  487.     char *file;
  488. {
  489.     int newfd;
  490.     VOID close(fd);
  491.     newfd = flags==-1 ? creat(file,mode) : open(file,flags,mode);
  492.     if (newfd < 0  ||  newfd == fd)
  493.         return newfd;
  494. #ifdef F_DUPFD
  495.     fd = fcntl(newfd, F_DUPFD, fd);
  496. #else
  497.     fd = dup2(newfd, fd);
  498. #endif
  499.     VOID close(newfd);
  500.     return fd;
  501. }
  502.  
  503. static void tryopen(fd,file,flags)
  504.     char *file;
  505. {
  506.     if (file  &&  fdreopen(fd,file,flags,0600) != fd) {
  507.         VOID write(fileno(stderr), file, strlen(file));
  508.         VOID write(fileno(stderr), ": cannot open\n", 14);
  509.         _exit(2);
  510.     }
  511. }
  512.  
  513.  
  514. /*
  515. /* Run in the background a command specified by the strings in 'inoutargs'.
  516. /* inoutargs[0], if nonnil, is the name of the input file.
  517. /* inoutargs[1], if nonnil, is the name of the output file.
  518. /* inoutargs[2..] form the command to be run in the background.
  519. /*/
  520. static int run_back(inoutargs)
  521.     register char **inoutargs;
  522. {
  523. #ifdef MSDOS
  524.     int result, stds[2], oldstds[2], i;
  525.     
  526.     if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
  527.         return -1;
  528.     stds[0] = fileno(stdin);
  529.     stds[1] = fileno(stdout);
  530.     for(i = 0; i < 2; i++)        /* save and redirect files */
  531.         {
  532.         if(inoutargs[i])
  533.             {
  534.             oldstds[i] = dup(stds[i]);
  535.             tryopen(stds[i], inoutargs[i], i ? -1 : 0);
  536.             }
  537.         }
  538.     result = spawnvp( 0, inoutargs[2], &inoutargs[2] );
  539.     for(i = 0; i < 2; i++)        /* restore redirected files */
  540.         {
  541.         if(inoutargs[i])
  542.             {
  543.             close(stds[i]);
  544. #ifdef F_DUPFD
  545.             fcntl(oldstds[i], F_DUPFD, stds[i]);
  546. #else
  547.             dup2(oldstds[i], stds[i]);
  548. #endif
  549.             close(oldstds[i]);
  550.             }
  551.         }
  552.     return result;
  553. #else
  554.     int pid;
  555.     if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
  556.         return -1;
  557.     if (!(pid = vfork())) {
  558.         tryopen(fileno(stdin), inoutargs[0], 0);
  559.         tryopen(fileno(stdout), inoutargs[1], -1);
  560.         VOID execv(inoutargs[2], &inoutargs[2]);
  561.         inoutargs[1] = "/bin/sh";
  562.         VOID execv(inoutargs[1], &inoutargs[1]);
  563.         VOID write(fileno(stderr), "/bin/sh: not found\n", 19);
  564.         _exit(2);
  565.     }
  566.     return pid;
  567. #endif /* MSDOS */
  568. }
  569.  
  570. #define CARGSMAX 20
  571. /*
  572. /* Run a command.
  573. /* The first two arguments are the input and output files (if nonnil);
  574. /* the rest specify the command and its arguments.
  575. /*/
  576. int run(va_alist)
  577.     va_dcl
  578. {
  579.     va_list ap;
  580.     int pid, wstatus, w;
  581.     char *rgargs[CARGSMAX];
  582.     register i = 0;
  583.     va_start(ap);
  584.     rgargs[0] = va_arg(ap, char *);
  585.     rgargs[1] = va_arg(ap, char *);
  586.     for (i =2; i< CARGSMAX; i++) {
  587.         rgargs[i] = va_arg(ap, char *);
  588.         if (rgargs[i] == NULL)
  589.         break;
  590.     }
  591.     va_end(ap);
  592.     pid = run_back(rgargs);
  593. #ifndef MSDOS
  594.     if (pid < 0)
  595. #endif /* MSDOS */
  596.         return pid;
  597. #ifndef MSDOS
  598.     for (;;)
  599.         if ((w = wait(&wstatus)) < 0)
  600.             return w;
  601.         else if (w == pid)
  602.             return wstatus;
  603. #endif /* NOT MSDOS */
  604. }
  605.     
  606. #ifdef MSDOS
  607. int Rename( from, to )
  608. char    *from;
  609. char    *to;
  610. {
  611.     if ( access( to, 0 ) == 0 ) {
  612.         if ( chmod( to, S_IWRITE | S_IREAD ) == -1 )
  613.             return (-1);
  614.         if ( unlink(to) != 0 )
  615.             return (-1);
  616.     }        
  617.         return ( rename( from, to ) );
  618. }
  619. #endif /* MSDOS */
  620.     
  621.     
  622.