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