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