1: /* 2: * RCS utilities 3: */ 4: #if !defined(lint) && defined(DOSCCS) 5: static char rcsid[]= "$Id: rcsutil.c,v 4.3.1 97/10/2 10:40:22 sms Exp $"; 6: #endif 7: /***************************************************************************** 8: ***************************************************************************** 9: * 10: * Copyright (C) 1982 by Walter F. Tichy 11: * Purdue University 12: * Computer Science Department 13: * West Lafayette, IN 47907 14: * 15: * All rights reserved. No part of this software may be sold or distributed 16: * in any form or by any means without the prior written permission of the 17: * author. 18: * Report problems and direct all inquiries to Tichy@purdue (ARPA net). 19: */ 20: 21: 22: 23: /* $Log: rcsutil.c,v $ 24: * Revision 4.3.1 97/10/2 sms 25: * Use unistd.h instead of declaring system functions locally 26: * 27: * Revision 4.3 87/10/18 10:40:22 narten 28: * Updating version numbers. Changes relative to 1.1 actually 29: * relative to 4.1 30: * 31: * Revision 1.3 87/09/24 14:01:01 narten 32: * Sources now pass through lint (if you ignore printf/sprintf/fprintf 33: * warnings) 34: * 35: * Revision 1.2 87/03/27 14:22:43 jenkins 36: * Port to suns 37: * 38: * Revision 1.1 84/01/23 14:50:43 kcs 39: * Initial revision 40: * 41: * Revision 4.1 83/05/10 15:53:13 wft 42: * Added getcaller() and findlock(). 43: * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal 44: * (needed for background jobs in older shells). Added restoreints(). 45: * Removed printing of full RCS path from logcommand(). 46: * 47: * Revision 3.8 83/02/15 15:41:49 wft 48: * Added routine fastcopy() to copy remainder of a file in blocks. 49: * 50: * Revision 3.7 82/12/24 15:25:19 wft 51: * added catchints(), ignoreints() for catching and ingnoring interrupts; 52: * fixed catchsig(). 53: * 54: * Revision 3.6 82/12/08 21:52:05 wft 55: * Using DATEFORM to format dates. 56: * 57: * Revision 3.5 82/12/04 18:20:49 wft 58: * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update 59: * lockedby-field. 60: * 61: * Revision 3.4 82/12/03 17:17:43 wft 62: * Added check to addlock() ensuring only one lock per person. 63: * Addlock also returns a pointer to the lock created. Deleted fancydate(). 64: * 65: * Revision 3.3 82/11/27 12:24:37 wft 66: * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c. 67: * Introduced macro SNOOP so that snoop can be placed in directory other than 68: * TARGETDIR. Changed %02d to %.2d for compatibility reasons. 69: * 70: * Revision 3.2 82/10/18 21:15:11 wft 71: * added function getfullRCSname(). 72: * 73: * Revision 3.1 82/10/13 16:17:37 wft 74: * Cleanup message is now suppressed in quiet mode. 75: */ 76: 77: 78: 79: 80: #include <sys/types.h> 81: #include <sys/stat.h> 82: #include <signal.h> 83: #include "rcsbase.h" 84: #include <pwd.h> 85: #include <unistd.h> 86: 87: extern char * malloc(); 88: extern char * bindex(); 89: extern FILE * finptr; 90: extern char * RCSfilename; 91: 92: sig_t oldSIGINT; /* saves the original value for SIGINT */ 93: 94: char * getcaller() 95: /* Function: gets the callers login from his uid. 96: * If the uid is root, tries to get the true login with getlogin(). 97: */ 98: { char * name; 99: int uid; 100: uid=getuid(); 101: if (uid==0) { 102: /* super user; try getlogin() to distinguish */ 103: name = getlogin(); 104: if (name!=nil && *name!='\0') 105: return name; 106: } 107: return(getpwuid(uid)->pw_name); 108: } 109: 110: 111: 112: struct hshentry * findlock(who,delete) 113: char * who; int delete; 114: /* Finds the first lock held by who and returns a pointer 115: * to the locked delta; also removes the lock if delete==true. 116: * Returns nil if there is no lock held by who. 117: */ 118: { 119: register struct lock * next, * trail; 120: struct lock dummy; 121: 122: dummy.nextlock=next=Locks; 123: trail = &dummy; 124: while (next!=nil) { 125: if(strcmp(who,next->login)==0) break; /*found a lock*/ 126: trail=next; 127: next=next->nextlock; 128: } 129: if (next!=nil) { 130: /* found one */ 131: if (delete) { 132: /* delete it */ 133: trail->nextlock=next->nextlock; 134: Locks=dummy.nextlock; 135: next->delta->lockedby=nil; /* reset locked-by */ 136: } 137: return next->delta; 138: } else return nil; 139: } 140: 141: 142: 143: 144: 145: 146: 147: struct lock * addlock(delta,who) 148: struct hshentry * delta; char * who; 149: /* Given a delta, addlock checks whether 150: * the delta is locked by somebody other than who. 151: * If so, an error message is printed, and false returned. 152: * If the delta is not reserved at all, a lock for it is added, 153: * and a pointer for the lock returned. 154: */ 155: { 156: struct lock * next; 157: 158: next=Locks; 159: while (next!=nil) { 160: if (cmpnum(delta->num,next->delta->num)==0) { 161: if (strcmp(who,next->login)==0) 162: return next; 163: /* lock exists already */ 164: else { 165: error("revision %s already locked by %s", 166: delta->num, next->login); 167: return false; 168: } 169: } else { 170: if (strcmp(who,next->login)==0) { 171: error("you already locked %s; only one lock allowed per person.", 172: next->delta->num); 173: return false; 174: } else { 175: next=next->nextlock; 176: } 177: } 178: } 179: /* not found; set up new lockblock */ 180: next= (struct lock *) malloc(sizeof (struct lock)); 181: delta->lockedby=next->login=who; 182: next->delta= delta; 183: next->nextlock=Locks; 184: Locks=next; 185: return next; 186: } 187: 188: 189: 190: int addsymbol(delta,name,rebind) 191: struct hshentry * delta; char * name; int rebind; 192: /* Function: adds a new symbolic name and associates it with node delta. 193: * If name already exists and rebind is true, the name is associated 194: * with the new delta; otherwise, an error message is printed and 195: * false returned. Returns true it successful. 196: */ 197: { register struct assoc * next; 198: next=Symbols; 199: while (next!=nil) { 200: if (strcmp(name,next->symbol)==0) { 201: if (rebind) { 202: next->delta=delta; 203: return true; 204: } else { 205: error("symbolic name %s already bound to %s", 206: name,next->delta->num); 207: return false; 208: } 209: } else next = next->nextassoc; 210: } 211: /* not found; insert new pair. */ 212: next = (struct assoc *) malloc(sizeof(struct assoc)); 213: next->symbol=name; 214: next->delta=delta; 215: next->nextassoc=Symbols; 216: Symbols = next; 217: return true; 218: } 219: 220: 221: 222: 223: int checkaccesslist(who) 224: char * who; 225: /* function: Returns true if who is the superuser, the owner of the 226: * file, the access list is empty, or who is on the access list. 227: * Prints an error message and returns false otherwise. 228: */ 229: { 230: register struct access * next; 231: struct stat statbuf; 232: 233: if ((AccessList==nil) || (strcmp(who,"root")==0)) 234: return true; 235: 236: next=AccessList; 237: do { 238: if (strcmp(who,next->login)==0) 239: return true; 240: next=next->nextaccess; 241: } while (next!=nil); 242: 243: VOID fstat(fileno(finptr),&statbuf); /* get owner of file */ 244: if (getuid() == statbuf.st_uid) return true; 245: 246: error("User %s not on the access list",who); 247: return false; 248: } 249: 250: catchsig(sig) 251: { 252: VOID signal(sig, SIG_IGN); 253: diagnose("\nRCS: cleaning up\n"); 254: VOID cleanup(); 255: exit(1); 256: } 257: 258: 259: void catchints() 260: { 261: cksignal(SIGINT); cksignal(SIGHUP); 262: cksignal(SIGQUIT); cksignal(SIGPIPE); 263: cksignal(SIGTERM); 264: } 265: 266: 267: cksignal(sig) 268: int sig; 269: { 270: if (signal(sig,SIG_IGN) != SIG_IGN) 271: VOID signal(sig,catchsig); 272: } 273: 274: void ignoreints() 275: { 276: VOID signal(SIGINT,SIG_IGN); VOID signal(SIGHUP,SIG_IGN); 277: VOID signal(SIGQUIT,SIG_IGN); VOID signal(SIGPIPE,SIG_IGN); 278: VOID signal(SIGTERM,SIG_IGN); 279: } 280: 281: 282: void restoreints() 283: { 284: if (oldSIGINT!=SIG_IGN) 285: VOID signal(SIGINT,catchsig); 286: VOID signal(SIGHUP,catchsig); VOID signal(SIGQUIT,catchsig); 287: VOID signal(SIGPIPE,catchsig); VOID signal(SIGTERM,catchsig); 288: } 289: 290: 291: fastcopy(inf,outf) 292: FILE * inf, * outf; 293: /* Function: copies the remainder of file inf to outf. First copies the 294: * rest that is in the IO-buffer of inf character by character, and then 295: * copies the remainder in blocks. 296: */ 297: { char buf[BUFSIZ]; 298: register int rcount, wcount; 299: 300: /* write the rest of the buffer to outf */ 301: while ((--inf->_cnt)>=0) { 302: VOID putc(*inf->_ptr++&0377,outf); 303: } 304: if (fflush(outf) == EOF) { 305: faterror("write error"); 306: } 307: 308: /*now read the rest of the file in blocks*/ 309: while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) { 310: wcount=write(fileno(outf),buf,rcount); 311: if (wcount!=rcount) { 312: faterror("write error"); 313: } 314: } 315: } 316: 317: 318: 319: 320: 321: 322: #ifdef SNOOPFILE 323: 324: #include "time.h" 325: extern struct tm* localtime(); 326: extern long time(); 327: 328: logcommand(commandname,delta, sequence,login) 329: char* commandname; struct hshentry * delta, * sequence[];char * login; 330: /* Function: start a process to write the file that 331: * logs the RCS command. 332: * Each line in the log file contains the following information: 333: * operation, revision(r), backward deltas applied(b), forward deltas applied(f), 334: * total deltas present(t), creation date of delta(d), date of operation(o), 335: * login of caller, RCS file name. 336: */ 337: { 338: char command[200]; 339: char curdate[datelength]; 340: register int i, backward, forward; 341: long clock; 342: struct tm * tm; 343: 344: clock=time((long *)0); 345: tm=localtime(&clock); 346: 347: VOID sprintf(curdate,DATEFORM, 348: tm->tm_year, tm->tm_mon+1, tm->tm_mday, 349: tm->tm_hour, tm->tm_min, tm->tm_sec); 350: 351: i= backward=forward=0; 352: while(sequence[i]!=nil) { /* count deltas to be applied*/ 353: if (countnumflds(sequence[i]->num) == 2) 354: backward++; /* reverse delta */ 355: else forward++; /* branch delta */ 356: i++; 357: } 358: VOID sprintf(command,"%s \"%s %10sr %3db %3df %3dt %sc %so %s %s\" &\n", 359: SNOOP, commandname,delta->num,backward,forward,TotalDeltas,delta->date, 360: curdate,login,bindex(RCSfilename,'/')); 361: VOID system(command); 362: } 363: #endif