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