xref: /dragonfly/gnu/usr.bin/rcs/rcsclean/rcsclean.c (revision 984263bc)
1 /* Clean up working files.  */
2 
3 /* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
4    Distributed under license by the Free Software Foundation, Inc.
5 
6 This file is part of RCS.
7 
8 RCS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12 
13 RCS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with RCS; see the file COPYING.
20 If not, write to the Free Software Foundation,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 Report problems and direct all questions to:
24 
25 	rcs-bugs@cs.purdue.edu
26 
27 */
28 
29 #include "rcsbase.h"
30 
31 #if has_dirent
32 	static int get_directory P((char const*,char***));
33 #endif
34 
35 static int unlock P((struct hshentry *));
36 static void cleanup P((void));
37 
38 static RILE *workptr;
39 static int exitstatus;
40 
41 mainProg(rcscleanId, "rcsclean", "$FreeBSD: src/gnu/usr.bin/rcs/rcsclean/rcsclean.c,v 1.5 1999/08/27 23:36:54 peter Exp $")
42 {
43 	static char const usage[] =
44 		"\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
45 
46 	static struct buf revision;
47 
48 	char *a, **newargv;
49 	char const *rev, *p;
50 	int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
51 	int Ttimeflag;
52 	struct hshentries *deltas;
53 	struct hshentry *delta;
54 	struct stat workstat;
55 
56 	setrid();
57 
58 	expmode = -1;
59 	rev = 0;
60 	suffixes = X_DEFAULT;
61 	perform = true;
62 	unlockflag = false;
63 	Ttimeflag = false;
64 
65 	argc = getRCSINIT(argc, argv, &newargv);
66 	argv = newargv;
67 	for (;;) {
68 		if (--argc < 1) {
69 #			if has_dirent
70 				argc = get_directory(".", &newargv);
71 				argv = newargv;
72 				break;
73 #			else
74 				faterror("no pathnames specified");
75 #			endif
76 		}
77 		a = *++argv;
78 		if (!*a  ||  *a++ != '-')
79 			break;
80 		switch (*a++) {
81 			case 'k':
82 				if (0 <= expmode)
83 					redefined('k');
84 				if ((expmode = str2expmode(a))  <  0)
85 					goto unknown;
86 				break;
87 
88 			case 'n':
89 				perform = false;
90 				goto handle_revision;
91 
92 			case 'q':
93 				quietflag = true;
94 				/* fall into */
95 			case 'r':
96 			handle_revision:
97 				if (*a) {
98 					if (rev)
99 						warn("redefinition of revision number");
100 					rev = a;
101 				}
102 				break;
103 
104 			case 'T':
105 				if (*a)
106 					goto unknown;
107 				Ttimeflag = true;
108 				break;
109 
110 			case 'u':
111 				unlockflag = true;
112 				goto handle_revision;
113 
114 			case 'V':
115 				setRCSversion(*argv);
116 				break;
117 
118 			case 'x':
119 				suffixes = a;
120 				break;
121 
122 			case 'z':
123 				zone_set(a);
124 				break;
125 
126 			default:
127 			unknown:
128 				error("unknown option: %s%s", *argv, usage);
129 		}
130 	}
131 
132 	dounlock = perform & unlockflag;
133 
134 	if (nerror)
135 	  cleanup();
136 	else
137 	  for (;  0 < argc;  cleanup(), ++argv, --argc) {
138 
139 		ffree();
140 
141 		if (!(
142 			0 < pairnames(
143 				argc, argv,
144 				dounlock ? rcswriteopen : rcsreadopen,
145 				true, true
146 			) &&
147 			(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
148 		))
149 			continue;
150 
151 		if (same_file(RCSstat, workstat, 0)) {
152 			rcserror("RCS file is the same as working file %s.",
153 				workname
154 			);
155 			continue;
156 		}
157 
158 		gettree();
159 
160 		p = 0;
161 		if (rev) {
162 			if (!fexpandsym(rev, &revision, workptr))
163 				continue;
164 			p = revision.string;
165 		} else if (Head)
166 			switch (unlockflag ? findlock(false,&delta) : 0) {
167 				default:
168 					continue;
169 				case 0:
170 					p = Dbranch ? Dbranch : "";
171 					break;
172 				case 1:
173 					p = delta->num;
174 					break;
175 			}
176 		delta = 0;
177 		deltas = 0;  /* Keep lint happy.  */
178 		if (p  &&  !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
179 			continue;
180 
181 		waslocked = delta && delta->lockedby;
182 		locker_expansion = unlock(delta);
183 		unlocked = locker_expansion & unlockflag;
184 		if (unlocked<waslocked  &&  workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
185 			continue;
186 
187 		if (unlocked && !checkaccesslist())
188 			continue;
189 
190 		if (dorewrite(dounlock, unlocked) != 0)
191 			continue;
192 
193 		if (0 <= expmode)
194 			Expand = expmode;
195 		else if (
196 			waslocked  &&
197 			Expand == KEYVAL_EXPAND  &&
198 			WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
199 		)
200 			Expand = KEYVALLOCK_EXPAND;
201 
202 		getdesc(false);
203 
204 		if (
205 			!delta ? workstat.st_size!=0 :
206 			0 < rcsfcmp(
207 				workptr, &workstat,
208 				buildrevision(deltas, delta, (FILE*)0, false),
209 				delta
210 			)
211 		)
212 			continue;
213 
214 		if (quietflag < unlocked)
215 			aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
216 
217 		if (perform & unlocked) {
218 			if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
219 			if (donerewrite(true,
220 				Ttimeflag ? RCSstat.st_mtime : (time_t)-1
221 			) != 0)
222 				continue;
223 		}
224 
225 		if (!quietflag)
226 			aprintf(stdout, "rm -f %s\n", workname);
227 		Izclose(&workptr);
228 		if (perform  &&  un_link(workname) != 0)
229 			eerror(workname);
230 
231 	  }
232 
233 	tempunlink();
234 	if (!quietflag)
235 		Ofclose(stdout);
236 	exitmain(exitstatus);
237 }
238 
239 	static void
240 cleanup()
241 {
242 	if (nerror) exitstatus = EXIT_FAILURE;
243 	Izclose(&finptr);
244 	Izclose(&workptr);
245 	Ozclose(&fcopy);
246 	ORCSclose();
247 	dirtempunlink();
248 }
249 
250 #if RCS_lint
251 #	define exiterr rcscleanExit
252 #endif
253 	void
254 exiterr()
255 {
256 	ORCSerror();
257 	dirtempunlink();
258 	tempunlink();
259 	_exit(EXIT_FAILURE);
260 }
261 
262 	static int
263 unlock(delta)
264 	struct hshentry *delta;
265 {
266 	register struct rcslock **al, *l;
267 
268 	if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
269 		for (al = &Locks;  (l = *al);  al = &l->nextlock)
270 			if (l->delta == delta) {
271 				*al = l->nextlock;
272 				delta->lockedby = 0;
273 				return true;
274 			}
275 	return false;
276 }
277 
278 #if has_dirent
279 	static int
280 get_directory(dirname, aargv)
281 	char const *dirname;
282 	char ***aargv;
283 /*
284  * Put a vector of all DIRNAME's directory entries names into *AARGV.
285  * Ignore names of RCS files.
286  * Yield the number of entries found.  Terminate the vector with 0.
287  * Allocate the storage for the vector and entry names.
288  * Do not sort the names.  Do not include '.' and '..'.
289  */
290 {
291 	int i, entries = 0, entries_max = 64;
292 	size_t chars = 0, chars_max = 1024;
293 	size_t *offset = tnalloc(size_t, entries_max);
294 	char *a = tnalloc(char, chars_max), **p;
295 	DIR *d;
296 	struct dirent *e;
297 
298 	if (!(d = opendir(dirname)))
299 		efaterror(dirname);
300 	while ((errno = 0,  e = readdir(d))) {
301 		char const *en = e->d_name;
302 		size_t s = strlen(en) + 1;
303 		if (en[0]=='.'   &&   (!en[1]  ||  (en[1]=='.' && !en[2])))
304 			continue;
305 		if (rcssuffix(en))
306 			continue;
307 		while (chars_max < s + chars)
308 			a = trealloc(char, a, chars_max<<=1);
309 		if (entries == entries_max)
310 			offset = trealloc(size_t, offset, entries_max<<=1);
311 		offset[entries++] = chars;
312 		VOID strcpy(a+chars, en);
313 		chars += s;
314 	}
315 #	if void_closedir
316 #		define close_directory(d) (closedir(d), 0)
317 #	else
318 #		define close_directory(d) closedir(d)
319 #	endif
320 	if (errno  ||  close_directory(d) != 0)
321 		efaterror(dirname);
322 	if (chars)
323 		a = trealloc(char, a, chars);
324 	else
325 		tfree(a);
326 	*aargv = p = tnalloc(char*, entries+1);
327 	for (i=0; i<entries; i++)
328 		*p++ = a + offset[i];
329 	*p = 0;
330 	tfree(offset);
331 	return entries;
332 }
333 #endif
334