xlint.c revision 55959
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[] = "$FreeBSD: head/usr.bin/xlint/xlint/xlint.c 55959 2000-01-14 09:25:31Z sheldonh $"; 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, "-$"); 325 appcstrg(&cppflags, "-C"); 326 appcstrg(&cppflags, "-Wcomment"); 327#ifdef __FreeBSD__ 328 appcstrg(&cppflags, "-D__FreeBSD__=" __XSTRING(__FreeBSD__)); 329#else 330# error "This ain't NetBSD. You lose!" 331 appcstrg(&cppflags, "-D__NetBSD__"); 332#endif 333 appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */ 334 appdef(&cppflags, "lint"); 335 appdef(&cppflags, "unix"); 336 337 appcstrg(&lcppflgs, "-Wtraditional"); 338 339 if (uname(&un) == -1) 340 err(1, "uname"); 341 appdef(&cppflags, un.machine); 342 appstrg(&lcppflgs, concat2("-D", un.machine)); 343 344#ifdef MACHINE_ARCH 345 if (strcmp(un.machine, MACHINE_ARCH) != 0) { 346 appdef(&cppflags, MACHINE_ARCH); 347 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH)); 348 } 349#endif 350 351 appcstrg(&deflibs, "c"); 352 353 if (signal(SIGHUP, terminate) == SIG_IGN) 354 (void)signal(SIGHUP, SIG_IGN); 355 (void)signal(SIGINT, terminate); 356 (void)signal(SIGQUIT, terminate); 357 (void)signal(SIGTERM, terminate); 358 359 while (argc > optind) { 360 361 argc -= optind; 362 argv += optind; 363 optind = 0; 364 365 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:U:V"); 366 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 '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 'i': 392 if (Cflag) 393 usage(); 394 iflag = 1; 395 break; 396 397 case 'n': 398 freelst(&deflibs); 399 break; 400 401 case 'p': 402 appcstrg(&l1flags, "-p"); 403 appcstrg(&l2flags, "-p"); 404 if (*deflibs != NULL) { 405 freelst(&deflibs); 406 appcstrg(&deflibs, "c"); 407 } 408 break; 409 410 case 's': 411 if (tflag) 412 usage(); 413 freelst(&lcppflgs); 414 appcstrg(&lcppflgs, "-trigraphs"); 415 appcstrg(&lcppflgs, "-Wtrigraphs"); 416 appcstrg(&lcppflgs, "-pedantic"); 417 appcstrg(&lcppflgs, "-D__STRICT_ANSI__"); 418 appcstrg(&l1flags, "-s"); 419 appcstrg(&l2flags, "-s"); 420 sflag = 1; 421 break; 422 423 case 't': 424 if (sflag) 425 usage(); 426 freelst(&lcppflgs); 427 appcstrg(&lcppflgs, "-traditional"); 428 appstrg(&lcppflgs, concat2("-D", MACHINE)); 429#ifdef MACHINE_ARCH 430 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH)); 431#endif 432 appcstrg(&l1flags, "-t"); 433 appcstrg(&l2flags, "-t"); 434 tflag = 1; 435 break; 436 437 case 'x': 438 appcstrg(&l2flags, "-x"); 439 break; 440 441 case 'C': 442 if (Cflag || oflag || iflag) 443 usage(); 444 Cflag = 1; 445 appstrg(&l2flags, concat2("-C", optarg)); 446 p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg)); 447 (void)sprintf(p2out, "llib-l%s.ln", optarg); 448 freelst(&deflibs); 449 break; 450 451 case 'D': 452 case 'I': 453 case 'U': 454 (void)sprintf(flgbuf, "-%c", c); 455 appstrg(&cppflags, concat2(flgbuf, optarg)); 456 break; 457 458 case 'l': 459 appcstrg(&libs, optarg); 460 break; 461 462 case 'o': 463 if (Cflag || oflag) 464 usage(); 465 oflag = 1; 466 outputfn = xstrdup(optarg); 467 break; 468 469 case 'L': 470 appcstrg(&libsrchpath, optarg); 471 break; 472 473 case 'H': 474 appcstrg(&l2flags, "-H"); 475 break; 476 477 case 'V': 478 Vflag = 1; 479 break; 480 481 case '?': 482 usage(); 483 /* NOTREACHED */ 484 485 case -1: 486 /* filename */ 487 fname(argv[0], argc == 1); 488 first = 0; 489 optind = 1; 490 } 491 492 } 493 494 if (first) 495 usage(); 496 497 if (iflag) 498 terminate(0); 499 500 if (!oflag) { 501 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0) 502 s = PATH_LINTLIB; 503 appcstrg(&libsrchpath, s); 504 findlibs(libs); 505 findlibs(deflibs); 506 } 507 508 (void)printf("Lint pass2:\n"); 509 lint2(); 510 511 if (oflag) 512 cat(p2in, outputfn); 513 514 if (Cflag) 515 p2out = NULL; 516 517 terminate(0); 518 /* NOTREACHED */ 519 return 0; 520} 521 522/* 523 * Read a file name from the command line 524 * and pass it through lint1 if it is a C source. 525 */ 526static void 527fname(name, last) 528 const char *name; 529 int last; 530{ 531 const char *bn, *suff; 532 char **args, *ofn, *path; 533 size_t len; 534 535 bn = basename(name, '/'); 536 suff = basename(bn, '.'); 537 538 if (strcmp(suff, "ln") == 0) { 539 /* only for lint2 */ 540 if (!iflag) 541 appcstrg(&p2in, name); 542 return; 543 } 544 545 if (strcmp(suff, "c") != 0 && 546 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) { 547 warnx("unknown file type: %s\n", name); 548 return; 549 } 550 551 if (!iflag || !first || !last) 552 (void)printf("%s:\n", Fflag ? name : bn); 553 554 /* build the name of the output file of lint1 */ 555 if (oflag) { 556 ofn = outputfn; 557 outputfn = NULL; 558 oflag = 0; 559 } else if (iflag) { 560 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2)); 561 len = bn == suff ? strlen(bn) : (suff - 1) - bn; 562 (void)sprintf(ofn, "%.*s", (int)len, bn); 563 (void)strcat(ofn, ".ln"); 564 } else { 565 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX")); 566 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir); 567 if (mktemp(ofn) == NULL) { 568 warn("can't make temp"); 569 terminate(-1); 570 } 571 } 572 if (!iflag) 573 appcstrg(&p1out, ofn); 574 575 args = xcalloc(1, sizeof (char *)); 576 577 /* run cpp */ 578 579 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/cpp")); 580 (void)sprintf(path, "%s/cpp", PATH_LIBEXEC); 581 582 appcstrg(&args, path); 583 applst(&args, cppflags); 584 applst(&args, lcppflgs); 585 appcstrg(&args, name); 586 appcstrg(&args, cppout); 587 588 runchild(path, args, cppout); 589 free(path); 590 freelst(&args); 591 592 /* run lint1 */ 593 594 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1")); 595 (void)sprintf(path, "%s/lint1", PATH_LIBEXEC); 596 597 appcstrg(&args, path); 598 applst(&args, l1flags); 599 appcstrg(&args, cppout); 600 appcstrg(&args, ofn); 601 602 runchild(path, args, ofn); 603 free(path); 604 freelst(&args); 605 606 appcstrg(&p2in, ofn); 607 free(ofn); 608 609 free(args); 610} 611 612static void 613runchild(path, args, crfn) 614 const char *path, *crfn; 615 char *const *args; 616{ 617 int status, rv, signo, i; 618 619 if (Vflag) { 620 for (i = 0; args[i] != NULL; i++) 621 (void)printf("%s ", args[i]); 622 (void)printf("\n"); 623 } 624 625 currfn = crfn; 626 627 (void)fflush(stdout); 628 629 switch (fork()) { 630 case -1: 631 warn("cannot fork"); 632 terminate(-1); 633 /* NOTREACHED */ 634 default: 635 /* parent */ 636 break; 637 case 0: 638 /* child */ 639 (void)execv(path, args); 640 warn("cannot exec %s", path); 641 exit(1); 642 /* NOTREACHED */ 643 } 644 645 while ((rv = wait(&status)) == -1 && errno == EINTR) ; 646 if (rv == -1) { 647 warn("wait"); 648 terminate(-1); 649 } 650 if (WIFSIGNALED(status)) { 651 signo = WTERMSIG(status); 652 warnx("%s got SIG%s", path, sys_signame[signo]); 653 terminate(-1); 654 } 655 if (WEXITSTATUS(status) != 0) 656 terminate(-1); 657 currfn = NULL; 658} 659 660static void 661findlibs(liblst) 662 char *const *liblst; 663{ 664 int i, k; 665 const char *lib, *path; 666 char *lfn; 667 size_t len; 668 669 lfn = NULL; 670 671 for (i = 0; (lib = liblst[i]) != NULL; i++) { 672 for (k = 0; (path = libsrchpath[k]) != NULL; k++) { 673 len = strlen(path) + strlen(lib); 674 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln")); 675 (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib); 676 if (rdok(lfn)) 677 break; 678 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln")); 679 (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib); 680 if (rdok(lfn)) 681 break; 682 } 683 if (path != NULL) { 684 appstrg(&l2libs, concat2("-l", lfn)); 685 } else { 686 warnx("cannot find llib-l%s.ln", lib); 687 } 688 } 689 690 free(lfn); 691} 692 693static int 694rdok(path) 695 const char *path; 696{ 697 struct stat sbuf; 698 699 if (stat(path, &sbuf) == -1) 700 return (0); 701 if ((sbuf.st_mode & S_IFMT) != S_IFREG) 702 return (0); 703 if (access(path, R_OK) == -1) 704 return (0); 705 return (1); 706} 707 708static void 709lint2() 710{ 711 char *path, **args; 712 713 args = xcalloc(1, sizeof (char *)); 714 715 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2")); 716 (void)sprintf(path, "%s/lint2", PATH_LIBEXEC); 717 718 appcstrg(&args, path); 719 applst(&args, l2flags); 720 applst(&args, l2libs); 721 applst(&args, p2in); 722 723 runchild(path, args, p2out); 724 free(path); 725 freelst(&args); 726 free(args); 727} 728 729static void 730cat(srcs, dest) 731 char *const *srcs; 732 const char *dest; 733{ 734 int ifd, ofd, i; 735 char *src, *buf; 736 ssize_t rlen; 737 738 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { 739 warn("cannot open %s", dest); 740 terminate(-1); 741 } 742 743 buf = xmalloc(MBLKSIZ); 744 745 for (i = 0; (src = srcs[i]) != NULL; i++) { 746 if ((ifd = open(src, O_RDONLY)) == -1) { 747 free(buf); 748 warn("cannot open %s", src); 749 terminate(-1); 750 } 751 do { 752 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) { 753 free(buf); 754 warn("read error on %s", src); 755 terminate(-1); 756 } 757 if (write(ofd, buf, (size_t)rlen) == -1) { 758 free(buf); 759 warn("write error on %s", dest); 760 terminate(-1); 761 } 762 } while (rlen == MBLKSIZ); 763 (void)close(ifd); 764 } 765 (void)close(ofd); 766 free(buf); 767} 768 769