186d7f5d3SJohn Marino /* Clean up working files. */
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino /* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
486d7f5d3SJohn Marino Distributed under license by the Free Software Foundation, Inc.
586d7f5d3SJohn Marino
686d7f5d3SJohn Marino This file is part of RCS.
786d7f5d3SJohn Marino
886d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
986d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
1086d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
1186d7f5d3SJohn Marino any later version.
1286d7f5d3SJohn Marino
1386d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
1486d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1586d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1686d7f5d3SJohn Marino GNU General Public License for more details.
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
1986d7f5d3SJohn Marino along with RCS; see the file COPYING.
2086d7f5d3SJohn Marino If not, write to the Free Software Foundation,
2186d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2286d7f5d3SJohn Marino
2386d7f5d3SJohn Marino Report problems and direct all questions to:
2486d7f5d3SJohn Marino
2586d7f5d3SJohn Marino rcs-bugs@cs.purdue.edu
2686d7f5d3SJohn Marino
2786d7f5d3SJohn Marino */
2886d7f5d3SJohn Marino /*
2986d7f5d3SJohn Marino * $FreeBSD: src/gnu/usr.bin/rcs/rcsclean/rcsclean.c,v 1.5 1999/08/27 23:36:54 peter Exp $
3086d7f5d3SJohn Marino * $DragonFly: src/gnu/usr.bin/rcs/rcsclean/rcsclean.c,v 1.2 2003/06/17 04:25:48 dillon Exp $
3186d7f5d3SJohn Marino */
3286d7f5d3SJohn Marino
3386d7f5d3SJohn Marino #include "rcsbase.h"
3486d7f5d3SJohn Marino
3586d7f5d3SJohn Marino #if has_dirent
3686d7f5d3SJohn Marino static int get_directory P((char const*,char***));
3786d7f5d3SJohn Marino #endif
3886d7f5d3SJohn Marino
3986d7f5d3SJohn Marino static int unlock P((struct hshentry *));
4086d7f5d3SJohn Marino static void cleanup P((void));
4186d7f5d3SJohn Marino
4286d7f5d3SJohn Marino static RILE *workptr;
4386d7f5d3SJohn Marino static int exitstatus;
4486d7f5d3SJohn Marino
4586d7f5d3SJohn Marino mainProg(rcscleanId, "rcsclean", "$DragonFly: src/gnu/usr.bin/rcs/rcsclean/rcsclean.c,v 1.2 2003/06/17 04:25:48 dillon Exp $")
4686d7f5d3SJohn Marino {
4786d7f5d3SJohn Marino static char const usage[] =
4886d7f5d3SJohn Marino "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
4986d7f5d3SJohn Marino
5086d7f5d3SJohn Marino static struct buf revision;
5186d7f5d3SJohn Marino
5286d7f5d3SJohn Marino char *a, **newargv;
5386d7f5d3SJohn Marino char const *rev, *p;
5486d7f5d3SJohn Marino int dounlock, expmode, perform, unlocked, unlockflag, waslocked;
5586d7f5d3SJohn Marino int Ttimeflag;
5686d7f5d3SJohn Marino struct hshentries *deltas;
5786d7f5d3SJohn Marino struct hshentry *delta;
5886d7f5d3SJohn Marino struct stat workstat;
5986d7f5d3SJohn Marino
6086d7f5d3SJohn Marino setrid();
6186d7f5d3SJohn Marino
6286d7f5d3SJohn Marino expmode = -1;
6386d7f5d3SJohn Marino rev = 0;
6486d7f5d3SJohn Marino suffixes = X_DEFAULT;
6586d7f5d3SJohn Marino perform = true;
6686d7f5d3SJohn Marino unlockflag = false;
6786d7f5d3SJohn Marino Ttimeflag = false;
6886d7f5d3SJohn Marino
6986d7f5d3SJohn Marino argc = getRCSINIT(argc, argv, &newargv);
7086d7f5d3SJohn Marino argv = newargv;
7186d7f5d3SJohn Marino for (;;) {
7286d7f5d3SJohn Marino if (--argc < 1) {
7386d7f5d3SJohn Marino # if has_dirent
7486d7f5d3SJohn Marino argc = get_directory(".", &newargv);
7586d7f5d3SJohn Marino argv = newargv;
7686d7f5d3SJohn Marino break;
7786d7f5d3SJohn Marino # else
7886d7f5d3SJohn Marino faterror("no pathnames specified");
7986d7f5d3SJohn Marino # endif
8086d7f5d3SJohn Marino }
8186d7f5d3SJohn Marino a = *++argv;
8286d7f5d3SJohn Marino if (!*a || *a++ != '-')
8386d7f5d3SJohn Marino break;
8486d7f5d3SJohn Marino switch (*a++) {
8586d7f5d3SJohn Marino case 'k':
8686d7f5d3SJohn Marino if (0 <= expmode)
8786d7f5d3SJohn Marino redefined('k');
8886d7f5d3SJohn Marino if ((expmode = str2expmode(a)) < 0)
8986d7f5d3SJohn Marino goto unknown;
9086d7f5d3SJohn Marino break;
9186d7f5d3SJohn Marino
9286d7f5d3SJohn Marino case 'n':
9386d7f5d3SJohn Marino perform = false;
9486d7f5d3SJohn Marino goto handle_revision;
9586d7f5d3SJohn Marino
9686d7f5d3SJohn Marino case 'q':
9786d7f5d3SJohn Marino quietflag = true;
9886d7f5d3SJohn Marino /* fall into */
9986d7f5d3SJohn Marino case 'r':
10086d7f5d3SJohn Marino handle_revision:
10186d7f5d3SJohn Marino if (*a) {
10286d7f5d3SJohn Marino if (rev)
10386d7f5d3SJohn Marino warn("redefinition of revision number");
10486d7f5d3SJohn Marino rev = a;
10586d7f5d3SJohn Marino }
10686d7f5d3SJohn Marino break;
10786d7f5d3SJohn Marino
10886d7f5d3SJohn Marino case 'T':
10986d7f5d3SJohn Marino if (*a)
11086d7f5d3SJohn Marino goto unknown;
11186d7f5d3SJohn Marino Ttimeflag = true;
11286d7f5d3SJohn Marino break;
11386d7f5d3SJohn Marino
11486d7f5d3SJohn Marino case 'u':
11586d7f5d3SJohn Marino unlockflag = true;
11686d7f5d3SJohn Marino goto handle_revision;
11786d7f5d3SJohn Marino
11886d7f5d3SJohn Marino case 'V':
11986d7f5d3SJohn Marino setRCSversion(*argv);
12086d7f5d3SJohn Marino break;
12186d7f5d3SJohn Marino
12286d7f5d3SJohn Marino case 'x':
12386d7f5d3SJohn Marino suffixes = a;
12486d7f5d3SJohn Marino break;
12586d7f5d3SJohn Marino
12686d7f5d3SJohn Marino case 'z':
12786d7f5d3SJohn Marino zone_set(a);
12886d7f5d3SJohn Marino break;
12986d7f5d3SJohn Marino
13086d7f5d3SJohn Marino default:
13186d7f5d3SJohn Marino unknown:
13286d7f5d3SJohn Marino error("unknown option: %s%s", *argv, usage);
13386d7f5d3SJohn Marino }
13486d7f5d3SJohn Marino }
13586d7f5d3SJohn Marino
13686d7f5d3SJohn Marino dounlock = perform & unlockflag;
13786d7f5d3SJohn Marino
13886d7f5d3SJohn Marino if (nerror)
13986d7f5d3SJohn Marino cleanup();
14086d7f5d3SJohn Marino else
14186d7f5d3SJohn Marino for (; 0 < argc; cleanup(), ++argv, --argc) {
14286d7f5d3SJohn Marino
14386d7f5d3SJohn Marino ffree();
14486d7f5d3SJohn Marino
14586d7f5d3SJohn Marino if (!(
14686d7f5d3SJohn Marino 0 < pairnames(
14786d7f5d3SJohn Marino argc, argv,
14886d7f5d3SJohn Marino dounlock ? rcswriteopen : rcsreadopen,
14986d7f5d3SJohn Marino true, true
15086d7f5d3SJohn Marino ) &&
15186d7f5d3SJohn Marino (workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
15286d7f5d3SJohn Marino ))
15386d7f5d3SJohn Marino continue;
15486d7f5d3SJohn Marino
15586d7f5d3SJohn Marino if (same_file(RCSstat, workstat, 0)) {
15686d7f5d3SJohn Marino rcserror("RCS file is the same as working file %s.",
15786d7f5d3SJohn Marino workname
15886d7f5d3SJohn Marino );
15986d7f5d3SJohn Marino continue;
16086d7f5d3SJohn Marino }
16186d7f5d3SJohn Marino
16286d7f5d3SJohn Marino gettree();
16386d7f5d3SJohn Marino
16486d7f5d3SJohn Marino p = 0;
16586d7f5d3SJohn Marino if (rev) {
16686d7f5d3SJohn Marino if (!fexpandsym(rev, &revision, workptr))
16786d7f5d3SJohn Marino continue;
16886d7f5d3SJohn Marino p = revision.string;
16986d7f5d3SJohn Marino } else if (Head)
17086d7f5d3SJohn Marino switch (unlockflag ? findlock(false,&delta) : 0) {
17186d7f5d3SJohn Marino default:
17286d7f5d3SJohn Marino continue;
17386d7f5d3SJohn Marino case 0:
17486d7f5d3SJohn Marino p = Dbranch ? Dbranch : "";
17586d7f5d3SJohn Marino break;
17686d7f5d3SJohn Marino case 1:
17786d7f5d3SJohn Marino p = delta->num;
17886d7f5d3SJohn Marino break;
17986d7f5d3SJohn Marino }
18086d7f5d3SJohn Marino delta = 0;
18186d7f5d3SJohn Marino deltas = 0; /* Keep lint happy. */
18286d7f5d3SJohn Marino if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas)))
18386d7f5d3SJohn Marino continue;
18486d7f5d3SJohn Marino
18586d7f5d3SJohn Marino waslocked = delta && delta->lockedby;
18686d7f5d3SJohn Marino locker_expansion = unlock(delta);
18786d7f5d3SJohn Marino unlocked = locker_expansion & unlockflag;
18886d7f5d3SJohn Marino if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
18986d7f5d3SJohn Marino continue;
19086d7f5d3SJohn Marino
19186d7f5d3SJohn Marino if (unlocked && !checkaccesslist())
19286d7f5d3SJohn Marino continue;
19386d7f5d3SJohn Marino
19486d7f5d3SJohn Marino if (dorewrite(dounlock, unlocked) != 0)
19586d7f5d3SJohn Marino continue;
19686d7f5d3SJohn Marino
19786d7f5d3SJohn Marino if (0 <= expmode)
19886d7f5d3SJohn Marino Expand = expmode;
19986d7f5d3SJohn Marino else if (
20086d7f5d3SJohn Marino waslocked &&
20186d7f5d3SJohn Marino Expand == KEYVAL_EXPAND &&
20286d7f5d3SJohn Marino WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
20386d7f5d3SJohn Marino )
20486d7f5d3SJohn Marino Expand = KEYVALLOCK_EXPAND;
20586d7f5d3SJohn Marino
20686d7f5d3SJohn Marino getdesc(false);
20786d7f5d3SJohn Marino
20886d7f5d3SJohn Marino if (
20986d7f5d3SJohn Marino !delta ? workstat.st_size!=0 :
21086d7f5d3SJohn Marino 0 < rcsfcmp(
21186d7f5d3SJohn Marino workptr, &workstat,
21286d7f5d3SJohn Marino buildrevision(deltas, delta, (FILE*)0, false),
21386d7f5d3SJohn Marino delta
21486d7f5d3SJohn Marino )
21586d7f5d3SJohn Marino )
21686d7f5d3SJohn Marino continue;
21786d7f5d3SJohn Marino
21886d7f5d3SJohn Marino if (quietflag < unlocked)
21986d7f5d3SJohn Marino aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
22086d7f5d3SJohn Marino
22186d7f5d3SJohn Marino if (perform & unlocked) {
22286d7f5d3SJohn Marino if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL);
22386d7f5d3SJohn Marino if (donerewrite(true,
22486d7f5d3SJohn Marino Ttimeflag ? RCSstat.st_mtime : (time_t)-1
22586d7f5d3SJohn Marino ) != 0)
22686d7f5d3SJohn Marino continue;
22786d7f5d3SJohn Marino }
22886d7f5d3SJohn Marino
22986d7f5d3SJohn Marino if (!quietflag)
23086d7f5d3SJohn Marino aprintf(stdout, "rm -f %s\n", workname);
23186d7f5d3SJohn Marino Izclose(&workptr);
23286d7f5d3SJohn Marino if (perform && un_link(workname) != 0)
23386d7f5d3SJohn Marino eerror(workname);
23486d7f5d3SJohn Marino
23586d7f5d3SJohn Marino }
23686d7f5d3SJohn Marino
23786d7f5d3SJohn Marino tempunlink();
23886d7f5d3SJohn Marino if (!quietflag)
23986d7f5d3SJohn Marino Ofclose(stdout);
24086d7f5d3SJohn Marino exitmain(exitstatus);
24186d7f5d3SJohn Marino }
24286d7f5d3SJohn Marino
24386d7f5d3SJohn Marino static void
cleanup()24486d7f5d3SJohn Marino cleanup()
24586d7f5d3SJohn Marino {
24686d7f5d3SJohn Marino if (nerror) exitstatus = EXIT_FAILURE;
24786d7f5d3SJohn Marino Izclose(&finptr);
24886d7f5d3SJohn Marino Izclose(&workptr);
24986d7f5d3SJohn Marino Ozclose(&fcopy);
25086d7f5d3SJohn Marino ORCSclose();
25186d7f5d3SJohn Marino dirtempunlink();
25286d7f5d3SJohn Marino }
25386d7f5d3SJohn Marino
25486d7f5d3SJohn Marino #if RCS_lint
25586d7f5d3SJohn Marino # define exiterr rcscleanExit
25686d7f5d3SJohn Marino #endif
25786d7f5d3SJohn Marino void
exiterr()25886d7f5d3SJohn Marino exiterr()
25986d7f5d3SJohn Marino {
26086d7f5d3SJohn Marino ORCSerror();
26186d7f5d3SJohn Marino dirtempunlink();
26286d7f5d3SJohn Marino tempunlink();
26386d7f5d3SJohn Marino _exit(EXIT_FAILURE);
26486d7f5d3SJohn Marino }
26586d7f5d3SJohn Marino
26686d7f5d3SJohn Marino static int
unlock(delta)26786d7f5d3SJohn Marino unlock(delta)
26886d7f5d3SJohn Marino struct hshentry *delta;
26986d7f5d3SJohn Marino {
27086d7f5d3SJohn Marino register struct rcslock **al, *l;
27186d7f5d3SJohn Marino
27286d7f5d3SJohn Marino if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0)
27386d7f5d3SJohn Marino for (al = &Locks; (l = *al); al = &l->nextlock)
27486d7f5d3SJohn Marino if (l->delta == delta) {
27586d7f5d3SJohn Marino *al = l->nextlock;
27686d7f5d3SJohn Marino delta->lockedby = 0;
27786d7f5d3SJohn Marino return true;
27886d7f5d3SJohn Marino }
27986d7f5d3SJohn Marino return false;
28086d7f5d3SJohn Marino }
28186d7f5d3SJohn Marino
28286d7f5d3SJohn Marino #if has_dirent
28386d7f5d3SJohn Marino static int
get_directory(dirname,aargv)28486d7f5d3SJohn Marino get_directory(dirname, aargv)
28586d7f5d3SJohn Marino char const *dirname;
28686d7f5d3SJohn Marino char ***aargv;
28786d7f5d3SJohn Marino /*
28886d7f5d3SJohn Marino * Put a vector of all DIRNAME's directory entries names into *AARGV.
28986d7f5d3SJohn Marino * Ignore names of RCS files.
29086d7f5d3SJohn Marino * Yield the number of entries found. Terminate the vector with 0.
29186d7f5d3SJohn Marino * Allocate the storage for the vector and entry names.
29286d7f5d3SJohn Marino * Do not sort the names. Do not include '.' and '..'.
29386d7f5d3SJohn Marino */
29486d7f5d3SJohn Marino {
29586d7f5d3SJohn Marino int i, entries = 0, entries_max = 64;
29686d7f5d3SJohn Marino size_t chars = 0, chars_max = 1024;
29786d7f5d3SJohn Marino size_t *offset = tnalloc(size_t, entries_max);
29886d7f5d3SJohn Marino char *a = tnalloc(char, chars_max), **p;
29986d7f5d3SJohn Marino DIR *d;
30086d7f5d3SJohn Marino struct dirent *e;
30186d7f5d3SJohn Marino
30286d7f5d3SJohn Marino if (!(d = opendir(dirname)))
30386d7f5d3SJohn Marino efaterror(dirname);
30486d7f5d3SJohn Marino while ((errno = 0, e = readdir(d))) {
30586d7f5d3SJohn Marino char const *en = e->d_name;
30686d7f5d3SJohn Marino size_t s = strlen(en) + 1;
30786d7f5d3SJohn Marino if (en[0]=='.' && (!en[1] || (en[1]=='.' && !en[2])))
30886d7f5d3SJohn Marino continue;
30986d7f5d3SJohn Marino if (rcssuffix(en))
31086d7f5d3SJohn Marino continue;
31186d7f5d3SJohn Marino while (chars_max < s + chars)
31286d7f5d3SJohn Marino a = trealloc(char, a, chars_max<<=1);
31386d7f5d3SJohn Marino if (entries == entries_max)
31486d7f5d3SJohn Marino offset = trealloc(size_t, offset, entries_max<<=1);
31586d7f5d3SJohn Marino offset[entries++] = chars;
31686d7f5d3SJohn Marino VOID strcpy(a+chars, en);
31786d7f5d3SJohn Marino chars += s;
31886d7f5d3SJohn Marino }
31986d7f5d3SJohn Marino # if void_closedir
32086d7f5d3SJohn Marino # define close_directory(d) (closedir(d), 0)
32186d7f5d3SJohn Marino # else
32286d7f5d3SJohn Marino # define close_directory(d) closedir(d)
32386d7f5d3SJohn Marino # endif
32486d7f5d3SJohn Marino if (errno || close_directory(d) != 0)
32586d7f5d3SJohn Marino efaterror(dirname);
32686d7f5d3SJohn Marino if (chars)
32786d7f5d3SJohn Marino a = trealloc(char, a, chars);
32886d7f5d3SJohn Marino else
32986d7f5d3SJohn Marino tfree(a);
33086d7f5d3SJohn Marino *aargv = p = tnalloc(char*, entries+1);
33186d7f5d3SJohn Marino for (i=0; i<entries; i++)
33286d7f5d3SJohn Marino *p++ = a + offset[i];
33386d7f5d3SJohn Marino *p = 0;
33486d7f5d3SJohn Marino tfree(offset);
33586d7f5d3SJohn Marino return entries;
33686d7f5d3SJohn Marino }
33786d7f5d3SJohn Marino #endif
338