GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cvs/admin.c Lines: 0 188 0.0 %
Date: 2017-11-07 Branches: 0 141 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: admin.c,v 1.68 2017/06/01 08:08:24 joris Exp $	*/
2
/*
3
 * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
4
 * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
5
 * Copyright (c) 2006, 2007 Xavier Santolaria <xsa@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/dirent.h>
22
23
#include <errno.h>
24
#include <fcntl.h>
25
#include <libgen.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <unistd.h>
29
30
#include "cvs.h"
31
#include "remote.h"
32
33
#define ADM_EFLAG	0x01
34
35
void	cvs_admin_local(struct cvs_file *);
36
37
struct cvs_cmd cvs_cmd_admin = {
38
	CVS_OP_ADMIN, CVS_USE_WDIR | CVS_LOCK_REPO, "admin",
39
	{ "adm", "rcs" },
40
	"Administrative front-end for RCS",
41
	"[-ILqU] [-A oldfile] [-a users] [-b branch]\n"
42
	"[-c string] [-e [users]] [-k mode] [-l [rev]] [-m rev:msg]\n"
43
	"[-N tag[:rev]] [-n tag[:rev]] [-o rev] [-s state[:rev]]"
44
	"[-t file | str]\n"
45
	"[-u [rev]] file ...",
46
	"A:a:b::c:e::Ik:l::Lm:N:n:o:qs:t:Uu::",
47
	NULL,
48
	cvs_admin
49
};
50
51
static int	 runflags = 0;
52
static int	 lkmode = RCS_LOCK_INVAL;
53
static char	*alist, *comment, *elist, *logmsg, *logstr, *koptstr;
54
static char	*oldfilename, *orange, *state, *staterevstr;
55
56
int
57
cvs_admin(int argc, char **argv)
58
{
59
	int ch;
60
	int flags;
61
	char *statestr;
62
	struct cvs_recursion cr;
63
64
	flags = CR_RECURSE_DIRS;
65
66
	alist = comment = elist = logmsg = logstr = NULL;
67
	oldfilename = orange = state = statestr = NULL;
68
69
	while ((ch = getopt(argc, argv, cvs_cmd_admin.cmd_opts)) != -1) {
70
		switch (ch) {
71
		case 'A':
72
			oldfilename = optarg;
73
			break;
74
		case 'a':
75
			alist = optarg;
76
			break;
77
		case 'b':
78
			break;
79
		case 'c':
80
			comment = optarg;
81
			break;
82
		case 'e':
83
			elist = optarg;
84
			runflags |= ADM_EFLAG;
85
			break;
86
		case 'I':
87
			break;
88
		case 'k':
89
			koptstr = optarg;
90
			kflag = rcs_kflag_get(koptstr);
91
			if (RCS_KWEXP_INVAL(kflag)) {
92
				cvs_log(LP_ERR,
93
				    "invalid RCS keyword expansion mode");
94
				fatal("%s", cvs_cmd_admin.cmd_synopsis);
95
			}
96
			break;
97
		case 'L':
98
			if (lkmode == RCS_LOCK_LOOSE) {
99
				cvs_log(LP_ERR, "-L and -U are incompatible");
100
				fatal("%s", cvs_cmd_admin.cmd_synopsis);
101
			}
102
			lkmode = RCS_LOCK_STRICT;
103
			break;
104
		case 'l':
105
			break;
106
		case 'm':
107
			logstr = optarg;
108
			break;
109
		case 'N':
110
			break;
111
		case 'n':
112
			break;
113
		case 'o':
114
			orange = optarg;
115
			break;
116
		case 'q':
117
			verbosity = 0;
118
			break;
119
		case 's':
120
			statestr = optarg;
121
			break;
122
		case 't':
123
			break;
124
		case 'U':
125
			if (lkmode == RCS_LOCK_STRICT) {
126
				cvs_log(LP_ERR, "-U and -L are incompatible");
127
				fatal("%s", cvs_cmd_admin.cmd_synopsis);
128
			}
129
			lkmode = RCS_LOCK_LOOSE;
130
			break;
131
		case 'u':
132
			break;
133
		default:
134
			fatal("%s", cvs_cmd_admin.cmd_synopsis);
135
		}
136
	}
137
138
	argc -= optind;
139
	argv += optind;
140
141
	if (argc == 0)
142
		fatal("%s", cvs_cmd_admin.cmd_synopsis);
143
144
	cr.enterdir = NULL;
145
	cr.leavedir = NULL;
146
147
	if (cvsroot_is_remote()) {
148
		cvs_client_connect_to_server();
149
		cr.fileproc = cvs_client_sendfile;
150
151
		if (oldfilename != NULL)
152
			cvs_client_send_request("Argument -A%s", oldfilename);
153
154
		if (alist != NULL)
155
			cvs_client_send_request("Argument -a%s", alist);
156
157
		if (comment != NULL)
158
			cvs_client_send_request("Argument -c%s", comment);
159
160
		if (runflags & ADM_EFLAG)
161
			cvs_client_send_request("Argument -e%s",
162
			    (elist != NULL) ? elist : "");
163
164
		if (koptstr != NULL)
165
			cvs_client_send_request("Argument -k%s", koptstr);
166
167
		if (lkmode == RCS_LOCK_STRICT)
168
			cvs_client_send_request("Argument -L");
169
		else if (lkmode == RCS_LOCK_LOOSE)
170
			cvs_client_send_request("Argument -U");
171
172
		if (logstr != NULL)
173
			cvs_client_send_logmsg(logstr);
174
175
		if (orange != NULL)
176
			cvs_client_send_request("Argument -o%s", orange);
177
178
		if (statestr != NULL)
179
			cvs_client_send_request("Argument -s%s", statestr);
180
181
		if (verbosity == 0)
182
			cvs_client_send_request("Argument -q");
183
184
	} else {
185
		if (statestr != NULL) {
186
			if ((staterevstr = strchr(statestr, ':')) != NULL)
187
				*staterevstr++ = '\0';
188
			state = statestr;
189
			if (rcs_state_check(state) < 0) {
190
				cvs_log(LP_ERR, "invalid state `%s'", state);
191
				state = NULL;
192
			}
193
		}
194
195
		flags |= CR_REPO;
196
		cr.fileproc = cvs_admin_local;
197
	}
198
199
	cr.flags = flags;
200
201
	cvs_file_run(argc, argv, &cr);
202
203
	if (cvsroot_is_remote()) {
204
		cvs_client_send_files(argv, argc);
205
		cvs_client_senddir(".");
206
		cvs_client_send_request("admin");
207
		cvs_client_get_responses();
208
	}
209
210
	return (0);
211
}
212
213
void
214
cvs_admin_local(struct cvs_file *cf)
215
{
216
	int i;
217
	RCSNUM *rev;
218
219
	cvs_log(LP_TRACE, "cvs_admin_local(%s)", cf->file_path);
220
221
	cvs_file_classify(cf, cvs_directory_tag);
222
223
	if (cf->file_type == CVS_DIR) {
224
		if (verbosity > 1)
225
			cvs_log(LP_NOTICE, "Administrating %s", cf->file_name);
226
		return;
227
	}
228
229
	if (cf->file_ent == NULL)
230
		return;
231
	else if (cf->file_status == FILE_ADDED) {
232
		cvs_log(LP_ERR, "cannot admin newly added file `%s'",
233
		    cf->file_name);
234
		return;
235
	}
236
237
	if (cf->file_rcs == NULL) {
238
		cvs_log(LP_ERR, "lost RCS file for `%s'", cf->file_path);
239
		return;
240
	}
241
242
	if (verbosity > 0)
243
		cvs_printf("RCS file: %s\n", cf->file_rcs->rf_path);
244
245
	if (oldfilename != NULL) {
246
		struct cvs_file *ocf;
247
		struct rcs_access *acp;
248
		int ofd;
249
		char *d, *f, fpath[PATH_MAX], repo[PATH_MAX];
250
251
252
		if ((f = basename(oldfilename)) == NULL)
253
			fatal("cvs_admin_local: basename failed");
254
		if ((d = dirname(oldfilename)) == NULL)
255
			fatal("cvs_admin_local: dirname failed");
256
257
		cvs_get_repository_path(d, repo, PATH_MAX);
258
259
		(void)xsnprintf(fpath, PATH_MAX, "%s/%s", repo, f);
260
261
		if (strlcat(fpath, RCS_FILE_EXT, PATH_MAX) >= PATH_MAX)
262
			fatal("cvs_admin_local: truncation");
263
264
		if ((ofd = open(fpath, O_RDONLY)) == -1)
265
			fatal("cvs_admin_local: open: `%s': %s", fpath,
266
			    strerror(errno));
267
268
		/* XXX: S_ISREG() check instead of blindly using CVS_FILE? */
