1*6541b77cSguenther /* $OpenBSD: rcsclean.c,v 1.57 2023/08/11 05:02:21 guenther Exp $ */
222447615Sjoris /*
322447615Sjoris * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
422447615Sjoris * All rights reserved.
522447615Sjoris *
622447615Sjoris * Redistribution and use in source and binary forms, with or without
722447615Sjoris * modification, are permitted provided that the following conditions
822447615Sjoris * are met:
922447615Sjoris *
1022447615Sjoris * 1. Redistributions of source code must retain the above copyright
1122447615Sjoris * notice, this list of conditions and the following disclaimer.
1222447615Sjoris * 2. The name of the author may not be used to endorse or promote products
1322447615Sjoris * derived from this software without specific prior written permission.
1422447615Sjoris *
1522447615Sjoris * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1622447615Sjoris * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
1722447615Sjoris * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
1822447615Sjoris * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1922447615Sjoris * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2022447615Sjoris * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2122447615Sjoris * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2222447615Sjoris * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2322447615Sjoris * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2422447615Sjoris * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2522447615Sjoris */
2622447615Sjoris
274781e2faSxsa #include <sys/types.h>
28*6541b77cSguenther #include <sys/stat.h>
294781e2faSxsa
304781e2faSxsa #include <dirent.h>
314781e2faSxsa #include <err.h>
324781e2faSxsa #include <stdio.h>
334781e2faSxsa #include <stdlib.h>
34099bc362Sguenther #include <time.h>
354781e2faSxsa #include <unistd.h>
3622447615Sjoris
3722447615Sjoris #include "rcsprog.h"
38cd8dad74Sxsa #include "diff.h"
3922447615Sjoris
40e7816acdSray static void rcsclean_file(char *, const char *);
41eda419a4Sxsa
4224b08d35Sjoris static int nflag = 0;
4324b08d35Sjoris static int kflag = RCS_KWEXP_ERR;
443e492fb7Sxsa static int uflag = 0;
4566d00473Sxsa static int flags = 0;
46bbfcb536Sjoris static char *locker = NULL;
4722447615Sjoris
4822447615Sjoris int
rcsclean_main(int argc,char ** argv)4922447615Sjoris rcsclean_main(int argc, char **argv)
5022447615Sjoris {
5166d00473Sxsa int i, ch;
5236076781Sray char *rev_str;
5322447615Sjoris DIR *dirp;
5422447615Sjoris struct dirent *dp;
5522447615Sjoris
5636076781Sray rev_str = NULL;
5722447615Sjoris
58098be35cSray while ((ch = rcs_getopt(argc, argv, "k:n::q::r::Tu::Vx::")) != -1) {
5922447615Sjoris switch (ch) {
6024b08d35Sjoris case 'k':
61a2b34663Sjoris kflag = rcs_kflag_get(rcs_optarg);
6224b08d35Sjoris if (RCS_KWEXP_INVAL(kflag)) {
6325a1df5bSxsa warnx("invalid RCS keyword substitution mode");
6424b08d35Sjoris (usage)();
6524b08d35Sjoris }
6624b08d35Sjoris break;
6724b08d35Sjoris case 'n':
6836076781Sray rcs_setrevstr(&rev_str, rcs_optarg);
6924b08d35Sjoris nflag = 1;
7024b08d35Sjoris break;
7122447615Sjoris case 'q':
7236076781Sray rcs_setrevstr(&rev_str, rcs_optarg);
73913586deSxsa flags |= QUIET;
7422447615Sjoris break;
7530b112ccSjoris case 'r':
7636076781Sray rcs_setrevstr(&rev_str, rcs_optarg);
7730b112ccSjoris break;
784ecf1ebbSxsa case 'T':
794ecf1ebbSxsa flags |= PRESERVETIME;
804ecf1ebbSxsa break;
813e492fb7Sxsa case 'u':
8236076781Sray rcs_setrevstr(&rev_str, rcs_optarg);
833e492fb7Sxsa uflag = 1;
843e492fb7Sxsa break;
8522447615Sjoris case 'V':
8622447615Sjoris printf("%s\n", rcs_version);
8722447615Sjoris exit(0);
887518c1e9Sxsa case 'x':
894365263eSray /* Use blank extension if none given. */
904365263eSray rcs_suffixes = rcs_optarg ? rcs_optarg : "";
917518c1e9Sxsa break;
9222447615Sjoris default:
93d3f3fa45Sray (usage)();
9422447615Sjoris }
9522447615Sjoris }
9622447615Sjoris
97a2b34663Sjoris argc -= rcs_optind;
98a2b34663Sjoris argv += rcs_optind;
9922447615Sjoris
100bbfcb536Sjoris if ((locker = getlogin()) == NULL)
101a3660ae3Sxsa err(1, "getlogin");
102bbfcb536Sjoris
10322447615Sjoris if (argc == 0) {
10422447615Sjoris if ((dirp = opendir(".")) == NULL) {
10582ca7eaaSxsa warn("opendir");
10622447615Sjoris (usage)();
10722447615Sjoris }
10822447615Sjoris
10922447615Sjoris while ((dp = readdir(dirp)) != NULL) {
11022447615Sjoris if (dp->d_type == DT_DIR)
11122447615Sjoris continue;
112e7816acdSray rcsclean_file(dp->d_name, rev_str);
11322447615Sjoris }
11422447615Sjoris
11582ca7eaaSxsa (void)closedir(dirp);
11636076781Sray } else
117e7816acdSray for (i = 0; i < argc; i++)
118e7816acdSray rcsclean_file(argv[i], rev_str);
11922447615Sjoris
12022447615Sjoris return (0);
12122447615Sjoris }
12222447615Sjoris
123960e00beSotto __dead void
rcsclean_usage(void)12422447615Sjoris rcsclean_usage(void)
12522447615Sjoris {
126248620a5Sderaadt fprintf(stderr,
127e3f96568Sjmc "usage: rcsclean [-TV] [-kmode] [-n[rev]] [-q[rev]] [-r[rev]]\n"
1287aeaf79eSxsa " [-u[rev]] [-xsuffixes] [-ztz] [file ...]\n");
129960e00beSotto
130960e00beSotto exit(1);
13122447615Sjoris }
13222447615Sjoris
133eda419a4Sxsa static void
rcsclean_file(char * fname,const char * rev_str)134e7816acdSray rcsclean_file(char *fname, const char *rev_str)
13522447615Sjoris {
136bc8d37c3Sjoris int fd, match;
13722447615Sjoris RCSFILE *file;
138b9fc9a72Sderaadt char fpath[PATH_MAX], numb[RCS_REV_BUFSZ];
139e7816acdSray RCSNUM *rev;
14022447615Sjoris BUF *b1, *b2;
141*6541b77cSguenther struct timespec rcs_mtime = { .tv_sec = 0, .tv_nsec = UTIME_OMIT };
14222447615Sjoris
143cd05622fSray b1 = b2 = NULL;
144cd05622fSray file = NULL;
145cd05622fSray rev = NULL;
14624b08d35Sjoris
147f3876e23Sray if ((fd = rcs_choosefile(fname, fpath, sizeof(fpath))) < 0)
148cd05622fSray goto out;
14922447615Sjoris
150bc8d37c3Sjoris if ((file = rcs_open(fpath, fd, RCS_RDWR)) == NULL)
151cd05622fSray goto out;
15222447615Sjoris
15366d00473Sxsa if (flags & PRESERVETIME)
154bc8d37c3Sjoris rcs_mtime = rcs_get_mtime(file);
15566d00473Sxsa
15624b08d35Sjoris rcs_kwexp_set(file, kflag);
15724b08d35Sjoris
158e7816acdSray if (rev_str == NULL)
159e7816acdSray rev = file->rf_head;
160e7816acdSray else if ((rev = rcs_getrevnum(rev_str, file)) == NULL) {
16182ca7eaaSxsa warnx("%s: Symbolic name `%s' is undefined.", fpath, rev_str);
162cd05622fSray goto out;
163e7816acdSray }
16422447615Sjoris
165e7816acdSray if ((b1 = rcs_getrev(file, rev)) == NULL) {
16682ca7eaaSxsa warnx("failed to get needed revision");
167cd05622fSray goto out;
16822447615Sjoris }
1690ee14128Sray if ((b2 = buf_load(fname)) == NULL) {
17082ca7eaaSxsa warnx("failed to load `%s'", fname);
171cd05622fSray goto out;
17222447615Sjoris }
17322447615Sjoris
174cd05622fSray /* If buffer lengths are the same, compare contents as well. */
1757bb3ddb0Sray if (buf_len(b1) != buf_len(b2))
17622447615Sjoris match = 0;
177cd05622fSray else {
178cd05622fSray size_t len, n;
17922447615Sjoris
1807bb3ddb0Sray len = buf_len(b1);
181cd05622fSray
182cd05622fSray match = 1;
183cd05622fSray for (n = 0; n < len; ++n)
1847bb3ddb0Sray if (buf_getc(b1, n) != buf_getc(b2, n)) {
185cd05622fSray match = 0;
186cd05622fSray break;
187cd05622fSray }
188cd05622fSray }
18922447615Sjoris
19058ae6f4cSxsa if (match == 1) {
1917249ec9bSderaadt if (uflag == 1 && !TAILQ_EMPTY(&(file->rf_locks))) {
192913586deSxsa if (!(flags & QUIET) && nflag == 0) {
1933e492fb7Sxsa printf("rcs -u%s %s\n",
194e7816acdSray rcsnum_tostr(rev, numb, sizeof(numb)),
1953e492fb7Sxsa fpath);
1963e492fb7Sxsa }
197e7816acdSray (void)rcs_lock_remove(file, locker, rev);
1983e492fb7Sxsa }
1993e492fb7Sxsa
2007dd67d45Sxsa if (TAILQ_EMPTY(&(file->rf_locks))) {
201913586deSxsa if (!(flags & QUIET))
20222447615Sjoris printf("rm -f %s\n", fname);
2033e492fb7Sxsa
2047dd67d45Sxsa if (nflag == 0)
20522447615Sjoris (void)unlink(fname);
20622447615Sjoris }
2077dd67d45Sxsa }
20822447615Sjoris
209bc8d37c3Sjoris rcs_write(file);
21066d00473Sxsa if (flags & PRESERVETIME)
211bc8d37c3Sjoris rcs_set_mtime(file, rcs_mtime);
212cd05622fSray
213cd05622fSray out:
2147bb3ddb0Sray buf_free(b1);
2157bb3ddb0Sray buf_free(b2);
216cd05622fSray if (file != NULL)
217cd05622fSray rcs_close(file);
21822447615Sjoris }
219