1 /* 2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc. 3 * 4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, 5 * and others. 6 * 7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk 8 * Portions Copyright (C) 1989-1992, Brian Berliner 9 * 10 * You may distribute under the terms of the GNU General Public License as 11 * specified in the README file that comes with the CVS source distribution. 12 * 13 * Patch 14 * 15 * Create a Larry Wall format "patch" file between a previous release and the 16 * current head of a module, or between two releases. Can specify the 17 * release as either a date or a revision number. 18 */ 19 20 #include "cvs.h" 21 #include "getline.h" 22 23 static RETSIGTYPE patch_cleanup (int); 24 static Dtype patch_dirproc (void *callerdat, const char *dir, 25 const char *repos, const char *update_dir, 26 List *entries); 27 static int patch_fileproc (void *callerdat, struct file_info *finfo); 28 static int patch_proc (int argc, char **argv, char *xwhere, 29 char *mwhere, char *mfile, int shorten, 30 int local_specified, char *mname, char *msg); 31 32 static int force_tag_match = 1; 33 static int patch_short = 0; 34 static int toptwo_diffs = 0; 35 static char *options = NULL; 36 static char *rev1 = NULL; 37 static int rev1_validated = 0; 38 static char *rev2 = NULL; 39 static int rev2_validated = 0; 40 static char *date1 = NULL; 41 static char *date2 = NULL; 42 static char *tmpfile1 = NULL; 43 static char *tmpfile2 = NULL; 44 static char *tmpfile3 = NULL; 45 static int unidiff = 0; 46 static int show_c_func = 0; 47 48 static const char *const patch_usage[] = 49 { 50 "Usage: %s %s [-flpR] [-c|-u] [-s|-t] [-V %%d] [-k kopt]\n", 51 " -r rev|-D date [-r rev2 | -D date2] modules...\n", 52 "\t-f\tForce a head revision match if tag/date not found.\n", 53 "\t-l\tLocal directory only, not recursive\n", 54 "\t-R\tProcess directories recursively.\n", 55 "\t-c\tContext diffs (default)\n", 56 "\t-u\tUnidiff format.\n", 57 "\t-p\tShow which C function each change is in.\n", /* --show-c-function */ 58 "\t-s\tShort patch - one liner per file.\n", 59 "\t-t\tTop two diffs - last change made to the file.\n", 60 "\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n", 61 "\t-k kopt\tSpecify keyword expansion mode.\n", 62 "\t-D date\tDate.\n", 63 "\t-r rev\tRevision - symbolic or numeric.\n", 64 "(Specify the --help global option for a list of other help options)\n", 65 NULL 66 }; 67 68 69 70 int 71 patch (int argc, char **argv) 72 { 73 register int i; 74 int local = 0; 75 int c; 76 int err = 0; 77 DBM *db; 78 79 if (argc == -1) 80 usage (patch_usage); 81 82 getoptreset (); 83 while ((c = getopt (argc, argv, "+V:k:cuftsQqlRD:r:p")) != -1) 84 { 85 switch (c) 86 { 87 case 'Q': 88 case 'q': 89 /* The CVS 1.5 client sends these options (in addition to 90 Global_option requests), so we must ignore them. */ 91 if (!server_active) 92 error (1, 0, 93 "-q or -Q must be specified before \"%s\"", 94 cvs_cmd_name); 95 break; 96 case 'f': 97 force_tag_match = 0; 98 break; 99 case 'l': 100 local = 1; 101 break; 102 case 'R': 103 local = 0; 104 break; 105 case 't': 106 toptwo_diffs = 1; 107 break; 108 case 's': 109 patch_short = 1; 110 break; 111 case 'D': 112 if (rev2 != NULL || date2 != NULL) 113 error (1, 0, 114 "no more than two revisions/dates can be specified"); 115 if (rev1 != NULL || date1 != NULL) 116 date2 = Make_Date (optarg); 117 else 118 date1 = Make_Date (optarg); 119 break; 120 case 'r': 121 if (rev2 != NULL || date2 != NULL) 122 error (1, 0, 123 "no more than two revisions/dates can be specified"); 124 if (rev1 != NULL || date1 != NULL) 125 rev2 = optarg; 126 else 127 rev1 = optarg; 128 break; 129 case 'k': 130 if (options) 131 free (options); 132 options = RCS_check_kflag (optarg); 133 break; 134 case 'V': 135 /* This option is pretty seriously broken: 136 1. It is not clear what it does (does it change keyword 137 expansion behavior? If so, how? Or does it have 138 something to do with what version of RCS we are using? 139 Or the format we write RCS files in?). 140 2. Because both it and -k use the options variable, 141 specifying both -V and -k doesn't work. 142 3. At least as of CVS 1.9, it doesn't work (failed 143 assertion in RCS_checkout where it asserts that options 144 starts with -k). Few people seem to be complaining. 145 In the future (perhaps the near future), I have in mind 146 removing it entirely, and updating NEWS and cvs.texinfo, 147 but in case it is a good idea to give people more time 148 to complain if they would miss it, I'll just add this 149 quick and dirty error message for now. */ 150 error (1, 0, 151 "the -V option is obsolete and should not be used"); 152 break; 153 case 'u': 154 unidiff = 1; /* Unidiff */ 155 break; 156 case 'c': /* Context diff */ 157 unidiff = 0; 158 break; 159 case 'p': 160 show_c_func = 1; 161 break; 162 case '?': 163 default: 164 usage (patch_usage); 165 break; 166 } 167 } 168 argc -= optind; 169 argv += optind; 170 171 /* Sanity checks */ 172 if (argc < 1) 173 usage (patch_usage); 174 175 if (toptwo_diffs && patch_short) 176 error (1, 0, "-t and -s options are mutually exclusive"); 177 if (toptwo_diffs && (date1 != NULL || date2 != NULL || 178 rev1 != NULL || rev2 != NULL)) 179 error (1, 0, "must not specify revisions/dates with -t option!"); 180 181 if (!toptwo_diffs && (date1 == NULL && date2 == NULL && 182 rev1 == NULL && rev2 == NULL)) 183 error (1, 0, "must specify at least one revision/date!"); 184 if (date1 != NULL && date2 != NULL) 185 if (RCS_datecmp (date1, date2) >= 0) 186 error (1, 0, "second date must come after first date!"); 187 188 /* if options is NULL, make it a NULL string */ 189 if (options == NULL) 190 options = xstrdup (""); 191 192 #ifdef CLIENT_SUPPORT 193 if (current_parsed_root->isremote) 194 { 195 /* We're the client side. Fire up the remote server. */ 196 start_server (); 197 198 ign_setup (); 199 200 if (local) 201 send_arg("-l"); 202 if (!force_tag_match) 203 send_arg("-f"); 204 if (toptwo_diffs) 205 send_arg("-t"); 206 if (patch_short) 207 send_arg("-s"); 208 if (unidiff) 209 send_arg("-u"); 210 if (show_c_func) 211 send_arg("-p"); 212 213 if (rev1) 214 option_with_arg ("-r", rev1); 215 if (date1) 216 client_senddate (date1); 217 if (rev2) 218 option_with_arg ("-r", rev2); 219 if (date2) 220 client_senddate (date2); 221 if (options[0] != '\0') 222 send_arg (options); 223 224 { 225 int i; 226 for (i = 0; i < argc; ++i) 227 send_arg (argv[i]); 228 } 229 230 send_to_server ("rdiff\012", 0); 231 return get_responses_and_close (); 232 } 233 #endif 234 235 /* clean up if we get a signal */ 236 #ifdef SIGABRT 237 (void)SIG_register (SIGABRT, patch_cleanup); 238 #endif 239 #ifdef SIGHUP 240 (void)SIG_register (SIGHUP, patch_cleanup); 241 #endif 242 #ifdef SIGINT 243 (void)SIG_register (SIGINT, patch_cleanup); 244 #endif 245 #ifdef SIGQUIT 246 (void)SIG_register (SIGQUIT, patch_cleanup); 247 #endif 248 #ifdef SIGPIPE 249 (void)SIG_register (SIGPIPE, patch_cleanup); 250 #endif 251 #ifdef SIGTERM 252 (void)SIG_register (SIGTERM, patch_cleanup); 253 #endif 254 255 db = open_module (); 256 for (i = 0; i < argc; i++) 257 err += do_module (db, argv[i], PATCH, "Patching", patch_proc, 258 NULL, 0, local, 0, 0, NULL); 259 close_module (db); 260 free (options); 261 patch_cleanup (0); 262 return err; 263 } 264 265 266 267 /* 268 * callback proc for doing the real work of patching 269 */ 270 /* ARGSUSED */ 271 static int 272 patch_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile, 273 int shorten, int local_specified, char *mname, char *msg) 274 { 275 char *myargv[2]; 276 int err = 0; 277 int which; 278 char *repository; 279 char *where; 280 281 TRACE ( TRACE_FUNCTION, "patch_proc ( %s, %s, %s, %d, %d, %s, %s )", 282 xwhere ? xwhere : "(null)", 283 mwhere ? mwhere : "(null)", 284 mfile ? mfile : "(null)", 285 shorten, local_specified, 286 mname ? mname : "(null)", 287 msg ? msg : "(null)" ); 288 289 repository = xmalloc (strlen (current_parsed_root->directory) 290 + strlen (argv[0]) 291 + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); 292 (void)sprintf (repository, "%s/%s", 293 current_parsed_root->directory, argv[0]); 294 where = xmalloc (strlen (argv[0]) 295 + (mfile == NULL ? 0 : strlen (mfile) + 1) 296 + 1); 297 (void)strcpy (where, argv[0]); 298 299 /* if mfile isn't null, we need to set up to do only part of the module */ 300 if (mfile != NULL) 301 { 302 char *cp; 303 char *path; 304 305 /* if the portion of the module is a path, put the dir part on repos */ 306 if ((cp = strrchr (mfile, '/')) != NULL) 307 { 308 *cp = '\0'; 309 (void)strcat (repository, "/"); 310 (void)strcat (repository, mfile); 311 (void)strcat (where, "/"); 312 (void)strcat (where, mfile); 313 mfile = cp + 1; 314 } 315 316 /* take care of the rest */ 317 path = xmalloc (strlen (repository) + strlen (mfile) + 2); 318 (void)sprintf (path, "%s/%s", repository, mfile); 319 if (isdir (path)) 320 { 321 /* directory means repository gets the dir tacked on */ 322 (void)strcpy (repository, path); 323 (void)strcat (where, "/"); 324 (void)strcat (where, mfile); 325 } 326 else 327 { 328 myargv[0] = argv[0]; 329 myargv[1] = mfile; 330 argc = 2; 331 argv = myargv; 332 } 333 free (path); 334 } 335 336 /* cd to the starting repository */ 337 if (CVS_CHDIR (repository) < 0) 338 { 339 error (0, errno, "cannot chdir to %s", repository); 340 free (repository); 341 free (where); 342 return 1; 343 } 344 345 if (force_tag_match) 346 which = W_REPOS | W_ATTIC; 347 else 348 which = W_REPOS; 349 350 if (rev1 != NULL && !rev1_validated) 351 { 352 tag_check_valid (rev1, argc - 1, argv + 1, local_specified, 0, 353 repository, false); 354 rev1_validated = 1; 355 } 356 if (rev2 != NULL && !rev2_validated) 357 { 358 tag_check_valid (rev2, argc - 1, argv + 1, local_specified, 0, 359 repository, false); 360 rev2_validated = 1; 361 } 362 363 /* start the recursion processor */ 364 err = start_recursion (patch_fileproc, NULL, patch_dirproc, NULL, NULL, 365 argc - 1, argv + 1, local_specified, 366 which, 0, CVS_LOCK_READ, where, 1, repository ); 367 free (repository); 368 free (where); 369 370 return err; 371 } 372 373 374 375 /* 376 * Called to examine a particular RCS file, as appropriate with the options 377 * that were set above. 378 */ 379 /* ARGSUSED */ 380 static int 381 patch_fileproc (void *callerdat, struct file_info *finfo) 382 { 383 struct utimbuf t; 384 char *vers_tag, *vers_head; 385 char *rcs = NULL; 386 char *rcs_orig = NULL; 387 RCSNode *rcsfile; 388 FILE *fp1, *fp2, *fp3; 389 int ret = 0; 390 int isattic = 0; 391 int retcode = 0; 392 char *file1; 393 char *file2; 394 char *strippath; 395 char *line1, *line2; 396 size_t line1_chars_allocated; 397 size_t line2_chars_allocated; 398 char *cp1, *cp2; 399 FILE *fp; 400 int line_length; 401 int dargc = 0; 402 size_t darg_allocated = 0; 403 char **dargv = NULL; 404 405 line1 = NULL; 406 line1_chars_allocated = 0; 407 line2 = NULL; 408 line2_chars_allocated = 0; 409 vers_tag = vers_head = NULL; 410 411 /* find the parsed rcs file */ 412 if ((rcsfile = finfo->rcs) == NULL) 413 { 414 ret = 1; 415 goto out2; 416 } 417 if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC)) 418 isattic = 1; 419 420 rcs_orig = rcs = Xasprintf ("%s%s", finfo->file, RCSEXT); 421 422 /* if vers_head is NULL, may have been removed from the release */ 423 if (isattic && rev2 == NULL && date2 == NULL) 424 vers_head = NULL; 425 else 426 { 427 vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match, 428 NULL); 429 if (vers_head != NULL && RCS_isdead (rcsfile, vers_head)) 430 { 431 free (vers_head); 432 vers_head = NULL; 433 } 434 } 435 436 if (toptwo_diffs) 437 { 438 if (vers_head == NULL) 439 { 440 ret = 1; 441 goto out2; 442 } 443 444 if (!date1) 445 date1 = xmalloc (MAXDATELEN); 446 *date1 = '\0'; 447 if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == (time_t)-1) 448 { 449 if (!really_quiet) 450 error (0, 0, "cannot find date in rcs file %s revision %s", 451 rcs, vers_head); 452 ret = 1; 453 goto out2; 454 } 455 } 456 vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match, NULL); 457 if (vers_tag != NULL && RCS_isdead (rcsfile, vers_tag)) 458 { 459 free (vers_tag); 460 vers_tag = NULL; 461 } 462 463 if ((vers_tag == NULL && vers_head == NULL) || 464 (vers_tag != NULL && vers_head != NULL && 465 strcmp (vers_head, vers_tag) == 0)) 466 { 467 /* Nothing known about specified revs or 468 * not changed between releases. 469 */ 470 ret = 0; 471 goto out2; 472 } 473 474 if (patch_short && (vers_tag == NULL || vers_head == NULL)) 475 { 476 /* For adds & removes with a short patch requested, we can print our 477 * error message now and get out. 478 */ 479 cvs_output ("File ", 0); 480 cvs_output (finfo->fullname, 0); 481 if (vers_tag == NULL) 482 { 483 cvs_output (" is new; ", 0); 484 cvs_output (rev2 ? rev2 : date2 ? date2 : "current", 0); 485 cvs_output (" revision ", 0); 486 cvs_output (vers_head, 0); 487 cvs_output ("\n", 1); 488 } 489 else 490 { 491 cvs_output (" is removed; ", 0); 492 cvs_output (rev1 ? rev1 : date1, 0); 493 cvs_output (" revision ", 0); 494 cvs_output (vers_tag, 0); 495 cvs_output ("\n", 1); 496 } 497 ret = 0; 498 goto out2; 499 } 500 501 /* Create 3 empty files. I'm not really sure there is any advantage 502 * to doing so now rather than just waiting until later. 503 * 504 * There is - cvs_temp_file opens the file so that it can guarantee that 505 * we have exclusive write access to the file. Unfortunately we spoil that 506 * by closing it and reopening it again. Of course any better solution 507 * requires that the RCS functions accept open file pointers rather than 508 * simple file names. 509 */ 510 if ((fp1 = cvs_temp_file (&tmpfile1)) == NULL) 511 { 512 error (0, errno, "cannot create temporary file %s", tmpfile1); 513 ret = 1; 514 goto out; 515 } 516 else 517 if (fclose (fp1) < 0) 518 error (0, errno, "warning: cannot close %s", tmpfile1); 519 if ((fp2 = cvs_temp_file (&tmpfile2)) == NULL) 520 { 521 error (0, errno, "cannot create temporary file %s", tmpfile2); 522 ret = 1; 523 goto out; 524 } 525 else 526 if (fclose (fp2) < 0) 527 error (0, errno, "warning: cannot close %s", tmpfile2); 528 if ((fp3 = cvs_temp_file (&tmpfile3)) == NULL) 529 { 530 error (0, errno, "cannot create temporary file %s", tmpfile3); 531 ret = 1; 532 goto out; 533 } 534 else 535 if (fclose (fp3) < 0) 536 error (0, errno, "warning: cannot close %s", tmpfile3); 537 538 if (vers_tag != NULL) 539 { 540 retcode = RCS_checkout (rcsfile, NULL, vers_tag, rev1, options, 541 tmpfile1, NULL, NULL); 542 if (retcode != 0) 543 { 544 error (0, 0, 545 "cannot check out revision %s of %s", vers_tag, rcs); 546 ret = 1; 547 goto out; 548 } 549 memset ((char *) &t, 0, sizeof (t)); 550 if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag, 551 NULL, 0)) != -1) 552 /* I believe this timestamp only affects the dates in our diffs, 553 and therefore should be on the server, not the client. */ 554 (void)utime (tmpfile1, &t); 555 } 556 else if (toptwo_diffs) 557 { 558 ret = 1; 559 goto out; 560 } 561 if (vers_head != NULL) 562 { 563 retcode = RCS_checkout (rcsfile, NULL, vers_head, rev2, options, 564 tmpfile2, NULL, NULL); 565 if (retcode != 0) 566 { 567 error (0, 0, 568 "cannot check out revision %s of %s", vers_head, rcs); 569 ret = 1; 570 goto out; 571 } 572 if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head, 573 NULL, 0)) != -1) 574 /* I believe this timestamp only affects the dates in our diffs, 575 and therefore should be on the server, not the client. */ 576 (void)utime (tmpfile2, &t); 577 } 578 579 if (unidiff) run_add_arg_p (&dargc, &darg_allocated, &dargv, "-u"); 580 else run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c"); 581 if (show_c_func) 582 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-p"); 583 switch (diff_exec (tmpfile1, tmpfile2, NULL, NULL, dargc, dargv, 584 tmpfile3)) 585 { 586 case -1: /* fork/wait failure */ 587 error (1, errno, "fork for diff failed on %s", rcs); 588 break; 589 case 0: /* nothing to do */ 590 break; 591 case 1: 592 /* 593 * The two revisions are really different, so read the first two 594 * lines of the diff output file, and munge them to include more 595 * reasonable file names that "patch" will understand, unless the 596 * user wanted a short patch. In that case, just output the short 597 * message. 598 */ 599 if (patch_short) 600 { 601 cvs_output ("File ", 0); 602 cvs_output (finfo->fullname, 0); 603 cvs_output (" changed from revision ", 0); 604 cvs_output (vers_tag, 0); 605 cvs_output (" to ", 0); 606 cvs_output (vers_head, 0); 607 cvs_output ("\n", 1); 608 ret = 0; 609 goto out; 610 } 611 612 /* Output an "Index:" line for patch to use */ 613 cvs_output ("Index: ", 0); 614 cvs_output (finfo->fullname, 0); 615 cvs_output ("\n", 1); 616 617 /* Now the munging. */ 618 fp = xfopen (tmpfile3, "r"); 619 if (getline (&line1, &line1_chars_allocated, fp) < 0 || 620 getline (&line2, &line2_chars_allocated, fp) < 0) 621 { 622 if (feof (fp)) 623 error (0, 0, "\ 624 failed to read diff file header %s for %s: end of file", tmpfile3, rcs); 625 else 626 error (0, errno, 627 "failed to read diff file header %s for %s", 628 tmpfile3, rcs); 629 ret = 1; 630 if (fclose (fp) < 0) 631 error (0, errno, "error closing %s", tmpfile3); 632 goto out; 633 } 634 if (!unidiff) 635 { 636 if (strncmp (line1, "*** ", 4) != 0 || 637 strncmp (line2, "--- ", 4) != 0 || 638 (cp1 = strchr (line1, '\t')) == NULL || 639 (cp2 = strchr (line2, '\t')) == NULL) 640 { 641 error (0, 0, "invalid diff header for %s", rcs); 642 ret = 1; 643 if (fclose (fp) < 0) 644 error (0, errno, "error closing %s", tmpfile3); 645 goto out; 646 } 647 } 648 else 649 { 650 if (strncmp (line1, "--- ", 4) != 0 || 651 strncmp (line2, "+++ ", 4) != 0 || 652 (cp1 = strchr (line1, '\t')) == NULL || 653 (cp2 = strchr (line2, '\t')) == NULL) 654 { 655 error (0, 0, "invalid unidiff header for %s", rcs); 656 ret = 1; 657 if (fclose (fp) < 0) 658 error (0, errno, "error closing %s", tmpfile3); 659 goto out; 660 } 661 } 662 assert (current_parsed_root != NULL); 663 assert (current_parsed_root->directory != NULL); 664 665 strippath = Xasprintf ("%s/", current_parsed_root->directory); 666 667 if (strncmp (rcs, strippath, strlen (strippath)) == 0) 668 rcs += strlen (strippath); 669 free (strippath); 670 if (vers_tag != NULL) 671 file1 = Xasprintf ("%s:%s", finfo->fullname, vers_tag); 672 else 673 file1 = xstrdup (DEVNULL); 674 675 file2 = Xasprintf ("%s:%s", finfo->fullname, 676 vers_head ? vers_head : "removed"); 677 678 /* Note that the string "diff" is specified by POSIX (for -c) 679 and is part of the diff output format, not the name of a 680 program. */ 681 if (unidiff) 682 { 683 cvs_output ("diff -u ", 0); 684 cvs_output (file1, 0); 685 cvs_output (" ", 1); 686 cvs_output (file2, 0); 687 cvs_output ("\n", 1); 688 689 cvs_output ("--- ", 0); 690 cvs_output (file1, 0); 691 cvs_output (cp1, 0); 692 cvs_output ("+++ ", 0); 693 } 694 else 695 { 696 cvs_output ("diff -c ", 0); 697 cvs_output (file1, 0); 698 cvs_output (" ", 1); 699 cvs_output (file2, 0); 700 cvs_output ("\n", 1); 701 702 cvs_output ("*** ", 0); 703 cvs_output (file1, 0); 704 cvs_output (cp1, 0); 705 cvs_output ("--- ", 0); 706 } 707 708 cvs_output (finfo->fullname, 0); 709 cvs_output (cp2, 0); 710 711 /* spew the rest of the diff out */ 712 while ((line_length 713 = getline (&line1, &line1_chars_allocated, fp)) 714 >= 0) 715 cvs_output (line1, 0); 716 if (line_length < 0 && !feof (fp)) 717 error (0, errno, "cannot read %s", tmpfile3); 718 719 if (fclose (fp) < 0) 720 error (0, errno, "cannot close %s", tmpfile3); 721 free (file1); 722 free (file2); 723 break; 724 default: 725 error (0, 0, "diff failed for %s", finfo->fullname); 726 } 727 out: 728 if (line1) 729 free (line1); 730 if (line2) 731 free (line2); 732 if (CVS_UNLINK (tmpfile1) < 0) 733 error (0, errno, "cannot unlink %s", tmpfile1); 734 if (CVS_UNLINK (tmpfile2) < 0) 735 error (0, errno, "cannot unlink %s", tmpfile2); 736 if (CVS_UNLINK (tmpfile3) < 0) 737 error (0, errno, "cannot unlink %s", tmpfile3); 738 free (tmpfile1); 739 free (tmpfile2); 740 free (tmpfile3); 741 tmpfile1 = tmpfile2 = tmpfile3 = NULL; 742 if (darg_allocated) 743 { 744 run_arg_free_p (dargc, dargv); 745 free (dargv); 746 } 747 748 out2: 749 if (vers_tag != NULL) 750 free (vers_tag); 751 if (vers_head != NULL) 752 free (vers_head); 753 if (rcs_orig) 754 free (rcs_orig); 755 return ret; 756 } 757 758 759 760 /* 761 * Print a warm fuzzy message 762 */ 763 /* ARGSUSED */ 764 static Dtype 765 patch_dirproc (void *callerdat, const char *dir, const char *repos, 766 const char *update_dir, List *entries) 767 { 768 if (!quiet) 769 error (0, 0, "Diffing %s", update_dir); 770 return R_PROCESS; 771 } 772 773 774 775 /* 776 * Clean up temporary files 777 */ 778 static RETSIGTYPE 779 patch_cleanup (int sig) 780 { 781 /* Note that the checks for existence_error are because we are 782 called from a signal handler, without SIG_begincrsect, so 783 we don't know whether the files got created. */ 784 785 static int reenter = 0; 786 787 if (reenter++) 788 _exit(1); 789 790 if (tmpfile1 != NULL) 791 { 792 if (unlink_file (tmpfile1) < 0 793 && !existence_error (errno)) 794 error (0, errno, "cannot remove %s", tmpfile1); 795 free (tmpfile1); 796 } 797 if (tmpfile2 != NULL) 798 { 799 if (unlink_file (tmpfile2) < 0 800 && !existence_error (errno)) 801 error (0, errno, "cannot remove %s", tmpfile2); 802 free (tmpfile2); 803 } 804 if (tmpfile3 != NULL) 805 { 806 if (unlink_file (tmpfile3) < 0 807 && !existence_error (errno)) 808 error (0, errno, "cannot remove %s", tmpfile3); 809 free (tmpfile3); 810 } 811 tmpfile1 = tmpfile2 = tmpfile3 = NULL; 812 813 if (sig != 0) 814 { 815 const char *name; 816 char temp[10]; 817 818 switch (sig) 819 { 820 #ifdef SIGABRT 821 case SIGABRT: 822 name = "abort"; 823 break; 824 #endif 825 #ifdef SIGHUP 826 case SIGHUP: 827 name = "hangup"; 828 break; 829 #endif 830 #ifdef SIGINT 831 case SIGINT: 832 name = "interrupt"; 833 break; 834 #endif 835 #ifdef SIGQUIT 836 case SIGQUIT: 837 name = "quit"; 838 break; 839 #endif 840 #ifdef SIGPIPE 841 case SIGPIPE: 842 name = "broken pipe"; 843 break; 844 #endif 845 #ifdef SIGTERM 846 case SIGTERM: 847 name = "termination"; 848 break; 849 #endif 850 default: 851 /* This case should never be reached, because we list 852 above all the signals for which we actually establish a 853 signal handler. */ 854 sprintf (temp, "%d", sig); 855 name = temp; 856 break; 857 } 858 error (0, 0, "received %s signal", name); 859 } 860 } 861