xlint.c revision 43191
1/* $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $ */ 2 3/* 4 * Copyright (c) 1994, 1995 Jochen Pohl 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 must retain the above copyright 11 * 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 by Jochen Pohl for 18 * The NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static char rcsid[] = "$NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $"; 36#endif 37 38#include <sys/param.h> 39#include <sys/wait.h> 40#include <sys/stat.h> 41#include <sys/utsname.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <signal.h> 45#include <string.h> 46#include <unistd.h> 47#include <fcntl.h> 48#include <err.h> 49#include <errno.h> 50#include <paths.h> 51 52#include "lint.h" 53#include "pathnames.h" 54 55/* directory for temporary files */ 56static const char *tmpdir; 57 58/* path name for cpp output */ 59static char *cppout; 60 61/* files created by 1st pass */ 62static char **p1out; 63 64/* input files for 2nd pass (without libraries) */ 65static char **p2in; 66 67/* library which will be created by 2nd pass */ 68static char *p2out; 69 70/* flags always passed to cpp */ 71static char **cppflags; 72 73/* flags for cpp, controled by sflag/tflag */ 74static char **lcppflgs; 75 76/* flags for lint1 */ 77static char **l1flags; 78 79/* flags for lint2 */ 80static char **l2flags; 81 82/* libraries for lint2 */ 83static char **l2libs; 84 85/* default libraries */ 86static char **deflibs; 87 88/* additional libraries */ 89static char **libs; 90 91/* search path for libraries */ 92static char **libsrchpath; 93 94/* flags */ 95static int iflag, oflag, Cflag, sflag, tflag, Fflag; 96 97/* print the commands executed to run the stages of compilation */ 98static int Vflag; 99 100/* filename for oflag */ 101static char *outputfn; 102 103/* reset after first .c source has been processed */ 104static int first = 1; 105 106/* 107 * name of a file which is currently written by a child and should 108 * be removed after abnormal termination of the child 109 */ 110static const char *currfn; 111 112 113static void appstrg __P((char ***, char *)); 114static void appcstrg __P((char ***, const char *)); 115static void applst __P((char ***, char *const *)); 116static void freelst __P((char ***)); 117static char *concat2 __P((const char *, const char *)); 118static char *concat3 __P((const char *, const char *, const char *)); 119static void terminate __P((int)); 120static const char *basename __P((const char *, int)); 121static void appdef __P((char ***, const char *)); 122static void usage __P((void)); 123static void fname __P((const char *, int)); 124static void runchild __P((const char *, char *const *, const char *)); 125static void findlibs __P((char *const *)); 126static int rdok __P((const char *)); 127static void lint2 __P((void)); 128static void cat __P((char *const *, const char *)); 129 130/* 131 * Some functions to deal with lists of strings. 132 * Take care that we get no surprises in case of asyncron signals. 133 */ 134static void 135appstrg(lstp, s) 136 char ***lstp, *s; 137{ 138 char **lst, **olst; 139 int i; 140 141 olst = *lstp; 142 for (i = 0; olst[i] != NULL; i++) ; 143 lst = xmalloc((i + 2) * sizeof (char *)); 144 (void)memcpy(lst, olst, i * sizeof (char *)); 145 lst[i] = s; 146 lst[i + 1] = NULL; 147 *lstp = lst; 148} 149 150static void 151appcstrg(lstp, s) 152 char ***lstp; 153 const char *s; 154{ 155 appstrg(lstp, xstrdup(s)); 156} 157 158static void 159applst(destp, src) 160 char ***destp; 161 char *const *src; 162{ 163 int i, k; 164 char **dest, **odest; 165 166 odest = *destp; 167 for (i = 0; odest[i] != NULL; i++) ; 168 for (k = 0; src[k] != NULL; k++) ; 169 dest = xmalloc((i + k + 1) * sizeof (char *)); 170 (void)memcpy(dest, odest, i * sizeof (char *)); 171 for (k = 0; src[k] != NULL; k++) 172 dest[i + k] = xstrdup(src[k]); 173 dest[i + k] = NULL; 174 *destp = dest; 175 free(odest); 176} 177 178static void 179freelst(lstp) 180 char ***lstp; 181{ 182 char *s; 183 int i; 184 185 for (i = 0; (*lstp)[i] != NULL; i++) ; 186 while (i-- > 0) { 187 s = (*lstp)[i]; 188 (*lstp)[i] = NULL; 189 free(s); 190 } 191} 192 193static char * 194concat2(s1, s2) 195 const char *s1, *s2; 196{ 197 char *s; 198 199 s = xmalloc(strlen(s1) + strlen(s2) + 1); 200 (void)strcpy(s, s1); 201 (void)strcat(s, s2); 202 203 return (s); 204} 205 206static char * 207concat3(s1, s2, s3) 208 const char *s1, *s2, *s3; 209{ 210 char *s; 211 212 s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1); 213 (void)strcpy(s, s1); 214 (void)strcat(s, s2); 215 (void)strcat(s, s3); 216 217 return (s); 218} 219 220/* 221 * Clean up after a signal. 222 */ 223static void 224terminate(signo) 225 int signo; 226{ 227 int i; 228 229 if (cppout != NULL) 230 (void)remove(cppout); 231 232 if (p1out != NULL) { 233 for (i = 0; p1out[i] != NULL; i++) 234 (void)remove(p1out[i]); 235 } 236 237 if (p2out != NULL) 238 (void)remove(p2out); 239 240 if (currfn != NULL) 241 (void)remove(currfn); 242 243 exit(signo != 0 ? 1 : 0); 244} 245 246/* 247 * Returns a pointer to the last component of strg after delim. 248 * Returns strg if the string does not contain delim. 249 */ 250static const char * 251basename(strg, delim) 252 const char *strg; 253 int delim; 254{ 255 const char *cp, *cp1, *cp2; 256 257 cp = cp1 = cp2 = strg; 258 while (*cp != '\0') { 259 if (*cp++ == delim) { 260 cp2 = cp1; 261 cp1 = cp; 262 } 263 } 264 return (*cp1 == '\0' ? cp2 : cp1); 265} 266 267static void 268appdef(lstp, def) 269 char ***lstp; 270 const char *def; 271{ 272 appstrg(lstp, concat2("-D__", def)); 273 appstrg(lstp, concat3("-D__", def, "__")); 274} 275 276static void 277usage() 278{ 279 (void)printf("lint [-abceghprvxzHF] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n"); 280 (void)printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n"); 281 (void)printf("\n"); 282 (void)printf("lint [-abceghprvzHF] [-s|-t] -Clibrary [-Dname[=def]]\n"); 283 (void)printf(" [-Idirectory] [-Uname] file ...\n"); 284 terminate(-1); 285} 286 287int 288main(argc, argv) 289 int argc; 290 char *argv[]; 291{ 292 int c; 293 char flgbuf[3], *tmp, *s; 294 size_t len; 295 struct utsname un; 296 297 if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) { 298 tmpdir = xstrdup(_PATH_TMP); 299 } else { 300 s = xmalloc(len + 2); 301 (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/"); 302 tmpdir = s; 303 } 304 305 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX")); 306 (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir); 307 if (mktemp(cppout) == NULL) { 308 warn("can't make temp"); 309 terminate(-1); 310 } 311 312 p1out = xcalloc(1, sizeof (char *)); 313 p2in = xcalloc(1, sizeof (char *)); 314 cppflags = xcalloc(1, sizeof (char *)); 315 lcppflgs = xcalloc(1, sizeof (char *)); 316 l1flags = xcalloc(1, sizeof (char *)); 317 l2flags = xcalloc(1, sizeof (char *)); 318 l2libs = xcalloc(1, sizeof (char *)); 319 deflibs = xcalloc(1, sizeof (char *)); 320 libs = xcalloc(1, sizeof (char *)); 321 libsrchpath = xcalloc(1, sizeof (char *)); 322 323 appcstrg(&cppflags, "-lang-c"); 324 appcstrg(&cppflags, "-undef"); 325 appcstrg(&cppflags, "-$"); 326 appcstrg(&cppflags, "-C"); 327 appcstrg(&cppflags, "-Wcomment"); 328#ifdef __FreeBSD__ 329 appcstrg(&cppflags, "-D__FreeBSD__=" __XSTRING(__FreeBSD__)); 330#else 331# error "This ain't NetBSD. You lose!" 332 appcstrg(&cppflags, "-D__NetBSD__"); 333#endif 334 appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */ 335 appdef(&cppflags, "lint"); 336 appdef(&cppflags, "unix"); 337 338 appcstrg(&lcppflgs, "-Wtraditional"); 339 340 if (uname(&un) == -1) 341 err(1, "uname"); 342 appdef(&cppflags, un.machine); 343 appstrg(&lcppflgs, concat2("-D", un.machine)); 344 345#ifdef MACHINE_ARCH 346 if (strcmp(un.machine, MACHINE_ARCH) != 0) { 347 appdef(&cppflags, MACHINE_ARCH); 348 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH)); 349 } 350#endif 351 352 appcstrg(&deflibs, "c"); 353 354 if (signal(SIGHUP, terminate) == SIG_IGN) 355 (void)signal(SIGHUP, SIG_IGN); 356 (void)signal(SIGINT, terminate); 357 (void)signal(SIGQUIT, terminate); 358 (void)signal(SIGTERM, terminate); 359 360 while (argc > optind) { 361 362 argc -= optind; 363 argv += optind; 364 optind = 0; 365 366 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:U:V"); 367 368 switch (c) { 369 370 case 'a': 371 case 'b': 372 case 'c': 373 case 'e': 374 case 'g': 375 case 'r': 376 case 'v': 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 'i': 393 if (Cflag) 394 usage(); 395 iflag = 1; 396 break; 397 398 case 'n': 399 freelst(&deflibs); 400 break; 401 402 case 'p': 403 appcstrg(&l1flags, "-p"); 404 appcstrg(&l2flags, "-p"); 405 if (*deflibs != NULL) { 406 freelst(&deflibs); 407 appcstrg(&deflibs, "c"); 408 } 409 break; 410 411 case 's': 412 if (tflag) 413 usage(); 414 freelst(&lcppflgs); 415 appcstrg(&lcppflgs, "-trigraphs"); 416 appcstrg(&lcppflgs, "-Wtrigraphs"); 417 appcstrg(&lcppflgs, "-pedantic"); 418 appcstrg(&lcppflgs, "-D__STRICT_ANSI__"); 419 appcstrg(&l1flags, "-s"); 420 appcstrg(&l2flags, "-s"); 421 sflag = 1; 422 break; 423 424 case 't': 425 if (sflag) 426 usage(); 427 freelst(&lcppflgs); 428 appcstrg(&lcppflgs, "-traditional"); 429 appstrg(&lcppflgs, concat2("-D", MACHINE)); 430#ifdef MACHINE_ARCH 431 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH)); 432#endif 433 appcstrg(&l1flags, "-t"); 434 appcstrg(&l2flags, "-t"); 435 tflag = 1; 436 break; 437 438 case 'x': 439 appcstrg(&l2flags, "-x"); 440 break; 441 442 case 'C': 443 if (Cflag || oflag || iflag) 444 usage(); 445 Cflag = 1; 446 appstrg(&l2flags, concat2("-C", optarg)); 447 p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg)); 448 (void)sprintf(p2out, "llib-l%s.ln", optarg); 449 freelst(&deflibs); 450 break; 451 452 case 'D': 453 case 'I': 454 case 'U': 455 (void)sprintf(flgbuf, "-%c", c); 456 appstrg(&cppflags, concat2(flgbuf, optarg)); 457 break; 458 459 case 'l': 460 appcstrg(&libs, optarg); 461 break; 462 463 case 'o': 464 if (Cflag || oflag) 465 usage(); 466 oflag = 1; 467 outputfn = xstrdup(optarg); 468 break; 469 470 case 'L': 471 appcstrg(&libsrchpath, optarg); 472 break; 473 474 case 'H': 475 appcstrg(&l2flags, "-H"); 476 break; 477 478 case 'V': 479 Vflag = 1; 480 break; 481 482 case '?': 483 usage(); 484 /* NOTREACHED */ 485 486 case -1: 487 /* filename */ 488 fname(argv[0], argc == 1); 489 first = 0; 490 optind = 1; 491 } 492 493 } 494 495 if (first) 496 usage(); 497 498 if (iflag) 499 terminate(0); 500 501 if (!oflag) { 502 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0) 503 s = PATH_LINTLIB; 504 appcstrg(&libsrchpath, s); 505 findlibs(libs); 506 findlibs(deflibs); 507 } 508 509 (void)printf("Lint pass2:\n"); 510 lint2(); 511 512 if (oflag) 513 cat(p2in, outputfn); 514 515 if (Cflag) 516 p2out = NULL; 517 518 terminate(0); 519 /* NOTREACHED */ 520 return 0; 521} 522 523/* 524 * Read a file name from the command line 525 * and pass it through lint1 if it is a C source. 526 */ 527static void 528fname(name, last) 529 const char *name; 530 int last; 531{ 532 const char *bn, *suff; 533 char **args, *ofn, *path; 534 size_t len; 535 536 bn = basename(name, '/'); 537 suff = basename(bn, '.'); 538 539 if (strcmp(suff, "ln") == 0) { 540 /* only for lint2 */ 541 if (!iflag) 542 appcstrg(&p2in, name); 543 return; 544 } 545 546 if (strcmp(suff, "c") != 0 && 547 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) { 548 warnx("unknown file type: %s\n", name); 549 return; 550 } 551 552 if (!iflag || !first || !last) 553 (void)printf("%s:\n", Fflag ? name : bn); 554 555 /* build the name of the output file of lint1 */ 556 if (oflag) { 557 ofn = outputfn; 558 outputfn = NULL; 559 oflag = 0; 560 } else if (iflag) { 561 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2)); 562 len = bn == suff ? strlen(bn) : (suff - 1) - bn; 563 (void)sprintf(ofn, "%.*s", (int)len, bn); 564 (void)strcat(ofn, ".ln"); 565 } else { 566 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX")); 567 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir); 568 if (mktemp(ofn) == NULL) { 569 warn("can't make temp"); 570 terminate(-1); 571 } 572 } 573 if (!iflag) 574 appcstrg(&p1out, ofn); 575 576 args = xcalloc(1, sizeof (char *)); 577 578 /* run cpp */ 579 580 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/cpp")); 581 (void)sprintf(path, "%s/cpp", PATH_LIBEXEC); 582 583 appcstrg(&args, path); 584 applst(&args, cppflags); 585 applst(&args, lcppflgs); 586 appcstrg(&args, name); 587 appcstrg(&args, cppout); 588 589 runchild(path, args, cppout); 590 free(path); 591 freelst(&args); 592 593 /* run lint1 */ 594 595 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1")); 596 (void)sprintf(path, "%s/lint1", PATH_LIBEXEC); 597 598 appcstrg(&args, path); 599 applst(&args, l1flags); 600 appcstrg(&args, cppout); 601 appcstrg(&args, ofn); 602 603 runchild(path, args, ofn); 604 free(path); 605 freelst(&args); 606 607 appcstrg(&p2in, ofn); 608 free(ofn); 609 610 free(args); 611} 612 613static void 614runchild(path, args, crfn) 615 const char *path, *crfn; 616 char *const *args; 617{ 618 int status, rv, signo, i; 619 620 if (Vflag) { 621 for (i = 0; args[i] != NULL; i++) 622 (void)printf("%s ", args[i]); 623 (void)printf("\n"); 624 } 625 626 currfn = crfn; 627 628 (void)fflush(stdout); 629 630 switch (fork()) { 631 case -1: 632 warn("cannot fork"); 633 terminate(-1); 634 /* NOTREACHED */ 635 default: 636 /* parent */ 637 break; 638 case 0: 639 /* child */ 640 (void)execv(path, args); 641 warn("cannot exec %s", path); 642 exit(1); 643 /* NOTREACHED */ 644 } 645 646 while ((rv = wait(&status)) == -1 && errno == EINTR) ; 647 if (rv == -1) { 648 warn("wait"); 649 terminate(-1); 650 } 651 if (WIFSIGNALED(status)) { 652 signo = WTERMSIG(status); 653 warnx("%s got SIG%s", path, sys_signame[signo]); 654 terminate(-1); 655 } 656 if (WEXITSTATUS(status) != 0) 657 terminate(-1); 658 currfn = NULL; 659} 660 661static void 662findlibs(liblst) 663 char *const *liblst; 664{ 665 int i, k; 666 const char *lib, *path; 667 char *lfn; 668 size_t len; 669 670 lfn = NULL; 671 672 for (i = 0; (lib = liblst[i]) != NULL; i++) { 673 for (k = 0; (path = libsrchpath[k]) != NULL; k++) { 674 len = strlen(path) + strlen(lib); 675 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln")); 676 (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib); 677 if (rdok(lfn)) 678 break; 679 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln")); 680 (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib); 681 if (rdok(lfn)) 682 break; 683 } 684 if (path != NULL) { 685 appstrg(&l2libs, concat2("-l", lfn)); 686 } else { 687 warnx("cannot find llib-l%s.ln", lib); 688 } 689 } 690 691 free(lfn); 692} 693 694static int 695rdok(path) 696 const char *path; 697{ 698 struct stat sbuf; 699 700 if (stat(path, &sbuf) == -1) 701 return (0); 702 if ((sbuf.st_mode & S_IFMT) != S_IFREG) 703 return (0); 704 if (access(path, R_OK) == -1) 705 return (0); 706 return (1); 707} 708 709static void 710lint2() 711{ 712 char *path, **args; 713 714 args = xcalloc(1, sizeof (char *)); 715 716 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2")); 717 (void)sprintf(path, "%s/lint2", PATH_LIBEXEC); 718 719 appcstrg(&args, path); 720 applst(&args, l2flags); 721 applst(&args, l2libs); 722 applst(&args, p2in); 723 724 runchild(path, args, p2out); 725 free(path); 726 freelst(&args); 727 free(args); 728} 729 730static void 731cat(srcs, dest) 732 char *const *srcs; 733 const char *dest; 734{ 735 int ifd, ofd, i; 736 char *src, *buf; 737 ssize_t rlen; 738 739 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { 740 warn("cannot open %s", dest); 741 terminate(-1); 742 } 743 744 buf = xmalloc(MBLKSIZ); 745 746 for (i = 0; (src = srcs[i]) != NULL; i++) { 747 if ((ifd = open(src, O_RDONLY)) == -1) { 748 free(buf); 749 warn("cannot open %s", src); 750 terminate(-1); 751 } 752 do { 753 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) { 754 free(buf); 755 warn("read error on %s", src); 756 terminate(-1); 757 } 758 if (write(ofd, buf, (size_t)rlen) == -1) { 759 free(buf); 760 warn("write error on %s", dest); 761 terminate(-1); 762 } 763 } while (rlen == MBLKSIZ); 764 (void)close(ifd); 765 } 766 (void)close(ofd); 767 free(buf); 768} 769 770