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