1 /* $OpenBSD: diff3prog.c,v 1.11 2009/10/27 23:59:37 deraadt Exp $ */ 2 3 /* 4 * Copyright (C) Caldera International Inc. 2001-2002. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code and documentation must retain the above 11 * copyright notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed or owned by Caldera 18 * International, Inc. 19 * 4. Neither the name of Caldera International, Inc. nor the names of other 20 * contributors may be used to endorse or promote products derived from 21 * this software without specific prior written permission. 22 * 23 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 28 * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 /*- 37 * Copyright (c) 1991, 1993 38 * The Regents of the University of California. All rights reserved. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)diff3.c 8.1 (Berkeley) 6/6/93 65 */ 66 67 #if 0 68 #ifndef lint 69 static char sccsid[] = "@(#)diff3.c 8.1 (Berkeley) 6/6/93"; 70 #endif 71 #endif /* not lint */ 72 #include <sys/cdefs.h> 73 __FBSDID("$FreeBSD$"); 74 75 #include <sys/capsicum.h> 76 #include <sys/procdesc.h> 77 #include <sys/types.h> 78 #include <sys/event.h> 79 #include <sys/wait.h> 80 81 #include <capsicum_helpers.h> 82 #include <ctype.h> 83 #include <err.h> 84 #include <getopt.h> 85 #include <stdio.h> 86 #include <stdlib.h> 87 #include <string.h> 88 #include <unistd.h> 89 90 91 /* 92 * "from" is first in range of changed lines; "to" is last+1 93 * from=to=line after point of insertion for added lines. 94 */ 95 struct range { 96 int from; 97 int to; 98 }; 99 100 struct diff { 101 struct range old; 102 struct range new; 103 }; 104 105 static size_t szchanges; 106 107 static struct diff *d13; 108 static struct diff *d23; 109 /* 110 * "de" is used to gather editing scripts. These are later spewed out in 111 * reverse order. Its first element must be all zero, the "new" component 112 * of "de" contains line positions or byte positions depending on when you 113 * look (!?). Array overlap indicates which sections in "de" correspond to 114 * lines that are different in all three files. 115 */ 116 static struct diff *de; 117 static char *overlap; 118 static int overlapcnt; 119 static FILE *fp[3]; 120 static int cline[3]; /* # of the last-read line in each file (0-2) */ 121 /* 122 * The latest known correspondence between line numbers of the 3 files 123 * is stored in last[1-3]; 124 */ 125 static int last[4]; 126 static int Aflag, eflag, iflag, mflag, Tflag; 127 static int oflag; /* indicates whether to mark overlaps (-E or -X)*/ 128 static int strip_cr; 129 static char *f1mark, *f2mark, *f3mark; 130 131 static bool duplicate(struct range *, struct range *); 132 static int edit(struct diff *, bool, int); 133 static char *getchange(FILE *); 134 static char *get_line(FILE *, size_t *); 135 static int number(char **); 136 static int readin(int fd, struct diff **); 137 static int skip(int, int, const char *); 138 static void change(int, struct range *, bool); 139 static void keep(int, struct range *); 140 static void merge(int, int); 141 static void prange(struct range *); 142 static void repos(int); 143 static void edscript(int) __dead2; 144 static void increase(void); 145 static void usage(void) __dead2; 146 147 enum { 148 DIFFPROG_OPT, 149 STRIPCR_OPT, 150 }; 151 152 #define DIFF_PATH "/usr/bin/diff" 153 154 #define OPTIONS "3aAeEiL:mTxX" 155 static struct option longopts[] = { 156 { "ed", no_argument, NULL, 'e' }, 157 { "show-overlap", no_argument, NULL, 'E' }, 158 { "overlap-only", no_argument, NULL, 'x' }, 159 { "initial-tab", no_argument, NULL, 'T' }, 160 { "text", no_argument, NULL, 'a' }, 161 { "strip-trailing-cr", no_argument, NULL, STRIPCR_OPT }, 162 { "show-all", no_argument, NULL, 'A' }, 163 { "easy-only", no_argument, NULL, '3' }, 164 { "merge", no_argument, NULL, 'm' }, 165 { "label", required_argument, NULL, 'L' }, 166 { "diff-program", required_argument, NULL, DIFFPROG_OPT }, 167 }; 168 169 static void 170 usage(void) 171 { 172 fprintf(stderr, "usage: diff3 [-3aAeEimTxX] [-L lable1] [-L label2] " 173 "[ -L label3] file1 file2 file3\n"); 174 exit (2); 175 } 176 177 static int 178 readin(int fd, struct diff **dd) 179 { 180 int a, b, c, d; 181 size_t i; 182 char kind, *p; 183 FILE *f; 184 185 f = fdopen(fd, "r"); 186 if (f == NULL) 187 err(2, "fdopen"); 188 for (i=0; (p = getchange(f)); i++) { 189 if (i >= szchanges - 1) 190 increase(); 191 a = b = number(&p); 192 if (*p == ',') { 193 p++; 194 b = number(&p); 195 } 196 kind = *p++; 197 c = d = number(&p); 198 if (*p==',') { 199 p++; 200 d = number(&p); 201 } 202 if (kind == 'a') 203 a++; 204 if (kind == 'd') 205 c++; 206 b++; 207 d++; 208 (*dd)[i].old.from = a; 209 (*dd)[i].old.to = b; 210 (*dd)[i].new.from = c; 211 (*dd)[i].new.to = d; 212 } 213 if (i) { 214 (*dd)[i].old.from = (*dd)[i-1].old.to; 215 (*dd)[i].new.from = (*dd)[i-1].new.to; 216 } 217 fclose(f); 218 return (i); 219 } 220 221 static int 222 diffexec(const char *diffprog, char **diffargv, int fd[]) 223 { 224 int pid, pd; 225 226 switch (pid = pdfork(&pd, PD_CLOEXEC)) { 227 case 0: 228 close(fd[0]); 229 if (dup2(fd[1], STDOUT_FILENO) == -1) 230 err(2, "child could not duplicate descriptor"); 231 close(fd[1]); 232 execvp(diffprog, diffargv); 233 err(2, "could not execute diff: %s", diffprog); 234 break; 235 case -1: 236 err(2, "could not fork"); 237 break; 238 } 239 close(fd[1]); 240 return (pd); 241 } 242 243 static int 244 number(char **lc) 245 { 246 int nn; 247 248 nn = 0; 249 while (isdigit((unsigned char)(**lc))) 250 nn = nn*10 + *(*lc)++ - '0'; 251 return (nn); 252 } 253 254 static char * 255 getchange(FILE *b) 256 { 257 char *line; 258 259 while ((line = get_line(b, NULL))) { 260 if (isdigit((unsigned char)line[0])) 261 return (line); 262 } 263 return (NULL); 264 } 265 266 267 static char * 268 get_line(FILE *b, size_t *n) 269 { 270 char *cp; 271 size_t len; 272 static char *buf; 273 static size_t bufsize; 274 275 if ((cp = fgetln(b, &len)) == NULL) 276 return (NULL); 277 278 if (cp[len - 1] != '\n') 279 len++; 280 if (len + 1 > bufsize) { 281 do { 282 bufsize += 1024; 283 } while (len + 1 > bufsize); 284 if ((buf = realloc(buf, bufsize)) == NULL) 285 err(EXIT_FAILURE, NULL); 286 } 287 memcpy(buf, cp, len - 1); 288 buf[len - 1] = '\n'; 289 buf[len] = '\0'; 290 if (n != NULL) 291 *n = len; 292 return (buf); 293 } 294 295 static void 296 merge(int m1, int m2) 297 { 298 struct diff *d1, *d2, *d3; 299 int j, t1, t2; 300 bool dup = false; 301 302 d1 = d13; 303 d2 = d23; 304 j = 0; 305 306 while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { 307 /* first file is different from the others */ 308 if (!t2 || (t1 && d1->new.to < d2->new.from)) { 309 /* stuff peculiar to 1st file */ 310 if (eflag == 0) { 311 printf("====1\n"); 312 change(1, &d1->old, false); 313 keep(2, &d1->new); 314 change(3, &d1->new, false); 315 } 316 d1++; 317 continue; 318 } 319 /* second file is different from others */ 320 if (!t1 || (t2 && d2->new.to < d1->new.from)) { 321 if (eflag == 0) { 322 printf("====2\n"); 323 keep(1, &d2->new); 324 change(3, &d2->new, false); 325 change(2, &d2->old, false); 326 } 327 d2++; 328 continue; 329 } 330 /* 331 * Merge overlapping changes in first file 332 * this happens after extension (see below). 333 */ 334 if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 335 d1[1].old.from = d1->old.from; 336 d1[1].new.from = d1->new.from; 337 d1++; 338 continue; 339 } 340 341 /* merge overlapping changes in second */ 342 if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 343 d2[1].old.from = d2->old.from; 344 d2[1].new.from = d2->new.from; 345 d2++; 346 continue; 347 } 348 /* stuff peculiar to third file or different in all */ 349 if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 350 dup = duplicate(&d1->old, &d2->old); 351 /* 352 * dup = 0 means all files differ 353 * dup = 1 means files 1 and 2 identical 354 */ 355 if (eflag == 0) { 356 printf("====%s\n", dup ? "3" : ""); 357 change(1, &d1->old, dup); 358 change(2, &d2->old, false); 359 d3 = d1->old.to > d1->old.from ? d1 : d2; 360 change(3, &d3->new, false); 361 } else 362 j = edit(d1, dup, j); 363 d1++; 364 d2++; 365 continue; 366 } 367 /* 368 * Overlapping changes from file 1 and 2; extend changes 369 * appropriately to make them coincide. 370 */ 371 if (d1->new.from < d2->new.from) { 372 d2->old.from -= d2->new.from - d1->new.from; 373 d2->new.from = d1->new.from; 374 } else if (d2->new.from < d1->new.from) { 375 d1->old.from -= d1->new.from - d2->new.from; 376 d1->new.from = d2->new.from; 377 } 378 if (d1->new.to > d2->new.to) { 379 d2->old.to += d1->new.to - d2->new.to; 380 d2->new.to = d1->new.to; 381 } else if (d2->new.to > d1->new.to) { 382 d1->old.to += d2->new.to - d1->new.to; 383 d1->new.to = d2->new.to; 384 } 385 } 386 if (eflag) 387 edscript(j); 388 } 389 390 /* 391 * The range of lines rold.from thru rold.to in file i is to be changed. 392 * It is to be printed only if it does not duplicate something to be 393 * printed later. 394 */ 395 static void 396 change(int i, struct range *rold, bool dup) 397 { 398 399 printf("%d:", i); 400 last[i] = rold->to; 401 prange(rold); 402 if (dup) 403 return; 404 i--; 405 skip(i, rold->from, NULL); 406 skip(i, rold->to, " "); 407 } 408 409 /* 410 * Print the range of line numbers, rold.from thru rold.to, as n1,n2 or 411 * n1. 412 */ 413 static void 414 prange(struct range *rold) 415 { 416 417 if (rold->to <= rold->from) 418 printf("%da\n", rold->from - 1); 419 else { 420 printf("%d", rold->from); 421 if (rold->to > rold->from+1) 422 printf(",%d", rold->to - 1); 423 printf("c\n"); 424 } 425 } 426 427 /* 428 * No difference was reported by diff between file 1 (or 2) and file 3, 429 * and an artificial dummy difference (trange) must be ginned up to 430 * correspond to the change reported in the other file. 431 */ 432 static void 433 keep(int i, struct range *rnew) 434 { 435 int delta; 436 struct range trange; 437 438 delta = last[3] - last[i]; 439 trange.from = rnew->from - delta; 440 trange.to = rnew->to - delta; 441 change(i, &trange, true); 442 } 443 444 /* 445 * skip to just before line number from in file "i". If "pr" is non-NULL, 446 * print all skipped stuff with string pr as a prefix. 447 */ 448 static int 449 skip(int i, int from, const char *pr) 450 { 451 size_t j, n; 452 char *line; 453 454 for (n = 0; cline[i] < from - 1; n += j) { 455 if ((line = get_line(fp[i], &j)) == NULL) 456 errx(EXIT_FAILURE, "logic error"); 457 if (pr != NULL) 458 printf("%s%s", Tflag == 1? "\t" : pr, line); 459 cline[i]++; 460 } 461 return ((int) n); 462 } 463 464 /* 465 * Return 1 or 0 according as the old range (in file 1) contains exactly 466 * the same data as the new range (in file 2). 467 */ 468 static bool 469 duplicate(struct range *r1, struct range *r2) 470 { 471 int c, d; 472 int nchar; 473 int nline; 474 475 if (r1->to-r1->from != r2->to-r2->from) 476 return (0); 477 skip(0, r1->from, NULL); 478 skip(1, r2->from, NULL); 479 nchar = 0; 480 for (nline=0; nline < r1->to - r1->from; nline++) { 481 do { 482 c = getc(fp[0]); 483 d = getc(fp[1]); 484 if (c == -1 || d== -1) 485 errx(EXIT_FAILURE, "logic error"); 486 nchar++; 487 if (c != d) { 488 repos(nchar); 489 return (0); 490 } 491 } while (c != '\n'); 492 } 493 repos(nchar); 494 return (1); 495 } 496 497 static void 498 repos(int nchar) 499 { 500 int i; 501 502 for (i = 0; i < 2; i++) 503 (void)fseek(fp[i], (long)-nchar, SEEK_CUR); 504 } 505 /* 506 * collect an editing script for later regurgitation 507 */ 508 static int 509 edit(struct diff *diff, bool dup, int j) 510 { 511 512 if (((dup + 1) & eflag) == 0) 513 return (j); 514 j++; 515 overlap[j] = !dup; 516 if (!dup) 517 overlapcnt++; 518 de[j].old.from = diff->old.from; 519 de[j].old.to = diff->old.to; 520 de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 521 de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 522 return (j); 523 } 524 525 /* regurgitate */ 526 static void 527 edscript(int n) 528 { 529 int k; 530 size_t j; 531 char block[BUFSIZ]; 532 533 for (; n > 0; n--) { 534 if (!oflag || !overlap[n]) { 535 prange(&de[n].old); 536 } else { 537 printf("%da\n", de[n].old.to -1); 538 if (Aflag) { 539 printf("%s\n", f2mark); 540 fseek(fp[1], de[n].old.from, SEEK_SET); 541 for (k = de[n].old.to - de[n].old.from; k > 0; k -= j) { 542 j = k > BUFSIZ ? BUFSIZ : k; 543 if (fread(block, 1, j, fp[1]) != j) 544 errx(2, "logic error"); 545 fwrite(block, 1, j, stdout); 546 } 547 printf("\n"); 548 } 549 printf("=======\n"); 550 } 551 fseek(fp[2], (long)de[n].new.from, SEEK_SET); 552 for (k = de[n].new.to - de[n].new.from; k > 0; k-= j) { 553 j = k > BUFSIZ ? BUFSIZ : k; 554 if (fread(block, 1, j, fp[2]) != j) 555 errx(2, "logic error"); 556 fwrite(block, 1, j, stdout); 557 } 558 if (!oflag || !overlap[n]) 559 printf(".\n"); 560 else { 561 printf("%s\n.\n", f3mark); 562 printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 563 } 564 } 565 if (iflag) 566 printf("w\nq\n"); 567 568 exit(eflag == 0 ? overlapcnt : 0); 569 } 570 571 static void 572 increase(void) 573 { 574 struct diff *p; 575 char *q; 576 size_t newsz, incr; 577 578 /* are the memset(3) calls needed? */ 579 newsz = szchanges == 0 ? 64 : 2 * szchanges; 580 incr = newsz - szchanges; 581 582 p = realloc(d13, newsz * sizeof(struct diff)); 583 if (p == NULL) 584 err(1, NULL); 585 memset(p + szchanges, 0, incr * sizeof(struct diff)); 586 d13 = p; 587 p = realloc(d23, newsz * sizeof(struct diff)); 588 if (p == NULL) 589 err(1, NULL); 590 memset(p + szchanges, 0, incr * sizeof(struct diff)); 591 d23 = p; 592 p = realloc(de, newsz * sizeof(struct diff)); 593 if (p == NULL) 594 err(1, NULL); 595 memset(p + szchanges, 0, incr * sizeof(struct diff)); 596 de = p; 597 q = realloc(overlap, newsz * sizeof(char)); 598 if (q == NULL) 599 err(1, NULL); 600 memset(q + szchanges, 0, incr * sizeof(char)); 601 overlap = q; 602 szchanges = newsz; 603 } 604 605 606 int 607 main(int argc, char **argv) 608 { 609 int ch, nblabels, status, m, n, kq, nke, nleft, i; 610 char *labels[] = { NULL, NULL, NULL }; 611 const char *diffprog = DIFF_PATH; 612 char *file1, *file2, *file3; 613 char *diffargv[6]; 614 int diffargc = 0; 615 int fd13[2], fd23[2]; 616 int pd13, pd23; 617 cap_rights_t rights_ro; 618 struct kevent *e; 619 620 nblabels = 0; 621 eflag = 0; 622 oflag = 0; 623 diffargv[diffargc++] = __DECONST(char *, diffprog); 624 while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { 625 switch (ch) { 626 case '3': 627 eflag = 2; 628 break; 629 case 'a': 630 diffargv[diffargc++] = __DECONST(char *, "-a"); 631 break; 632 case 'A': 633 Aflag = 1; 634 break; 635 case 'e': 636 eflag = 3; 637 break; 638 case 'E': 639 eflag = 3; 640 oflag = 1; 641 break; 642 case 'i': 643 iflag = 1; 644 break; 645 case 'L': 646 oflag = 1; 647 if (nblabels >= 3) 648 errx(2, "too many file label options"); 649 labels[nblabels++] = optarg; 650 break; 651 case 'm': 652 Aflag = 1; 653 oflag = 1; 654 mflag = 1; 655 break; 656 case 'T': 657 Tflag = 1; 658 break; 659 case 'x': 660 eflag = 1; 661 break; 662 case 'X': 663 oflag = 1; 664 eflag = 1; 665 break; 666 case DIFFPROG_OPT: 667 diffprog = optarg; 668 break; 669 case STRIPCR_OPT: 670 strip_cr = 1; 671 break; 672 } 673 } 674 argc -= optind; 675 argv += optind; 676 677 if (Aflag) { 678 eflag = 3; 679 oflag = 1; 680 } 681 682 if (argc != 3) 683 usage(); 684 685 if (caph_limit_stdio() == -1) 686 err(2, "unable to limit stdio"); 687 688 cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); 689 690 kq = kqueue(); 691 if (kq == -1) 692 err(2, "kqueue"); 693 694 e = malloc(2 * sizeof(struct kevent)); 695 if (e == NULL) 696 err(2, "malloc"); 697 698 /* TODO stdio */ 699 file1 = argv[0]; 700 file2 = argv[1]; 701 file3 = argv[2]; 702 703 if (oflag) { 704 asprintf(&f1mark, "<<<<<<< %s", 705 labels[0] != NULL ? labels[0] : file1); 706 if (f1mark == NULL) 707 err(2, "asprintf"); 708 asprintf(&f2mark, "||||||| %s", 709 labels[1] != NULL ? labels[1] : file2); 710 if (f2mark == NULL) 711 err(2, "asprintf"); 712 asprintf(&f3mark, ">>>>>>> %s", 713 labels[2] != NULL ? labels[2] : file3); 714 if (f3mark == NULL) 715 err(2, "asprintf"); 716 } 717 fp[0] = fopen(file1, "r"); 718 if (fp[0] == NULL) 719 err(2, "Can't open %s", file1); 720 if (caph_rights_limit(fileno(fp[0]), &rights_ro) < 0) 721 err(2, "unable to limit rights on: %s", file1); 722 723 fp[1] = fopen(file2, "r"); 724 if (fp[1] == NULL) 725 err(2, "Can't open %s", file2); 726 if (caph_rights_limit(fileno(fp[1]), &rights_ro) < 0) 727 err(2, "unable to limit rights on: %s", file2); 728 729 fp[2] = fopen(file3, "r"); 730 if (fp[2] == NULL) 731 err(2, "Can't open %s", file3); 732 if (caph_rights_limit(fileno(fp[2]), &rights_ro) < 0) 733 err(2, "unable to limit rights on: %s", file3); 734 735 if (pipe(fd13)) 736 err(2, "pipe"); 737 if (pipe(fd23)) 738 err(2, "pipe"); 739 740 diffargv[diffargc] = file1; 741 diffargv[diffargc + 1] = file3; 742 diffargv[diffargc + 2] = NULL; 743 744 nleft = 0; 745 pd13 = diffexec(diffprog, diffargv, fd13); 746 EV_SET(e + nleft , pd13, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL); 747 if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) 748 err(2, "kevent1"); 749 nleft++; 750 751 diffargv[diffargc] = file2; 752 pd23 = diffexec(diffprog, diffargv, fd23); 753 EV_SET(e + nleft , pd23, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL); 754 if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) 755 err(2, "kevent2"); 756 nleft++; 757 758 caph_cache_catpages(); 759 if (caph_enter() < 0) 760 err(2, "unable to enter capability mode"); 761 762 /* parse diffs */ 763 increase(); 764 m = readin(fd13[0], &d13); 765 n = readin(fd23[0], &d23); 766 767 /* waitpid cooked over pdforks */ 768 while (nleft > 0) { 769 nke = kevent(kq, NULL, 0, e, nleft, NULL); 770 if (nke == -1) 771 err(2, "kevent"); 772 for (i = 0; i < nke; i++) { 773 status = e[i].data; 774 if (WIFEXITED(status) && WEXITSTATUS(status) >= 2) 775 errx(2, "diff exited abormally"); 776 else if (WIFSIGNALED(status)) 777 errx(2, "diff killed by signal %d", 778 WTERMSIG(status)); 779 } 780 nleft -= nke; 781 } 782 merge(m, n); 783 784 return (EXIT_SUCCESS); 785 } 786