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