5 static char rcsid
[]= "$Id: rcsutil.c,v 1.1 1993/03/21 09:58:09 cgd Exp $ Purdue CS";
8 /* Copyright (C) 1982, 1988, 1989 Walter Tichy
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
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.
21 * Report all problems and direct all questions to:
22 * rcs-bugs@cs.purdue.edu
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
40 * Revision 4.5 88/11/08 16:01:02 narten
41 * corrected use of varargs routines
43 * Revision 4.4 88/11/08 12:00:28 narten
44 * changes from eggert@sm.unisys.com (Paul Eggert)
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.
51 * Revision 4.3 87/10/18 10:40:22 narten
52 * Updating version numbers. Changes relative to 1.1 actually
55 * Revision 1.3 87/09/24 14:01:01 narten
56 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
59 * Revision 1.2 87/03/27 14:22:43 jenkins
62 * Revision 1.1 84/01/23 14:50:43 kcs
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().
71 * Revision 3.8 83/02/15 15:41:49 wft
72 * Added routine fastcopy() to copy remainder of a file in blocks.
74 * Revision 3.7 82/12/24 15:25:19 wft
75 * added catchints(), ignoreints() for catching and ingnoring interrupts;
78 * Revision 3.6 82/12/08 21:52:05 wft
79 * Using DATEFORM to format dates.
81 * Revision 3.5 82/12/04 18:20:49 wft
82 * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
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().
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.
94 * Revision 3.2 82/10/18 21:15:11 wft
95 * added function getfullRCSname().
97 * Revision 3.1 82/10/13 16:17:37 wft
98 * Cleanup message is now suppressed in quiet mode.
104 #include <sys/types.h>
105 #include <sys/stat.h>
111 #if defined(USG) || defined(V4_2BSD)
119 extern char * bindex();
120 extern FILE * finptr
;
121 extern char * RCSfilename
;
122 extern char * getlogin();
123 extern char * malloc();
130 if (!(p
= malloc(size
))) {
131 faterror("out of memory");
139 /* Function: gets the callers login from his uid.
140 * If the uid is root, tries to get the true login with getlogin().
145 static int special_user();
147 pw
= getpwuid(getuid());
148 if (pw
== NULL
|| special_user(name
= pw
->pw_name
))
149 if ((name
= getlogin()) == NULL
|| *name
== 0)
150 name
= pw
== NULL
? "nobody" : pw
->pw_name
;
159 static char *u
[] = { "root", "daemon", "bin", "news", 0 };
162 if (**p
== *s
&& strcmp(*p
, s
) == 0)
168 struct hshentry
* findlock(who
,delete)
169 char * who
; int delete;
170 /* Finds the first lock held by who and returns a pointer
171 * to the locked delta; also removes the lock if delete==true.
172 * Returns nil if there is no lock held by who.
175 register struct lock
* next
, * trail
;
178 dummy
.nextlock
=next
=Locks
;
181 if(strcmp(who
,next
->login
)==0) break; /*found a lock*/
189 trail
->nextlock
=next
->nextlock
;
190 Locks
=dummy
.nextlock
;
191 next
->delta
->lockedby
=nil
; /* reset locked-by */
203 struct lock
* addlock(delta
,who
)
204 struct hshentry
* delta
; char * who
;
205 /* Given a delta, addlock checks whether
206 * the delta is locked by somebody other than who.
207 * If so, an error message is printed, and false returned.
208 * If the delta is not reserved at all, a lock for it is added,
209 * and a pointer for the lock returned.
216 if (cmpnum(delta
->num
,next
->delta
->num
)==0) {
217 if (strcmp(who
,next
->login
)==0)
219 /* lock exists already */
221 error("revision %s already locked by %s",
222 delta
->num
, next
->login
);
226 if (strcmp(who
,next
->login
)==0) {
227 error("you already locked %s; only one lock allowed per person.",
235 /* not found; set up new lockblock */
236 next
= (struct lock
*) talloc(sizeof (struct lock
));
237 delta
->lockedby
=next
->login
=who
;
239 next
->nextlock
=Locks
;
246 int addsymbol(delta
,name
,rebind
)
247 struct hshentry
* delta
; char * name
; int rebind
;
248 /* Function: adds a new symbolic name and associates it with node delta.
249 * If name already exists and rebind is true, the name is associated
250 * with the new delta; otherwise, an error message is printed and
251 * false returned. Returns true it successful.
253 { register struct assoc
* next
;
256 if (strcmp(name
,next
->symbol
)==0) {
261 error("symbolic name %s already bound to %s",
262 name
,next
->delta
->num
);
265 } else next
= next
->nextassoc
;
267 /* not found; insert new pair. */
268 next
= (struct assoc
*) talloc(sizeof(struct assoc
));
271 next
->nextassoc
=Symbols
;
279 int checkaccesslist(who
)
281 /* function: Returns true if who is the superuser, the owner of the
282 * file, the access list is empty, or who is on the access list.
283 * Prints an error message and returns false otherwise.
286 register struct access
* next
;
289 if ((AccessList
==nil
) || (strcmp(who
,"root")==0))
294 if (strcmp(who
,next
->login
)==0)
296 next
=next
->nextaccess
;
299 VOID
fstat(fileno(finptr
),&statbuf
); /* get owner of file */
300 if (getuid() == statbuf
.st_uid
) return true;
302 error("User %s not on the access list",who
);
307 static SIGNAL_TYPE
catchsig(s
)
310 diagnose("\nRCS: cleaning up\n");
318 static sig
[] = {SIGINT
,SIGHUP
,SIGQUIT
,SIGPIPE
,SIGTERM
};
319 #define SIGS (sizeof(sig)/sizeof(*sig))
320 static SIGNAL_TYPE (*catcher
[SIGS
])();
325 for (i
=SIGS
; 0<=--i
; )
327 signal(sig
[i
],SIG_IGN
) == SIG_IGN
? SIG_IGN
: catchsig
;
334 for (i
=SIGS
; 0<=--i
; )
335 VOID
signal(sig
[i
], SIG_IGN
);
341 for (i
=SIGS
; 0<=--i
; )
342 if (catcher
[i
] != SIG_IGN
)
343 VOID
signal(sig
[i
], catcher
[i
]);
348 /* Function: copies the remainder of file inf to outf. First copies the
349 * rest that is in the IO-buffer of inf character by character, and then
350 * copies the remainder in blocks.
353 register int rcount
, wcount
;
355 /* write the rest of the buffer to outf */
357 while (--inf
->_r
>= 0)
358 VOID
putc(*inf
->_p
++, outf
);
360 while ((--inf
->_cnt
)>=0) {
361 VOID
putc(*inf
->_ptr
++&0377,outf
);
364 if (fflush(outf
) == EOF
) {
368 /*now read the rest of the file in blocks*/
369 while ((rcount
=read(fileno(inf
),buf
,BUFSIZ
))>0) {
370 wcount
=write(fileno(outf
),buf
,rcount
);
371 if (wcount
!=rcount
) {
385 extern struct tm
* localtime();
388 logcommand(commandname
,delta
, sequence
,login
)
389 char* commandname
; struct hshentry
* delta
, * sequence
[];char * login
;
390 /* Function: start a process to write the file that
391 * logs the RCS command.
392 * Each line in the log file contains the following information:
393 * operation, revision(r), backward deltas applied(b), forward deltas applied(f),
394 * total deltas present(t), creation date of delta(d), date of operation(o),
395 * login of caller, RCS file name.
399 char curdate
[datelength
];
401 register int i
, backward
, forward
;
405 clock
=time((long *)0);
406 tm
=localtime(&clock
);
408 VOID
sprintf(curdate
,DATEFORM
,
409 tm
->tm_year
, tm
->tm_mon
+1, tm
->tm_mday
,
410 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
412 i
= backward
=forward
=0;
413 while(sequence
[i
]!=nil
) { /* count deltas to be applied*/
414 if (countnumflds(sequence
[i
]->num
) == 2)
415 backward
++; /* reverse delta */
416 else forward
++; /* branch delta */
419 VOID
sprintf(logline
,"%s %10sr %3db %3df %3dt %sc %so %s %s",
420 commandname
,delta
->num
,backward
,forward
,TotalDeltas
,delta
->date
,
421 curdate
,login
,bindex(getfullRCSname(),'/'));
424 inoutargs
[2] = SNOOP
;
425 inoutargs
[3] = logline
;
427 VOID
run_back(inoutargs
);
432 static int fdreopen(fd
, file
, flags
, mode
)
437 newfd
= flags
==-1 ? creat(file
,mode
) : open(file
,flags
,mode
);
438 if (newfd
< 0 || newfd
== fd
)
441 fd
= fcntl(newfd
, F_DUPFD
, fd
);
443 fd
= dup2(newfd
, fd
);
449 static void tryopen(fd
,file
,flags
)
452 if (file
&& fdreopen(fd
,file
,flags
,0600) != fd
) {
453 VOID
write(fileno(stderr
), file
, strlen(file
));
454 VOID
write(fileno(stderr
), ": cannot open\n", 14);
460 /* Run in the background a command specified by the strings in 'inoutargs'.
461 /* inoutargs[0], if nonnil, is the name of the input file.
462 /* inoutargs[1], if nonnil, is the name of the output file.
463 /* inoutargs[2..] form the command to be run in the background.
465 static int run_back(inoutargs)
466 register char **inoutargs;
469 if (fflush(stdout) == EOF || fflush(stderr) == EOF)
471 if (!(pid = vfork())) {
472 tryopen(fileno(stdin), inoutargs[0], 0);
473 tryopen(fileno(stdout), inoutargs[1], -1);
474 VOID execv(inoutargs[2], &inoutargs[2]);
475 inoutargs[1] = "/bin/sh";
476 VOID execv(inoutargs[1], &inoutargs[1]);
477 VOID write(fileno(stderr), "/bin/sh: not found\n", 19);
486 /* The first two arguments are the input and output files (if nonnil);
487 /* the rest specify the command and its arguments.
494 char *rgargs[CARGSMAX];
497 rgargs[0] = va_arg(ap, char *);
498 rgargs[1] = va_arg(ap, char *);
499 for (i =2; i< CARGSMAX; i++) {
500 rgargs[i] = va_arg(ap, char *);
501 if (rgargs[i] == NULL)
505 pid = run_back(rgargs);
509 if ((w = wait(&wstatus)) < 0)