111891Speter/* Clean up working files. */ 29Sjkh 311891Speter/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert 49Sjkh Distributed under license by the Free Software Foundation, Inc. 59Sjkh 69SjkhThis file is part of RCS. 79Sjkh 89SjkhRCS is free software; you can redistribute it and/or modify 99Sjkhit under the terms of the GNU General Public License as published by 109Sjkhthe Free Software Foundation; either version 2, or (at your option) 119Sjkhany later version. 129Sjkh 139SjkhRCS is distributed in the hope that it will be useful, 149Sjkhbut WITHOUT ANY WARRANTY; without even the implied warranty of 159SjkhMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 169SjkhGNU General Public License for more details. 179Sjkh 189SjkhYou should have received a copy of the GNU General Public License 1911891Speteralong with RCS; see the file COPYING. 2011891SpeterIf not, write to the Free Software Foundation, 2111891Speter59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 229Sjkh 239SjkhReport problems and direct all questions to: 249Sjkh 259Sjkh rcs-bugs@cs.purdue.edu 269Sjkh 279Sjkh*/ 289Sjkh 299Sjkh#include "rcsbase.h" 309Sjkh 319Sjkh#if has_dirent 329Sjkh static int get_directory P((char const*,char***)); 339Sjkh#endif 349Sjkh 359Sjkhstatic int unlock P((struct hshentry *)); 369Sjkhstatic void cleanup P((void)); 379Sjkh 389Sjkhstatic RILE *workptr; 399Sjkhstatic int exitstatus; 409Sjkh 4150472SpetermainProg(rcscleanId, "rcsclean", "$FreeBSD: releng/11.0/gnu/usr.bin/rcs/rcsclean/rcsclean.c 50472 1999-08-27 23:37:10Z peter $") 429Sjkh{ 439Sjkh static char const usage[] = 4411891Speter "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ..."; 459Sjkh 469Sjkh static struct buf revision; 479Sjkh 489Sjkh char *a, **newargv; 499Sjkh char const *rev, *p; 5011891Speter int dounlock, expmode, perform, unlocked, unlockflag, waslocked; 5111891Speter int Ttimeflag; 529Sjkh struct hshentries *deltas; 539Sjkh struct hshentry *delta; 549Sjkh struct stat workstat; 559Sjkh 569Sjkh setrid(); 579Sjkh 589Sjkh expmode = -1; 5911891Speter rev = 0; 609Sjkh suffixes = X_DEFAULT; 619Sjkh perform = true; 629Sjkh unlockflag = false; 6311891Speter Ttimeflag = false; 649Sjkh 659Sjkh argc = getRCSINIT(argc, argv, &newargv); 669Sjkh argv = newargv; 679Sjkh for (;;) { 6811891Speter if (--argc < 1) { 699Sjkh# if has_dirent 709Sjkh argc = get_directory(".", &newargv); 719Sjkh argv = newargv; 729Sjkh break; 739Sjkh# else 7411891Speter faterror("no pathnames specified"); 759Sjkh# endif 769Sjkh } 779Sjkh a = *++argv; 7811891Speter if (!*a || *a++ != '-') 799Sjkh break; 809Sjkh switch (*a++) { 819Sjkh case 'k': 829Sjkh if (0 <= expmode) 839Sjkh redefined('k'); 849Sjkh if ((expmode = str2expmode(a)) < 0) 859Sjkh goto unknown; 869Sjkh break; 879Sjkh 889Sjkh case 'n': 899Sjkh perform = false; 909Sjkh goto handle_revision; 919Sjkh 929Sjkh case 'q': 939Sjkh quietflag = true; 949Sjkh /* fall into */ 959Sjkh case 'r': 969Sjkh handle_revision: 979Sjkh if (*a) { 989Sjkh if (rev) 999Sjkh warn("redefinition of revision number"); 1009Sjkh rev = a; 1019Sjkh } 1029Sjkh break; 1039Sjkh 10411891Speter case 'T': 10511891Speter if (*a) 10611891Speter goto unknown; 10711891Speter Ttimeflag = true; 10811891Speter break; 10911891Speter 1109Sjkh case 'u': 1119Sjkh unlockflag = true; 1129Sjkh goto handle_revision; 1139Sjkh 1149Sjkh case 'V': 1159Sjkh setRCSversion(*argv); 1169Sjkh break; 1179Sjkh 1189Sjkh case 'x': 1199Sjkh suffixes = a; 1209Sjkh break; 1219Sjkh 12211891Speter case 'z': 12311891Speter zone_set(a); 12411891Speter break; 12511891Speter 1269Sjkh default: 1279Sjkh unknown: 12811891Speter error("unknown option: %s%s", *argv, usage); 1299Sjkh } 1309Sjkh } 1319Sjkh 13211891Speter dounlock = perform & unlockflag; 13311891Speter 13411891Speter if (nerror) 13511891Speter cleanup(); 13611891Speter else 13711891Speter for (; 0 < argc; cleanup(), ++argv, --argc) { 13811891Speter 1399Sjkh ffree(); 1409Sjkh 1419Sjkh if (!( 14211891Speter 0 < pairnames( 1439Sjkh argc, argv, 14411891Speter dounlock ? rcswriteopen : rcsreadopen, 1459Sjkh true, true 1469Sjkh ) && 14711891Speter (workptr = Iopen(workname, FOPEN_R_WORK, &workstat)) 1489Sjkh )) 1499Sjkh continue; 1509Sjkh 15111891Speter if (same_file(RCSstat, workstat, 0)) { 15211891Speter rcserror("RCS file is the same as working file %s.", 15311891Speter workname 15411891Speter ); 15511891Speter continue; 15611891Speter } 15711891Speter 1589Sjkh gettree(); 1599Sjkh 1609Sjkh p = 0; 1619Sjkh if (rev) { 1629Sjkh if (!fexpandsym(rev, &revision, workptr)) 1639Sjkh continue; 1649Sjkh p = revision.string; 1659Sjkh } else if (Head) 1669Sjkh switch (unlockflag ? findlock(false,&delta) : 0) { 1679Sjkh default: 1689Sjkh continue; 1699Sjkh case 0: 1709Sjkh p = Dbranch ? Dbranch : ""; 1719Sjkh break; 1729Sjkh case 1: 1739Sjkh p = delta->num; 1749Sjkh break; 1759Sjkh } 1769Sjkh delta = 0; 1779Sjkh deltas = 0; /* Keep lint happy. */ 1789Sjkh if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas))) 1799Sjkh continue; 1809Sjkh 1819Sjkh waslocked = delta && delta->lockedby; 1829Sjkh locker_expansion = unlock(delta); 1839Sjkh unlocked = locker_expansion & unlockflag; 1849Sjkh if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH)) 1859Sjkh continue; 1869Sjkh 18711891Speter if (unlocked && !checkaccesslist()) 1889Sjkh continue; 1899Sjkh 19011891Speter if (dorewrite(dounlock, unlocked) != 0) 19111891Speter continue; 19211891Speter 1939Sjkh if (0 <= expmode) 1949Sjkh Expand = expmode; 1959Sjkh else if ( 1969Sjkh waslocked && 1979Sjkh Expand == KEYVAL_EXPAND && 1989Sjkh WORKMODE(RCSstat.st_mode,true) == workstat.st_mode 1999Sjkh ) 2009Sjkh Expand = KEYVALLOCK_EXPAND; 2019Sjkh 2029Sjkh getdesc(false); 2039Sjkh 2049Sjkh if ( 20511891Speter !delta ? workstat.st_size!=0 : 2069Sjkh 0 < rcsfcmp( 20711891Speter workptr, &workstat, 20811891Speter buildrevision(deltas, delta, (FILE*)0, false), 20911891Speter delta 2109Sjkh ) 2119Sjkh ) 2129Sjkh continue; 2139Sjkh 2149Sjkh if (quietflag < unlocked) 21511891Speter aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname); 2169Sjkh 21711891Speter if (perform & unlocked) { 21811891Speter if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL); 21911891Speter if (donerewrite(true, 22011891Speter Ttimeflag ? RCSstat.st_mtime : (time_t)-1 22111891Speter ) != 0) 22211891Speter continue; 22311891Speter } 2249Sjkh 2259Sjkh if (!quietflag) 22611891Speter aprintf(stdout, "rm -f %s\n", workname); 2279Sjkh Izclose(&workptr); 22811891Speter if (perform && un_link(workname) != 0) 22911891Speter eerror(workname); 2309Sjkh 23111891Speter } 2329Sjkh 2339Sjkh tempunlink(); 2349Sjkh if (!quietflag) 2359Sjkh Ofclose(stdout); 2369Sjkh exitmain(exitstatus); 2379Sjkh} 2389Sjkh 2399Sjkh static void 2409Sjkhcleanup() 2419Sjkh{ 2429Sjkh if (nerror) exitstatus = EXIT_FAILURE; 2439Sjkh Izclose(&finptr); 2449Sjkh Izclose(&workptr); 2459Sjkh Ozclose(&fcopy); 24611891Speter ORCSclose(); 2479Sjkh dirtempunlink(); 2489Sjkh} 2499Sjkh 25011891Speter#if RCS_lint 25111891Speter# define exiterr rcscleanExit 2529Sjkh#endif 25311891Speter void 2549Sjkhexiterr() 2559Sjkh{ 25611891Speter ORCSerror(); 2579Sjkh dirtempunlink(); 2589Sjkh tempunlink(); 2599Sjkh _exit(EXIT_FAILURE); 2609Sjkh} 2619Sjkh 2629Sjkh static int 2639Sjkhunlock(delta) 2649Sjkh struct hshentry *delta; 2659Sjkh{ 26611891Speter register struct rcslock **al, *l; 2679Sjkh 2689Sjkh if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0) 2699Sjkh for (al = &Locks; (l = *al); al = &l->nextlock) 2709Sjkh if (l->delta == delta) { 2719Sjkh *al = l->nextlock; 2729Sjkh delta->lockedby = 0; 2739Sjkh return true; 2749Sjkh } 2759Sjkh return false; 2769Sjkh} 2779Sjkh 2789Sjkh#if has_dirent 2799Sjkh static int 2809Sjkhget_directory(dirname, aargv) 2819Sjkh char const *dirname; 2829Sjkh char ***aargv; 2839Sjkh/* 2849Sjkh * Put a vector of all DIRNAME's directory entries names into *AARGV. 2859Sjkh * Ignore names of RCS files. 2869Sjkh * Yield the number of entries found. Terminate the vector with 0. 2879Sjkh * Allocate the storage for the vector and entry names. 2889Sjkh * Do not sort the names. Do not include '.' and '..'. 2899Sjkh */ 2909Sjkh{ 2919Sjkh int i, entries = 0, entries_max = 64; 2929Sjkh size_t chars = 0, chars_max = 1024; 2939Sjkh size_t *offset = tnalloc(size_t, entries_max); 2949Sjkh char *a = tnalloc(char, chars_max), **p; 2959Sjkh DIR *d; 2969Sjkh struct dirent *e; 2979Sjkh 2989Sjkh if (!(d = opendir(dirname))) 2999Sjkh efaterror(dirname); 3009Sjkh while ((errno = 0, e = readdir(d))) { 3019Sjkh char const *en = e->d_name; 3029Sjkh size_t s = strlen(en) + 1; 30311891Speter if (en[0]=='.' && (!en[1] || (en[1]=='.' && !en[2]))) 3049Sjkh continue; 3059Sjkh if (rcssuffix(en)) 3069Sjkh continue; 3079Sjkh while (chars_max < s + chars) 3089Sjkh a = trealloc(char, a, chars_max<<=1); 3099Sjkh if (entries == entries_max) 3109Sjkh offset = trealloc(size_t, offset, entries_max<<=1); 3119Sjkh offset[entries++] = chars; 3129Sjkh VOID strcpy(a+chars, en); 3139Sjkh chars += s; 3149Sjkh } 31511891Speter# if void_closedir 31611891Speter# define close_directory(d) (closedir(d), 0) 31711891Speter# else 31811891Speter# define close_directory(d) closedir(d) 31911891Speter# endif 32011891Speter if (errno || close_directory(d) != 0) 3219Sjkh efaterror(dirname); 3229Sjkh if (chars) 3239Sjkh a = trealloc(char, a, chars); 3249Sjkh else 3259Sjkh tfree(a); 3269Sjkh *aargv = p = tnalloc(char*, entries+1); 3279Sjkh for (i=0; i<entries; i++) 3289Sjkh *p++ = a + offset[i]; 3299Sjkh *p = 0; 3309Sjkh tfree(offset); 3319Sjkh return entries; 3329Sjkh} 3339Sjkh#endif 334