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