1 /* $OpenBSD: import.c,v 1.101 2009/06/27 16:55:31 martynas 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 <string.h> 23 #include <unistd.h> 24 25 #include "cvs.h" 26 #include "diff.h" 27 #include "remote.h" 28 29 void cvs_import_local(struct cvs_file *); 30 31 static void import_loginfo(char *); 32 static void import_new(struct cvs_file *); 33 static void import_printf(const char *, ...) 34 __attribute__((format(printf, 1, 2))); 35 static void import_update(struct cvs_file *); 36 static void import_tag(struct cvs_file *, RCSNUM *, RCSNUM *); 37 static BUF *import_get_rcsdiff(struct cvs_file *, RCSNUM *); 38 39 #define IMPORT_DEFAULT_BRANCH "1.1.1" 40 41 extern char *loginfo; 42 extern char *logmsg; 43 44 static char *import_branch = IMPORT_DEFAULT_BRANCH; 45 static char *vendor_tag = NULL; 46 static char **release_tags; 47 static char *koptstr; 48 static int dflag = 0; 49 static int tagcount = 0; 50 static BUF *logbuf; 51 52 char *import_repository = NULL; 53 int import_conflicts = 0; 54 55 struct cvs_cmd cvs_cmd_import = { 56 CVS_OP_IMPORT, CVS_USE_WDIR, "import", 57 { "im", "imp" }, 58 "Import sources into CVS, using vendor branches", 59 "[-b branch] [-d] [-k mode] [-m message] " 60 "repository vendor-tag release-tags", 61 "b:dk:m:", 62 NULL, 63 cvs_import 64 }; 65 66 int 67 cvs_import(int argc, char **argv) 68 { 69 int i, ch; 70 char repo[MAXPATHLEN], *arg = "."; 71 struct cvs_recursion cr; 72 struct trigger_list *line_list; 73 74 while ((ch = getopt(argc, argv, cvs_cmd_import.cmd_opts)) != -1) { 75 switch (ch) { 76 case 'b': 77 import_branch = optarg; 78 break; 79 case 'd': 80 dflag = 1; 81 break; 82 case 'k': 83 koptstr = optarg; 84 kflag = rcs_kflag_get(koptstr); 85 if (RCS_KWEXP_INVAL(kflag)) { 86 cvs_log(LP_ERR, 87 "invalid RCS keyword expansion mode"); 88 fatal("%s", cvs_cmd_import.cmd_synopsis); 89 } 90 break; 91 case 'm': 92 logmsg = optarg; 93 break; 94 default: 95 fatal("%s", cvs_cmd_import.cmd_synopsis); 96 break; 97 } 98 } 99 100 argc -= optind; 101 argv += optind; 102 103 if (argc < 3) 104 fatal("%s", cvs_cmd_import.cmd_synopsis); 105 106 import_repository = argv[0]; 107 vendor_tag = argv[1]; 108 argc -= 2; 109 argv += 2; 110 111 release_tags = argv; 112 tagcount = argc; 113 114 if (!rcs_sym_check(vendor_tag)) 115 fatal("invalid symbol: %s", vendor_tag); 116 117 for (i = 0; i < tagcount; i++) { 118 if (!rcs_sym_check(release_tags[i])) 119 fatal("invalid symbol: %s", release_tags[i]); 120 } 121 122 if (logmsg == NULL) { 123 if (cvs_server_active) 124 fatal("no log message specified"); 125 else 126 logmsg = cvs_logmsg_create(NULL, NULL, NULL, NULL); 127 } 128 129 if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 130 cvs_client_connect_to_server(); 131 132 cvs_client_send_request("Argument -b%s", IMPORT_DEFAULT_BRANCH); 133 134 if (kflag) 135 cvs_client_send_request("Argument -k%s", koptstr); 136 137 cvs_client_send_logmsg(logmsg); 138 cvs_client_send_request("Argument %s", import_repository); 139 cvs_client_send_request("Argument %s", vendor_tag); 140 for (i = 0; i < tagcount; i++) 141 cvs_client_send_request("Argument %s", release_tags[i]); 142 143 cr.enterdir = NULL; 144 cr.leavedir = NULL; 145 cr.fileproc = cvs_client_sendfile; 146 cr.flags = CR_RECURSE_DIRS; 147 148 cvs_file_run(1, &arg, &cr); 149 cvs_client_senddir("."); 150 cvs_client_send_request("import"); 151 152 cvs_client_get_responses(); 153 return (0); 154 } 155 156 if (cvs_logmsg_verify(logmsg)) 157 return (0); 158 159 (void)xsnprintf(repo, sizeof(repo), "%s/%s", 160 current_cvsroot->cr_dir, import_repository); 161 162 import_loginfo(import_repository); 163 164 if (cvs_noexec != 1) { 165 if (mkdir(repo, 0755) == -1 && errno != EEXIST) 166 fatal("cvs_import: %s: %s", repo, strerror(errno)); 167 } 168 169 cr.enterdir = NULL; 170 cr.leavedir = NULL; 171 cr.fileproc = cvs_import_local; 172 cr.flags = CR_RECURSE_DIRS; 173 cvs_file_run(1, &arg, &cr); 174 175 if (import_conflicts != 0) { 176 import_printf("\n%d conflicts created by this import.\n\n", 177 import_conflicts); 178 import_printf("Use the following command to help the merge:\n"); 179 import_printf("\topencvs checkout "); 180 import_printf("-j%s:yesterday -j%s %s\n\n", vendor_tag, 181 vendor_tag, import_repository); 182 } else { 183 import_printf("\nNo conflicts created by this import.\n\n"); 184 } 185 186 loginfo = cvs_buf_release(logbuf); 187 logbuf = NULL; 188 189 line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO, import_repository); 190 if (line_list != NULL) { 191 cvs_trigger_handle(CVS_TRIGGER_LOGINFO, import_repository, 192 loginfo, line_list, NULL); 193 cvs_trigger_freelist(line_list); 194 } 195 196 xfree(loginfo); 197 return (0); 198 } 199 200 static void 201 import_printf(const char *fmt, ...) 202 { 203 char *str; 204 va_list vap; 205 206 va_start(vap, fmt); 207 if (vasprintf(&str, fmt, vap) == -1) 208 fatal("import_printf: could not allocate memory"); 209 va_end(vap); 210 211 cvs_printf("%s", str); 212 cvs_buf_puts(logbuf, str); 213 214 xfree(str); 215 } 216 217 void 218 cvs_import_local(struct cvs_file *cf) 219 { 220 int isnew; 221 struct stat st; 222 char repo[MAXPATHLEN]; 223 224 cvs_log(LP_TRACE, "cvs_import_local(%s)", cf->file_path); 225 226 cvs_file_classify(cf, cvs_directory_tag); 227 228 if (cf->file_type == CVS_DIR) { 229 if (!strcmp(cf->file_path, ".")) 230 return; 231 232 if (verbosity > 1) 233 cvs_log(LP_NOTICE, "Importing %s", cf->file_path); 234 235 if (cvs_noexec == 1) 236 return; 237 238 if (mkdir(cf->file_rpath, 0755) == -1 && errno != EEXIST) 239 fatal("cvs_import_local: %s: %s", cf->file_rpath, 240 strerror(errno)); 241 242 return; 243 } 244 245 isnew = 1; 246 (void)xsnprintf(repo, sizeof(repo), "%s/%s/%s/%s%s", 247 current_cvsroot->cr_dir, cf->file_wd, CVS_PATH_ATTIC, 248 cf->file_name, RCS_FILE_EXT); 249 250 if (cf->file_rcs != NULL || stat(repo, &st) != -1) 251 isnew = 0; 252 253 if (isnew == 1) 254 import_new(cf); 255 else 256 import_update(cf); 257 } 258 259 static void 260 import_loginfo(char *repo) 261 { 262 int i; 263 char pwd[MAXPATHLEN]; 264 265 if (getcwd(pwd, sizeof(pwd)) == NULL) 266 fatal("Can't get working directory"); 267 268 logbuf = cvs_buf_alloc(1024); 269 cvs_trigger_loginfo_header(logbuf, repo); 270 271 cvs_buf_puts(logbuf, "Log Message:\n"); 272 cvs_buf_puts(logbuf, logmsg); 273 if (logmsg[0] != '\0' && logmsg[strlen(logmsg) - 1] != '\n') 274 cvs_buf_putc(logbuf, '\n'); 275 cvs_buf_putc(logbuf, '\n'); 276 277 cvs_buf_puts(logbuf, "Status:\n\n"); 278 279 cvs_buf_puts(logbuf, "Vendor Tag:\t"); 280 cvs_buf_puts(logbuf, vendor_tag); 281 cvs_buf_putc(logbuf, '\n'); 282 cvs_buf_puts(logbuf, "Release Tags:\t"); 283 284 for (i = 0; i < tagcount ; i++) { 285 cvs_buf_puts(logbuf, "\t\t"); 286 cvs_buf_puts(logbuf, release_tags[i]); 287 cvs_buf_putc(logbuf, '\n'); 288 } 289 cvs_buf_putc(logbuf, '\n'); 290 cvs_buf_putc(logbuf, '\n'); 291 } 292 293 static void 294 import_new(struct cvs_file *cf) 295 { 296 int i; 297 BUF *bp; 298 mode_t mode; 299 time_t tstamp; 300 struct stat st; 301 struct rcs_branch *brp; 302 struct rcs_delta *rdp; 303 RCSNUM *branch, *brev; 304 305 tstamp = -1; 306 307 cvs_log(LP_TRACE, "import_new(%s)", cf->file_name); 308 309 if (cvs_noexec == 1) { 310 import_printf("N %s/%s\n", import_repository, cf->file_path); 311 return; 312 } 313 314 if (fstat(cf->fd, &st) == -1) 315 fatal("import_new: %s", strerror(errno)); 316 317 mode = st.st_mode; 318 319 if (dflag == 1) 320 tstamp = st.st_mtime; 321 322 if ((branch = rcsnum_parse(import_branch)) == NULL) 323 fatal("import_new: failed to parse branch"); 324 325 bp = cvs_buf_load_fd(cf->fd); 326 327 if ((brev = rcsnum_brtorev(branch)) == NULL) 328 fatal("import_new: failed to get first branch revision"); 329 330 cf->repo_fd = open(cf->file_rpath, O_CREAT | O_RDONLY); 331 if (cf->repo_fd < 0) 332 fatal("import_new: %s: %s", cf->file_rpath, strerror(errno)); 333 334 cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, RCS_CREATE, 335 (mode & ~(S_IWUSR | S_IWGRP | S_IWOTH))); 336 if (cf->file_rcs == NULL) 337 fatal("import_new: failed to create RCS file for %s", 338 cf->file_path); 339 340 rcs_branch_set(cf->file_rcs, branch); 341 342 if (rcs_sym_add(cf->file_rcs, vendor_tag, branch) == -1) 343 fatal("import_new: failed to add vendor tag"); 344 345 for (i = 0; i < tagcount; i++) { 346 if (rcs_sym_add(cf->file_rcs, release_tags[i], brev) == -1) 347 fatal("import_new: failed to add release tag"); 348 } 349 350 if (rcs_rev_add(cf->file_rcs, brev, logmsg, tstamp, NULL) == -1) 351 fatal("import_new: failed to create first branch revision"); 352 353 if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, "Initial revision", 354 tstamp, NULL) == -1) 355 fatal("import_new: failed to create first revision"); 356 357 if ((rdp = rcs_findrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) 358 fatal("import_new: cannot find newly added revision"); 359 360 brp = xmalloc(sizeof(*brp)); 361 brp->rb_num = rcsnum_alloc(); 362 rcsnum_cpy(brev, brp->rb_num, 0); 363 TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list); 364 365 if (rcs_deltatext_set(cf->file_rcs, 366 cf->file_rcs->rf_head, bp) == -1) 367 fatal("import_new: failed to set deltatext"); 368 369 if (kflag) 370 rcs_kwexp_set(cf->file_rcs, kflag); 371 372 rcs_write(cf->file_rcs); 373 import_printf("N %s/%s\n", import_repository, cf->file_path); 374 375 rcsnum_free(branch); 376 rcsnum_free(brev); 377 } 378 379 static void 380 import_update(struct cvs_file *cf) 381 { 382 int ret; 383 BUF *b1, *b2, *d; 384 char branch[CVS_REV_BUFSZ]; 385 RCSNUM *newrev, *rev, *brev; 386 387 cvs_log(LP_TRACE, "import_update(%s)", cf->file_path); 388 389 if (cf->file_rcs->rf_head == NULL) 390 fatal("no head revision in RCS file for `%s'", cf->file_path); 391 392 if ((rev = rcs_translate_tag(import_branch, cf->file_rcs)) == NULL) 393 fatal("import_update: could not translate tag `%s'", 394 import_branch); 395 396 if ((brev = rcsnum_parse(import_branch)) == NULL) 397 fatal("import_update: rcsnum_parse failed"); 398 399 b1 = rcs_rev_getbuf(cf->file_rcs, rev, RCS_KWEXP_NONE); 400 b2 = cvs_buf_load_fd(cf->fd); 401 402 ret = cvs_buf_differ(b1, b2); 403 cvs_buf_free(b1); 404 cvs_buf_free(b2); 405 if (ret == 0) { 406 import_tag(cf, brev, rev); 407 rcsnum_free(brev); 408 if (cvs_noexec != 1) 409 rcs_write(cf->file_rcs); 410 import_printf("U %s/%s\n", import_repository, cf->file_path); 411 return; 412 } 413 414 if (cf->file_rcs->rf_branch != NULL) 415 rcsnum_tostr(cf->file_rcs->rf_branch, branch, sizeof(branch)); 416 417 if (cf->file_rcs->rf_branch == NULL || cf->in_attic == 1 || 418 strcmp(branch, import_branch)) { 419 import_conflicts++; 420 import_printf("C %s/%s\n", import_repository, cf->file_path); 421 } else { 422 import_printf("U %s/%s\n", import_repository, cf->file_path); 423 } 424 425 if (cvs_noexec == 1) 426 return; 427 428 d = import_get_rcsdiff(cf, rev); 429 newrev = rcsnum_inc(rev); 430 431 if (rcs_rev_add(cf->file_rcs, newrev, logmsg, -1, NULL) == -1) 432 fatal("import_update: failed to add new revision"); 433 434 if (rcs_deltatext_set(cf->file_rcs, newrev, d) == -1) 435 fatal("import_update: failed to set deltatext"); 436 437 import_tag(cf, brev, newrev); 438 439 if (kflag) 440 rcs_kwexp_set(cf->file_rcs, kflag); 441 442 rcsnum_free(brev); 443 rcs_write(cf->file_rcs); 444 } 445 446 static void 447 import_tag(struct cvs_file *cf, RCSNUM *branch, RCSNUM *newrev) 448 { 449 int i; 450 451 if (cvs_noexec != 1) { 452 rcs_sym_add(cf->file_rcs, vendor_tag, branch); 453 454 for (i = 0; i < tagcount; i++) 455 rcs_sym_add(cf->file_rcs, release_tags[i], newrev); 456 } 457 } 458 459 static BUF * 460 import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev) 461 { 462 char *p1, *p2; 463 BUF *b1, *b2; 464 int fd1, fd2; 465 466 b2 = cvs_buf_alloc(128); 467 468 b1 = cvs_buf_load_fd(cf->fd); 469 470 (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 471 fd1 = cvs_buf_write_stmp(b1, p1, NULL); 472 cvs_buf_free(b1); 473 474 (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 475 fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE); 476 477 diff_format = D_RCSDIFF; 478 if (diffreg(p2, p1, fd2, fd1, b2, D_FORCEASCII) == D_ERROR) 479 fatal("import_get_rcsdiff: failed to get RCS patch"); 480 481 close(fd1); 482 close(fd2); 483 484 (void)unlink(p1); 485 (void)unlink(p2); 486 487 xfree(p1); 488 xfree(p2); 489 490 return (b2); 491 } 492