1 /* $NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. 5 * Copyright (c) 1994, 1995 Jochen Pohl 6 * All Rights Reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Jochen Pohl for 19 * The NetBSD Project. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #if defined(__RCSID) && !defined(lint) 37 __RCSID("$NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv Exp $"); 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/wait.h> 42 #include <sys/stat.h> 43 #include <sys/utsname.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <paths.h> 47 #include <signal.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "lint.h" 54 #include "pathnames.h" 55 56 int main(int, char *[]); 57 58 /* directory for temporary files */ 59 static const char *tmpdir; 60 61 /* path name for cpp output */ 62 static char *cppout; 63 64 /* file descriptor for cpp output */ 65 static int cppoutfd = -1; 66 67 /* files created by 1st pass */ 68 static char **p1out; 69 70 /* input files for 2nd pass (without libraries) */ 71 static char **p2in; 72 73 /* library which will be created by 2nd pass */ 74 static char *p2out; 75 76 /* flags always passed to cc(1) */ 77 static char **cflags; 78 79 /* flags for cc(1), controled by sflag/tflag */ 80 static char **lcflags; 81 82 /* flags for lint1 */ 83 static char **l1flags; 84 85 /* flags for lint2 */ 86 static char **l2flags; 87 88 /* libraries for lint2 */ 89 static char **l2libs; 90 91 /* default libraries */ 92 static char **deflibs; 93 94 /* additional libraries */ 95 static char **libs; 96 97 /* search path for libraries */ 98 static char **libsrchpath; 99 100 static char *libexec_path; 101 102 /* flags */ 103 static int iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag; 104 105 /* print the commands executed to run the stages of compilation */ 106 static int Vflag; 107 108 /* filename for oflag */ 109 static char *outputfn; 110 111 /* reset after first .c source has been processed */ 112 static int first = 1; 113 114 /* 115 * name of a file which is currently written by a child and should 116 * be removed after abnormal termination of the child 117 */ 118 static const char *currfn; 119 120 #if !defined(TARGET_PREFIX) 121 #define TARGET_PREFIX "" 122 #endif 123 static const char target_prefix[] = TARGET_PREFIX; 124 125 static void appstrg(char ***, char *); 126 static void appcstrg(char ***, const char *); 127 static void applst(char ***, char *const *); 128 static void freelst(char ***); 129 static char *concat2(const char *, const char *); 130 static char *concat3(const char *, const char *, const char *); 131 static void terminate(int) __attribute__((__noreturn__)); 132 static const char *lbasename(const char *, int); 133 static void appdef(char ***, const char *); 134 static void usage(void); 135 static void fname(const char *); 136 static void runchild(const char *, char *const *, const char *, int); 137 static void findlibs(char *const *); 138 static int rdok(const char *); 139 static void lint2(void); 140 static void cat(char *const *, const char *); 141 142 /* 143 * Some functions to deal with lists of strings. 144 * Take care that we get no surprises in case of asyncron signals. 145 */ 146 static void 147 appstrg(char ***lstp, char *s) 148 { 149 char **lst, **olst; 150 int i; 151 152 olst = *lstp; 153 for (i = 0; olst[i] != NULL; i++) 154 continue; 155 lst = xrealloc(olst, (i + 2) * sizeof (char *)); 156 lst[i] = s; 157 lst[i + 1] = NULL; 158 *lstp = lst; 159 } 160 161 static void 162 appcstrg(char ***lstp, const char *s) 163 { 164 165 appstrg(lstp, xstrdup(s)); 166 } 167 168 static void 169 applst(char ***destp, char *const *src) 170 { 171 int i, k; 172 char **dest, **odest; 173 174 odest = *destp; 175 for (i = 0; odest[i] != NULL; i++) 176 continue; 177 for (k = 0; src[k] != NULL; k++) 178 continue; 179 dest = xrealloc(odest, (i + k + 1) * sizeof (char *)); 180 for (k = 0; src[k] != NULL; k++) 181 dest[i + k] = xstrdup(src[k]); 182 dest[i + k] = NULL; 183 *destp = dest; 184 } 185 186 static void 187 freelst(char ***lstp) 188 { 189 char *s; 190 int i; 191 192 for (i = 0; (*lstp)[i] != NULL; i++) 193 continue; 194 while (i-- > 0) { 195 s = (*lstp)[i]; 196 (*lstp)[i] = NULL; 197 free(s); 198 } 199 } 200 201 static char * 202 concat2(const char *s1, const char *s2) 203 { 204 char *s; 205 206 s = xmalloc(strlen(s1) + strlen(s2) + 1); 207 (void)strcpy(s, s1); 208 (void)strcat(s, s2); 209 210 return (s); 211 } 212 213 static char * 214 concat3(const char *s1, const char *s2, const char *s3) 215 { 216 char *s; 217 218 s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1); 219 (void)strcpy(s, s1); 220 (void)strcat(s, s2); 221 (void)strcat(s, s3); 222 223 return (s); 224 } 225 226 /* 227 * Clean up after a signal. 228 */ 229 static void 230 terminate(int signo) 231 { 232 int i; 233 234 if (cppoutfd != -1) 235 (void)close(cppoutfd); 236 if (cppout != NULL) 237 (void)remove(cppout); 238 239 if (p1out != NULL) { 240 for (i = 0; p1out[i] != NULL; i++) 241 (void)remove(p1out[i]); 242 } 243 244 if (p2out != NULL) 245 (void)remove(p2out); 246 247 if (currfn != NULL) 248 (void)remove(currfn); 249 250 exit(signo != 0 ? 1 : 0); 251 } 252 253 /* 254 * Returns a pointer to the last component of strg after delim. 255 * Returns strg if the string does not contain delim. 256 */ 257 static const char * 258 lbasename(const char *strg, int delim) 259 { 260 const char *cp, *cp1, *cp2; 261 262 cp = cp1 = cp2 = strg; 263 while (*cp != '\0') { 264 if (*cp++ == delim) { 265 cp2 = cp1; 266 cp1 = cp; 267 } 268 } 269 return (*cp1 == '\0' ? cp2 : cp1); 270 } 271 272 static void 273 appdef(char ***lstp, const char *def) 274 { 275 276 appstrg(lstp, concat2("-D__", def)); 277 appstrg(lstp, concat3("-D__", def, "__")); 278 } 279 280 static void 281 usage(void) 282 { 283 284 (void)fprintf(stderr, 285 "Usage: %s [-abceghprvwxzHF] [-s|-t] [-i|-nu] [-Dname[=def]]" 286 " [-Uname] [-X <id>[,<id>]...\n", getprogname()); 287 (void)fprintf(stderr, 288 "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]" 289 " file...\n"); 290 (void)fprintf(stderr, 291 " %s [-abceghprvwzHF] [-s|-t] -Clibrary [-Dname[=def]]\n" 292 " [-X <id>[,<id>]...\n", getprogname()); 293 (void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file" 294 " ...\n"); 295 terminate(-1); 296 } 297 298 299 int 300 main(int argc, char *argv[]) 301 { 302 int c; 303 char flgbuf[3], *tmp, *s; 304 size_t len; 305 306 setprogname(argv[0]); 307 308 if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) { 309 tmpdir = xstrdup(_PATH_TMP); 310 } else { 311 s = xmalloc(len + 2); 312 (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/"); 313 tmpdir = s; 314 } 315 316 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX")); 317 (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir); 318 cppoutfd = mkstemp(cppout); 319 if (cppoutfd == -1) { 320 warn("can't make temp"); 321 terminate(-1); 322 } 323 324 p1out = xcalloc(1, sizeof (char *)); 325 p2in = xcalloc(1, sizeof (char *)); 326 cflags = xcalloc(1, sizeof (char *)); 327 lcflags = xcalloc(1, sizeof (char *)); 328 l1flags = xcalloc(1, sizeof (char *)); 329 l2flags = xcalloc(1, sizeof (char *)); 330 l2libs = xcalloc(1, sizeof (char *)); 331 deflibs = xcalloc(1, sizeof (char *)); 332 libs = xcalloc(1, sizeof (char *)); 333 libsrchpath = xcalloc(1, sizeof (char *)); 334 335 appcstrg(&cflags, "-E"); 336 appcstrg(&cflags, "-x"); 337 appcstrg(&cflags, "c"); 338 #if 0 339 appcstrg(&cflags, "-D__attribute__(x)="); 340 appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0"); 341 #else 342 appcstrg(&cflags, "-U__GNUC__"); 343 #endif 344 appcstrg(&cflags, "-Wp,-$"); 345 appcstrg(&cflags, "-Wp,-CC"); 346 appcstrg(&cflags, "-Wcomment"); 347 appcstrg(&cflags, "-D__LINT__"); 348 appcstrg(&cflags, "-Dlint"); /* XXX don't def. with -s */ 349 350 appdef(&cflags, "lint"); 351 352 appcstrg(&lcflags, "-Wtraditional"); 353 354 appcstrg(&deflibs, "c"); 355 356 if (signal(SIGHUP, terminate) == SIG_IGN) 357 (void)signal(SIGHUP, SIG_IGN); 358 (void)signal(SIGINT, terminate); 359 (void)signal(SIGQUIT, terminate); 360 (void)signal(SIGTERM, terminate); 361 362 while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:U:VX:")) != -1) { 363 switch (c) { 364 365 case 'a': 366 case 'b': 367 case 'c': 368 case 'e': 369 case 'g': 370 case 'r': 371 case 'v': 372 case 'w': 373 case 'z': 374 (void)sprintf(flgbuf, "-%c", c); 375 appcstrg(&l1flags, flgbuf); 376 break; 377 378 case 'F': 379 Fflag = 1; 380 /* FALLTHROUGH */ 381 case 'u': 382 case 'h': 383 (void)sprintf(flgbuf, "-%c", c); 384 appcstrg(&l1flags, flgbuf); 385 appcstrg(&l2flags, flgbuf); 386 break; 387 388 case 'X': 389 (void)sprintf(flgbuf, "-%c", c); 390 appcstrg(&l1flags, flgbuf); 391 appcstrg(&l1flags, optarg); 392 break; 393 394 case 'i': 395 if (Cflag) 396 usage(); 397 iflag = 1; 398 break; 399 400 case 'n': 401 freelst(&deflibs); 402 break; 403 404 case 'p': 405 appcstrg(&l1flags, "-p"); 406 appcstrg(&l2flags, "-p"); 407 if (*deflibs != NULL) { 408 freelst(&deflibs); 409 appcstrg(&deflibs, "c"); 410 } 411 break; 412 413 case 's': 414 if (tflag) 415 usage(); 416 freelst(&lcflags); 417 appcstrg(&lcflags, "-trigraphs"); 418 appcstrg(&lcflags, "-Wtrigraphs"); 419 appcstrg(&lcflags, "-pedantic"); 420 appcstrg(&lcflags, "-D__STRICT_ANSI__"); 421 appcstrg(&l1flags, "-s"); 422 appcstrg(&l2flags, "-s"); 423 sflag = 1; 424 break; 425 426 #if !HAVE_CONFIG_H 427 case 't': 428 if (sflag) 429 usage(); 430 freelst(&lcflags); 431 appcstrg(&lcflags, "-traditional"); 432 appstrg(&lcflags, concat2("-D", MACHINE)); 433 appstrg(&lcflags, concat2("-D", MACHINE_ARCH)); 434 appcstrg(&l1flags, "-t"); 435 appcstrg(&l2flags, "-t"); 436 tflag = 1; 437 break; 438 #endif 439 440 case 'x': 441 appcstrg(&l2flags, "-x"); 442 break; 443 444 case 'C': 445 if (Cflag || oflag || iflag) 446 usage(); 447 Cflag = 1; 448 appstrg(&l2flags, concat2("-C", optarg)); 449 p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg)); 450 (void)sprintf(p2out, "llib-l%s.ln", optarg); 451 freelst(&deflibs); 452 break; 453 454 case 'd': 455 if (dflag) 456 usage(); 457 dflag = 1; 458 appcstrg(&cflags, "-nostdinc"); 459 appcstrg(&cflags, "-idirafter"); 460 appcstrg(&cflags, optarg); 461 break; 462 463 case 'D': 464 case 'I': 465 case 'U': 466 (void)sprintf(flgbuf, "-%c", c); 467 appstrg(&cflags, concat2(flgbuf, optarg)); 468 break; 469 470 case 'l': 471 appcstrg(&libs, optarg); 472 break; 473 474 case 'o': 475 if (Cflag || oflag) 476 usage(); 477 oflag = 1; 478 outputfn = xstrdup(optarg); 479 break; 480 481 case 'L': 482 appcstrg(&libsrchpath, optarg); 483 break; 484 485 case 'H': 486 appcstrg(&l2flags, "-H"); 487 break; 488 489 case 'B': 490 Bflag = 1; 491 libexec_path = xstrdup(optarg); 492 break; 493 494 case 'V': 495 Vflag = 1; 496 break; 497 498 default: 499 usage(); 500 /* NOTREACHED */ 501 } 502 } 503 argc -= optind; 504 argv += optind; 505 506 /* 507 * To avoid modifying getopt(3)'s state engine midstream, we 508 * explicitly accept just a few options after the first source file. 509 * 510 * In particular, only -l<lib> and -L<libdir> (and these with a space 511 * after -l or -L) are allowed. 512 */ 513 while (argc > 0) { 514 const char *arg = argv[0]; 515 516 if (arg[0] == '-') { 517 char ***list; 518 519 /* option */ 520 switch (arg[1]) { 521 case 'l': 522 list = &libs; 523 break; 524 525 case 'L': 526 list = &libsrchpath; 527 break; 528 529 default: 530 usage(); 531 /* NOTREACHED */ 532 } 533 if (arg[2]) 534 appcstrg(list, arg + 2); 535 else if (argc > 1) { 536 argc--; 537 appcstrg(list, *++argv); 538 } else 539 usage(); 540 } else { 541 /* filename */ 542 fname(arg); 543 first = 0; 544 } 545 argc--; 546 argv++; 547 } 548 549 if (first) 550 usage(); 551 552 if (iflag) 553 terminate(0); 554 555 if (!oflag) { 556 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0) 557 s = PATH_LINTLIB; 558 appcstrg(&libsrchpath, s); 559 findlibs(libs); 560 findlibs(deflibs); 561 } 562 563 (void)printf("Lint pass2:\n"); 564 lint2(); 565 566 if (oflag) 567 cat(p2in, outputfn); 568 569 if (Cflag) 570 p2out = NULL; 571 572 terminate(0); 573 /* NOTREACHED */ 574 } 575 576 /* 577 * Read a file name from the command line 578 * and pass it through lint1 if it is a C source. 579 */ 580 static void 581 fname(const char *name) 582 { 583 const char *bn, *suff; 584 char **args, *ofn, *path; 585 size_t len; 586 int is_stdin; 587 int fd; 588 589 is_stdin = (strcmp(name, "-") == 0); 590 bn = lbasename(name, '/'); 591 suff = lbasename(bn, '.'); 592 593 if (strcmp(suff, "ln") == 0) { 594 /* only for lint2 */ 595 if (!iflag) 596 appcstrg(&p2in, name); 597 return; 598 } 599 600 if (!is_stdin && strcmp(suff, "c") != 0 && 601 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) { 602 warnx("unknown file type: %s\n", name); 603 return; 604 } 605 606 if (!iflag || !first) 607 (void)printf("%s:\n", 608 is_stdin ? "{standard input}" : Fflag ? name : bn); 609 610 /* build the name of the output file of lint1 */ 611 if (oflag) { 612 ofn = outputfn; 613 outputfn = NULL; 614 oflag = 0; 615 } else if (iflag) { 616 if (is_stdin) { 617 warnx("-i not supported without -o for standard input"); 618 return; 619 } 620 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2)); 621 len = bn == suff ? strlen(bn) : (suff - 1) - bn; 622 (void)sprintf(ofn, "%.*s", (int)len, bn); 623 (void)strcat(ofn, ".ln"); 624 } else { 625 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX")); 626 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir); 627 fd = mkstemp(ofn); 628 if (fd == -1) { 629 warn("can't make temp"); 630 terminate(-1); 631 } 632 close(fd); 633 } 634 if (!iflag) 635 appcstrg(&p1out, ofn); 636 637 args = xcalloc(1, sizeof (char *)); 638 639 /* run cc */ 640 641 if (getenv("CC") == NULL) { 642 path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc")); 643 (void)sprintf(path, "%s/cc", PATH_USRBIN); 644 } else { 645 path = strdup(getenv("CC")); 646 } 647 648 appcstrg(&args, path); 649 applst(&args, cflags); 650 applst(&args, lcflags); 651 appcstrg(&args, name); 652 653 /* we reuse the same tmp file for cpp output, so rewind and truncate */ 654 if (lseek(cppoutfd, SEEK_SET, (off_t)0) != 0) { 655 warn("lseek"); 656 terminate(-1); 657 } 658 if (ftruncate(cppoutfd, (off_t)0) != 0) { 659 warn("ftruncate"); 660 terminate(-1); 661 } 662 663 runchild(path, args, cppout, cppoutfd); 664 free(path); 665 freelst(&args); 666 667 /* run lint1 */ 668 669 if (!Bflag) { 670 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") + 671 strlen(target_prefix)); 672 (void)sprintf(path, "%s/%slint1", PATH_LIBEXEC, 673 target_prefix); 674 } else { 675 /* 676 * XXX Unclear whether we should be using target_prefix 677 * XXX here. --thorpej@wasabisystems.com 678 */ 679 path = xmalloc(strlen(libexec_path) + sizeof ("/lint1")); 680 (void)sprintf(path, "%s/lint1", libexec_path); 681 } 682 683 appcstrg(&args, path); 684 applst(&args, l1flags); 685 appcstrg(&args, cppout); 686 appcstrg(&args, ofn); 687 688 runchild(path, args, ofn, -1); 689 free(path); 690 freelst(&args); 691 692 appcstrg(&p2in, ofn); 693 free(ofn); 694 695 free(args); 696 } 697 698 static void 699 runchild(const char *path, char *const *args, const char *crfn, int fdout) 700 { 701 int status, rv, signo, i; 702 703 if (Vflag) { 704 for (i = 0; args[i] != NULL; i++) 705 (void)printf("%s ", args[i]); 706 (void)printf("\n"); 707 } 708 709 currfn = crfn; 710 711 (void)fflush(stdout); 712 713 switch (vfork()) { 714 case -1: 715 warn("cannot fork"); 716 terminate(-1); 717 /* NOTREACHED */ 718 default: 719 /* parent */ 720 break; 721 case 0: 722 /* child */ 723 724 /* setup the standard output if necessary */ 725 if (fdout != -1) { 726 dup2(fdout, STDOUT_FILENO); 727 close(fdout); 728 } 729 (void)execvp(path, args); 730 warn("cannot exec %s", path); 731 _exit(1); 732 /* NOTREACHED */ 733 } 734 735 while ((rv = wait(&status)) == -1 && errno == EINTR) ; 736 if (rv == -1) { 737 warn("wait"); 738 terminate(-1); 739 } 740 if (WIFSIGNALED(status)) { 741 signo = WTERMSIG(status); 742 #if HAVE_DECL_SYS_SIGNAME 743 warnx("%s got SIG%s", path, sys_signame[signo]); 744 #else 745 warnx("%s got signal %d", path, signo); 746 #endif 747 terminate(-1); 748 } 749 if (WEXITSTATUS(status) != 0) 750 terminate(-1); 751 currfn = NULL; 752 } 753 754 static void 755 findlibs(char *const *liblst) 756 { 757 int i, k; 758 const char *lib, *path; 759 char *lfn; 760 size_t len; 761 762 lfn = NULL; 763 764 for (i = 0; (lib = liblst[i]) != NULL; i++) { 765 for (k = 0; (path = libsrchpath[k]) != NULL; k++) { 766 len = strlen(path) + strlen(lib); 767 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln")); 768 (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib); 769 if (rdok(lfn)) 770 break; 771 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln")); 772 (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib); 773 if (rdok(lfn)) 774 break; 775 } 776 if (path != NULL) { 777 appstrg(&l2libs, concat2("-l", lfn)); 778 } else { 779 warnx("cannot find llib-l%s.ln", lib); 780 } 781 } 782 783 free(lfn); 784 } 785 786 static int 787 rdok(const char *path) 788 { 789 struct stat sbuf; 790 791 if (stat(path, &sbuf) == -1) 792 return (0); 793 if (!S_ISREG(sbuf.st_mode)) 794 return (0); 795 if (access(path, R_OK) == -1) 796 return (0); 797 return (1); 798 } 799 800 static void 801 lint2(void) 802 { 803 char *path, **args; 804 805 args = xcalloc(1, sizeof (char *)); 806 807 if (!Bflag) { 808 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") + 809 strlen(target_prefix)); 810 (void)sprintf(path, "%s/%slint2", PATH_LIBEXEC, 811 target_prefix); 812 } else { 813 /* 814 * XXX Unclear whether we should be using target_prefix 815 * XXX here. --thorpej@wasabisystems.com 816 */ 817 path = xmalloc(strlen(libexec_path) + sizeof ("/lint2")); 818 (void)sprintf(path, "%s/lint2", libexec_path); 819 } 820 821 appcstrg(&args, path); 822 applst(&args, l2flags); 823 applst(&args, l2libs); 824 applst(&args, p2in); 825 826 runchild(path, args, p2out, -1); 827 free(path); 828 freelst(&args); 829 free(args); 830 } 831 832 static void 833 cat(char *const *srcs, const char *dest) 834 { 835 int ifd, ofd, i; 836 char *src, *buf; 837 ssize_t rlen; 838 839 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { 840 warn("cannot open %s", dest); 841 terminate(-1); 842 } 843 844 buf = xmalloc(MBLKSIZ); 845 846 for (i = 0; (src = srcs[i]) != NULL; i++) { 847 if ((ifd = open(src, O_RDONLY)) == -1) { 848 free(buf); 849 warn("cannot open %s", src); 850 terminate(-1); 851 } 852 do { 853 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) { 854 free(buf); 855 warn("read error on %s", src); 856 terminate(-1); 857 } 858 if (write(ofd, buf, (size_t)rlen) == -1) { 859 free(buf); 860 warn("write error on %s", dest); 861 terminate(-1); 862 } 863 } while (rlen == MBLKSIZ); 864 (void)close(ifd); 865 } 866 (void)close(ofd); 867 free(buf); 868 } 869