269
		ocf = cvs_file_get_cf(d, f, oldfilename, ofd, CVS_FILE, 0);
270
271
		ocf->file_rcs = rcs_open(fpath, ofd, RCS_READ, 0444);
272
		if (ocf->file_rcs == NULL)
273
			fatal("cvs_admin_local: rcs_open failed");
274
275
		TAILQ_FOREACH(acp, &(ocf->file_rcs->rf_access), ra_list)
276
			rcs_access_add(cf->file_rcs, acp->ra_name);
277
278
		cvs_file_free(ocf);
279
	}
280
281
	if (alist != NULL) {
282
		struct cvs_argvector *aargv;
283
284
		aargv = cvs_strsplit(alist, ",");
285
		for (i = 0; aargv->argv[i] != NULL; i++)
286
			rcs_access_add(cf->file_rcs, aargv->argv[i]);
287
288
		cvs_argv_destroy(aargv);
289
	}
290
291
	if (comment != NULL)
292
		rcs_comment_set(cf->file_rcs, comment);
293
294
	if (elist != NULL) {
295
		struct cvs_argvector *eargv;
296
297
		eargv = cvs_strsplit(elist, ",");
298
		for (i = 0; eargv->argv[i] != NULL; i++)
299
			rcs_access_remove(cf->file_rcs, eargv->argv[i]);
300
301
		cvs_argv_destroy(eargv);
302
	} else if (runflags & ADM_EFLAG) {
303
		struct rcs_access *rap;
304
305
		while (!TAILQ_EMPTY(&(cf->file_rcs->rf_access))) {
306
			rap = TAILQ_FIRST(&(cf->file_rcs->rf_access));
307
			TAILQ_REMOVE(&(cf->file_rcs->rf_access), rap, ra_list);
308
			free(rap->ra_name);
309
			free(rap);
310
		}
311
		/* no synced anymore */
312
		cf->file_rcs->rf_flags &= ~RCS_SYNCED;
313
	}
