GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cvs/import.c Lines: 118 256 46.1 %
Date: 2017-11-07 Branches: 42 133 31.6 %

Line Branch Exec Source
1
/*	$OpenBSD: import.c,v 1.108 2017/06/01 08:08:24 joris Exp $	*/
2
/*
3
 * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/stat.h>
19
20
#include <errno.h>
21
#include <fcntl.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <unistd.h>
25
26
#include "cvs.h"
27
#include "diff.h"
28
#include "remote.h"
29
30
void	cvs_import_local(struct cvs_file *);
31
32
static void import_loginfo(char *);
33
static void import_new(struct cvs_file *);
34
static void import_printf(const char *, ...)
35
	__attribute__((format(printf, 1, 2)));
36
static void import_update(struct cvs_file *);
37
static void import_tag(struct cvs_file *, RCSNUM *, RCSNUM *);
38
static BUF *import_get_rcsdiff(struct cvs_file *, RCSNUM *);
39
40
#define IMPORT_DEFAULT_BRANCH	"1.1.1"
41
42
extern char *loginfo;
43
extern char *logmsg;
44
45
static char *import_branch = IMPORT_DEFAULT_BRANCH;
46
static char *vendor_tag = NULL;
47
static char **release_tags;
48
static char *koptstr;
49
static int dflag = 0;
50
static int tagcount = 0;
51
static BUF *logbuf;
52
53
char *import_repository = NULL;
54
int import_conflicts = 0;
55
56
struct cvs_cmd cvs_cmd_import = {
57
	CVS_OP_IMPORT, CVS_USE_WDIR, "import",
58
	{ "im", "imp" },
59
	"Import sources into CVS, using vendor branches",
60
	"[-b branch] [-d] [-k mode] [-m message] "
61
	"repository vendor-tag release-tags",
62
	"b:dk:m:",
63
	NULL,
64
	cvs_import
65
};
66
67
int
68
cvs_import(int argc, char **argv)
69
{
70
	int i, ch;
71
2
	char repo[PATH_MAX], *arg = ".";
72
1
	struct cvs_recursion cr;
73
	struct trigger_list *line_list;
74
75
3
	while ((ch = getopt(argc, argv, cvs_cmd_import.cmd_opts)) != -1) {
76

1
		switch (ch) {
77
		case 'b':
78
			import_branch = optarg;
79
			break;
80
		case 'd':
81
			dflag = 1;
82
			break;
83
		case 'k':
84
			koptstr = optarg;
85
			kflag = rcs_kflag_get(koptstr);
86
			if (RCS_KWEXP_INVAL(kflag)) {
87
				cvs_log(LP_ERR,
88
				    "invalid RCS keyword expansion mode");
89
				fatal("%s", cvs_cmd_import.cmd_synopsis);
90
			}
91
			break;
92
		case 'm':
93
1
			logmsg = optarg;
94
1
			break;
95
		default:
96
			fatal("%s", cvs_cmd_import.cmd_synopsis);
97
			break;
98
		}
99
	}
100
101
1
	argc -= optind;
102
1
	argv += optind;
103
104
1
	if (argc < 3)
105
		fatal("%s", cvs_cmd_import.cmd_synopsis);
106
107
1
	import_repository = argv[0];
108
1
	vendor_tag = argv[1];
109
1
	argc -= 2;
110
1
	argv += 2;
111
112
1
	release_tags = argv;
113
1
	tagcount = argc;
114
115
1
	if (!rcs_sym_check(vendor_tag))
116
		fatal("invalid symbol: %s", vendor_tag);
117
118
4
	for (i = 0; i < tagcount; i++) {
119
1
		if (!rcs_sym_check(release_tags[i]))
120
			fatal("invalid symbol: %s", release_tags[i]);
121
	}
122
123
1
	if (logmsg == NULL) {
124
		if (cvs_server_active)
125
			fatal("no log message specified");
126
		else
127
			logmsg = cvs_logmsg_create(NULL, NULL, NULL, NULL);
128
	}
129
130
1
	if (cvsroot_is_remote()) {
131
		cvs_client_connect_to_server();
132
133
		cvs_client_send_request("Argument -b%s", IMPORT_DEFAULT_BRANCH);
134
135
		if (kflag)
136
			cvs_client_send_request("Argument -k%s", koptstr);
137
138
		cvs_client_send_logmsg(logmsg);
139
		cvs_client_send_request("Argument %s", import_repository);
140
		cvs_client_send_request("Argument %s", vendor_tag);
141
		for (i = 0; i < tagcount; i++)
142
			cvs_client_send_request("Argument %s", release_tags[i]);
143
144
		cr.enterdir = NULL;
145
		cr.leavedir = NULL;
146
		cr.fileproc = cvs_client_sendfile;
147
		cr.flags = CR_RECURSE_DIRS;
148
149
		cvs_file_run(1, &arg, &cr);
150
		cvs_client_senddir(".");
151
		cvs_client_send_request("import");
152
153
		cvs_client_get_responses();
154
		return (0);
155
	}
156
157
1
	if (cvs_logmsg_verify(logmsg))
158
		return (0);
159
160
2
	(void)xsnprintf(repo, sizeof(repo), "%s/%s",
161
1
	    current_cvsroot->cr_dir, import_repository);
162
163
1
	import_loginfo(import_repository);
164
165
1
	if (cvs_noexec != 1)
166
1
		cvs_mkdir(repo, 0755);
167
168
1
	cr.enterdir = NULL;
169
1
	cr.leavedir = NULL;
170
1
	cr.fileproc = cvs_import_local;
171
1
	cr.flags = CR_RECURSE_DIRS;
172
1
	cvs_file_run(1, &arg, &cr);
173
174
1
	if (import_conflicts != 0) {
175
		import_printf("\n%d conflicts created by this import.\n\n",
176
		    import_conflicts);
177
		import_printf("Use the following command to help the merge:\n");
178
		import_printf("\topencvs checkout ");
179
		import_printf("-j%s:yesterday -j%s %s\n\n", vendor_tag,
180
		    vendor_tag, import_repository);
181
	} else {
182
1
		import_printf("\nNo conflicts created by this import.\n\n");
183
	}
184
185
1
	loginfo = buf_release(logbuf);
186
1
	logbuf = NULL;
187
188
1
	line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO, import_repository);
189
1
	if (line_list != NULL) {
190
		cvs_trigger_handle(CVS_TRIGGER_LOGINFO, import_repository,
191
		    loginfo, line_list, NULL);
192
		cvs_trigger_freelist(line_list);
193
	}
194
195
1
	free(loginfo);
196
1
	return (0);
197
1
}
198
199
static void
200
import_printf(const char *fmt, ...)
201
{
202
4
	char *str;
203
2
	va_list vap;
204
205
2
	va_start(vap, fmt);
206
2
	if (vasprintf(&str, fmt, vap) == -1)
207
		fatal("import_printf: could not allocate memory");
208
2
	va_end(vap);
209
210
2
	cvs_printf("%s", str);
211
2
	buf_puts(logbuf, str);
212
213
2
	free(str);
214
2
}
215
216
void
217
cvs_import_ignored(const char *path)
218
{
219
	const char *p;
220
221
	for (p = path; p[0] == '.' && p[1] == '/';)
222
		p += 2;
223
224
	import_printf("I %s/%s\n", import_repository, p);
225
}
226
227
void
228
cvs_import_local(struct cvs_file *cf)
229
{
230
	int isnew;
231
4
	struct stat st;
232
2
	char repo[PATH_MAX];
233
234
2
	cvs_log(LP_TRACE, "cvs_import_local(%s)", cf->file_path);
235
236
2
	cvs_file_classify(cf, cvs_directory_tag);
237
238
2
	if (cf->file_type == CVS_DIR) {
239
1
		if (!strcmp(cf->file_path, "."))
240
1
			return;
241
242
		if (verbosity > 1)
243
			cvs_log(LP_NOTICE, "Importing %s", cf->file_path);
244
245
		if (cvs_noexec == 1)
246
			return;
247
248
		if (mkdir(cf->file_rpath, 0755) == -1 && errno != EEXIST)
249
			fatal("cvs_import_local: %s: %s", cf->file_rpath,
250
			    strerror(errno));
251
252
		return;
253
	}
254
255
	isnew = 1;
256
2
	(void)xsnprintf(repo, sizeof(repo), "%s/%s/%s/%s%s",
257
1
	    current_cvsroot->cr_dir, cf->file_wd, CVS_PATH_ATTIC,
258
1
	    cf->file_name, RCS_FILE_EXT);
259
260

2
	if (cf->file_rcs != NULL || stat(repo, &st) != -1)
261
		isnew = 0;
262
263
1
	if (isnew == 1)
264
1
		import_new(cf);
265
	else
266
		import_update(cf);
267
3
}
268
269
static void
270
import_loginfo(char *repo)
271
{
272
	int i;
273
2
	char pwd[PATH_MAX];
274
275
1
	if (getcwd(pwd, sizeof(pwd)) == NULL)
276
		fatal("Can't get working directory");
277
278
1
	logbuf = buf_alloc(1024);
279
1
	cvs_trigger_loginfo_header(logbuf, repo);
280
281
1
	buf_puts(logbuf, "Log Message:\n");
282
1
	buf_puts(logbuf, logmsg);
283

2
	if (logmsg[0] != '\0' && logmsg[strlen(logmsg) - 1] != '\n')
284
1
		buf_putc(logbuf, '\n');
285
1
	buf_putc(logbuf, '\n');
286
287
1
	buf_puts(logbuf, "Status:\n\n");
288
289
1
	buf_puts(logbuf, "Vendor Tag:\t");
290
1
	buf_puts(logbuf, vendor_tag);
291
1
	buf_putc(logbuf, '\n');
292
1
	buf_puts(logbuf, "Release Tags:\t");
293
294
4
	for (i = 0; i < tagcount ; i++) {
295
1
		buf_puts(logbuf, "\t\t");
296
1
		buf_puts(logbuf, release_tags[i]);
297
1
		buf_putc(logbuf, '\n');
298
	}
299
1
	buf_putc(logbuf, '\n');
300
1
	buf_putc(logbuf, '\n');
301
1
}
302
303
static void
304
import_new(struct cvs_file *cf)
305
{
306
	int i;
307
	BUF *bp;
308
	mode_t mode;
309
	time_t tstamp;
310
2
	struct stat st;
311
	struct rcs_branch *brp;
312
	struct rcs_delta *rdp;
313
	RCSNUM *branch, *brev;
314
315
	tstamp = -1;
316
317
1
	cvs_log(LP_TRACE, "import_new(%s)", cf->file_name);
318
319
1
	if (cvs_noexec == 1) {
320
		import_printf("N %s/%s\n", import_repository, cf->file_path);
321
		return;
322
	}
323
324
1
	if (fstat(cf->fd, &st) == -1)
325
		fatal("import_new: %s", strerror(errno));
326
327
1
	mode = st.st_mode;
328
329
1
	if (dflag == 1)
330
		tstamp = st.st_mtime;
331
332
1
	if ((branch = rcsnum_parse(import_branch)) == NULL)
333
		fatal("import_new: failed to parse branch");
334
335
1
	bp = buf_load_fd(cf->fd);
336
337
1
	if ((brev = rcsnum_brtorev(branch)) == NULL)
338
		fatal("import_new: failed to get first branch revision");
339
340
1
	cf->repo_fd = open(cf->file_rpath, O_CREAT | O_RDONLY);
341
1
	if (cf->repo_fd < 0)
342
		fatal("import_new: %s: %s", cf->file_rpath, strerror(errno));
343
344
1
	cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, RCS_CREATE,
345
1
	    (mode & ~(S_IWUSR | S_IWGRP | S_IWOTH)));
346
1
	if (cf->file_rcs == NULL)
347
		fatal("import_new: failed to create RCS file for %s",
348
		    cf->file_path);
349
350
1
	rcs_branch_set(cf->file_rcs, branch);
351
352
1
	if (rcs_sym_add(cf->file_rcs, vendor_tag, branch) == -1)
353
		fatal("import_new: failed to add vendor tag");
354
355
4
	for (i = 0; i < tagcount; i++) {
356
1
		if (rcs_sym_add(cf->file_rcs, release_tags[i], brev) == -1)
357
			fatal("import_new: failed to add release tag");
358
	}
359
360
1
	if (rcs_rev_add(cf->file_rcs, brev, logmsg, tstamp, NULL) == -1)
361
		fatal("import_new: failed to create first branch revision");
362
363
2
	if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, "Initial revision",
364
1
	    tstamp, NULL) == -1)
365
		fatal("import_new: failed to create first revision");
366
367
1
	if ((rdp = rcs_findrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL)
368
		fatal("import_new: cannot find newly added revision");
369
370
1
	brp = xmalloc(sizeof(*brp));
371
1
	brp->rb_num = rcsnum_alloc();
372
1
	rcsnum_cpy(brev, brp->rb_num, 0);
373
1
	TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list);
374
375
3
	if (rcs_deltatext_set(cf->file_rcs,
376
2
	    cf->file_rcs->rf_head, bp) == -1)
377
		fatal("import_new: failed to set deltatext");
378
379
1
	if (kflag)
380
		rcs_kwexp_set(cf->file_rcs, kflag);
381
382
1
	rcs_write(cf->file_rcs);
383
1
	import_printf("N %s/%s\n", import_repository, cf->file_path);
384
385
1
	free(branch);
386
1
	free(brev);
387
2
}
388
389
static void
390
import_update(struct cvs_file *cf)
391
{
392
	int ret;
393
	BUF *b1, *b2, *d;
394
	char branch[CVS_REV_BUFSZ];
395
	RCSNUM *newrev, *rev, *brev;
396
397
	cvs_log(LP_TRACE, "import_update(%s)", cf->file_path);
398
399
	if (cf->file_rcs->rf_head == NULL)
400
		fatal("no head revision in RCS file for `%s'", cf->file_path);
401
402
	if ((rev = rcs_translate_tag(import_branch, cf->file_rcs)) == NULL)
403
		fatal("import_update: could not translate tag `%s'",
404
		    import_branch);
405
406
	if ((brev = rcsnum_parse(import_branch)) == NULL)
407
		fatal("import_update: rcsnum_parse failed");
408
409
	b1 = rcs_rev_getbuf(cf->file_rcs, rev, RCS_KWEXP_NONE);
410
	b2 = buf_load_fd(cf->fd);
411
412
	ret = buf_differ(b1, b2);
413
	buf_free(b1);
414
	buf_free(b2);
415
	if (ret == 0) {
416
		import_tag(cf, brev, rev);
417
		free(brev);
418
		if (cvs_noexec != 1)
419
			rcs_write(cf->file_rcs);
420
		import_printf("U %s/%s\n", import_repository, cf->file_path);
421
		return;
422
	}
423
424
	if (cf->file_rcs->rf_branch != NULL)
425
		rcsnum_tostr(cf->file_rcs->rf_branch, branch, sizeof(branch));
426
427
	if (cf->file_rcs->rf_branch == NULL || cf->in_attic == 1 ||
428
	    strcmp(branch, import_branch)) {
429
		import_conflicts++;
430
		import_printf("C %s/%s\n", import_repository, cf->file_path);
431
	} else {
432
		import_printf("U %s/%s\n", import_repository, cf->file_path);
433
	}
434
435
	if (cvs_noexec == 1)
436
		return;
437
438
	d = import_get_rcsdiff(cf, rev);
439
	newrev = rcsnum_inc(rev);
440
441
	if (rcs_rev_add(cf->file_rcs, newrev, logmsg, -1, NULL) == -1)
442
		fatal("import_update: failed to add new revision");
443
444
	if (rcs_deltatext_set(cf->file_rcs, newrev, d) == -1)
445
		fatal("import_update: failed to set deltatext");
446
447
	import_tag(cf, brev, newrev);
448
449
	if (kflag)
450
		rcs_kwexp_set(cf->file_rcs, kflag);
451
452
	free(brev);
453
	rcs_write(cf->file_rcs);
454
}
455
456
static void
457
import_tag(struct cvs_file *cf, RCSNUM *branch, RCSNUM *newrev)
458
{
459
	int i;
460
461
	if (cvs_noexec != 1) {
462
		rcs_sym_add(cf->file_rcs, vendor_tag, branch);
463
464
		for (i = 0; i < tagcount; i++)
465
			rcs_sym_add(cf->file_rcs, release_tags[i], newrev);
466
	}
467
}
468
469
static BUF *
470
import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev)
471
{
472
	char *p1, *p2;
473
	BUF *b1, *b2;
474
	int fd1, fd2;
475
476
	b2 = buf_alloc(128);
477
478
	b1 = buf_load_fd(cf->fd);
479
480
	(void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
481
	fd1 = buf_write_stmp(b1, p1, NULL);
482
	buf_free(b1);
483
484
	(void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
485
	fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE);
486
487
	diff_format = D_RCSDIFF;
488
	if (diffreg(p2, p1, fd2, fd1, b2, D_FORCEASCII) == D_ERROR)
489
		fatal("import_get_rcsdiff: failed to get RCS patch");
490
491
	close(fd1);
492
	close(fd2);
493
494
	(void)unlink(p1);
495
	(void)unlink(p2);
496
497
	free(p1);
498
	free(p2);
499
500
	return (b2);
501
}