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