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 MAX_CHECK 768 /* 3 kb of chars */ 153 #define DIFF_PATH "/usr/bin/diff" 154 155 156 #define OPTIONS "3aAeEiL:mTxX" 157 static struct option longopts[] = { 158 { "ed", no_argument, NULL, 'e' }, 159 { "show-overlap", no_argument, NULL, 'E' }, 160 { "overlap-only", no_argument, NULL, 'x' }, 161 { "initial-tab", no_argument, NULL, 'T' }, 162 { "text", no_argument, NULL, 'a' }, 163 { "strip-trailing-cr", no_argument, NULL, STRIPCR_OPT }, 164 { "show-all", no_argument, NULL, 'A' }, 165 { "easy-only", no_argument, NULL, '3' }, 166 { "merge", no_argument, NULL, 'm' }, 167 { "label", required_argument, NULL, 'L' }, 168 { "diff-program", required_argument, NULL, DIFFPROG_OPT }, 169 }; 170 171 static void 172 usage(void) 173 { 174 fprintf(stderr, "usage: diff3 [-3aAeEimTxX] [-L lable1] [-L label2] " 175 "[ -L label3] file1 file2 file3\n"); 176 exit (2); 177 } 178 179 static int 180 readin(int fd, struct diff **dd) 181 { 182 int a, b, c, d; 183 size_t i; 184 char kind, *p; 185 FILE *f; 186 187 f = fdopen(fd, "r"); 188 if (f == NULL) 189 err(2, "fdopen"); 190 for (i=0; (p = getchange(f)); i++) { 191 if (i >= szchanges - 1) 192 increase(); 193 a = b = number(&p); 194 if (*p == ',') { 195 p++; 196 b = number(&p); 197 } 198 kind = *p++; 199 c = d = number(&p); 200 if (*p==',') { 201 p++; 202 d = number(&p); 203 } 204 if (kind == 'a') 205 a++; 206 if (kind == 'd') 207 c++; 208 b++; 209 d++; 210 (*dd)[i].old.from = a; 211 (*dd)[i].old.to = b; 212 (*dd)[i].new.from = c; 213 (*dd)[i].new.to = d; 214 } 215 if (i) { 216 (*dd)[i].old.from = (*dd)[i-1].old.to; 217 (*dd)[i].new.from = (*dd)[i-1].new.to; 218 } 219 fclose(f); 220 return (i); 221 } 222 223 static int 224 diffexec(const char *diffprog, char **diffargv, int fd[]) 225 { 226 int pid, pd; 227 228 switch (pid = pdfork(&pd, PD_CLOEXEC)) { 229 case 0: 230 close(fd[0]); 231 if (dup2(fd[1], STDOUT_FILENO) == -1) 232 err(2, "child could not duplicate descriptor"); 233 close(fd[1]); 234 execvp(diffprog, diffargv); 235 err(2, "could not execute diff: %s", diffprog); 236 break; 237 case -1: 238 err(2, "could not fork"); 239 break; 240 } 241 close(fd[1]); 242 return (pd); 243 } 244 245 static int 246 number(char **lc) 247 { 248 int nn; 249 250 nn = 0; 251 while (isdigit((unsigned char)(**lc))) 252 nn = nn*10 + *(*lc)++ - '0'; 253 return (nn); 254 } 255 256 static char * 257 getchange(FILE *b) 258 { 259 char *line; 260 261 while ((line = get_line(b, NULL))) { 262 if (isdigit((unsigned char)line[0])) 263 return (line); 264 } 265 return (NULL); 266 } 267 268 269 static char * 270 get_line(FILE *b, size_t *n) 271 { 272 char *cp; 273 size_t len; 274 static char *buf; 275 static size_t bufsize; 276 277 if ((cp = fgetln(b, &len)) == NULL) 278 return (NULL); 279 280 if (cp[len - 1] != '\n') 281 len++; 282 if (len + 1 > bufsize) { 283 do { 284 bufsize += 1024; 285 } while (len + 1 > bufsize); 286 if ((buf = realloc(buf, bufsize)) == NULL) 287 err(EXIT_FAILURE, NULL); 288 } 289 memcpy(buf, cp, len - 1); 290 buf[len - 1] = '\n'; 291 buf[len] = '\0'; 292 if (n != NULL) 293 *n = len; 294 return (buf); 295 } 296 297 static void 298 merge(int m1, int m2) 299 { 300 struct diff *d1, *d2, *d3; 301 int j, t1, t2; 302 bool dup = false; 303 304 d1 = d13; 305 d2 = d23; 306 j = 0; 307 308 while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { 309 /* first file is different from the others */ 310 if (!t2 || (t1 && d1->new.to < d2->new.from)) { 311 /* stuff peculiar to 1st file */ 312 if (eflag == 0) { 313 printf("====1\n"); 314 change(1, &d1->old, false); 315 keep(2, &d1->new); 316 change(3, &d1->new, false); 317 } 318 d1++; 319 continue; 320 } 321 /* second file is different from others */ 322 if (!t1 || (t2 && d2->new.to < d1->new.from)) { 323 if (eflag == 0) { 324 printf("====2\n"); 325 keep(1, &d2->new); 326 change(3, &d2->new, false); 327 change(2, &d2->old, false); 328 } 329 d2++; 330 continue; 331 } 332 /* 333 * Merge overlapping changes in first file 334 * this happens after extension (see below). 335 */ 336 if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 337 d1[1].old.from = d1->old.from; 338 d1[1].new.from = d1->new.from; 339 d1++; 340 continue; 341 } 342 343 /* merge overlapping changes in second */ 344 if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 345 d2[1].old.from = d2->old.from; 346 d2[1].new.from = d2->new.from; 347 d2++; 348 continue; 349 } 350 /* stuff peculiar to third file or different in all */ 351 if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 352 dup = duplicate(&d1->old, &d2->old); 353 /* 354 * dup = 0 means all files differ 355 * dup = 1 means files 1 and 2 identical 356 */ 357 if (eflag == 0) { 358 printf("====%s\n", dup ? "3" : ""); 359 change(1, &d1->old, dup); 360 change(2, &d2->old, false); 361 d3 = d1->old.to > d1->old.from ? d1 : d2; 362 change(3, &d3->new, false); 363 } else 364 j = edit(d1, dup, j); 365 d1++; 366 d2++; 367 continue; 368 } 369 /* 370 * Overlapping changes from file 1 and 2; extend changes 371 * appropriately to make them coincide. 372 */ 373 if (d1->new.from < d2->new.from) { 374 d2->old.from -= d2->new.from - d1->new.from; 375 d2->new.from = d1->new.from; 376 } else if (d2->new.from < d1->new.from) { 377 d1->old.from -= d1->new.from - d2->new.from; 378 d1->new.from = d2->new.from; 379 } 380 if (d1->new.to > d2->new.to) { 381 d2->old.to += d1->new.to - d2->new.to; 382 d2->new.to = d1->new.to; 383 } else if (d2->new.to > d1->new.to) { 384 d1->old.to += d2->new.to - d1->new.to; 385 d1->new.to = d2->new.to; 386 } 387 } 388 if (eflag) 389 edscript(j); 390 } 391 392 /* 393 * The range of lines rold.from thru rold.to in file i is to be changed. 394 * It is to be printed only if it does not duplicate something to be 395 * printed later. 396 */ 397 static void 398 change(int i, struct range *rold, bool dup) 399 { 400 401 printf("%d:", i); 402 last[i] = rold->to; 403 prange(rold); 404 if (dup) 405 return; 406 i--; 407 skip(i, rold->from, NULL); 408 skip(i, rold->to, " "); 409 } 410 411 /* 412 * Print the range of line numbers, rold.from thru rold.to, as n1,n2 or 413 * n1. 414 */ 415 static void 416 prange(struct range *rold) 417 { 418 419 if (rold->to <= rold->from) 420 printf("%da\n", rold->from - 1); 421 else { 422 printf("%d", rold->from); 423 if (rold->to > rold->from+1) 424 printf(",%d", rold->to - 1); 425 printf("c\n"); 426 } 427 } 428 429 /* 430 * No difference was reported by diff between file 1 (or 2) and file 3, 431 * and an artificial dummy difference (trange) must be ginned up to 432 * correspond to the change reported in the other file. 433 */ 434 static void 435 keep(int i, struct range *rnew) 436 { 437 int delta; 438 struct range trange; 439 440 delta = last[3] - last[i]; 441 trange.from = rnew->from - delta; 442 trange.to = rnew->to - delta; 443 change(i, &trange, true); 444 } 445 446 /* 447 * skip to just before line number from in file "i". If "pr" is non-NULL, 448 * print all skipped stuff with string pr as a prefix. 449 */ 450 static int 451 skip(int i, int from, const char *pr) 452 { 453 size_t j, n; 454 char *line; 455 456 for (n = 0; cline[i] < from - 1; n += j) { 457 if ((line = get_line(fp[i], &j)) == NULL) 458 errx(EXIT_FAILURE, "logic error"); 459 if (pr != NULL) 460 printf("%s%s", Tflag == 1? "\t" : pr, line); 461 cline[i]++; 462 } 463 return ((int) n); 464 } 465 466 /* 467 * Return 1 or 0 according as the old range (in file 1) contains exactly 468 * the same data as the new range (in file 2). 469 */ 470 static bool 471 duplicate(struct range *r1, struct range *r2) 472 { 473 int c, d; 474 int nchar; 475 int nline; 476 477 if (r1->to-r1->from != r2->to-r2->from) 478 return (0); 479 skip(0, r1->from, NULL); 480 skip(1, r2->from, NULL); 481 nchar = 0; 482 for (nline=0; nline < r1->to - r1->from; nline++) { 483 do { 484 c = getc(fp[0]); 485 d = getc(fp[1]); 486 if (c == -1 || d== -1) 487 errx(EXIT_FAILURE, "logic error"); 488 nchar++; 489 if (c != d) { 490 repos(nchar); 491 return (0); 492 } 493 } while (c != '\n'); 494 } 495 repos(nchar); 496 return (1); 497 } 498 499 static void 500 repos(int nchar) 501 { 502 int i; 503 504 for (i = 0; i < 2; i++) 505 (void)fseek(fp[i], (long)-nchar, SEEK_CUR); 506 } 507 /* 508 * collect an editing script for later regurgitation 509 */ 510 static int 511 edit(struct diff *diff, bool dup, int j) 512 { 513 514 if (((dup + 1) & eflag) == 0) 515 return (j); 516 j++; 517 overlap[j] = !dup; 518 if (!dup) 519 overlapcnt++; 520 de[j].old.from = diff->old.from; 521 de[j].old.to = diff->old.to; 522 de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 523 de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 524 return (j); 525 } 526 527 /* regurgitate */ 528 static void 529 edscript(int n) 530 { 531 int k; 532 size_t j; 533 char block[BUFSIZ]; 534 535 for (; n > 0; n--) { 536 if (!oflag || !overlap[n]) { 537 prange(&de[n].old); 538 } else { 539 printf("%da\n", de[n].old.to -1); 540 if (Aflag) { 541 printf("%s\n", f2mark); 542 fseek(fp[1], de[n].old.from, SEEK_SET); 543 for (k = de[n].old.to - de[n].old.from; k > 0; k -= j) { 544 j = k > BUFSIZ ? BUFSIZ : k; 545 if (fread(block, 1, j, fp[1]) != j) 546 errx(2, "logic error"); 547 fwrite(block, 1, j, stdout); 548 } 549 printf("\n"); 550 } 551 printf("=======\n"); 552 } 553 fseek(fp[2], (long)de[n].new.from, SEEK_SET); 554 for (k = de[n].new.to - de[n].new.from; k > 0; k-= j) { 555 j = k > BUFSIZ ? BUFSIZ : k; 556 if (fread(block, 1, j, fp[2]) != j) 557 errx(2, "logic error"); 558 fwrite(block, 1, j, stdout); 559 } 560 if (!oflag || !overlap[n]) 561 printf(".\n"); 562 else { 563 printf("%s\n.\n", f3mark); 564 printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 565 } 566 } 567 if (iflag) 568 printf("w\nq\n"); 569 570 exit(eflag == 0 ? overlapcnt : 0); 571 } 572 573 static void 574 increase(void) 575 { 576 struct diff *p; 577 char *q; 578 size_t newsz, incr; 579 580 /* are the memset(3) calls needed? */ 581 newsz = szchanges == 0 ? 64 : 2 * szchanges; 582 incr = newsz - szchanges; 583 584 p = realloc(d13, newsz * sizeof(struct diff)); 585 if (p == NULL) 586 err(1, NULL); 587 memset(p + szchanges, 0, incr * sizeof(struct diff)); 588 d13 = p; 589 p = realloc(d23, newsz * sizeof(struct diff)); 590 if (p == NULL) 591 err(1, NULL); 592 memset(p + szchanges, 0, incr * sizeof(struct diff)); 593 d23 = p; 594 p = realloc(de, newsz * sizeof(struct diff)); 595 if (p == NULL) 596 err(1, NULL); 597 memset(p + szchanges, 0, incr * sizeof(struct diff)); 598 de = p; 599 q = realloc(overlap, newsz * sizeof(char)); 600 if (q == NULL) 601 err(1, NULL); 602 memset(q + szchanges, 0, incr * sizeof(char)); 603 overlap = q; 604 szchanges = newsz; 605 } 606 607 608 int 609 main(int argc, char **argv) 610 { 611 int ch, nblabels, status, m, n, kq, nke, nleft, i; 612 char *labels[] = { NULL, NULL, NULL }; 613 const char *diffprog = DIFF_PATH; 614 char *file1, *file2, *file3; 615 char *diffargv[6]; 616 int diffargc = 0; 617 int fd13[2], fd23[2]; 618 int pd13, pd23; 619 cap_rights_t rights_ro; 620 struct kevent *e; 621 622 nblabels = 0; 623 eflag = 0; 624 oflag = 0; 625 diffargv[diffargc++] = __DECONST(char *, diffprog); 626 while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { 627 switch (ch) { 628 case '3': 629 eflag = 2; 630 break; 631 case 'a': 632 diffargv[diffargc++] = __DECONST(char *, "-a"); 633 break; 634 case 'A': 635 Aflag = 1; 636 break; 637 case 'e': 638 eflag = 3; 639 break; 640 case 'E': 641 eflag = 3; 642 oflag = 1; 643 break; 644 case 'i': 645 iflag = 1; 646 break; 647 case 'L': 648 oflag = 1; 649 if (nblabels >= 3) 650 errx(2, "too many file label options"); 651 labels[nblabels++] = optarg; 652 break; 653 case 'm': 654 Aflag = 1; 655 oflag = 1; 656 mflag = 1; 657 break; 658 case 'T': 659 Tflag = 1; 660 break; 661 case 'x': 662 eflag = 1; 663 break; 664 case 'X': 665 oflag = 1; 666 eflag = 1; 667 break; 668 case DIFFPROG_OPT: 669 diffprog = optarg; 670 break; 671 case STRIPCR_OPT: 672 strip_cr = 1; 673 break; 674 } 675 } 676 argc -= optind; 677 argv += optind; 678 679 if (Aflag) { 680 eflag = 3; 681 oflag = 1; 682 } 683 684 if (argc != 3) 685 usage(); 686 687 if (caph_limit_stdio() == -1) 688 err(2, "unable to limit stdio"); 689 690 cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); 691 692 kq = kqueue(); 693 if (kq == -1) 694 err(2, "kqueue"); 695 696 e = malloc(2 * sizeof(struct kevent)); 697 if (e == NULL) 698 err(2, "malloc"); 699 700 /* TODO stdio */ 701 file1 = argv[0]; 702 file2 = argv[1]; 703 file3 = argv[2]; 704 705 if (oflag) { 706 asprintf(&f1mark, "<<<<<<< %s", 707 labels[0] != NULL ? labels[0] : file1); 708 if (f1mark == NULL) 709 err(2, "asprintf"); 710 asprintf(&f2mark, "||||||| %s", 711 labels[1] != NULL ? labels[1] : file2); 712 if (f2mark == NULL) 713 err(2, "asprintf"); 714 asprintf(&f3mark, ">>>>>>> %s", 715 labels[2] != NULL ? labels[2] : file3); 716 if (f3mark == NULL) 717 err(2, "asprintf"); 718 } 719 fp[0] = fopen(file1, "r"); 720 if (fp[0] == NULL) 721 err(2, "Can't open %s", file1); 722 if (cap_rights_limit(fileno(fp[0]), &rights_ro) < 0) 723 err(2, "unable to limit rights on: %s", file1); 724 725 fp[1] = fopen(file2, "r"); 726 if (fp[1] == NULL) 727 err(2, "Can't open %s", file2); 728 if (cap_rights_limit(fileno(fp[1]), &rights_ro) < 0) 729 err(2, "unable to limit rights on: %s", file2); 730 731 fp[2] = fopen(file3, "r"); 732 if (fp[2] == NULL) 733 err(2, "Can't open %s", file3); 734 if (cap_rights_limit(fileno(fp[2]), &rights_ro) < 0) 735 err(2, "unable to limit rights on: %s", file3); 736 737 if (pipe(fd13)) 738 err(2, "pipe"); 739 if (pipe(fd23)) 740 err(2, "pipe"); 741 742 diffargv[diffargc] = file1; 743 diffargv[diffargc + 1] = file3; 744 diffargv[diffargc + 2] = NULL; 745 746 nleft = 0; 747 pd13 = diffexec(diffprog, diffargv, fd13); 748 EV_SET(e + nleft , pd13, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL); 749 if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) 750 err(2, "kevent1"); 751 nleft++; 752 753 diffargv[diffargc] = file2; 754 pd23 = diffexec(diffprog, diffargv, fd23); 755 EV_SET(e + nleft , pd23, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL); 756 if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) 757 err(2, "kevent2"); 758 nleft++; 759 760 caph_cache_catpages(); 761 if (cap_enter() < 0 && errno != ENOSYS) 762 err(2, "unable to enter capability mode"); 763 764 /* parse diffs */ 765 increase(); 766 m = readin(fd13[0], &d13); 767 n = readin(fd23[0], &d23); 768 769 /* waitpid cooked over pdforks */ 770 while (nleft > 0) { 771 nke = kevent(kq, NULL, 0, e, nleft, NULL); 772 if (nke == -1) 773 err(2, "kevent"); 774 for (i = 0; i < nke; i++) { 775 status = e[i].data; 776 if (WIFEXITED(status) && WEXITSTATUS(status) >= 2) 777 errx(2, "diff exited abormally"); 778 else if (WIFSIGNALED(status)) 779 errx(2, "diff killed by signal %d", 780 WTERMSIG(status)); 781 } 782 nleft -= nke; 783 } 784 merge(m, n); 785 786 return (EXIT_SUCCESS); 787 } 788