1281168Spfg/* $NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $ */ 212099Sjoerg 312099Sjoerg/* 491592Smarkm * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. 512099Sjoerg * Copyright (c) 1994, 1995 Jochen Pohl 612099Sjoerg * All Rights Reserved. 712099Sjoerg * 812099Sjoerg * Redistribution and use in source and binary forms, with or without 912099Sjoerg * modification, are permitted provided that the following conditions 1012099Sjoerg * are met: 1112099Sjoerg * 1. Redistributions of source code must retain the above copyright 1212099Sjoerg * notice, this list of conditions and the following disclaimer. 1312099Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1412099Sjoerg * notice, this list of conditions and the following disclaimer in the 1512099Sjoerg * documentation and/or other materials provided with the distribution. 1612099Sjoerg * 3. All advertising materials mentioning features or use of this software 1712099Sjoerg * must display the following acknowledgement: 1812099Sjoerg * This product includes software developed by Jochen Pohl for 1912099Sjoerg * The NetBSD Project. 2012099Sjoerg * 4. The name of the author may not be used to endorse or promote products 2112099Sjoerg * derived from this software without specific prior written permission. 2212099Sjoerg * 2312099Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2412099Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2512099Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2612099Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2712099Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2812099Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2912099Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3012099Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3112099Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3212099Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3312099Sjoerg */ 3412099Sjoerg 3591592Smarkm#include <sys/cdefs.h> 3691592Smarkm#if defined(__RCSID) && !defined(lint) 37281168Spfg__RCSID("$NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $"); 3812099Sjoerg#endif 3991592Smarkm__FBSDID("$FreeBSD$"); 4012099Sjoerg 4112099Sjoerg#include <sys/param.h> 4212099Sjoerg#include <sys/wait.h> 4312099Sjoerg#include <sys/stat.h> 4412099Sjoerg#include <sys/utsname.h> 45102770Siedowse#include <err.h> 4691592Smarkm#include <errno.h> 4791592Smarkm#include <fcntl.h> 4891592Smarkm#include <paths.h> 4991592Smarkm#include <signal.h> 5012099Sjoerg#include <stdio.h> 5112099Sjoerg#include <stdlib.h> 5212099Sjoerg#include <string.h> 5312099Sjoerg#include <unistd.h> 5412099Sjoerg 5512099Sjoerg#include "lint.h" 5612099Sjoerg#include "pathnames.h" 5712099Sjoerg 58100364Smarkm#define DEFAULT_PATH _PATH_DEFPATH 59100364Smarkm 6091592Smarkmint main(int, char *[]); 6191592Smarkm 6212099Sjoerg/* directory for temporary files */ 6312099Sjoergstatic const char *tmpdir; 6412099Sjoerg 6512099Sjoerg/* path name for cpp output */ 6612099Sjoergstatic char *cppout; 6712099Sjoerg 6891592Smarkm/* file descriptor for cpp output */ 6975710Sasmodaistatic int cppoutfd = -1; 7075710Sasmodai 7112099Sjoerg/* files created by 1st pass */ 7212099Sjoergstatic char **p1out; 7312099Sjoerg 7412099Sjoerg/* input files for 2nd pass (without libraries) */ 7512099Sjoergstatic char **p2in; 7612099Sjoerg 7712099Sjoerg/* library which will be created by 2nd pass */ 7812099Sjoergstatic char *p2out; 7912099Sjoerg 8075710Sasmodai/* flags always passed to cc(1) */ 8175710Sasmodaistatic char **cflags; 8212099Sjoerg 83228992Suqs/* flags for cc(1), controlled by sflag/tflag */ 8475710Sasmodaistatic char **lcflags; 8512099Sjoerg 8612099Sjoerg/* flags for lint1 */ 8712099Sjoergstatic char **l1flags; 8812099Sjoerg 8912099Sjoerg/* flags for lint2 */ 9012099Sjoergstatic char **l2flags; 9112099Sjoerg 9212099Sjoerg/* libraries for lint2 */ 9312099Sjoergstatic char **l2libs; 9412099Sjoerg 9512099Sjoerg/* default libraries */ 9612099Sjoergstatic char **deflibs; 9712099Sjoerg 9812099Sjoerg/* additional libraries */ 9912099Sjoergstatic char **libs; 10012099Sjoerg 10112099Sjoerg/* search path for libraries */ 10212099Sjoergstatic char **libsrchpath; 10312099Sjoerg 10491592Smarkmstatic char *libexec_path; 10591592Smarkm 10612099Sjoerg/* flags */ 107281168Spfgstatic int iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag, Sflag; 10812099Sjoerg 10912099Sjoerg/* print the commands executed to run the stages of compilation */ 11012099Sjoergstatic int Vflag; 11112099Sjoerg 11212099Sjoerg/* filename for oflag */ 11312099Sjoergstatic char *outputfn; 11412099Sjoerg 11512099Sjoerg/* reset after first .c source has been processed */ 11612099Sjoergstatic int first = 1; 11712099Sjoerg 11812099Sjoerg/* 11912099Sjoerg * name of a file which is currently written by a child and should 12012099Sjoerg * be removed after abnormal termination of the child 12112099Sjoerg */ 12212099Sjoergstatic const char *currfn; 12312099Sjoerg 12491592Smarkm#if !defined(TARGET_PREFIX) 12591592Smarkm#define TARGET_PREFIX "" 12691592Smarkm#endif 12791592Smarkmstatic const char target_prefix[] = TARGET_PREFIX; 12812099Sjoerg 12991592Smarkmstatic void appstrg(char ***, char *); 13091592Smarkmstatic void appcstrg(char ***, const char *); 13191592Smarkmstatic void applst(char ***, char *const *); 13291592Smarkmstatic void freelst(char ***); 13391592Smarkmstatic char *concat2(const char *, const char *); 13491592Smarkmstatic char *concat3(const char *, const char *, const char *); 13591592Smarkmstatic void terminate(int) __attribute__((__noreturn__)); 13691592Smarkmstatic const char *lbasename(const char *, int); 13791592Smarkmstatic void appdef(char ***, const char *); 138201610Sdwmalonestatic void usage(void) __dead2; 13991592Smarkmstatic void fname(const char *); 14091592Smarkmstatic void runchild(const char *, char *const *, const char *, int); 14191592Smarkmstatic void findlibs(char *const *); 14291592Smarkmstatic int rdok(const char *); 14391592Smarkmstatic void lint2(void); 14491592Smarkmstatic void cat(char *const *, const char *); 14512099Sjoerg 14612099Sjoerg/* 14712099Sjoerg * Some functions to deal with lists of strings. 148281168Spfg * Take care that we get no surprises in case of asynchronous signals. 14912099Sjoerg */ 15012099Sjoergstatic void 15191592Smarkmappstrg(char ***lstp, char *s) 15212099Sjoerg{ 15312099Sjoerg char **lst, **olst; 15412099Sjoerg int i; 15512099Sjoerg 15612099Sjoerg olst = *lstp; 15791592Smarkm for (i = 0; olst[i] != NULL; i++) 15891592Smarkm continue; 15991592Smarkm lst = xrealloc(olst, (i + 2) * sizeof (char *)); 16012099Sjoerg lst[i] = s; 16112099Sjoerg lst[i + 1] = NULL; 16212099Sjoerg *lstp = lst; 16391592Smarkm} 16412099Sjoerg 16512099Sjoergstatic void 16691592Smarkmappcstrg(char ***lstp, const char *s) 16712099Sjoerg{ 16880284Sobrien 16991592Smarkm appstrg(lstp, xstrdup(s)); 17012099Sjoerg} 17112099Sjoerg 17212099Sjoergstatic void 17391592Smarkmapplst(char ***destp, char *const *src) 17412099Sjoerg{ 17512099Sjoerg int i, k; 17612099Sjoerg char **dest, **odest; 17712099Sjoerg 17812099Sjoerg odest = *destp; 17991592Smarkm for (i = 0; odest[i] != NULL; i++) 18091592Smarkm continue; 18112099Sjoerg for (k = 0; src[k] != NULL; k++) 18291592Smarkm continue; 18391592Smarkm dest = xrealloc(odest, (i + k + 1) * sizeof (char *)); 18491592Smarkm for (k = 0; src[k] != NULL; k++) 18591818Smarkm dest[i + k] = xstrdup(src[k]); 18612099Sjoerg dest[i + k] = NULL; 18712099Sjoerg *destp = dest; 18812099Sjoerg} 18912099Sjoerg 19012099Sjoergstatic void 19191592Smarkmfreelst(char ***lstp) 19212099Sjoerg{ 19312099Sjoerg char *s; 19412099Sjoerg int i; 19512099Sjoerg 19691592Smarkm for (i = 0; (*lstp)[i] != NULL; i++) 19791592Smarkm continue; 19812099Sjoerg while (i-- > 0) { 19912099Sjoerg s = (*lstp)[i]; 20012099Sjoerg (*lstp)[i] = NULL; 20112099Sjoerg free(s); 20212099Sjoerg } 20312099Sjoerg} 20412099Sjoerg 20512099Sjoergstatic char * 20691592Smarkmconcat2(const char *s1, const char *s2) 20712099Sjoerg{ 20812099Sjoerg char *s; 20912099Sjoerg 21091818Smarkm s = xmalloc(strlen(s1) + strlen(s2) + 1); 21112099Sjoerg (void)strcpy(s, s1); 21212099Sjoerg (void)strcat(s, s2); 21312099Sjoerg 21412099Sjoerg return (s); 21512099Sjoerg} 21612099Sjoerg 21712099Sjoergstatic char * 21891592Smarkmconcat3(const char *s1, const char *s2, const char *s3) 21912099Sjoerg{ 22012099Sjoerg char *s; 22112099Sjoerg 22291818Smarkm s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1); 22312099Sjoerg (void)strcpy(s, s1); 22412099Sjoerg (void)strcat(s, s2); 22512099Sjoerg (void)strcat(s, s3); 22612099Sjoerg 22712099Sjoerg return (s); 22812099Sjoerg} 22912099Sjoerg 23012099Sjoerg/* 23112099Sjoerg * Clean up after a signal. 23212099Sjoerg */ 23312099Sjoergstatic void 23491592Smarkmterminate(int signo) 23512099Sjoerg{ 23612099Sjoerg int i; 23712099Sjoerg 23875710Sasmodai if (cppoutfd != -1) 23975710Sasmodai (void)close(cppoutfd); 24012099Sjoerg if (cppout != NULL) 24112099Sjoerg (void)remove(cppout); 24212099Sjoerg 24312099Sjoerg if (p1out != NULL) { 24412099Sjoerg for (i = 0; p1out[i] != NULL; i++) 24512099Sjoerg (void)remove(p1out[i]); 24612099Sjoerg } 24712099Sjoerg 24812099Sjoerg if (p2out != NULL) 24912099Sjoerg (void)remove(p2out); 25012099Sjoerg 25112099Sjoerg if (currfn != NULL) 25212099Sjoerg (void)remove(currfn); 25312099Sjoerg 25412099Sjoerg exit(signo != 0 ? 1 : 0); 25512099Sjoerg} 25612099Sjoerg 25712099Sjoerg/* 25812099Sjoerg * Returns a pointer to the last component of strg after delim. 25912099Sjoerg * Returns strg if the string does not contain delim. 26012099Sjoerg */ 26112099Sjoergstatic const char * 26291592Smarkmlbasename(const char *strg, int delim) 26312099Sjoerg{ 26412099Sjoerg const char *cp, *cp1, *cp2; 26512099Sjoerg 26612099Sjoerg cp = cp1 = cp2 = strg; 26712099Sjoerg while (*cp != '\0') { 26812099Sjoerg if (*cp++ == delim) { 26912099Sjoerg cp2 = cp1; 27012099Sjoerg cp1 = cp; 27112099Sjoerg } 27212099Sjoerg } 27312099Sjoerg return (*cp1 == '\0' ? cp2 : cp1); 27412099Sjoerg} 27512099Sjoerg 27612099Sjoergstatic void 27791592Smarkmappdef(char ***lstp, const char *def) 27812099Sjoerg{ 27991592Smarkm 28012099Sjoerg appstrg(lstp, concat2("-D__", def)); 28112099Sjoerg appstrg(lstp, concat3("-D__", def, "__")); 28212099Sjoerg} 28312099Sjoerg 28412099Sjoergstatic void 28591592Smarkmusage(void) 28612099Sjoerg{ 28791592Smarkm 28891592Smarkm (void)fprintf(stderr, 289281168Spfg "usage: lint [-abceghprvwxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]]" 29094124Sru " [-Uname] [-X <id>[,<id>]...\n"); 29191592Smarkm (void)fprintf(stderr, 29291592Smarkm "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]" 29391592Smarkm " file...\n"); 29491592Smarkm (void)fprintf(stderr, 295281168Spfg " lint [-abceghprvwzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n" 29694124Sru " [-X <id>[,<id>]...\n"); 29791592Smarkm (void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file" 29891592Smarkm " ...\n"); 29912099Sjoerg terminate(-1); 30012099Sjoerg} 30112099Sjoerg 30291592Smarkm 30312099Sjoergint 30491592Smarkmmain(int argc, char *argv[]) 30512099Sjoerg{ 30612099Sjoerg int c; 307201610Sdwmalone char flgbuf[3], *s; 308201610Sdwmalone const char *tmp; 30912099Sjoerg size_t len; 31012099Sjoerg 31112099Sjoerg if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) { 312201610Sdwmalone tmpdir = _PATH_TMP; 31312099Sjoerg } else { 31491818Smarkm s = xmalloc(len + 2); 31512099Sjoerg (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/"); 31612099Sjoerg tmpdir = s; 31712099Sjoerg } 31812099Sjoerg 31991818Smarkm cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX")); 32012099Sjoerg (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir); 32175710Sasmodai cppoutfd = mkstemp(cppout); 32275710Sasmodai if (cppoutfd == -1) { 32312099Sjoerg warn("can't make temp"); 32412099Sjoerg terminate(-1); 32512099Sjoerg } 32612099Sjoerg 32791592Smarkm p1out = xcalloc(1, sizeof (char *)); 32891592Smarkm p2in = xcalloc(1, sizeof (char *)); 32991592Smarkm cflags = xcalloc(1, sizeof (char *)); 33091592Smarkm lcflags = xcalloc(1, sizeof (char *)); 33191592Smarkm l1flags = xcalloc(1, sizeof (char *)); 33291592Smarkm l2flags = xcalloc(1, sizeof (char *)); 33391592Smarkm l2libs = xcalloc(1, sizeof (char *)); 33491592Smarkm deflibs = xcalloc(1, sizeof (char *)); 33591592Smarkm libs = xcalloc(1, sizeof (char *)); 33691592Smarkm libsrchpath = xcalloc(1, sizeof (char *)); 33712099Sjoerg 33875710Sasmodai appcstrg(&cflags, "-E"); 33975710Sasmodai appcstrg(&cflags, "-x"); 34075710Sasmodai appcstrg(&cflags, "c"); 34191592Smarkm#if 0 34275710Sasmodai appcstrg(&cflags, "-D__attribute__(x)="); 34391592Smarkm appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0"); 34491592Smarkm#else 34591592Smarkm appcstrg(&cflags, "-U__GNUC__"); 34692089Smarkm appcstrg(&cflags, "-undef"); 34791592Smarkm#endif 348281168Spfg#if 0 349281168Spfg appcstrg(&cflags, "-Wp,-$"); 350281168Spfg#endif 35194034Speter appcstrg(&cflags, "-Wp,-C"); 35275710Sasmodai appcstrg(&cflags, "-Wcomment"); 35391592Smarkm appcstrg(&cflags, "-D__LINT__"); 35475710Sasmodai appcstrg(&cflags, "-Dlint"); /* XXX don't def. with -s */ 35512099Sjoerg 35675710Sasmodai appdef(&cflags, "lint"); 35712099Sjoerg 35812099Sjoerg appcstrg(&deflibs, "c"); 35912099Sjoerg 36012099Sjoerg if (signal(SIGHUP, terminate) == SIG_IGN) 36112099Sjoerg (void)signal(SIGHUP, SIG_IGN); 36212099Sjoerg (void)signal(SIGINT, terminate); 36312099Sjoerg (void)signal(SIGQUIT, terminate); 36412099Sjoerg (void)signal(SIGTERM, terminate); 365281168Spfg while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:M:SU:VX:")) != -1) { 36612099Sjoerg switch (c) { 36712099Sjoerg 36812099Sjoerg case 'a': 36912099Sjoerg case 'b': 37012099Sjoerg case 'c': 37112099Sjoerg case 'e': 37212099Sjoerg case 'g': 37312099Sjoerg case 'r': 37412099Sjoerg case 'v': 37591592Smarkm case 'w': 37612099Sjoerg case 'z': 37712099Sjoerg (void)sprintf(flgbuf, "-%c", c); 37812099Sjoerg appcstrg(&l1flags, flgbuf); 37912099Sjoerg break; 38012099Sjoerg 38112099Sjoerg case 'F': 38212099Sjoerg Fflag = 1; 38312099Sjoerg /* FALLTHROUGH */ 38412099Sjoerg case 'u': 38512099Sjoerg case 'h': 38612099Sjoerg (void)sprintf(flgbuf, "-%c", c); 38712099Sjoerg appcstrg(&l1flags, flgbuf); 38812099Sjoerg appcstrg(&l2flags, flgbuf); 38912099Sjoerg break; 39012099Sjoerg 39191592Smarkm case 'X': 39291592Smarkm (void)sprintf(flgbuf, "-%c", c); 39391592Smarkm appcstrg(&l1flags, flgbuf); 39491592Smarkm appcstrg(&l1flags, optarg); 39591592Smarkm break; 39691592Smarkm 39712099Sjoerg case 'i': 39812099Sjoerg if (Cflag) 39912099Sjoerg usage(); 40012099Sjoerg iflag = 1; 40112099Sjoerg break; 40212099Sjoerg 40312099Sjoerg case 'n': 40412099Sjoerg freelst(&deflibs); 40512099Sjoerg break; 40612099Sjoerg 40712099Sjoerg case 'p': 408162493Skan appcstrg(&lcflags, "-Wtraditional"); 409162493Skan appcstrg(&lcflags, "-Wno-system-headers"); 41012099Sjoerg appcstrg(&l1flags, "-p"); 41112099Sjoerg appcstrg(&l2flags, "-p"); 41212099Sjoerg if (*deflibs != NULL) { 41312099Sjoerg freelst(&deflibs); 41412099Sjoerg appcstrg(&deflibs, "c"); 41512099Sjoerg } 41612099Sjoerg break; 41712099Sjoerg 41812099Sjoerg case 's': 41912099Sjoerg if (tflag) 42012099Sjoerg usage(); 42175710Sasmodai freelst(&lcflags); 42275710Sasmodai appcstrg(&lcflags, "-trigraphs"); 42375710Sasmodai appcstrg(&lcflags, "-Wtrigraphs"); 42475710Sasmodai appcstrg(&lcflags, "-pedantic"); 42575710Sasmodai appcstrg(&lcflags, "-D__STRICT_ANSI__"); 42612099Sjoerg appcstrg(&l1flags, "-s"); 42712099Sjoerg appcstrg(&l2flags, "-s"); 42812099Sjoerg sflag = 1; 42912099Sjoerg break; 43012099Sjoerg 431281168Spfg case 'S': 432281168Spfg if (tflag) 433281168Spfg usage(); 434281168Spfg appcstrg(&l1flags, "-S"); 435281168Spfg Sflag = 1; 436281168Spfg break; 437281168Spfg 43891592Smarkm#if !HAVE_CONFIG_H 43912099Sjoerg case 't': 44012099Sjoerg if (sflag) 44112099Sjoerg usage(); 44275710Sasmodai freelst(&lcflags); 44375710Sasmodai appcstrg(&lcflags, "-traditional"); 44475710Sasmodai appstrg(&lcflags, concat2("-D", MACHINE)); 44575710Sasmodai appstrg(&lcflags, concat2("-D", MACHINE_ARCH)); 44612099Sjoerg appcstrg(&l1flags, "-t"); 44712099Sjoerg appcstrg(&l2flags, "-t"); 44812099Sjoerg tflag = 1; 44912099Sjoerg break; 45091592Smarkm#endif 45112099Sjoerg 45212099Sjoerg case 'x': 45312099Sjoerg appcstrg(&l2flags, "-x"); 45412099Sjoerg break; 45512099Sjoerg 45612099Sjoerg case 'C': 45712099Sjoerg if (Cflag || oflag || iflag) 45812099Sjoerg usage(); 45912099Sjoerg Cflag = 1; 46012099Sjoerg appstrg(&l2flags, concat2("-C", optarg)); 46191818Smarkm p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg)); 46212099Sjoerg (void)sprintf(p2out, "llib-l%s.ln", optarg); 46312099Sjoerg freelst(&deflibs); 46412099Sjoerg break; 46512099Sjoerg 46691592Smarkm case 'd': 46791592Smarkm if (dflag) 46891592Smarkm usage(); 46991592Smarkm dflag = 1; 47091592Smarkm appcstrg(&cflags, "-nostdinc"); 47191592Smarkm appcstrg(&cflags, "-idirafter"); 47291592Smarkm appcstrg(&cflags, optarg); 47391592Smarkm break; 47491592Smarkm 47512099Sjoerg case 'D': 47612099Sjoerg case 'I': 477281168Spfg case 'M': 47812099Sjoerg case 'U': 47912099Sjoerg (void)sprintf(flgbuf, "-%c", c); 48075710Sasmodai appstrg(&cflags, concat2(flgbuf, optarg)); 48112099Sjoerg break; 48212099Sjoerg 48312099Sjoerg case 'l': 48412099Sjoerg appcstrg(&libs, optarg); 48512099Sjoerg break; 48612099Sjoerg 48712099Sjoerg case 'o': 48812099Sjoerg if (Cflag || oflag) 48912099Sjoerg usage(); 49012099Sjoerg oflag = 1; 49191818Smarkm outputfn = xstrdup(optarg); 49212099Sjoerg break; 49312099Sjoerg 49412099Sjoerg case 'L': 49512099Sjoerg appcstrg(&libsrchpath, optarg); 49612099Sjoerg break; 49712099Sjoerg 49812099Sjoerg case 'H': 49912099Sjoerg appcstrg(&l2flags, "-H"); 50012099Sjoerg break; 50112099Sjoerg 50291592Smarkm case 'B': 50391592Smarkm Bflag = 1; 50491592Smarkm libexec_path = xstrdup(optarg); 50591592Smarkm break; 50691592Smarkm 50712099Sjoerg case 'V': 50812099Sjoerg Vflag = 1; 50912099Sjoerg break; 51012099Sjoerg 51191592Smarkm default: 51212099Sjoerg usage(); 51312099Sjoerg /* NOTREACHED */ 51491592Smarkm } 51591592Smarkm } 51691592Smarkm argc -= optind; 51791592Smarkm argv += optind; 51812099Sjoerg 51991592Smarkm /* 52091592Smarkm * To avoid modifying getopt(3)'s state engine midstream, we 52191592Smarkm * explicitly accept just a few options after the first source file. 52291592Smarkm * 52391592Smarkm * In particular, only -l<lib> and -L<libdir> (and these with a space 52491592Smarkm * after -l or -L) are allowed. 52591592Smarkm */ 52691592Smarkm while (argc > 0) { 52791592Smarkm const char *arg = argv[0]; 52891592Smarkm 52991592Smarkm if (arg[0] == '-') { 53091592Smarkm char ***list; 53191592Smarkm 53291592Smarkm /* option */ 53391592Smarkm switch (arg[1]) { 53491592Smarkm case 'l': 53591592Smarkm list = &libs; 53691592Smarkm break; 53791592Smarkm 53891592Smarkm case 'L': 53991592Smarkm list = &libsrchpath; 54091592Smarkm break; 54191592Smarkm 54291592Smarkm default: 54391592Smarkm usage(); 54491592Smarkm /* NOTREACHED */ 54591592Smarkm } 54691592Smarkm if (arg[2]) 54791592Smarkm appcstrg(list, arg + 2); 54891592Smarkm else if (argc > 1) { 54991592Smarkm argc--; 55091592Smarkm appcstrg(list, *++argv); 55191592Smarkm } else 55291592Smarkm usage(); 55391592Smarkm } else { 55412099Sjoerg /* filename */ 55591592Smarkm fname(arg); 55612099Sjoerg first = 0; 55712099Sjoerg } 55891592Smarkm argc--; 55991592Smarkm argv++; 56012099Sjoerg } 56112099Sjoerg 56212099Sjoerg if (first) 56312099Sjoerg usage(); 56412099Sjoerg 56512099Sjoerg if (iflag) 56612099Sjoerg terminate(0); 56712099Sjoerg 56812099Sjoerg if (!oflag) { 569201610Sdwmalone if ((tmp = getenv("LIBDIR")) == NULL || strlen(tmp) == 0) 570201610Sdwmalone tmp = PATH_LINTLIB; 571201610Sdwmalone appcstrg(&libsrchpath, tmp); 57212099Sjoerg findlibs(libs); 57312099Sjoerg findlibs(deflibs); 57412099Sjoerg } 57512099Sjoerg 57612099Sjoerg (void)printf("Lint pass2:\n"); 57712099Sjoerg lint2(); 57812099Sjoerg 57912099Sjoerg if (oflag) 58012099Sjoerg cat(p2in, outputfn); 58112099Sjoerg 58212099Sjoerg if (Cflag) 58312099Sjoerg p2out = NULL; 58412099Sjoerg 58512099Sjoerg terminate(0); 58612099Sjoerg /* NOTREACHED */ 58712099Sjoerg} 58812099Sjoerg 58912099Sjoerg/* 59012099Sjoerg * Read a file name from the command line 59112099Sjoerg * and pass it through lint1 if it is a C source. 59212099Sjoerg */ 59312099Sjoergstatic void 59491592Smarkmfname(const char *name) 59512099Sjoerg{ 59612099Sjoerg const char *bn, *suff; 597102770Siedowse char **args, *ofn, *p, *pathname; 59812099Sjoerg size_t len; 59991592Smarkm int is_stdin; 60075710Sasmodai int fd; 60112099Sjoerg 60291592Smarkm is_stdin = (strcmp(name, "-") == 0); 60391592Smarkm bn = lbasename(name, '/'); 60491592Smarkm suff = lbasename(bn, '.'); 60512099Sjoerg 60612099Sjoerg if (strcmp(suff, "ln") == 0) { 60712099Sjoerg /* only for lint2 */ 60812099Sjoerg if (!iflag) 60912099Sjoerg appcstrg(&p2in, name); 61012099Sjoerg return; 61112099Sjoerg } 61212099Sjoerg 61391592Smarkm if (!is_stdin && strcmp(suff, "c") != 0 && 61412099Sjoerg (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) { 61512099Sjoerg warnx("unknown file type: %s\n", name); 61612099Sjoerg return; 61712099Sjoerg } 61812099Sjoerg 61991592Smarkm if (!iflag || !first) 62091592Smarkm (void)printf("%s:\n", 62191592Smarkm is_stdin ? "{standard input}" : Fflag ? name : bn); 62212099Sjoerg 62312099Sjoerg /* build the name of the output file of lint1 */ 62412099Sjoerg if (oflag) { 62512099Sjoerg ofn = outputfn; 62612099Sjoerg outputfn = NULL; 62712099Sjoerg oflag = 0; 62812099Sjoerg } else if (iflag) { 62991592Smarkm if (is_stdin) { 63091592Smarkm warnx("-i not supported without -o for standard input"); 63191592Smarkm return; 63291592Smarkm } 63391592Smarkm ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2)); 634201610Sdwmalone len = bn == suff ? strlen(bn) : (size_t)((suff - 1) - bn); 63512099Sjoerg (void)sprintf(ofn, "%.*s", (int)len, bn); 63612099Sjoerg (void)strcat(ofn, ".ln"); 63712099Sjoerg } else { 63891818Smarkm ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX")); 63912099Sjoerg (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir); 64075710Sasmodai fd = mkstemp(ofn); 64175710Sasmodai if (fd == -1) { 64212099Sjoerg warn("can't make temp"); 64312099Sjoerg terminate(-1); 64412099Sjoerg } 64575710Sasmodai close(fd); 64612099Sjoerg } 64712099Sjoerg if (!iflag) 64812099Sjoerg appcstrg(&p1out, ofn); 64912099Sjoerg 65091818Smarkm args = xcalloc(1, sizeof (char *)); 65112099Sjoerg 65275710Sasmodai /* run cc */ 65312099Sjoerg 65491592Smarkm if (getenv("CC") == NULL) { 655100364Smarkm pathname = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc")); 656100364Smarkm (void)sprintf(pathname, "%s/cc", PATH_USRBIN); 657102770Siedowse appcstrg(&args, pathname); 658102770Siedowse } else { 659100364Smarkm pathname = strdup(getenv("CC")); 660102770Siedowse for (p = strtok(pathname, " \t"); p; p = strtok(NULL, " \t")) 661102770Siedowse appcstrg(&args, p); 662102770Siedowse } 66312099Sjoerg 66475710Sasmodai applst(&args, cflags); 66575710Sasmodai applst(&args, lcflags); 66612099Sjoerg appcstrg(&args, name); 66712099Sjoerg 66875710Sasmodai /* we reuse the same tmp file for cpp output, so rewind and truncate */ 669227123Sjilles if (lseek(cppoutfd, (off_t)0, SEEK_SET) != 0) { 67075710Sasmodai warn("lseek"); 67175710Sasmodai terminate(-1); 67275710Sasmodai } 67375710Sasmodai if (ftruncate(cppoutfd, (off_t)0) != 0) { 67475710Sasmodai warn("ftruncate"); 67575710Sasmodai terminate(-1); 67675710Sasmodai } 67775710Sasmodai 678100364Smarkm runchild(pathname, args, cppout, cppoutfd); 679100364Smarkm free(pathname); 68012099Sjoerg freelst(&args); 68112099Sjoerg 68212099Sjoerg /* run lint1 */ 68312099Sjoerg 68491592Smarkm if (!Bflag) { 685100364Smarkm pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") + 68691592Smarkm strlen(target_prefix)); 687100364Smarkm (void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC, 68891592Smarkm target_prefix); 68991592Smarkm } else { 69091592Smarkm /* 69191592Smarkm * XXX Unclear whether we should be using target_prefix 69291592Smarkm * XXX here. --thorpej@wasabisystems.com 69391592Smarkm */ 694100364Smarkm pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1")); 695100364Smarkm (void)sprintf(pathname, "%s/lint1", libexec_path); 69691592Smarkm } 69712099Sjoerg 698100364Smarkm appcstrg(&args, pathname); 69912099Sjoerg applst(&args, l1flags); 70012099Sjoerg appcstrg(&args, cppout); 70112099Sjoerg appcstrg(&args, ofn); 70212099Sjoerg 703100364Smarkm runchild(pathname, args, ofn, -1); 704100364Smarkm free(pathname); 70512099Sjoerg freelst(&args); 70612099Sjoerg 70712099Sjoerg appcstrg(&p2in, ofn); 70812099Sjoerg free(ofn); 70912099Sjoerg 71012099Sjoerg free(args); 71112099Sjoerg} 71212099Sjoerg 71312099Sjoergstatic void 71491592Smarkmrunchild(const char *path, char *const *args, const char *crfn, int fdout) 71512099Sjoerg{ 71612099Sjoerg int status, rv, signo, i; 71712099Sjoerg 71812099Sjoerg if (Vflag) { 71912099Sjoerg for (i = 0; args[i] != NULL; i++) 72012099Sjoerg (void)printf("%s ", args[i]); 72112099Sjoerg (void)printf("\n"); 72212099Sjoerg } 72312099Sjoerg 72412099Sjoerg currfn = crfn; 72512099Sjoerg 72612099Sjoerg (void)fflush(stdout); 72712099Sjoerg 72875710Sasmodai switch (vfork()) { 72912099Sjoerg case -1: 73012099Sjoerg warn("cannot fork"); 73112099Sjoerg terminate(-1); 73212099Sjoerg /* NOTREACHED */ 73312099Sjoerg default: 73412099Sjoerg /* parent */ 73512099Sjoerg break; 73612099Sjoerg case 0: 73712099Sjoerg /* child */ 73875710Sasmodai 73975710Sasmodai /* setup the standard output if necessary */ 74075710Sasmodai if (fdout != -1) { 74175710Sasmodai dup2(fdout, STDOUT_FILENO); 74275710Sasmodai close(fdout); 74375710Sasmodai } 74491592Smarkm (void)execvp(path, args); 74512099Sjoerg warn("cannot exec %s", path); 74675710Sasmodai _exit(1); 74712099Sjoerg /* NOTREACHED */ 74812099Sjoerg } 74912099Sjoerg 75012099Sjoerg while ((rv = wait(&status)) == -1 && errno == EINTR) ; 75112099Sjoerg if (rv == -1) { 75212099Sjoerg warn("wait"); 75312099Sjoerg terminate(-1); 75412099Sjoerg } 75512099Sjoerg if (WIFSIGNALED(status)) { 75612099Sjoerg signo = WTERMSIG(status); 75791592Smarkm#if HAVE_DECL_SYS_SIGNAME 75812099Sjoerg warnx("%s got SIG%s", path, sys_signame[signo]); 75991592Smarkm#else 76091592Smarkm warnx("%s got signal %d", path, signo); 76191592Smarkm#endif 76212099Sjoerg terminate(-1); 76312099Sjoerg } 76412099Sjoerg if (WEXITSTATUS(status) != 0) 76512099Sjoerg terminate(-1); 76612099Sjoerg currfn = NULL; 76712099Sjoerg} 76812099Sjoerg 76912099Sjoergstatic void 77091592Smarkmfindlibs(char *const *liblst) 77112099Sjoerg{ 77212099Sjoerg int i, k; 77312099Sjoerg const char *lib, *path; 77412099Sjoerg char *lfn; 77512099Sjoerg size_t len; 77612099Sjoerg 77712099Sjoerg lfn = NULL; 77812099Sjoerg 77912099Sjoerg for (i = 0; (lib = liblst[i]) != NULL; i++) { 78012099Sjoerg for (k = 0; (path = libsrchpath[k]) != NULL; k++) { 78112099Sjoerg len = strlen(path) + strlen(lib); 78291818Smarkm lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln")); 78312099Sjoerg (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib); 78412099Sjoerg if (rdok(lfn)) 78512099Sjoerg break; 78691818Smarkm lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln")); 78712099Sjoerg (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib); 78812099Sjoerg if (rdok(lfn)) 78912099Sjoerg break; 79012099Sjoerg } 79112099Sjoerg if (path != NULL) { 79212099Sjoerg appstrg(&l2libs, concat2("-l", lfn)); 79312099Sjoerg } else { 79412099Sjoerg warnx("cannot find llib-l%s.ln", lib); 79512099Sjoerg } 79612099Sjoerg } 79712099Sjoerg 79812099Sjoerg free(lfn); 79912099Sjoerg} 80012099Sjoerg 80112099Sjoergstatic int 80291592Smarkmrdok(const char *path) 80312099Sjoerg{ 80412099Sjoerg struct stat sbuf; 80512099Sjoerg 80612099Sjoerg if (stat(path, &sbuf) == -1) 80712099Sjoerg return (0); 80891592Smarkm if (!S_ISREG(sbuf.st_mode)) 80912099Sjoerg return (0); 81012099Sjoerg if (access(path, R_OK) == -1) 81112099Sjoerg return (0); 81212099Sjoerg return (1); 81312099Sjoerg} 81412099Sjoerg 81512099Sjoergstatic void 81691592Smarkmlint2(void) 81712099Sjoerg{ 81812099Sjoerg char *path, **args; 81912099Sjoerg 82091818Smarkm args = xcalloc(1, sizeof (char *)); 82112099Sjoerg 82291592Smarkm if (!Bflag) { 82391592Smarkm path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") + 82491592Smarkm strlen(target_prefix)); 82591592Smarkm (void)sprintf(path, "%s/%slint2", PATH_LIBEXEC, 82691592Smarkm target_prefix); 82791592Smarkm } else { 82891592Smarkm /* 82991592Smarkm * XXX Unclear whether we should be using target_prefix 83091592Smarkm * XXX here. --thorpej@wasabisystems.com 83191592Smarkm */ 83291592Smarkm path = xmalloc(strlen(libexec_path) + sizeof ("/lint2")); 83391592Smarkm (void)sprintf(path, "%s/lint2", libexec_path); 83491592Smarkm } 83591592Smarkm 83612099Sjoerg appcstrg(&args, path); 83712099Sjoerg applst(&args, l2flags); 83812099Sjoerg applst(&args, l2libs); 83912099Sjoerg applst(&args, p2in); 84012099Sjoerg 84175710Sasmodai runchild(path, args, p2out, -1); 84212099Sjoerg free(path); 84312099Sjoerg freelst(&args); 84412099Sjoerg free(args); 84512099Sjoerg} 84612099Sjoerg 84712099Sjoergstatic void 84891592Smarkmcat(char *const *srcs, const char *dest) 84912099Sjoerg{ 85012099Sjoerg int ifd, ofd, i; 85112099Sjoerg char *src, *buf; 85212099Sjoerg ssize_t rlen; 85312099Sjoerg 85412099Sjoerg if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { 85512099Sjoerg warn("cannot open %s", dest); 85612099Sjoerg terminate(-1); 85712099Sjoerg } 85812099Sjoerg 85991818Smarkm buf = xmalloc(MBLKSIZ); 86012099Sjoerg 86112099Sjoerg for (i = 0; (src = srcs[i]) != NULL; i++) { 86212099Sjoerg if ((ifd = open(src, O_RDONLY)) == -1) { 86312099Sjoerg free(buf); 86412099Sjoerg warn("cannot open %s", src); 86512099Sjoerg terminate(-1); 86612099Sjoerg } 86712099Sjoerg do { 86812099Sjoerg if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) { 86912099Sjoerg free(buf); 87012099Sjoerg warn("read error on %s", src); 87112099Sjoerg terminate(-1); 87212099Sjoerg } 87312099Sjoerg if (write(ofd, buf, (size_t)rlen) == -1) { 87412099Sjoerg free(buf); 87512099Sjoerg warn("write error on %s", dest); 87612099Sjoerg terminate(-1); 87712099Sjoerg } 87812099Sjoerg } while (rlen == MBLKSIZ); 87912099Sjoerg (void)close(ifd); 88012099Sjoerg } 88112099Sjoerg (void)close(ofd); 88212099Sjoerg free(buf); 88312099Sjoerg} 884