|
|
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.