xref: /netbsd-src/external/gpl2/rcs/dist/src/rcsclean.c (revision fa28c6faa16e0b00edee7acdcaf4899797043def)
1*fa28c6faSchristos /*	$NetBSD: rcsclean.c,v 1.2 2016/01/14 04:22:39 christos Exp $	*/
27bdc2678Schristos 
37bdc2678Schristos /* Clean up working files.  */
47bdc2678Schristos 
57bdc2678Schristos /* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
67bdc2678Schristos    Distributed under license by the Free Software Foundation, Inc.
77bdc2678Schristos 
87bdc2678Schristos This file is part of RCS.
97bdc2678Schristos 
107bdc2678Schristos RCS is free software; you can redistribute it and/or modify
117bdc2678Schristos it under the terms of the GNU General Public License as published by
127bdc2678Schristos the Free Software Foundation; either version 2, or (at your option)
137bdc2678Schristos any later version.
147bdc2678Schristos 
157bdc2678Schristos RCS is distributed in the hope that it will be useful,
167bdc2678Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
177bdc2678Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
187bdc2678Schristos GNU General Public License for more details.
197bdc2678Schristos 
207bdc2678Schristos You should have received a copy of the GNU General Public License
217bdc2678Schristos along with RCS; see the file COPYING.
227bdc2678Schristos If not, write to the Free Software Foundation,
237bdc2678Schristos 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
247bdc2678Schristos 
257bdc2678Schristos Report problems and direct all questions to:
267bdc2678Schristos 
277bdc2678Schristos 	rcs-bugs@cs.purdue.edu
287bdc2678Schristos 
297bdc2678Schristos */
307bdc2678Schristos 
317bdc2678Schristos #include "rcsbase.h"
327bdc2678Schristos 
337bdc2678Schristos #if has_dirent
347bdc2678Schristos 	static int get_directory P((char const*,char***));
357bdc2678Schristos #endif
367bdc2678Schristos 
377bdc2678Schristos static int unlock P((struct hshentry *));
387bdc2678Schristos static void cleanup P((void));
397bdc2678Schristos 
407bdc2678Schristos static RILE *workptr;
417bdc2678Schristos static int exitstatus;
427bdc2678Schristos 
437bdc2678Schristos mainProg(rcscleanId, "rcsclean", "Id: rcsclean.c,v 5.9 1995/06/16 06:19:24 eggert Exp ")
447bdc2678Schristos {
457bdc2678Schristos 	static char const usage[] =
467bdc2678Schristos 		"\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
477bdc2678Schristos 
487bdc2678Schristos 	static struct buf revision;
497bdc2678Schristos 
507bdc2678Schristos 	char *a, **newargv;
517bdc2678Schristos 	char const *rev, *p;
527bdc2678Schristos 	int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
537bdc2678Schristos 	int Ttimeflag;
547bdc2678Schristos 	struct hshentries *deltas;
557bdc2678Schristos 	struct hshentry *delta;
567bdc2678Schristos 	struct stat workstat;
577bdc2678Schristos 
587bdc2678Schristos 	setrid();
597bdc2678Schristos 
607bdc2678Schristos 	expmode = -1;
617bdc2678Schristos 	rev = 0;
627bdc2678Schristos 	suffixes = X_DEFAULT;
637bdc2678Schristos 	perform = true;
647bdc2678Schristos 	unlockflag = false;
657bdc2678Schristos 	Ttimeflag = false;
667bdc2678Schristos 
677bdc2678Schristos 	argc = getRCSINIT(argc, argv, &newargv);
687bdc2678Schristos 	argv = newargv;
697bdc2678Schristos 	for (;;) {
707bdc2678Schristos 		if (--argc < 1) {
717bdc2678Schristos #			if has_dirent
727bdc2678Schristos 				argc = get_directory(".", &newargv);
737bdc2678Schristos 				argv = newargv;
747bdc2678Schristos 				break;
757bdc2678Schristos #			else
767bdc2678Schristos 				faterror("no pathnames specified");
777bdc2678Schristos #			endif
787bdc2678Schristos 		}
797bdc2678Schristos 		a = *++argv;
807bdc2678Schristos 		if (!*a  ||  *a++ != '-')
817bdc2678Schristos 			break;
827bdc2678Schristos 		switch (*a++) {
837bdc2678Schristos 			case 'k':
847bdc2678Schristos 				if (0 <= expmode)
857bdc2678Schristos 					redefined('k');
867bdc2678Schristos 				if ((expmode = str2expmode(a))  <  0)
877bdc2678Schristos 					goto unknown;
887bdc2678Schristos 				break;
897bdc2678Schristos 
907bdc2678Schristos 			case 'n':
917bdc2678Schristos 				perform = false;
927bdc2678Schristos 				goto handle_revision;
937bdc2678Schristos 
947bdc2678Schristos 			case 'q':
957bdc2678Schristos 				quietflag = true;
967bdc2678Schristos 				/* fall into */
977bdc2678Schristos 			case 'r':
987bdc2678Schristos 			handle_revision:
997bdc2678Schristos 				if (*a) {
1007bdc2678Schristos 					if (rev)
1017bdc2678Schristos 						warn("redefinition of revision number");
1027bdc2678Schristos 					rev = a;
1037bdc2678Schristos 				}
1047bdc2678Schristos 				break;
1057bdc2678Schristos 
1067bdc2678Schristos 			case 'T':
1077bdc2678Schristos 				if (*a)
1087bdc2678Schristos 					goto unknown;
1097bdc2678Schristos 				Ttimeflag = true;
1107bdc2678Schristos 				break;
1117bdc2678Schristos 
1127bdc2678Schristos 			case 'u':
1137bdc2678Schristos 				unlockflag = true;
1147bdc2678Schristos 				goto handle_revision;
1157bdc2678Schristos 
1167bdc2678Schristos 			case 'V':
1177bdc2678Schristos 				setRCSversion(*argv);
1187bdc2678Schristos 				break;
1197bdc2678Schristos 
1207bdc2678Schristos 			case 'x':
1217bdc2678Schristos 				suffixes = a;
1227bdc2678Schristos 				break;
1237bdc2678Schristos 
1247bdc2678Schristos 			case 'z':
1257bdc2678Schristos 				zone_set(a);
1267bdc2678Schristos 				break;
1277bdc2678Schristos 
1287bdc2678Schristos 			default:
1297bdc2678Schristos 			unknown:
1307bdc2678Schristos 				error("unknown option: %s%s", *argv, usage);
1317bdc2678Schristos 		}
1327bdc2678Schristos 	}
1337bdc2678Schristos 
1347bdc2678Schristos 	dounlock = perform & unlockflag;
1357bdc2678Schristos 
1367bdc2678Schristos 	if (nerror)
1377bdc2678Schristos 	  cleanup();
1387bdc2678Schristos 	else
1397bdc2678Schristos 	  for (;  0 < argc;  cleanup(), ++argv, --argc) {
1407bdc2678Schristos 
1417bdc2678Schristos 		ffree();
1427bdc2678Schristos 
1437bdc2678Schristos 		if (!(
1447bdc2678Schristos 			0 < pairnames(
1457bdc2678Schristos 				argc, argv,
1467bdc2678Schristos 				dounlock ? rcswriteopen : rcsreadopen,
1477bdc2678Schristos 				true, true
1487bdc2678Schristos 			) &&
1497bdc2678Schristos 			(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
1507bdc2678Schristos 		))
1517bdc2678Schristos 			continue;
1527bdc2678Schristos 
1537bdc2678Schristos 		if (same_file(RCSstat, workstat, 0)) {
1547bdc2678Schristos 			rcserror("RCS file is the same as working file %s.",
1557bdc2678Schristos 				workname
1567bdc2678Schristos 			);
1577bdc2678Schristos 			continue;
1587bdc2678Schristos 		}
1597bdc2678Schristos 
1607bdc2678Schristos 		gettree();
1617bdc2678Schristos 
1627bdc2678Schristos 		p = 0;
1637bdc2678Schristos 		if (rev) {
1647bdc2678Schristos 			if (!fexpandsym(rev, &revision, workptr))
1657bdc2678Schristos 				continue;
1667bdc2678Schristos 			p = revision.string;
1677bdc2678Schristos 		} else if (Head)
1687bdc2678Schristos 			switch (unlockflag ? findlock(false,&delta) : 0) {
1697bdc2678Schristos 				default:
1707bdc2678Schristos 					continue;
1717bdc2678Schristos 				case 0:
1727bdc2678Schristos 					p = Dbranch ? Dbranch : "";
1737bdc2678Schristos 					break;
1747bdc2678Schristos 				case 1:
1757bdc2678Schristos 					p = delta->num;
1767bdc2678Schristos 					break;
1777bdc2678Schristos 			}
1787bdc2678Schristos 		delta = 0;
1797bdc2678Schristos 		deltas = 0;  /* Keep lint happy.  */
1807bdc2678Schristos 		if (p  &&  !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
1817bdc2678Schristos 			continue;
1827bdc2678Schristos 
1837bdc2678Schristos 		waslocked = delta && delta->lockedby;
1847bdc2678Schristos 		locker_expansion = unlock(delta);
1857bdc2678Schristos 		unlocked = locker_expansion & unlockflag;
1867bdc2678Schristos 		if (unlocked<waslocked  &&  workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
1877bdc2678Schristos 			continue;
1887bdc2678Schristos 
1897bdc2678Schristos 		if (unlocked && !checkaccesslist())
1907bdc2678Schristos 			continue;
1917bdc2678Schristos 
1927bdc2678Schristos 		if (dorewrite(dounlock, unlocked) != 0)
1937bdc2678Schristos 			continue;
1947bdc2678Schristos 
1957bdc2678Schristos 		if (0 <= expmode)
1967bdc2678Schristos 			Expand = expmode;
1977bdc2678Schristos 		else if (
1987bdc2678Schristos 			waslocked  &&
1997bdc2678Schristos 			Expand == KEYVAL_EXPAND  &&
2007bdc2678Schristos 			WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
2017bdc2678Schristos 		)
2027bdc2678Schristos 			Expand = KEYVALLOCK_EXPAND;
2037bdc2678Schristos 
2047bdc2678Schristos 		getdesc(false);
2057bdc2678Schristos 
2067bdc2678Schristos 		if (
2077bdc2678Schristos 			!delta ? workstat.st_size!=0 :
2087bdc2678Schristos 			0 < rcsfcmp(
2097bdc2678Schristos 				workptr, &workstat,
2107bdc2678Schristos 				buildrevision(deltas, delta, (FILE*)0, false),
2117bdc2678Schristos 				delta
2127bdc2678Schristos 			)
2137bdc2678Schristos 		)
2147bdc2678Schristos 			continue;
2157bdc2678Schristos 
2167bdc2678Schristos 		if (quietflag < unlocked)
2177bdc2678Schristos 			aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
2187bdc2678Schristos 
2197bdc2678Schristos 		if (perform & unlocked) {
2207bdc2678Schristos 			if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
2217bdc2678Schristos 			if (donerewrite(true,
2227bdc2678Schristos 				Ttimeflag ? RCSstat.st_mtime : (time_t)-1
2237bdc2678Schristos 			) != 0)
2247bdc2678Schristos 				continue;
2257bdc2678Schristos 		}
2267bdc2678Schristos 
2277bdc2678Schristos 		if (!quietflag)
2287bdc2678Schristos 			aprintf(stdout, "rm -f %s\n", workname);
2297bdc2678Schristos 		Izclose(&workptr);
2307bdc2678Schristos 		if (perform  &&  un_link(workname) != 0)
2317bdc2678Schristos 			eerror(workname);
2327bdc2678Schristos 
2337bdc2678Schristos 	  }
2347bdc2678Schristos 
2357bdc2678Schristos 	tempunlink();
2367bdc2678Schristos 	if (!quietflag)
2377bdc2678Schristos 		Ofclose(stdout);
2387bdc2678Schristos 	exitmain(exitstatus);
2397bdc2678Schristos }
2407bdc2678Schristos 
2417bdc2678Schristos 	static void
cleanup()2427bdc2678Schristos cleanup()
2437bdc2678Schristos {
2447bdc2678Schristos 	if (nerror) exitstatus = EXIT_FAILURE;
2457bdc2678Schristos 	Izclose(&finptr);
2467bdc2678Schristos 	Izclose(&workptr);
2477bdc2678Schristos 	Ozclose(&fcopy);
2487bdc2678Schristos 	ORCSclose();
2497bdc2678Schristos 	dirtempunlink();
2507bdc2678Schristos }
2517bdc2678Schristos 
2527bdc2678Schristos #if RCS_lint
2537bdc2678Schristos #	define exiterr rcscleanExit
2547bdc2678Schristos #endif
2557bdc2678Schristos 	void
exiterr()2567bdc2678Schristos exiterr()
2577bdc2678Schristos {
2587bdc2678Schristos 	ORCSerror();
2597bdc2678Schristos 	dirtempunlink();
2607bdc2678Schristos 	tempunlink();
2617bdc2678Schristos 	_exit(EXIT_FAILURE);
2627bdc2678Schristos }
2637bdc2678Schristos 
2647bdc2678Schristos 	static int
unlock(delta)2657bdc2678Schristos unlock(delta)
2667bdc2678Schristos 	struct hshentry *delta;
2677bdc2678Schristos {
2687bdc2678Schristos 	register struct rcslock **al, *l;
2697bdc2678Schristos 
2707bdc2678Schristos 	if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
2717bdc2678Schristos 		for (al = &Locks;  (l = *al);  al = &l->nextlock)
2727bdc2678Schristos 			if (l->delta == delta) {
2737bdc2678Schristos 				*al = l->nextlock;
2747bdc2678Schristos 				delta->lockedby = 0;
2757bdc2678Schristos 				return true;
2767bdc2678Schristos 			}
2777bdc2678Schristos 	return false;
2787bdc2678Schristos }
2797bdc2678Schristos 
2807bdc2678Schristos #if has_dirent
2817bdc2678Schristos 	static int
get_directory(dirname,aargv)2827bdc2678Schristos get_directory(dirname, aargv)
2837bdc2678Schristos 	char const *dirname;
2847bdc2678Schristos 	char ***aargv;
2857bdc2678Schristos /*
2867bdc2678Schristos  * Put a vector of all DIRNAME's directory entries names into *AARGV.
2877bdc2678Schristos  * Ignore names of RCS files.
2887bdc2678Schristos  * Yield the number of entries found.  Terminate the vector with 0.
2897bdc2678Schristos  * Allocate the storage for the vector and entry names.
2907bdc2678Schristos  * Do not sort the names.  Do not include '.' and '..'.
2917bdc2678Schristos  */
2927bdc2678Schristos {
2937bdc2678Schristos 	int i, entries = 0, entries_max = 64;
2947bdc2678Schristos 	size_t chars = 0, chars_max = 1024;
2957bdc2678Schristos 	size_t *offset = tnalloc(size_t, entries_max);
2967bdc2678Schristos 	char *a = tnalloc(char, chars_max), **p;
2977bdc2678Schristos 	DIR *d;
2987bdc2678Schristos 	struct dirent *e;
2997bdc2678Schristos 
3007bdc2678Schristos 	if (!(d = opendir(dirname)))
3017bdc2678Schristos 		efaterror(dirname);
3027bdc2678Schristos 	while ((errno = 0,  e = readdir(d))) {
3037bdc2678Schristos 		char const *en = e->d_name;
3047bdc2678Schristos 		size_t s = strlen(en) + 1;
3057bdc2678Schristos 		if (en[0]=='.'   &&   (!en[1]  ||  (en[1]=='.' && !en[2])))
3067bdc2678Schristos 			continue;
3077bdc2678Schristos 		if (rcssuffix(en))
3087bdc2678Schristos 			continue;
3097bdc2678Schristos 		while (chars_max < s + chars)
3107bdc2678Schristos 			a = trealloc(char, a, chars_max<<=1);
3117bdc2678Schristos 		if (entries == entries_max)
3127bdc2678Schristos 			offset = trealloc(size_t, offset, entries_max<<=1);
3137bdc2678Schristos 		offset[entries++] = chars;
3147bdc2678Schristos 		VOID strcpy(a+chars, en);
3157bdc2678Schristos 		chars += s;
3167bdc2678Schristos 	}
3177bdc2678Schristos #	if void_closedir
3187bdc2678Schristos #		define close_directory(d) (closedir(d), 0)
3197bdc2678Schristos #	else
3207bdc2678Schristos #		define close_directory(d) closedir(d)
3217bdc2678Schristos #	endif
3227bdc2678Schristos 	if (errno  ||  close_directory(d) != 0)
3237bdc2678Schristos 		efaterror(dirname);
3247bdc2678Schristos 	if (chars)
3257bdc2678Schristos 		a = trealloc(char, a, chars);
326*fa28c6faSchristos 	else {
3277bdc2678Schristos 		tfree(a);
328*fa28c6faSchristos 		a = NULL;
329*fa28c6faSchristos 	}
3307bdc2678Schristos 	*aargv = p = tnalloc(char*, entries+1);
331*fa28c6faSchristos 	if (a)
3327bdc2678Schristos 		for (i=0; i<entries; i++)
3337bdc2678Schristos 			*p++ = a + offset[i];
3347bdc2678Schristos 	*p = 0;
3357bdc2678Schristos 	tfree(offset);
3367bdc2678Schristos 	return entries;
3377bdc2678Schristos }
3387bdc2678Schristos #endif
339