1235783Skib/* Clean up working files. */ 2235783Skib 3235783Skib/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert 4235783Skib Distributed under license by the Free Software Foundation, Inc. 5235783Skib 6235783SkibThis file is part of RCS. 7235783Skib 8235783SkibRCS is free software; you can redistribute it and/or modify 9235783Skibit under the terms of the GNU General Public License as published by 10235783Skibthe Free Software Foundation; either version 2, or (at your option) 11235783Skibany later version. 12235783Skib 13235783SkibRCS is distributed in the hope that it will be useful, 14235783Skibbut WITHOUT ANY WARRANTY; without even the implied warranty of 15235783SkibMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16235783SkibGNU General Public License for more details. 17235783Skib 18235783SkibYou should have received a copy of the GNU General Public License 19235783Skibalong with RCS; see the file COPYING. 20235783SkibIf not, write to the Free Software Foundation, 21235783Skib59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22235783Skib 23235783SkibReport problems and direct all questions to: 24235783Skib 25235783Skib rcs-bugs@cs.purdue.edu 26235783Skib 27235783Skib*/ 28235783Skib 29235783Skib#include "rcsbase.h" 30235783Skib 31235783Skib#if has_dirent 32235783Skib static int get_directory P((char const*,char***)); 33235783Skib#endif 34235783Skib 35235783Skibstatic int unlock P((struct hshentry *)); 36235783Skibstatic void cleanup P((void)); 37235783Skib 38235783Skibstatic RILE *workptr; 39235783Skibstatic int exitstatus; 40235783Skib 41235783SkibmainProg(rcscleanId, "rcsclean", "$FreeBSD$") 42235783Skib{ 43235783Skib static char const usage[] = 44235783Skib "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ..."; 45235783Skib 46235783Skib static struct buf revision; 47235783Skib 48235783Skib char *a, **newargv; 49235783Skib char const *rev, *p; 50235783Skib int dounlock, expmode, perform, unlocked, unlockflag, waslocked; 51235783Skib int Ttimeflag; 52235783Skib struct hshentries *deltas; 53235783Skib struct hshentry *delta; 54235783Skib struct stat workstat; 55235783Skib 56235783Skib setrid(); 57282199Sdumbbell 58235783Skib expmode = -1; 59235783Skib rev = 0; 60235783Skib suffixes = X_DEFAULT; 61235783Skib perform = true; 62235783Skib unlockflag = false; 63235783Skib Ttimeflag = false; 64235783Skib 65282199Sdumbbell argc = getRCSINIT(argc, argv, &newargv); 66282199Sdumbbell argv = newargv; 67282199Sdumbbell for (;;) { 68282199Sdumbbell if (--argc < 1) { 69235783Skib# if has_dirent 70235783Skib argc = get_directory(".", &newargv); 71235783Skib argv = newargv; 72235783Skib break; 73235783Skib# else 74235783Skib faterror("no pathnames specified"); 75282199Sdumbbell# endif 76282199Sdumbbell } 77282199Sdumbbell a = *++argv; 78282199Sdumbbell if (!*a || *a++ != '-') 79282199Sdumbbell break; 80282199Sdumbbell switch (*a++) { 81282199Sdumbbell case 'k': 82235783Skib if (0 <= expmode) 83282199Sdumbbell redefined('k'); 84282199Sdumbbell if ((expmode = str2expmode(a)) < 0) 85235783Skib goto unknown; 86282199Sdumbbell break; 87235783Skib 88282199Sdumbbell case 'n': 89235783Skib perform = false; 90282199Sdumbbell goto handle_revision; 91282199Sdumbbell 92235783Skib case 'q': 93235783Skib quietflag = true; 94235783Skib /* fall into */ 95235783Skib case 'r': 96235783Skib handle_revision: 97282199Sdumbbell if (*a) { 98235783Skib if (rev) 99235783Skib warn("redefinition of revision number"); 100235783Skib rev = a; 101235783Skib } 102235783Skib break; 103235783Skib 104235783Skib case 'T': 105235783Skib if (*a) 106282199Sdumbbell goto unknown; 107282199Sdumbbell Ttimeflag = true; 108235783Skib break; 109235783Skib 110235783Skib case 'u': 111235783Skib unlockflag = true; 112235783Skib goto handle_revision; 113235783Skib 114235783Skib case 'V': 115235783Skib setRCSversion(*argv); 116235783Skib break; 117235783Skib 118235783Skib case 'x': 119235783Skib suffixes = a; 120282199Sdumbbell break; 121235783Skib 122282199Sdumbbell case 'z': 123235783Skib zone_set(a); 124282199Sdumbbell break; 125282199Sdumbbell 126282199Sdumbbell default: 127282199Sdumbbell unknown: 128282199Sdumbbell error("unknown option: %s%s", *argv, usage); 129282199Sdumbbell } 130282199Sdumbbell } 131235783Skib 132235783Skib dounlock = perform & unlockflag; 133235783Skib 134235783Skib if (nerror) 135235783Skib cleanup(); 136235783Skib else 137235783Skib for (; 0 < argc; cleanup(), ++argv, --argc) { 138254880Sdumbbell 139235783Skib ffree(); 140235783Skib 141282199Sdumbbell if (!( 142235783Skib 0 < pairnames( 143282199Sdumbbell argc, argv, 144235783Skib dounlock ? rcswriteopen : rcsreadopen, 145235783Skib true, true 146235783Skib ) && 147235783Skib (workptr = Iopen(workname, FOPEN_R_WORK, &workstat)) 148235783Skib )) 149235783Skib continue; 150282199Sdumbbell 151282199Sdumbbell if (same_file(RCSstat, workstat, 0)) { 152282199Sdumbbell rcserror("RCS file is the same as working file %s.", 153282199Sdumbbell workname 154235783Skib ); 155235783Skib continue; 156235783Skib } 157235783Skib 158282199Sdumbbell gettree(); 159235783Skib 160282199Sdumbbell p = 0; 161282199Sdumbbell if (rev) { 162235783Skib if (!fexpandsym(rev, &revision, workptr)) 163235783Skib continue; 164235783Skib p = revision.string; 165235783Skib } else if (Head) 166282199Sdumbbell switch (unlockflag ? findlock(false,&delta) : 0) { 167235783Skib default: 168282199Sdumbbell continue; 169235783Skib case 0: 170282199Sdumbbell p = Dbranch ? Dbranch : ""; 171282199Sdumbbell break; 172282199Sdumbbell case 1: 173235783Skib p = delta->num; 174282199Sdumbbell break; 175282199Sdumbbell } 176282199Sdumbbell delta = 0; 177282199Sdumbbell deltas = 0; /* Keep lint happy. */ 178282199Sdumbbell if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas))) 179282199Sdumbbell continue; 180282199Sdumbbell 181282199Sdumbbell waslocked = delta && delta->lockedby; 182282199Sdumbbell locker_expansion = unlock(delta); 183282199Sdumbbell unlocked = locker_expansion & unlockflag; 184282199Sdumbbell if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH)) 185282199Sdumbbell continue; 186282199Sdumbbell 187282199Sdumbbell if (unlocked && !checkaccesslist()) 188282199Sdumbbell continue; 189282199Sdumbbell 190282199Sdumbbell if (dorewrite(dounlock, unlocked) != 0) 191235783Skib continue; 192282199Sdumbbell 193235783Skib if (0 <= expmode) 194282199Sdumbbell Expand = expmode; 195282199Sdumbbell else if ( 196282199Sdumbbell waslocked && 197282199Sdumbbell Expand == KEYVAL_EXPAND && 198235783Skib WORKMODE(RCSstat.st_mode,true) == workstat.st_mode 199235783Skib ) 200282199Sdumbbell Expand = KEYVALLOCK_EXPAND; 201282199Sdumbbell 202282199Sdumbbell getdesc(false); 203235783Skib 204282199Sdumbbell if ( 205282199Sdumbbell !delta ? workstat.st_size!=0 : 206282199Sdumbbell 0 < rcsfcmp( 207282199Sdumbbell workptr, &workstat, 208282199Sdumbbell buildrevision(deltas, delta, (FILE*)0, false), 209235783Skib delta 210282199Sdumbbell ) 211235783Skib ) 212282199Sdumbbell continue; 213282199Sdumbbell 214282199Sdumbbell if (quietflag < unlocked) 215282199Sdumbbell aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname); 216282199Sdumbbell 217282199Sdumbbell if (perform & unlocked) { 218282199Sdumbbell if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL); 219282199Sdumbbell if (donerewrite(true, 220282199Sdumbbell Ttimeflag ? RCSstat.st_mtime : (time_t)-1 221235783Skib ) != 0) 222282199Sdumbbell continue; 223282199Sdumbbell } 224235783Skib 225282199Sdumbbell if (!quietflag) 226282199Sdumbbell aprintf(stdout, "rm -f %s\n", workname); 227282199Sdumbbell Izclose(&workptr); 228282199Sdumbbell if (perform && un_link(workname) != 0) 229282199Sdumbbell eerror(workname); 230282199Sdumbbell 231282199Sdumbbell } 232282199Sdumbbell 233282199Sdumbbell tempunlink(); 234282199Sdumbbell if (!quietflag) 235282199Sdumbbell Ofclose(stdout); 236282199Sdumbbell exitmain(exitstatus); 237282199Sdumbbell} 238282199Sdumbbell 239282199Sdumbbell static void 240282199Sdumbbellcleanup() 241235783Skib{ 242282199Sdumbbell if (nerror) exitstatus = EXIT_FAILURE; 243235783Skib Izclose(&finptr); 244235783Skib Izclose(&workptr); 245282199Sdumbbell Ozclose(&fcopy); 246235783Skib ORCSclose(); 247282199Sdumbbell dirtempunlink(); 248282199Sdumbbell} 249282199Sdumbbell 250235783Skib#if RCS_lint 251282199Sdumbbell# define exiterr rcscleanExit 252235783Skib#endif 253282199Sdumbbell void 254282199Sdumbbellexiterr() 255282199Sdumbbell{ 256282199Sdumbbell ORCSerror(); 257235783Skib dirtempunlink(); 258282199Sdumbbell tempunlink(); 259235783Skib _exit(EXIT_FAILURE); 260282199Sdumbbell} 261282199Sdumbbell 262235783Skib static int 263282199Sdumbbellunlock(delta) 264282199Sdumbbell struct hshentry *delta; 265282199Sdumbbell{ 266235783Skib register struct rcslock **al, *l; 267282199Sdumbbell 268282199Sdumbbell if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0) 269235783Skib for (al = &Locks; (l = *al); al = &l->nextlock) 270282199Sdumbbell if (l->delta == delta) { 271282199Sdumbbell *al = l->nextlock; 272282199Sdumbbell delta->lockedby = 0; 273282199Sdumbbell return true; 274282199Sdumbbell } 275282199Sdumbbell return false; 276235783Skib} 277282199Sdumbbell 278235783Skib#if has_dirent 279282199Sdumbbell static int 280235783Skibget_directory(dirname, aargv) 281282199Sdumbbell char const *dirname; 282235783Skib char ***aargv; 283282199Sdumbbell/* 284282199Sdumbbell * Put a vector of all DIRNAME's directory entries names into *AARGV. 285282199Sdumbbell * Ignore names of RCS files. 286282199Sdumbbell * Yield the number of entries found. Terminate the vector with 0. 287235783Skib * Allocate the storage for the vector and entry names. 288282199Sdumbbell * Do not sort the names. Do not include '.' and '..'. 289235783Skib */ 290282199Sdumbbell{ 291282199Sdumbbell int i, entries = 0, entries_max = 64; 292235783Skib size_t chars = 0, chars_max = 1024; 293282199Sdumbbell size_t *offset = tnalloc(size_t, entries_max); 294235783Skib char *a = tnalloc(char, chars_max), **p; 295282199Sdumbbell DIR *d; 296235783Skib struct dirent *e; 297235783Skib 298282199Sdumbbell if (!(d = opendir(dirname))) 299282199Sdumbbell efaterror(dirname); 300235783Skib while ((errno = 0, e = readdir(d))) { 301282199Sdumbbell char const *en = e->d_name; 302254836Sdumbbell size_t s = strlen(en) + 1; 303235783Skib if (en[0]=='.' && (!en[1] || (en[1]=='.' && !en[2]))) 304282199Sdumbbell continue; 305282199Sdumbbell if (rcssuffix(en)) 306254836Sdumbbell continue; 307282199Sdumbbell while (chars_max < s + chars) 308254836Sdumbbell a = trealloc(char, a, chars_max<<=1); 309282199Sdumbbell if (entries == entries_max) 310235783Skib offset = trealloc(size_t, offset, entries_max<<=1); 311235783Skib offset[entries++] = chars; 312235783Skib VOID strcpy(a+chars, en); 313282199Sdumbbell chars += s; 314282199Sdumbbell } 315235783Skib# if void_closedir 316282199Sdumbbell# define close_directory(d) (closedir(d), 0) 317235783Skib# else 318282199Sdumbbell# define close_directory(d) closedir(d) 319235783Skib# endif 320282199Sdumbbell if (errno || close_directory(d) != 0) 321282199Sdumbbell efaterror(dirname); 322282199Sdumbbell if (chars) 323282199Sdumbbell a = trealloc(char, a, chars); 324235783Skib else 325282199Sdumbbell tfree(a); 326254836Sdumbbell *aargv = p = tnalloc(char*, entries+1); 327282199Sdumbbell for (i=0; i<entries; i++) 328282199Sdumbbell *p++ = a + offset[i]; 329282199Sdumbbell *p = 0; 330282199Sdumbbell tfree(offset); 331282199Sdumbbell return entries; 332282199Sdumbbell} 333282199Sdumbbell#endif 334282199Sdumbbell