314
315
	/* Default `-kv' is accepted here. */
316
	if (kflag) {
317
		if (cf->file_rcs->rf_expand == NULL ||
318
		    strcmp(cf->file_rcs->rf_expand, koptstr) != 0)
319
			rcs_kwexp_set(cf->file_rcs, kflag);
320
	}
321
322
	if (logstr != NULL) {
323
		if ((logmsg = strchr(logstr, ':')) == NULL) {
324
			cvs_log(LP_ERR, "missing log message");
325
			return;
326
		}
327
328
		*logmsg++ = '\0';
329
		if ((rev = rcsnum_parse(logstr)) == NULL) {
330
			cvs_log(LP_ERR, "`%s' bad revision number", logstr);
331
			return;
332
		}
333
334
		if (rcs_rev_setlog(cf->file_rcs, rev, logmsg) < 0) {
335
			cvs_log(LP_ERR, "failed to set logmsg for `%s' to `%s'",
336
			    logstr, logmsg);
337
			free(rev);
338
			return;
339
		}
340
341
		free(rev);
342
	}
343
344
	if (orange != NULL) {
345
		struct rcs_delta *rdp, *nrdp;
346
		char b[CVS_REV_BUFSZ];
347
348
		cvs_revision_select(cf->file_rcs, orange);
349
		for (rdp = TAILQ_FIRST(&(cf->file_rcs->rf_delta));
350
		    rdp != NULL; rdp = nrdp) {
351
			nrdp = TAILQ_NEXT(rdp, rd_list);
352
353
			/*
354
			 * Delete selected revisions.
355
			 */
356
			if (rdp->rd_flags & RCS_RD_SELECT) {
357
				rcsnum_tostr(rdp->rd_num, b, sizeof(b));
358
				if (verbosity > 0)
359
					cvs_printf("deleting revision %s\n", b);
360
361
				(void)rcs_rev_remove(cf->file_rcs, rdp->rd_num);
362
			}
363
		}
364
	}
365
366
	if (state != NULL) {
367
		if (staterevstr != NULL) {
368
			if ((rev = rcsnum_parse(staterevstr)) == NULL) {
369
				cvs_log(LP_ERR, "`%s' bad revision number",
370
				    staterevstr);
371
				return;
372
			}
373
		} else if (cf->file_rcs->rf_head != NULL) {
374
			rev = rcsnum_alloc();
375
			rcsnum_cpy(cf->file_rcs->rf_head, rev, 0);
376
		} else {
377
			cvs_log(LP_ERR, "head revision missing");
378
			return;
379
		}
380
381
		(void)rcs_state_set(cf->file_rcs, rev, state);
382
383
		free(rev);
384
	}
385
386
	if (lkmode != RCS_LOCK_INVAL)
387
		(void)rcs_lock_setmode(cf->file_rcs, lkmode);
388
389
	rcs_write(cf->file_rcs);
390
391
	if (verbosity > 0)
392
		cvs_printf("done\n");
393
}