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