|
|
1.1 ! root 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: * All rights reserved. ! 10: * ! 11: * Redistribution and use in source and binary forms are permitted ! 12: * provided that the above copyright notice and this paragraph are ! 13: * duplicated in all such forms and that any documentation, ! 14: * advertising materials, and other materials related to such ! 15: * distribution and use acknowledge that the software was developed ! 16: * by Walter Tichy. ! 17: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 18: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 19: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 20: * ! 21: * Report all problems and direct all questions to: ! 22: * [email protected] ! 23: * ! 24: ! 25: ! 26: ! 27: ! 28: ! 29: ! 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 [email protected] (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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.