xref: /openbsd-src/usr.bin/rcs/rcsclean.c (revision 6541b77c94127ecd11c0a5f7b2cdfe2db3a4a356)
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