1100364Smarkm/* $NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv 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) 37100364Smarkm__RCSID("$NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv 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 */ 10791592Smarkmstatic int iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag; 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. 14812099Sjoerg * Take care that we get no surprises in case of asyncron 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, 28995258Sdes "usage: lint [-abceghprvwxzHF] [-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, 29594124Sru " lint [-abceghprvwzHF] [-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 34894034Speter appcstrg(&cflags, "-Wp,-C"); 34975710Sasmodai appcstrg(&cflags, "-Wcomment"); 35091592Smarkm appcstrg(&cflags, "-D__LINT__"); 35175710Sasmodai appcstrg(&cflags, "-Dlint"); /* XXX don't def. with -s */ 35212099Sjoerg 35375710Sasmodai appdef(&cflags, "lint"); 35412099Sjoerg 35512099Sjoerg appcstrg(&deflibs, "c"); 35612099Sjoerg 35712099Sjoerg if (signal(SIGHUP, terminate) == SIG_IGN) 35812099Sjoerg (void)signal(SIGHUP, SIG_IGN); 35912099Sjoerg (void)signal(SIGINT, terminate); 36012099Sjoerg (void)signal(SIGQUIT, terminate); 36112099Sjoerg (void)signal(SIGTERM, terminate); 36212099Sjoerg 36391592Smarkm while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:U:VX:")) != -1) { 36412099Sjoerg switch (c) { 36512099Sjoerg 36612099Sjoerg case 'a': 36712099Sjoerg case 'b': 36812099Sjoerg case 'c': 36912099Sjoerg case 'e': 37012099Sjoerg case 'g': 37112099Sjoerg case 'r': 37212099Sjoerg case 'v': 37391592Smarkm case 'w': 37412099Sjoerg case 'z': 37512099Sjoerg (void)sprintf(flgbuf, "-%c", c); 37612099Sjoerg appcstrg(&l1flags, flgbuf); 37712099Sjoerg break; 37812099Sjoerg 37912099Sjoerg case 'F': 38012099Sjoerg Fflag = 1; 38112099Sjoerg /* FALLTHROUGH */ 38212099Sjoerg case 'u': 38312099Sjoerg case 'h': 38412099Sjoerg (void)sprintf(flgbuf, "-%c", c); 38512099Sjoerg appcstrg(&l1flags, flgbuf); 38612099Sjoerg appcstrg(&l2flags, flgbuf); 38712099Sjoerg break; 38812099Sjoerg 38991592Smarkm case 'X': 39091592Smarkm (void)sprintf(flgbuf, "-%c", c); 39191592Smarkm appcstrg(&l1flags, flgbuf); 39291592Smarkm appcstrg(&l1flags, optarg); 39391592Smarkm break; 39491592Smarkm 39512099Sjoerg case 'i': 39612099Sjoerg if (Cflag) 39712099Sjoerg usage(); 39812099Sjoerg iflag = 1; 39912099Sjoerg break; 40012099Sjoerg 40112099Sjoerg case 'n': 40212099Sjoerg freelst(&deflibs); 40312099Sjoerg break; 40412099Sjoerg 40512099Sjoerg case 'p': 406162493Skan appcstrg(&lcflags, "-Wtraditional"); 407162493Skan appcstrg(&lcflags, "-Wno-system-headers"); 40812099Sjoerg appcstrg(&l1flags, "-p"); 40912099Sjoerg appcstrg(&l2flags, "-p"); 41012099Sjoerg if (*deflibs != NULL) { 41112099Sjoerg freelst(&deflibs); 41212099Sjoerg appcstrg(&deflibs, "c"); 41312099Sjoerg } 41412099Sjoerg break; 41512099Sjoerg 41612099Sjoerg case 's': 41712099Sjoerg if (tflag) 41812099Sjoerg usage(); 41975710Sasmodai freelst(&lcflags); 42075710Sasmodai appcstrg(&lcflags, "-trigraphs"); 42175710Sasmodai appcstrg(&lcflags, "-Wtrigraphs"); 42275710Sasmodai appcstrg(&lcflags, "-pedantic"); 42375710Sasmodai appcstrg(&lcflags, "-D__STRICT_ANSI__"); 42412099Sjoerg appcstrg(&l1flags, "-s"); 42512099Sjoerg appcstrg(&l2flags, "-s"); 42612099Sjoerg sflag = 1; 42712099Sjoerg break; 42812099Sjoerg 42991592Smarkm#if !HAVE_CONFIG_H 43012099Sjoerg case 't': 43112099Sjoerg if (sflag) 43212099Sjoerg usage(); 43375710Sasmodai freelst(&lcflags); 43475710Sasmodai appcstrg(&lcflags, "-traditional"); 43575710Sasmodai appstrg(&lcflags, concat2("-D", MACHINE)); 43675710Sasmodai appstrg(&lcflags, concat2("-D", MACHINE_ARCH)); 43712099Sjoerg appcstrg(&l1flags, "-t"); 43812099Sjoerg appcstrg(&l2flags, "-t"); 43912099Sjoerg tflag = 1; 44012099Sjoerg break; 44191592Smarkm#endif 44212099Sjoerg 44312099Sjoerg case 'x': 44412099Sjoerg appcstrg(&l2flags, "-x"); 44512099Sjoerg break; 44612099Sjoerg 44712099Sjoerg case 'C': 44812099Sjoerg if (Cflag || oflag || iflag) 44912099Sjoerg usage(); 45012099Sjoerg Cflag = 1; 45112099Sjoerg appstrg(&l2flags, concat2("-C", optarg)); 45291818Smarkm p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg)); 45312099Sjoerg (void)sprintf(p2out, "llib-l%s.ln", optarg); 45412099Sjoerg freelst(&deflibs); 45512099Sjoerg break; 45612099Sjoerg 45791592Smarkm case 'd': 45891592Smarkm if (dflag) 45991592Smarkm usage(); 46091592Smarkm dflag = 1; 46191592Smarkm appcstrg(&cflags, "-nostdinc"); 46291592Smarkm appcstrg(&cflags, "-idirafter"); 46391592Smarkm appcstrg(&cflags, optarg); 46491592Smarkm break; 46591592Smarkm 46612099Sjoerg case 'D': 46712099Sjoerg case 'I': 46812099Sjoerg case 'U': 46912099Sjoerg (void)sprintf(flgbuf, "-%c", c); 47075710Sasmodai appstrg(&cflags, concat2(flgbuf, optarg)); 47112099Sjoerg break; 47212099Sjoerg 47312099Sjoerg case 'l': 47412099Sjoerg appcstrg(&libs, optarg); 47512099Sjoerg break; 47612099Sjoerg 47712099Sjoerg case 'o': 47812099Sjoerg if (Cflag || oflag) 47912099Sjoerg usage(); 48012099Sjoerg oflag = 1; 48191818Smarkm outputfn = xstrdup(optarg); 48212099Sjoerg break; 48312099Sjoerg 48412099Sjoerg case 'L': 48512099Sjoerg appcstrg(&libsrchpath, optarg); 48612099Sjoerg break; 48712099Sjoerg 48812099Sjoerg case 'H': 48912099Sjoerg appcstrg(&l2flags, "-H"); 49012099Sjoerg break; 49112099Sjoerg 49291592Smarkm case 'B': 49391592Smarkm Bflag = 1; 49491592Smarkm libexec_path = xstrdup(optarg); 49591592Smarkm break; 49691592Smarkm 49712099Sjoerg case 'V': 49812099Sjoerg Vflag = 1; 49912099Sjoerg break; 50012099Sjoerg 50191592Smarkm default: 50212099Sjoerg usage(); 50312099Sjoerg /* NOTREACHED */ 50491592Smarkm } 50591592Smarkm } 50691592Smarkm argc -= optind; 50791592Smarkm argv += optind; 50812099Sjoerg 50991592Smarkm /* 51091592Smarkm * To avoid modifying getopt(3)'s state engine midstream, we 51191592Smarkm * explicitly accept just a few options after the first source file. 51291592Smarkm * 51391592Smarkm * In particular, only -l<lib> and -L<libdir> (and these with a space 51491592Smarkm * after -l or -L) are allowed. 51591592Smarkm */ 51691592Smarkm while (argc > 0) { 51791592Smarkm const char *arg = argv[0]; 51891592Smarkm 51991592Smarkm if (arg[0] == '-') { 52091592Smarkm char ***list; 52191592Smarkm 52291592Smarkm /* option */ 52391592Smarkm switch (arg[1]) { 52491592Smarkm case 'l': 52591592Smarkm list = &libs; 52691592Smarkm break; 52791592Smarkm 52891592Smarkm case 'L': 52991592Smarkm list = &libsrchpath; 53091592Smarkm break; 53191592Smarkm 53291592Smarkm default: 53391592Smarkm usage(); 53491592Smarkm /* NOTREACHED */ 53591592Smarkm } 53691592Smarkm if (arg[2]) 53791592Smarkm appcstrg(list, arg + 2); 53891592Smarkm else if (argc > 1) { 53991592Smarkm argc--; 54091592Smarkm appcstrg(list, *++argv); 54191592Smarkm } else 54291592Smarkm usage(); 54391592Smarkm } else { 54412099Sjoerg /* filename */ 54591592Smarkm fname(arg); 54612099Sjoerg first = 0; 54712099Sjoerg } 54891592Smarkm argc--; 54991592Smarkm argv++; 55012099Sjoerg } 55112099Sjoerg 55212099Sjoerg if (first) 55312099Sjoerg usage(); 55412099Sjoerg 55512099Sjoerg if (iflag) 55612099Sjoerg terminate(0); 55712099Sjoerg 55812099Sjoerg if (!oflag) { 559201610Sdwmalone if ((tmp = getenv("LIBDIR")) == NULL || strlen(tmp) == 0) 560201610Sdwmalone tmp = PATH_LINTLIB; 561201610Sdwmalone appcstrg(&libsrchpath, tmp); 56212099Sjoerg findlibs(libs); 56312099Sjoerg findlibs(deflibs); 56412099Sjoerg } 56512099Sjoerg 56612099Sjoerg (void)printf("Lint pass2:\n"); 56712099Sjoerg lint2(); 56812099Sjoerg 56912099Sjoerg if (oflag) 57012099Sjoerg cat(p2in, outputfn); 57112099Sjoerg 57212099Sjoerg if (Cflag) 57312099Sjoerg p2out = NULL; 57412099Sjoerg 57512099Sjoerg terminate(0); 57612099Sjoerg /* NOTREACHED */ 57712099Sjoerg} 57812099Sjoerg 57912099Sjoerg/* 58012099Sjoerg * Read a file name from the command line 58112099Sjoerg * and pass it through lint1 if it is a C source. 58212099Sjoerg */ 58312099Sjoergstatic void 58491592Smarkmfname(const char *name) 58512099Sjoerg{ 58612099Sjoerg const char *bn, *suff; 587102770Siedowse char **args, *ofn, *p, *pathname; 58812099Sjoerg size_t len; 58991592Smarkm int is_stdin; 59075710Sasmodai int fd; 59112099Sjoerg 59291592Smarkm is_stdin = (strcmp(name, "-") == 0); 59391592Smarkm bn = lbasename(name, '/'); 59491592Smarkm suff = lbasename(bn, '.'); 59512099Sjoerg 59612099Sjoerg if (strcmp(suff, "ln") == 0) { 59712099Sjoerg /* only for lint2 */ 59812099Sjoerg if (!iflag) 59912099Sjoerg appcstrg(&p2in, name); 60012099Sjoerg return; 60112099Sjoerg } 60212099Sjoerg 60391592Smarkm if (!is_stdin && strcmp(suff, "c") != 0 && 60412099Sjoerg (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) { 60512099Sjoerg warnx("unknown file type: %s\n", name); 60612099Sjoerg return; 60712099Sjoerg } 60812099Sjoerg 60991592Smarkm if (!iflag || !first) 61091592Smarkm (void)printf("%s:\n", 61191592Smarkm is_stdin ? "{standard input}" : Fflag ? name : bn); 61212099Sjoerg 61312099Sjoerg /* build the name of the output file of lint1 */ 61412099Sjoerg if (oflag) { 61512099Sjoerg ofn = outputfn; 61612099Sjoerg outputfn = NULL; 61712099Sjoerg oflag = 0; 61812099Sjoerg } else if (iflag) { 61991592Smarkm if (is_stdin) { 62091592Smarkm warnx("-i not supported without -o for standard input"); 62191592Smarkm return; 62291592Smarkm } 62391592Smarkm ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2)); 624201610Sdwmalone len = bn == suff ? strlen(bn) : (size_t)((suff - 1) - bn); 62512099Sjoerg (void)sprintf(ofn, "%.*s", (int)len, bn); 62612099Sjoerg (void)strcat(ofn, ".ln"); 62712099Sjoerg } else { 62891818Smarkm ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX")); 62912099Sjoerg (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir); 63075710Sasmodai fd = mkstemp(ofn); 63175710Sasmodai if (fd == -1) { 63212099Sjoerg warn("can't make temp"); 63312099Sjoerg terminate(-1); 63412099Sjoerg } 63575710Sasmodai close(fd); 63612099Sjoerg } 63712099Sjoerg if (!iflag) 63812099Sjoerg appcstrg(&p1out, ofn); 63912099Sjoerg 64091818Smarkm args = xcalloc(1, sizeof (char *)); 64112099Sjoerg 64275710Sasmodai /* run cc */ 64312099Sjoerg 64491592Smarkm if (getenv("CC") == NULL) { 645100364Smarkm pathname = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc")); 646100364Smarkm (void)sprintf(pathname, "%s/cc", PATH_USRBIN); 647102770Siedowse appcstrg(&args, pathname); 648102770Siedowse } else { 649100364Smarkm pathname = strdup(getenv("CC")); 650102770Siedowse for (p = strtok(pathname, " \t"); p; p = strtok(NULL, " \t")) 651102770Siedowse appcstrg(&args, p); 652102770Siedowse } 65312099Sjoerg 65475710Sasmodai applst(&args, cflags); 65575710Sasmodai applst(&args, lcflags); 65612099Sjoerg appcstrg(&args, name); 65712099Sjoerg 65875710Sasmodai /* we reuse the same tmp file for cpp output, so rewind and truncate */ 659227123Sjilles if (lseek(cppoutfd, (off_t)0, SEEK_SET) != 0) { 66075710Sasmodai warn("lseek"); 66175710Sasmodai terminate(-1); 66275710Sasmodai } 66375710Sasmodai if (ftruncate(cppoutfd, (off_t)0) != 0) { 66475710Sasmodai warn("ftruncate"); 66575710Sasmodai terminate(-1); 66675710Sasmodai } 66775710Sasmodai 668100364Smarkm runchild(pathname, args, cppout, cppoutfd); 669100364Smarkm free(pathname); 67012099Sjoerg freelst(&args); 67112099Sjoerg 67212099Sjoerg /* run lint1 */ 67312099Sjoerg 67491592Smarkm if (!Bflag) { 675100364Smarkm pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") + 67691592Smarkm strlen(target_prefix)); 677100364Smarkm (void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC, 67891592Smarkm target_prefix); 67991592Smarkm } else { 68091592Smarkm /* 68191592Smarkm * XXX Unclear whether we should be using target_prefix 68291592Smarkm * XXX here. --thorpej@wasabisystems.com 68391592Smarkm */ 684100364Smarkm pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1")); 685100364Smarkm (void)sprintf(pathname, "%s/lint1", libexec_path); 68691592Smarkm } 68712099Sjoerg 688100364Smarkm appcstrg(&args, pathname); 68912099Sjoerg applst(&args, l1flags); 69012099Sjoerg appcstrg(&args, cppout); 69112099Sjoerg appcstrg(&args, ofn); 69212099Sjoerg 693100364Smarkm runchild(pathname, args, ofn, -1); 694100364Smarkm free(pathname); 69512099Sjoerg freelst(&args); 69612099Sjoerg 69712099Sjoerg appcstrg(&p2in, ofn); 69812099Sjoerg free(ofn); 69912099Sjoerg 70012099Sjoerg free(args); 70112099Sjoerg} 70212099Sjoerg 70312099Sjoergstatic void 70491592Smarkmrunchild(const char *path, char *const *args, const char *crfn, int fdout) 70512099Sjoerg{ 70612099Sjoerg int status, rv, signo, i; 70712099Sjoerg 70812099Sjoerg if (Vflag) { 70912099Sjoerg for (i = 0; args[i] != NULL; i++) 71012099Sjoerg (void)printf("%s ", args[i]); 71112099Sjoerg (void)printf("\n"); 71212099Sjoerg } 71312099Sjoerg 71412099Sjoerg currfn = crfn; 71512099Sjoerg 71612099Sjoerg (void)fflush(stdout); 71712099Sjoerg 71875710Sasmodai switch (vfork()) { 71912099Sjoerg case -1: 72012099Sjoerg warn("cannot fork"); 72112099Sjoerg terminate(-1); 72212099Sjoerg /* NOTREACHED */ 72312099Sjoerg default: 72412099Sjoerg /* parent */ 72512099Sjoerg break; 72612099Sjoerg case 0: 72712099Sjoerg /* child */ 72875710Sasmodai 72975710Sasmodai /* setup the standard output if necessary */ 73075710Sasmodai if (fdout != -1) { 73175710Sasmodai dup2(fdout, STDOUT_FILENO); 73275710Sasmodai close(fdout); 73375710Sasmodai } 73491592Smarkm (void)execvp(path, args); 73512099Sjoerg warn("cannot exec %s", path); 73675710Sasmodai _exit(1); 73712099Sjoerg /* NOTREACHED */ 73812099Sjoerg } 73912099Sjoerg 74012099Sjoerg while ((rv = wait(&status)) == -1 && errno == EINTR) ; 74112099Sjoerg if (rv == -1) { 74212099Sjoerg warn("wait"); 74312099Sjoerg terminate(-1); 74412099Sjoerg } 74512099Sjoerg if (WIFSIGNALED(status)) { 74612099Sjoerg signo = WTERMSIG(status); 74791592Smarkm#if HAVE_DECL_SYS_SIGNAME 74812099Sjoerg warnx("%s got SIG%s", path, sys_signame[signo]); 74991592Smarkm#else 75091592Smarkm warnx("%s got signal %d", path, signo); 75191592Smarkm#endif 75212099Sjoerg terminate(-1); 75312099Sjoerg } 75412099Sjoerg if (WEXITSTATUS(status) != 0) 75512099Sjoerg terminate(-1); 75612099Sjoerg currfn = NULL; 75712099Sjoerg} 75812099Sjoerg 75912099Sjoergstatic void 76091592Smarkmfindlibs(char *const *liblst) 76112099Sjoerg{ 76212099Sjoerg int i, k; 76312099Sjoerg const char *lib, *path; 76412099Sjoerg char *lfn; 76512099Sjoerg size_t len; 76612099Sjoerg 76712099Sjoerg lfn = NULL; 76812099Sjoerg 76912099Sjoerg for (i = 0; (lib = liblst[i]) != NULL; i++) { 77012099Sjoerg for (k = 0; (path = libsrchpath[k]) != NULL; k++) { 77112099Sjoerg len = strlen(path) + strlen(lib); 77291818Smarkm lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln")); 77312099Sjoerg (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib); 77412099Sjoerg if (rdok(lfn)) 77512099Sjoerg break; 77691818Smarkm lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln")); 77712099Sjoerg (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib); 77812099Sjoerg if (rdok(lfn)) 77912099Sjoerg break; 78012099Sjoerg } 78112099Sjoerg if (path != NULL) { 78212099Sjoerg appstrg(&l2libs, concat2("-l", lfn)); 78312099Sjoerg } else { 78412099Sjoerg warnx("cannot find llib-l%s.ln", lib); 78512099Sjoerg } 78612099Sjoerg } 78712099Sjoerg 78812099Sjoerg free(lfn); 78912099Sjoerg} 79012099Sjoerg 79112099Sjoergstatic int 79291592Smarkmrdok(const char *path) 79312099Sjoerg{ 79412099Sjoerg struct stat sbuf; 79512099Sjoerg 79612099Sjoerg if (stat(path, &sbuf) == -1) 79712099Sjoerg return (0); 79891592Smarkm if (!S_ISREG(sbuf.st_mode)) 79912099Sjoerg return (0); 80012099Sjoerg if (access(path, R_OK) == -1) 80112099Sjoerg return (0); 80212099Sjoerg return (1); 80312099Sjoerg} 80412099Sjoerg 80512099Sjoergstatic void 80691592Smarkmlint2(void) 80712099Sjoerg{ 80812099Sjoerg char *path, **args; 80912099Sjoerg 81091818Smarkm args = xcalloc(1, sizeof (char *)); 81112099Sjoerg 81291592Smarkm if (!Bflag) { 81391592Smarkm path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") + 81491592Smarkm strlen(target_prefix)); 81591592Smarkm (void)sprintf(path, "%s/%slint2", PATH_LIBEXEC, 81691592Smarkm target_prefix); 81791592Smarkm } else { 81891592Smarkm /* 81991592Smarkm * XXX Unclear whether we should be using target_prefix 82091592Smarkm * XXX here. --thorpej@wasabisystems.com 82191592Smarkm */ 82291592Smarkm path = xmalloc(strlen(libexec_path) + sizeof ("/lint2")); 82391592Smarkm (void)sprintf(path, "%s/lint2", libexec_path); 82491592Smarkm } 82591592Smarkm 82612099Sjoerg appcstrg(&args, path); 82712099Sjoerg applst(&args, l2flags); 82812099Sjoerg applst(&args, l2libs); 82912099Sjoerg applst(&args, p2in); 83012099Sjoerg 83175710Sasmodai runchild(path, args, p2out, -1); 83212099Sjoerg free(path); 83312099Sjoerg freelst(&args); 83412099Sjoerg free(args); 83512099Sjoerg} 83612099Sjoerg 83712099Sjoergstatic void 83891592Smarkmcat(char *const *srcs, const char *dest) 83912099Sjoerg{ 84012099Sjoerg int ifd, ofd, i; 84112099Sjoerg char *src, *buf; 84212099Sjoerg ssize_t rlen; 84312099Sjoerg 84412099Sjoerg if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { 84512099Sjoerg warn("cannot open %s", dest); 84612099Sjoerg terminate(-1); 84712099Sjoerg } 84812099Sjoerg 84991818Smarkm buf = xmalloc(MBLKSIZ); 85012099Sjoerg 85112099Sjoerg for (i = 0; (src = srcs[i]) != NULL; i++) { 85212099Sjoerg if ((ifd = open(src, O_RDONLY)) == -1) { 85312099Sjoerg free(buf); 85412099Sjoerg warn("cannot open %s", src); 85512099Sjoerg terminate(-1); 85612099Sjoerg } 85712099Sjoerg do { 85812099Sjoerg if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) { 85912099Sjoerg free(buf); 86012099Sjoerg warn("read error on %s", src); 86112099Sjoerg terminate(-1); 86212099Sjoerg } 86312099Sjoerg if (write(ofd, buf, (size_t)rlen) == -1) { 86412099Sjoerg free(buf); 86512099Sjoerg warn("write error on %s", dest); 86612099Sjoerg terminate(-1); 86712099Sjoerg } 86812099Sjoerg } while (rlen == MBLKSIZ); 86912099Sjoerg (void)close(ifd); 87012099Sjoerg } 87112099Sjoerg (void)close(ofd); 87212099Sjoerg free(buf); 87312099Sjoerg} 874