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 8This file is part of RCS. 9 10RCS is free software; you can redistribute it and/or modify 11it under the terms of the GNU General Public License as published by 12the Free Software Foundation; either version 2, or (at your option) 13any later version. 14 15RCS is distributed in the hope that it will be useful, 16but WITHOUT ANY WARRANTY; without even the implied warranty of 17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18GNU General Public License for more details. 19 20You should have received a copy of the GNU General Public License 21along with RCS; see the file COPYING. 22If not, write to the Free Software Foundation, 2359 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 25Report 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 37static int unlock P((struct hshentry *)); 38static void cleanup P((void)); 39 40static RILE *workptr; 41static int exitstatus; 42 43mainProg(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 242cleanup() 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 256exiterr() 257{ 258 ORCSerror(); 259 dirtempunlink(); 260 tempunlink(); 261 _exit(EXIT_FAILURE); 262} 263 264 static int 265unlock(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 282get_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