xref: /dflybsd-src/gnu/usr.bin/rcs/rcsclean/rcsclean.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* Clean up working files.  */
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino /* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
486d7f5d3SJohn Marino    Distributed under license by the Free Software Foundation, Inc.
586d7f5d3SJohn Marino 
686d7f5d3SJohn Marino This file is part of RCS.
786d7f5d3SJohn Marino 
886d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
986d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
1086d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
1186d7f5d3SJohn Marino any later version.
1286d7f5d3SJohn Marino 
1386d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
1486d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1586d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1686d7f5d3SJohn Marino GNU General Public License for more details.
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
1986d7f5d3SJohn Marino along with RCS; see the file COPYING.
2086d7f5d3SJohn Marino If not, write to the Free Software Foundation,
2186d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2286d7f5d3SJohn Marino 
2386d7f5d3SJohn Marino Report problems and direct all questions to:
2486d7f5d3SJohn Marino 
2586d7f5d3SJohn Marino 	rcs-bugs@cs.purdue.edu
2686d7f5d3SJohn Marino 
2786d7f5d3SJohn Marino */
2886d7f5d3SJohn Marino /*
2986d7f5d3SJohn Marino  * $FreeBSD: src/gnu/usr.bin/rcs/rcsclean/rcsclean.c,v 1.5 1999/08/27 23:36:54 peter Exp $
3086d7f5d3SJohn Marino  * $DragonFly: src/gnu/usr.bin/rcs/rcsclean/rcsclean.c,v 1.2 2003/06/17 04:25:48 dillon Exp $
3186d7f5d3SJohn Marino  */
3286d7f5d3SJohn Marino 
3386d7f5d3SJohn Marino #include "rcsbase.h"
3486d7f5d3SJohn Marino 
3586d7f5d3SJohn Marino #if has_dirent
3686d7f5d3SJohn Marino 	static int get_directory P((char const*,char***));
3786d7f5d3SJohn Marino #endif
3886d7f5d3SJohn Marino 
3986d7f5d3SJohn Marino static int unlock P((struct hshentry *));
4086d7f5d3SJohn Marino static void cleanup P((void));
4186d7f5d3SJohn Marino 
4286d7f5d3SJohn Marino static RILE *workptr;
4386d7f5d3SJohn Marino static int exitstatus;
4486d7f5d3SJohn Marino 
4586d7f5d3SJohn Marino mainProg(rcscleanId, "rcsclean", "$DragonFly: src/gnu/usr.bin/rcs/rcsclean/rcsclean.c,v 1.2 2003/06/17 04:25:48 dillon Exp $")
4686d7f5d3SJohn Marino {
4786d7f5d3SJohn Marino 	static char const usage[] =
4886d7f5d3SJohn Marino 		"\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
4986d7f5d3SJohn Marino 
5086d7f5d3SJohn Marino 	static struct buf revision;
5186d7f5d3SJohn Marino 
5286d7f5d3SJohn Marino 	char *a, **newargv;
5386d7f5d3SJohn Marino 	char const *rev, *p;
5486d7f5d3SJohn Marino 	int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
5586d7f5d3SJohn Marino 	int Ttimeflag;
5686d7f5d3SJohn Marino 	struct hshentries *deltas;
5786d7f5d3SJohn Marino 	struct hshentry *delta;
5886d7f5d3SJohn Marino 	struct stat workstat;
5986d7f5d3SJohn Marino 
6086d7f5d3SJohn Marino 	setrid();
6186d7f5d3SJohn Marino 
6286d7f5d3SJohn Marino 	expmode = -1;
6386d7f5d3SJohn Marino 	rev = 0;
6486d7f5d3SJohn Marino 	suffixes = X_DEFAULT;
6586d7f5d3SJohn Marino 	perform = true;
6686d7f5d3SJohn Marino 	unlockflag = false;
6786d7f5d3SJohn Marino 	Ttimeflag = false;
6886d7f5d3SJohn Marino 
6986d7f5d3SJohn Marino 	argc = getRCSINIT(argc, argv, &newargv);
7086d7f5d3SJohn Marino 	argv = newargv;
7186d7f5d3SJohn Marino 	for (;;) {
7286d7f5d3SJohn Marino 		if (--argc < 1) {
7386d7f5d3SJohn Marino #			if has_dirent
7486d7f5d3SJohn Marino 				argc = get_directory(".", &newargv);
7586d7f5d3SJohn Marino 				argv = newargv;
7686d7f5d3SJohn Marino 				break;
7786d7f5d3SJohn Marino #			else
7886d7f5d3SJohn Marino 				faterror("no pathnames specified");
7986d7f5d3SJohn Marino #			endif
8086d7f5d3SJohn Marino 		}
8186d7f5d3SJohn Marino 		a = *++argv;
8286d7f5d3SJohn Marino 		if (!*a  ||  *a++ != '-')
8386d7f5d3SJohn Marino 			break;
8486d7f5d3SJohn Marino 		switch (*a++) {
8586d7f5d3SJohn Marino 			case 'k':
8686d7f5d3SJohn Marino 				if (0 <= expmode)
8786d7f5d3SJohn Marino 					redefined('k');
8886d7f5d3SJohn Marino 				if ((expmode = str2expmode(a))  <  0)
8986d7f5d3SJohn Marino 					goto unknown;
9086d7f5d3SJohn Marino 				break;
9186d7f5d3SJohn Marino 
9286d7f5d3SJohn Marino 			case 'n':
9386d7f5d3SJohn Marino 				perform = false;
9486d7f5d3SJohn Marino 				goto handle_revision;
9586d7f5d3SJohn Marino 
9686d7f5d3SJohn Marino 			case 'q':
9786d7f5d3SJohn Marino 				quietflag = true;
9886d7f5d3SJohn Marino 				/* fall into */
9986d7f5d3SJohn Marino 			case 'r':
10086d7f5d3SJohn Marino 			handle_revision:
10186d7f5d3SJohn Marino 				if (*a) {
10286d7f5d3SJohn Marino 					if (rev)
10386d7f5d3SJohn Marino 						warn("redefinition of revision number");
10486d7f5d3SJohn Marino 					rev = a;
10586d7f5d3SJohn Marino 				}
10686d7f5d3SJohn Marino 				break;
10786d7f5d3SJohn Marino 
10886d7f5d3SJohn Marino 			case 'T':
10986d7f5d3SJohn Marino 				if (*a)
11086d7f5d3SJohn Marino 					goto unknown;
11186d7f5d3SJohn Marino 				Ttimeflag = true;
11286d7f5d3SJohn Marino 				break;
11386d7f5d3SJohn Marino 
11486d7f5d3SJohn Marino 			case 'u':
11586d7f5d3SJohn Marino 				unlockflag = true;
11686d7f5d3SJohn Marino 				goto handle_revision;
11786d7f5d3SJohn Marino 
11886d7f5d3SJohn Marino 			case 'V':
11986d7f5d3SJohn Marino 				setRCSversion(*argv);
12086d7f5d3SJohn Marino 				break;
12186d7f5d3SJohn Marino 
12286d7f5d3SJohn Marino 			case 'x':
12386d7f5d3SJohn Marino 				suffixes = a;
12486d7f5d3SJohn Marino 				break;
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino 			case 'z':
12786d7f5d3SJohn Marino 				zone_set(a);
12886d7f5d3SJohn Marino 				break;
12986d7f5d3SJohn Marino 
13086d7f5d3SJohn Marino 			default:
13186d7f5d3SJohn Marino 			unknown:
13286d7f5d3SJohn Marino 				error("unknown option: %s%s", *argv, usage);
13386d7f5d3SJohn Marino 		}
13486d7f5d3SJohn Marino 	}
13586d7f5d3SJohn Marino 
13686d7f5d3SJohn Marino 	dounlock = perform & unlockflag;
13786d7f5d3SJohn Marino 
13886d7f5d3SJohn Marino 	if (nerror)
13986d7f5d3SJohn Marino 	  cleanup();
14086d7f5d3SJohn Marino 	else
14186d7f5d3SJohn Marino 	  for (;  0 < argc;  cleanup(), ++argv, --argc) {
14286d7f5d3SJohn Marino 
14386d7f5d3SJohn Marino 		ffree();
14486d7f5d3SJohn Marino 
14586d7f5d3SJohn Marino 		if (!(
14686d7f5d3SJohn Marino 			0 < pairnames(
14786d7f5d3SJohn Marino 				argc, argv,
14886d7f5d3SJohn Marino 				dounlock ? rcswriteopen : rcsreadopen,
14986d7f5d3SJohn Marino 				true, true
15086d7f5d3SJohn Marino 			) &&
15186d7f5d3SJohn Marino 			(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
15286d7f5d3SJohn Marino 		))
15386d7f5d3SJohn Marino 			continue;
15486d7f5d3SJohn Marino 
15586d7f5d3SJohn Marino 		if (same_file(RCSstat, workstat, 0)) {
15686d7f5d3SJohn Marino 			rcserror("RCS file is the same as working file %s.",
15786d7f5d3SJohn Marino 				workname
15886d7f5d3SJohn Marino 			);
15986d7f5d3SJohn Marino 			continue;
16086d7f5d3SJohn Marino 		}
16186d7f5d3SJohn Marino 
16286d7f5d3SJohn Marino 		gettree();
16386d7f5d3SJohn Marino 
16486d7f5d3SJohn Marino 		p = 0;
16586d7f5d3SJohn Marino 		if (rev) {
16686d7f5d3SJohn Marino 			if (!fexpandsym(rev, &revision, workptr))
16786d7f5d3SJohn Marino 				continue;
16886d7f5d3SJohn Marino 			p = revision.string;
16986d7f5d3SJohn Marino 		} else if (Head)
17086d7f5d3SJohn Marino 			switch (unlockflag ? findlock(false,&delta) : 0) {
17186d7f5d3SJohn Marino 				default:
17286d7f5d3SJohn Marino 					continue;
17386d7f5d3SJohn Marino 				case 0:
17486d7f5d3SJohn Marino 					p = Dbranch ? Dbranch : "";
17586d7f5d3SJohn Marino 					break;
17686d7f5d3SJohn Marino 				case 1:
17786d7f5d3SJohn Marino 					p = delta->num;
17886d7f5d3SJohn Marino 					break;
17986d7f5d3SJohn Marino 			}
18086d7f5d3SJohn Marino 		delta = 0;
18186d7f5d3SJohn Marino 		deltas = 0;  /* Keep lint happy.  */
18286d7f5d3SJohn Marino 		if (p  &&  !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
18386d7f5d3SJohn Marino 			continue;
18486d7f5d3SJohn Marino 
18586d7f5d3SJohn Marino 		waslocked = delta && delta->lockedby;
18686d7f5d3SJohn Marino 		locker_expansion = unlock(delta);
18786d7f5d3SJohn Marino 		unlocked = locker_expansion & unlockflag;
18886d7f5d3SJohn Marino 		if (unlocked<waslocked  &&  workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
18986d7f5d3SJohn Marino 			continue;
19086d7f5d3SJohn Marino 
19186d7f5d3SJohn Marino 		if (unlocked && !checkaccesslist())
19286d7f5d3SJohn Marino 			continue;
19386d7f5d3SJohn Marino 
19486d7f5d3SJohn Marino 		if (dorewrite(dounlock, unlocked) != 0)
19586d7f5d3SJohn Marino 			continue;
19686d7f5d3SJohn Marino 
19786d7f5d3SJohn Marino 		if (0 <= expmode)
19886d7f5d3SJohn Marino 			Expand = expmode;
19986d7f5d3SJohn Marino 		else if (
20086d7f5d3SJohn Marino 			waslocked  &&
20186d7f5d3SJohn Marino 			Expand == KEYVAL_EXPAND  &&
20286d7f5d3SJohn Marino 			WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
20386d7f5d3SJohn Marino 		)
20486d7f5d3SJohn Marino 			Expand = KEYVALLOCK_EXPAND;
20586d7f5d3SJohn Marino 
20686d7f5d3SJohn Marino 		getdesc(false);
20786d7f5d3SJohn Marino 
20886d7f5d3SJohn Marino 		if (
20986d7f5d3SJohn Marino 			!delta ? workstat.st_size!=0 :
21086d7f5d3SJohn Marino 			0 < rcsfcmp(
21186d7f5d3SJohn Marino 				workptr, &workstat,
21286d7f5d3SJohn Marino 				buildrevision(deltas, delta, (FILE*)0, false),
21386d7f5d3SJohn Marino 				delta
21486d7f5d3SJohn Marino 			)
21586d7f5d3SJohn Marino 		)
21686d7f5d3SJohn Marino 			continue;
21786d7f5d3SJohn Marino 
21886d7f5d3SJohn Marino 		if (quietflag < unlocked)
21986d7f5d3SJohn Marino 			aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
22086d7f5d3SJohn Marino 
22186d7f5d3SJohn Marino 		if (perform & unlocked) {
22286d7f5d3SJohn Marino 			if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
22386d7f5d3SJohn Marino 			if (donerewrite(true,
22486d7f5d3SJohn Marino 				Ttimeflag ? RCSstat.st_mtime : (time_t)-1
22586d7f5d3SJohn Marino 			) != 0)
22686d7f5d3SJohn Marino 				continue;
22786d7f5d3SJohn Marino 		}
22886d7f5d3SJohn Marino 
22986d7f5d3SJohn Marino 		if (!quietflag)
23086d7f5d3SJohn Marino 			aprintf(stdout, "rm -f %s\n", workname);
23186d7f5d3SJohn Marino 		Izclose(&workptr);
23286d7f5d3SJohn Marino 		if (perform  &&  un_link(workname) != 0)
23386d7f5d3SJohn Marino 			eerror(workname);
23486d7f5d3SJohn Marino 
23586d7f5d3SJohn Marino 	  }
23686d7f5d3SJohn Marino 
23786d7f5d3SJohn Marino 	tempunlink();
23886d7f5d3SJohn Marino 	if (!quietflag)
23986d7f5d3SJohn Marino 		Ofclose(stdout);
24086d7f5d3SJohn Marino 	exitmain(exitstatus);
24186d7f5d3SJohn Marino }
24286d7f5d3SJohn Marino 
24386d7f5d3SJohn Marino 	static void
cleanup()24486d7f5d3SJohn Marino cleanup()
24586d7f5d3SJohn Marino {
24686d7f5d3SJohn Marino 	if (nerror) exitstatus = EXIT_FAILURE;
24786d7f5d3SJohn Marino 	Izclose(&finptr);
24886d7f5d3SJohn Marino 	Izclose(&workptr);
24986d7f5d3SJohn Marino 	Ozclose(&fcopy);
25086d7f5d3SJohn Marino 	ORCSclose();
25186d7f5d3SJohn Marino 	dirtempunlink();
25286d7f5d3SJohn Marino }
25386d7f5d3SJohn Marino 
25486d7f5d3SJohn Marino #if RCS_lint
25586d7f5d3SJohn Marino #	define exiterr rcscleanExit
25686d7f5d3SJohn Marino #endif
25786d7f5d3SJohn Marino 	void
exiterr()25886d7f5d3SJohn Marino exiterr()
25986d7f5d3SJohn Marino {
26086d7f5d3SJohn Marino 	ORCSerror();
26186d7f5d3SJohn Marino 	dirtempunlink();
26286d7f5d3SJohn Marino 	tempunlink();
26386d7f5d3SJohn Marino 	_exit(EXIT_FAILURE);
26486d7f5d3SJohn Marino }
26586d7f5d3SJohn Marino 
26686d7f5d3SJohn Marino 	static int
unlock(delta)26786d7f5d3SJohn Marino unlock(delta)
26886d7f5d3SJohn Marino 	struct hshentry *delta;
26986d7f5d3SJohn Marino {
27086d7f5d3SJohn Marino 	register struct rcslock **al, *l;
27186d7f5d3SJohn Marino 
27286d7f5d3SJohn Marino 	if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
27386d7f5d3SJohn Marino 		for (al = &Locks;  (l = *al);  al = &l->nextlock)
27486d7f5d3SJohn Marino 			if (l->delta == delta) {
27586d7f5d3SJohn Marino 				*al = l->nextlock;
27686d7f5d3SJohn Marino 				delta->lockedby = 0;
27786d7f5d3SJohn Marino 				return true;
27886d7f5d3SJohn Marino 			}
27986d7f5d3SJohn Marino 	return false;
28086d7f5d3SJohn Marino }
28186d7f5d3SJohn Marino 
28286d7f5d3SJohn Marino #if has_dirent
28386d7f5d3SJohn Marino 	static int
get_directory(dirname,aargv)28486d7f5d3SJohn Marino get_directory(dirname, aargv)
28586d7f5d3SJohn Marino 	char const *dirname;
28686d7f5d3SJohn Marino 	char ***aargv;
28786d7f5d3SJohn Marino /*
28886d7f5d3SJohn Marino  * Put a vector of all DIRNAME's directory entries names into *AARGV.
28986d7f5d3SJohn Marino  * Ignore names of RCS files.
29086d7f5d3SJohn Marino  * Yield the number of entries found.  Terminate the vector with 0.
29186d7f5d3SJohn Marino  * Allocate the storage for the vector and entry names.
29286d7f5d3SJohn Marino  * Do not sort the names.  Do not include '.' and '..'.
29386d7f5d3SJohn Marino  */
29486d7f5d3SJohn Marino {
29586d7f5d3SJohn Marino 	int i, entries = 0, entries_max = 64;
29686d7f5d3SJohn Marino 	size_t chars = 0, chars_max = 1024;
29786d7f5d3SJohn Marino 	size_t *offset = tnalloc(size_t, entries_max);
29886d7f5d3SJohn Marino 	char *a = tnalloc(char, chars_max), **p;
29986d7f5d3SJohn Marino 	DIR *d;
30086d7f5d3SJohn Marino 	struct dirent *e;
30186d7f5d3SJohn Marino 
30286d7f5d3SJohn Marino 	if (!(d = opendir(dirname)))
30386d7f5d3SJohn Marino 		efaterror(dirname);
30486d7f5d3SJohn Marino 	while ((errno = 0,  e = readdir(d))) {
30586d7f5d3SJohn Marino 		char const *en = e->d_name;
30686d7f5d3SJohn Marino 		size_t s = strlen(en) + 1;
30786d7f5d3SJohn Marino 		if (en[0]=='.'   &&   (!en[1]  ||  (en[1]=='.' && !en[2])))
30886d7f5d3SJohn Marino 			continue;
30986d7f5d3SJohn Marino 		if (rcssuffix(en))
31086d7f5d3SJohn Marino 			continue;
31186d7f5d3SJohn Marino 		while (chars_max < s + chars)
31286d7f5d3SJohn Marino 			a = trealloc(char, a, chars_max<<=1);
31386d7f5d3SJohn Marino 		if (entries == entries_max)
31486d7f5d3SJohn Marino 			offset = trealloc(size_t, offset, entries_max<<=1);
31586d7f5d3SJohn Marino 		offset[entries++] = chars;
31686d7f5d3SJohn Marino 		VOID strcpy(a+chars, en);
31786d7f5d3SJohn Marino 		chars += s;
31886d7f5d3SJohn Marino 	}
31986d7f5d3SJohn Marino #	if void_closedir
32086d7f5d3SJohn Marino #		define close_directory(d) (closedir(d), 0)
32186d7f5d3SJohn Marino #	else
32286d7f5d3SJohn Marino #		define close_directory(d) closedir(d)
32386d7f5d3SJohn Marino #	endif
32486d7f5d3SJohn Marino 	if (errno  ||  close_directory(d) != 0)
32586d7f5d3SJohn Marino 		efaterror(dirname);
32686d7f5d3SJohn Marino 	if (chars)
32786d7f5d3SJohn Marino 		a = trealloc(char, a, chars);
32886d7f5d3SJohn Marino 	else
32986d7f5d3SJohn Marino 		tfree(a);
33086d7f5d3SJohn Marino 	*aargv = p = tnalloc(char*, entries+1);
33186d7f5d3SJohn Marino 	for (i=0; i<entries; i++)
33286d7f5d3SJohn Marino 		*p++ = a + offset[i];
33386d7f5d3SJohn Marino 	*p = 0;
33486d7f5d3SJohn Marino 	tfree(offset);
33586d7f5d3SJohn Marino 	return entries;
33686d7f5d3SJohn Marino }
33786d7f5d3SJohn Marino #endif
338