GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rcs/rcsclean.c Lines: 48 88 54.5 %
Date: 2017-11-07 Branches: 33 67 49.3 %

Line Branch Exec Source
1
/*	$OpenBSD: rcsclean.c,v 1.56 2016/08/26 09:02:54 guenther Exp $	*/
2
/*
3
 * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. The name of the author may not be used to endorse or promote products
13
 *    derived from this software without specific prior written permission.
14
 *
15
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19
 * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include <sys/types.h>
28
29
#include <dirent.h>
30
#include <err.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <time.h>
34
#include <unistd.h>
35
36
#include "rcsprog.h"
37
#include "diff.h"
38
39
static void	rcsclean_file(char *, const char *);
40
41
static int nflag = 0;
42
static int kflag = RCS_KWEXP_ERR;
43
static int uflag = 0;
44
static int flags = 0;
45
static char *locker = NULL;
46
47
int
48
rcsclean_main(int argc, char **argv)
49
{
50
	int i, ch;
51
20
	char *rev_str;
52
	DIR *dirp;
53
	struct dirent *dp;
54
55
10
	rev_str = NULL;
56
57
32
	while ((ch = rcs_getopt(argc, argv, "k:n::q::r::Tu::Vx::")) != -1) {
58


12
		switch (ch) {
59
		case 'k':
60
			kflag = rcs_kflag_get(rcs_optarg);
61
			if (RCS_KWEXP_INVAL(kflag)) {
62
				warnx("invalid RCS keyword substitution mode");
63
				(usage)();
64
			}
65
			break;
66
		case 'n':
67
			rcs_setrevstr(&rev_str, rcs_optarg);
68
			nflag = 1;
69
			break;
70
		case 'q':
71
10
			rcs_setrevstr(&rev_str, rcs_optarg);
72
10
			flags |= QUIET;
73
10
			break;
74
		case 'r':
75
			rcs_setrevstr(&rev_str, rcs_optarg);
76
			break;
77
		case 'T':
78
			flags |= PRESERVETIME;
79
			break;
80
		case 'u':
81
2
			rcs_setrevstr(&rev_str, rcs_optarg);
82
2
			uflag = 1;
83
2
			break;
84
		case 'V':
85
			printf("%s\n", rcs_version);
86
			exit(0);
87
		case 'x':
88
			/* Use blank extension if none given. */
89
			rcs_suffixes = rcs_optarg ? rcs_optarg : "";
90
			break;
91
		default:
92
			(usage)();
93
		}
94
	}
95
96
10
	argc -= rcs_optind;
97
10
	argv += rcs_optind;
98
99
10
	if ((locker = getlogin()) == NULL)
100
		err(1, "getlogin");
101
102
10
	if (argc == 0) {
103
		if ((dirp = opendir(".")) == NULL) {
104
			warn("opendir");
105
			(usage)();
106
		}
107
108
		while ((dp = readdir(dirp)) != NULL) {
109
			if (dp->d_type == DT_DIR)
110
				continue;
111
			rcsclean_file(dp->d_name, rev_str);
112
		}
113
114
		(void)closedir(dirp);
115
	} else
116
40
		for (i = 0; i < argc; i++)
117
10
			rcsclean_file(argv[i], rev_str);
118
119
10
	return (0);
120
10
}
121
122
__dead void
123
rcsclean_usage(void)
124
{
125
	fprintf(stderr,
126
	    "usage: rcsclean [-TV] [-kmode] [-n[rev]] [-q[rev]] [-r[rev]]\n"
127
	    "                [-u[rev]] [-xsuffixes] [-ztz] [file ...]\n");
128
129
	exit(1);
130
}
131
132
static void
133
rcsclean_file(char *fname, const char *rev_str)
134
{
135
	int fd, match;
136
	RCSFILE *file;
137
20
	char fpath[PATH_MAX], numb[RCS_REV_BUFSZ];
138
	RCSNUM *rev;
139
	BUF *b1, *b2;
140
	time_t rcs_mtime = -1;
141
142
	b1 = b2 = NULL;
143
	file = NULL;
144
	rev = NULL;
145
146
10
	if ((fd = rcs_choosefile(fname, fpath, sizeof(fpath))) < 0)
147
		goto out;
148
149
7
	if ((file = rcs_open(fpath, fd, RCS_RDWR)) == NULL)
150
		goto out;
151
152
7
	if (flags & PRESERVETIME)
153
		rcs_mtime = rcs_get_mtime(file);
154
155
7
	rcs_kwexp_set(file, kflag);
156
157
7
	if (rev_str == NULL)
158
5
		rev = file->rf_head;
159
2
	else if ((rev = rcs_getrevnum(rev_str, file)) == NULL) {
160
		warnx("%s: Symbolic name `%s' is undefined.", fpath, rev_str);
161
		goto out;
162
	}
163
164
7
	if ((b1 = rcs_getrev(file, rev)) == NULL) {
165
		warnx("failed to get needed revision");
166
		goto out;
167
	}
168
7
	if ((b2 = buf_load(fname)) == NULL) {
169
		warnx("failed to load `%s'", fname);
170
		goto out;
171
	}
172
173
	/* If buffer lengths are the same, compare contents as well. */
174
7
	if (buf_len(b1) != buf_len(b2))
175
2
		match = 0;
176
	else {
177
		size_t len, n;
178
179
5
		len = buf_len(b1);
180
181
		match = 1;
182
10
		for (n = 0; n < len; ++n)
183
			if (buf_getc(b1, n) != buf_getc(b2, n)) {
184
				match = 0;
185
				break;
186
			}
187
	}
188
189
7
	if (match == 1) {
190

6
		if (uflag == 1 && !TAILQ_EMPTY(&(file->rf_locks))) {
191
1
			if (!(flags & QUIET) && nflag == 0) {
192
				printf("rcs -u%s %s\n",
193
				    rcsnum_tostr(rev, numb, sizeof(numb)),
194
				    fpath);
195
			}
196
1
			(void)rcs_lock_remove(file, locker, rev);
197
1
		}
198
199
5
		if (TAILQ_EMPTY(&(file->rf_locks))) {
200
4
			if (!(flags & QUIET))
201
				printf("rm -f %s\n", fname);
202
203
4
			if (nflag == 0)
204
4
				(void)unlink(fname);
205
		}
206
	}
207
208
7
	rcs_write(file);
209
7
	if (flags & PRESERVETIME)
210
		rcs_set_mtime(file, rcs_mtime);
211
212
out:
213
10
	buf_free(b1);
214
10
	buf_free(b2);
215
10
	if (file != NULL)
216
7
		rcs_close(file);
217
10
}