xlint.c revision 92089
191592Smarkm/* $NetBSD: xlint.c,v 1.26 2002/01/22 01:14:03 thorpej 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)
3791592Smarkm__RCSID("$NetBSD: xlint.c,v 1.26 2002/01/22 01:14:03 thorpej Exp $");
3812099Sjoerg#endif
3991592Smarkm__FBSDID("$FreeBSD: head/usr.bin/xlint/xlint/xlint.c 92089 2002-03-11 11:32:55Z markm $");
4012099Sjoerg
4112099Sjoerg#include <sys/param.h>
4212099Sjoerg#include <sys/wait.h>
4312099Sjoerg#include <sys/stat.h>
4412099Sjoerg#include <sys/utsname.h>
4591592Smarkm#include <errno.h>
4691592Smarkm#include <fcntl.h>
4791592Smarkm#include <paths.h>
4891592Smarkm#include <signal.h>
4912099Sjoerg#include <stdio.h>
5012099Sjoerg#include <stdlib.h>
5112099Sjoerg#include <string.h>
5212099Sjoerg#include <unistd.h>
5312099Sjoerg
5412099Sjoerg#include "lint.h"
5512099Sjoerg#include "pathnames.h"
5612099Sjoerg
5791592Smarkmint main(int, char *[]);
5891592Smarkm
5912099Sjoerg/* directory for temporary files */
6012099Sjoergstatic	const	char *tmpdir;
6112099Sjoerg
6212099Sjoerg/* path name for cpp output */
6312099Sjoergstatic	char	*cppout;
6412099Sjoerg
6591592Smarkm/* file descriptor for cpp output */
6675710Sasmodaistatic	int	cppoutfd = -1;
6775710Sasmodai
6812099Sjoerg/* files created by 1st pass */
6912099Sjoergstatic	char	**p1out;
7012099Sjoerg
7112099Sjoerg/* input files for 2nd pass (without libraries) */
7212099Sjoergstatic	char	**p2in;
7312099Sjoerg
7412099Sjoerg/* library which will be created by 2nd pass */
7512099Sjoergstatic	char	*p2out;
7612099Sjoerg
7775710Sasmodai/* flags always passed to cc(1) */
7875710Sasmodaistatic	char	**cflags;
7912099Sjoerg
8075710Sasmodai/* flags for cc(1), controled by sflag/tflag */
8175710Sasmodaistatic	char	**lcflags;
8212099Sjoerg
8312099Sjoerg/* flags for lint1 */
8412099Sjoergstatic	char	**l1flags;
8512099Sjoerg
8612099Sjoerg/* flags for lint2 */
8712099Sjoergstatic	char	**l2flags;
8812099Sjoerg
8912099Sjoerg/* libraries for lint2 */
9012099Sjoergstatic	char	**l2libs;
9112099Sjoerg
9212099Sjoerg/* default libraries */
9312099Sjoergstatic	char	**deflibs;
9412099Sjoerg
9512099Sjoerg/* additional libraries */
9612099Sjoergstatic	char	**libs;
9712099Sjoerg
9812099Sjoerg/* search path for libraries */
9912099Sjoergstatic	char	**libsrchpath;
10012099Sjoerg
10191592Smarkmstatic  char	*libexec_path;
10291592Smarkm
10312099Sjoerg/* flags */
10491592Smarkmstatic	int	iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag;
10512099Sjoerg
10612099Sjoerg/* print the commands executed to run the stages of compilation */
10712099Sjoergstatic	int	Vflag;
10812099Sjoerg
10912099Sjoerg/* filename for oflag */
11012099Sjoergstatic	char	*outputfn;
11112099Sjoerg
11212099Sjoerg/* reset after first .c source has been processed */
11312099Sjoergstatic	int	first = 1;
11412099Sjoerg
11512099Sjoerg/*
11612099Sjoerg * name of a file which is currently written by a child and should
11712099Sjoerg * be removed after abnormal termination of the child
11812099Sjoerg */
11912099Sjoergstatic	const	char *currfn;
12012099Sjoerg
12191592Smarkm#if !defined(TARGET_PREFIX)
12291592Smarkm#define	TARGET_PREFIX	""
12391592Smarkm#endif
12491592Smarkmstatic const char target_prefix[] = TARGET_PREFIX;
12512099Sjoerg
12691592Smarkmstatic	void	appstrg(char ***, char *);
12791592Smarkmstatic	void	appcstrg(char ***, const char *);
12891592Smarkmstatic	void	applst(char ***, char *const *);
12991592Smarkmstatic	void	freelst(char ***);
13091592Smarkmstatic	char	*concat2(const char *, const char *);
13191592Smarkmstatic	char	*concat3(const char *, const char *, const char *);
13291592Smarkmstatic	void	terminate(int) __attribute__((__noreturn__));
13391592Smarkmstatic	const	char *lbasename(const char *, int);
13491592Smarkmstatic	void	appdef(char ***, const char *);
13591592Smarkmstatic	void	usage(void);
13691592Smarkmstatic	void	fname(const char *);
13791592Smarkmstatic	void	runchild(const char *, char *const *, const char *, int);
13891592Smarkmstatic	void	findlibs(char *const *);
13991592Smarkmstatic	int	rdok(const char *);
14091592Smarkmstatic	void	lint2(void);
14191592Smarkmstatic	void	cat(char *const *, const char *);
14212099Sjoerg
14312099Sjoerg/*
14412099Sjoerg * Some functions to deal with lists of strings.
14512099Sjoerg * Take care that we get no surprises in case of asyncron signals.
14612099Sjoerg */
14712099Sjoergstatic void
14891592Smarkmappstrg(char ***lstp, char *s)
14912099Sjoerg{
15012099Sjoerg	char	**lst, **olst;
15112099Sjoerg	int	i;
15212099Sjoerg
15312099Sjoerg	olst = *lstp;
15491592Smarkm	for (i = 0; olst[i] != NULL; i++)
15591592Smarkm		continue;
15691592Smarkm	lst = xrealloc(olst, (i + 2) * sizeof (char *));
15712099Sjoerg	lst[i] = s;
15812099Sjoerg	lst[i + 1] = NULL;
15912099Sjoerg	*lstp = lst;
16091592Smarkm}
16112099Sjoerg
16212099Sjoergstatic void
16391592Smarkmappcstrg(char ***lstp, const char *s)
16412099Sjoerg{
16580284Sobrien
16691592Smarkm	appstrg(lstp, xstrdup(s));
16712099Sjoerg}
16812099Sjoerg
16912099Sjoergstatic void
17091592Smarkmapplst(char ***destp, char *const *src)
17112099Sjoerg{
17212099Sjoerg	int	i, k;
17312099Sjoerg	char	**dest, **odest;
17412099Sjoerg
17512099Sjoerg	odest = *destp;
17691592Smarkm	for (i = 0; odest[i] != NULL; i++)
17791592Smarkm		continue;
17812099Sjoerg	for (k = 0; src[k] != NULL; k++)
17991592Smarkm		continue;
18091592Smarkm	dest = xrealloc(odest, (i + k + 1) * sizeof (char *));
18191592Smarkm	for (k = 0; src[k] != NULL; k++)
18291818Smarkm		dest[i + k] = xstrdup(src[k]);
18312099Sjoerg	dest[i + k] = NULL;
18412099Sjoerg	*destp = dest;
18512099Sjoerg}
18612099Sjoerg
18712099Sjoergstatic void
18891592Smarkmfreelst(char ***lstp)
18912099Sjoerg{
19012099Sjoerg	char	*s;
19112099Sjoerg	int	i;
19212099Sjoerg
19391592Smarkm	for (i = 0; (*lstp)[i] != NULL; i++)
19491592Smarkm		continue;
19512099Sjoerg	while (i-- > 0) {
19612099Sjoerg		s = (*lstp)[i];
19712099Sjoerg		(*lstp)[i] = NULL;
19812099Sjoerg		free(s);
19912099Sjoerg	}
20012099Sjoerg}
20112099Sjoerg
20212099Sjoergstatic char *
20391592Smarkmconcat2(const char *s1, const char *s2)
20412099Sjoerg{
20512099Sjoerg	char	*s;
20612099Sjoerg
20791818Smarkm	s = xmalloc(strlen(s1) + strlen(s2) + 1);
20812099Sjoerg	(void)strcpy(s, s1);
20912099Sjoerg	(void)strcat(s, s2);
21012099Sjoerg
21112099Sjoerg	return (s);
21212099Sjoerg}
21312099Sjoerg
21412099Sjoergstatic char *
21591592Smarkmconcat3(const char *s1, const char *s2, const char *s3)
21612099Sjoerg{
21712099Sjoerg	char	*s;
21812099Sjoerg
21991818Smarkm	s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
22012099Sjoerg	(void)strcpy(s, s1);
22112099Sjoerg	(void)strcat(s, s2);
22212099Sjoerg	(void)strcat(s, s3);
22312099Sjoerg
22412099Sjoerg	return (s);
22512099Sjoerg}
22612099Sjoerg
22712099Sjoerg/*
22812099Sjoerg * Clean up after a signal.
22912099Sjoerg */
23012099Sjoergstatic void
23191592Smarkmterminate(int signo)
23212099Sjoerg{
23312099Sjoerg	int	i;
23412099Sjoerg
23575710Sasmodai	if (cppoutfd != -1)
23675710Sasmodai		(void)close(cppoutfd);
23712099Sjoerg	if (cppout != NULL)
23812099Sjoerg		(void)remove(cppout);
23912099Sjoerg
24012099Sjoerg	if (p1out != NULL) {
24112099Sjoerg		for (i = 0; p1out[i] != NULL; i++)
24212099Sjoerg			(void)remove(p1out[i]);
24312099Sjoerg	}
24412099Sjoerg
24512099Sjoerg	if (p2out != NULL)
24612099Sjoerg		(void)remove(p2out);
24712099Sjoerg
24812099Sjoerg	if (currfn != NULL)
24912099Sjoerg		(void)remove(currfn);
25012099Sjoerg
25112099Sjoerg	exit(signo != 0 ? 1 : 0);
25212099Sjoerg}
25312099Sjoerg
25412099Sjoerg/*
25512099Sjoerg * Returns a pointer to the last component of strg after delim.
25612099Sjoerg * Returns strg if the string does not contain delim.
25712099Sjoerg */
25812099Sjoergstatic const char *
25991592Smarkmlbasename(const char *strg, int delim)
26012099Sjoerg{
26112099Sjoerg	const	char *cp, *cp1, *cp2;
26212099Sjoerg
26312099Sjoerg	cp = cp1 = cp2 = strg;
26412099Sjoerg	while (*cp != '\0') {
26512099Sjoerg		if (*cp++ == delim) {
26612099Sjoerg			cp2 = cp1;
26712099Sjoerg			cp1 = cp;
26812099Sjoerg		}
26912099Sjoerg	}
27012099Sjoerg	return (*cp1 == '\0' ? cp2 : cp1);
27112099Sjoerg}
27212099Sjoerg
27312099Sjoergstatic void
27491592Smarkmappdef(char ***lstp, const char *def)
27512099Sjoerg{
27691592Smarkm
27712099Sjoerg	appstrg(lstp, concat2("-D__", def));
27812099Sjoerg	appstrg(lstp, concat3("-D__", def, "__"));
27912099Sjoerg}
28012099Sjoerg
28112099Sjoergstatic void
28291592Smarkmusage(void)
28312099Sjoerg{
28491592Smarkm
28591592Smarkm	(void)fprintf(stderr,
28691592Smarkm	    "Usage: %s [-abceghprvwxzHF] [-s|-t] [-i|-nu] [-Dname[=def]]"
28791592Smarkm	    " [-Uname] [-X <id>[,<id>]...\n", getprogname());
28891592Smarkm	(void)fprintf(stderr,
28991592Smarkm	    "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
29091592Smarkm	    " file...\n");
29191592Smarkm	(void)fprintf(stderr,
29291592Smarkm	    "       %s [-abceghprvwzHF] [-s|-t] -Clibrary [-Dname[=def]]\n"
29391592Smarkm	    " [-X <id>[,<id>]...\n", getprogname());
29491592Smarkm	(void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file"
29591592Smarkm	    " ...\n");
29612099Sjoerg	terminate(-1);
29712099Sjoerg}
29812099Sjoerg
29991592Smarkm
30012099Sjoergint
30191592Smarkmmain(int argc, char *argv[])
30212099Sjoerg{
30312099Sjoerg	int	c;
30412099Sjoerg	char	flgbuf[3], *tmp, *s;
30512099Sjoerg	size_t	len;
30612099Sjoerg
30791592Smarkm	setprogname(argv[0]);
30891592Smarkm
30912099Sjoerg	if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
31091818Smarkm		tmpdir = xstrdup(_PATH_TMP);
31112099Sjoerg	} else {
31291818Smarkm		s = xmalloc(len + 2);
31312099Sjoerg		(void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
31412099Sjoerg		tmpdir = s;
31512099Sjoerg	}
31612099Sjoerg
31791818Smarkm	cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
31812099Sjoerg	(void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
31975710Sasmodai	cppoutfd = mkstemp(cppout);
32075710Sasmodai	if (cppoutfd == -1) {
32112099Sjoerg		warn("can't make temp");
32212099Sjoerg		terminate(-1);
32312099Sjoerg	}
32412099Sjoerg
32591592Smarkm	p1out = xcalloc(1, sizeof (char *));
32691592Smarkm	p2in = xcalloc(1, sizeof (char *));
32791592Smarkm	cflags = xcalloc(1, sizeof (char *));
32891592Smarkm	lcflags = xcalloc(1, sizeof (char *));
32991592Smarkm	l1flags = xcalloc(1, sizeof (char *));
33091592Smarkm	l2flags = xcalloc(1, sizeof (char *));
33191592Smarkm	l2libs = xcalloc(1, sizeof (char *));
33291592Smarkm	deflibs = xcalloc(1, sizeof (char *));
33391592Smarkm	libs = xcalloc(1, sizeof (char *));
33491592Smarkm	libsrchpath = xcalloc(1, sizeof (char *));
33512099Sjoerg
33675710Sasmodai	appcstrg(&cflags, "-E");
33775710Sasmodai	appcstrg(&cflags, "-x");
33875710Sasmodai	appcstrg(&cflags, "c");
33991592Smarkm#if 0
34075710Sasmodai	appcstrg(&cflags, "-D__attribute__(x)=");
34191592Smarkm	appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0");
34291592Smarkm#else
34391592Smarkm	appcstrg(&cflags, "-U__GNUC__");
34492089Smarkm	appcstrg(&cflags, "-undef");
34591592Smarkm#endif
34675710Sasmodai	appcstrg(&cflags, "-Wp,-$");
34791592Smarkm	appcstrg(&cflags, "-Wp,-CC");
34875710Sasmodai	appcstrg(&cflags, "-Wcomment");
34991592Smarkm	appcstrg(&cflags, "-D__LINT__");
35075710Sasmodai	appcstrg(&cflags, "-Dlint");		/* XXX don't def. with -s */
35112099Sjoerg
35275710Sasmodai	appdef(&cflags, "lint");
35312099Sjoerg
35475710Sasmodai	appcstrg(&lcflags, "-Wtraditional");
35512099Sjoerg
35612099Sjoerg	appcstrg(&deflibs, "c");
35712099Sjoerg
35812099Sjoerg	if (signal(SIGHUP, terminate) == SIG_IGN)
35912099Sjoerg		(void)signal(SIGHUP, SIG_IGN);
36012099Sjoerg	(void)signal(SIGINT, terminate);
36112099Sjoerg	(void)signal(SIGQUIT, terminate);
36212099Sjoerg	(void)signal(SIGTERM, terminate);
36312099Sjoerg
36491592Smarkm	while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:U:VX:")) != -1) {
36512099Sjoerg		switch (c) {
36612099Sjoerg
36712099Sjoerg		case 'a':
36812099Sjoerg		case 'b':
36912099Sjoerg		case 'c':
37012099Sjoerg		case 'e':
37112099Sjoerg		case 'g':
37212099Sjoerg		case 'r':
37312099Sjoerg		case 'v':
37491592Smarkm		case 'w':
37512099Sjoerg		case 'z':
37612099Sjoerg			(void)sprintf(flgbuf, "-%c", c);
37712099Sjoerg			appcstrg(&l1flags, flgbuf);
37812099Sjoerg			break;
37912099Sjoerg
38012099Sjoerg		case 'F':
38112099Sjoerg			Fflag = 1;
38212099Sjoerg			/* FALLTHROUGH */
38312099Sjoerg		case 'u':
38412099Sjoerg		case 'h':
38512099Sjoerg			(void)sprintf(flgbuf, "-%c", c);
38612099Sjoerg			appcstrg(&l1flags, flgbuf);
38712099Sjoerg			appcstrg(&l2flags, flgbuf);
38812099Sjoerg			break;
38912099Sjoerg
39091592Smarkm		case 'X':
39191592Smarkm			(void)sprintf(flgbuf, "-%c", c);
39291592Smarkm			appcstrg(&l1flags, flgbuf);
39391592Smarkm			appcstrg(&l1flags, optarg);
39491592Smarkm			break;
39591592Smarkm
39612099Sjoerg		case 'i':
39712099Sjoerg			if (Cflag)
39812099Sjoerg				usage();
39912099Sjoerg			iflag = 1;
40012099Sjoerg			break;
40112099Sjoerg
40212099Sjoerg		case 'n':
40312099Sjoerg			freelst(&deflibs);
40412099Sjoerg			break;
40512099Sjoerg
40612099Sjoerg		case 'p':
40712099Sjoerg			appcstrg(&l1flags, "-p");
40812099Sjoerg			appcstrg(&l2flags, "-p");
40912099Sjoerg			if (*deflibs != NULL) {
41012099Sjoerg				freelst(&deflibs);
41112099Sjoerg				appcstrg(&deflibs, "c");
41212099Sjoerg			}
41312099Sjoerg			break;
41412099Sjoerg
41512099Sjoerg		case 's':
41612099Sjoerg			if (tflag)
41712099Sjoerg				usage();
41875710Sasmodai			freelst(&lcflags);
41975710Sasmodai			appcstrg(&lcflags, "-trigraphs");
42075710Sasmodai			appcstrg(&lcflags, "-Wtrigraphs");
42175710Sasmodai			appcstrg(&lcflags, "-pedantic");
42275710Sasmodai			appcstrg(&lcflags, "-D__STRICT_ANSI__");
42312099Sjoerg			appcstrg(&l1flags, "-s");
42412099Sjoerg			appcstrg(&l2flags, "-s");
42512099Sjoerg			sflag = 1;
42612099Sjoerg			break;
42712099Sjoerg
42891592Smarkm#if !HAVE_CONFIG_H
42912099Sjoerg		case 't':
43012099Sjoerg			if (sflag)
43112099Sjoerg				usage();
43275710Sasmodai			freelst(&lcflags);
43375710Sasmodai			appcstrg(&lcflags, "-traditional");
43475710Sasmodai			appstrg(&lcflags, concat2("-D", MACHINE));
43575710Sasmodai			appstrg(&lcflags, concat2("-D", MACHINE_ARCH));
43612099Sjoerg			appcstrg(&l1flags, "-t");
43712099Sjoerg			appcstrg(&l2flags, "-t");
43812099Sjoerg			tflag = 1;
43912099Sjoerg			break;
44091592Smarkm#endif
44112099Sjoerg
44212099Sjoerg		case 'x':
44312099Sjoerg			appcstrg(&l2flags, "-x");
44412099Sjoerg			break;
44512099Sjoerg
44612099Sjoerg		case 'C':
44712099Sjoerg			if (Cflag || oflag || iflag)
44812099Sjoerg				usage();
44912099Sjoerg			Cflag = 1;
45012099Sjoerg			appstrg(&l2flags, concat2("-C", optarg));
45191818Smarkm			p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
45212099Sjoerg			(void)sprintf(p2out, "llib-l%s.ln", optarg);
45312099Sjoerg			freelst(&deflibs);
45412099Sjoerg			break;
45512099Sjoerg
45691592Smarkm		case 'd':
45791592Smarkm			if (dflag)
45891592Smarkm				usage();
45991592Smarkm			dflag = 1;
46091592Smarkm			appcstrg(&cflags, "-nostdinc");
46191592Smarkm			appcstrg(&cflags, "-idirafter");
46291592Smarkm			appcstrg(&cflags, optarg);
46391592Smarkm			break;
46491592Smarkm
46512099Sjoerg		case 'D':
46612099Sjoerg		case 'I':
46712099Sjoerg		case 'U':
46812099Sjoerg			(void)sprintf(flgbuf, "-%c", c);
46975710Sasmodai			appstrg(&cflags, concat2(flgbuf, optarg));
47012099Sjoerg			break;
47112099Sjoerg
47212099Sjoerg		case 'l':
47312099Sjoerg			appcstrg(&libs, optarg);
47412099Sjoerg			break;
47512099Sjoerg
47612099Sjoerg		case 'o':
47712099Sjoerg			if (Cflag || oflag)
47812099Sjoerg				usage();
47912099Sjoerg			oflag = 1;
48091818Smarkm			outputfn = xstrdup(optarg);
48112099Sjoerg			break;
48212099Sjoerg
48312099Sjoerg		case 'L':
48412099Sjoerg			appcstrg(&libsrchpath, optarg);
48512099Sjoerg			break;
48612099Sjoerg
48712099Sjoerg		case 'H':
48812099Sjoerg			appcstrg(&l2flags, "-H");
48912099Sjoerg			break;
49012099Sjoerg
49191592Smarkm		case 'B':
49291592Smarkm			Bflag = 1;
49391592Smarkm			libexec_path = xstrdup(optarg);
49491592Smarkm			break;
49591592Smarkm
49612099Sjoerg		case 'V':
49712099Sjoerg			Vflag = 1;
49812099Sjoerg			break;
49912099Sjoerg
50091592Smarkm		default:
50112099Sjoerg			usage();
50212099Sjoerg			/* NOTREACHED */
50391592Smarkm		}
50491592Smarkm	}
50591592Smarkm	argc -= optind;
50691592Smarkm	argv += optind;
50712099Sjoerg
50891592Smarkm	/*
50991592Smarkm	 * To avoid modifying getopt(3)'s state engine midstream, we
51091592Smarkm	 * explicitly accept just a few options after the first source file.
51191592Smarkm	 *
51291592Smarkm	 * In particular, only -l<lib> and -L<libdir> (and these with a space
51391592Smarkm	 * after -l or -L) are allowed.
51491592Smarkm	 */
51591592Smarkm	while (argc > 0) {
51691592Smarkm		const char *arg = argv[0];
51791592Smarkm
51891592Smarkm		if (arg[0] == '-') {
51991592Smarkm			char ***list;
52091592Smarkm
52191592Smarkm			/* option */
52291592Smarkm			switch (arg[1]) {
52391592Smarkm			case 'l':
52491592Smarkm				list = &libs;
52591592Smarkm				break;
52691592Smarkm
52791592Smarkm			case 'L':
52891592Smarkm				list = &libsrchpath;
52991592Smarkm				break;
53091592Smarkm
53191592Smarkm			default:
53291592Smarkm				usage();
53391592Smarkm				/* NOTREACHED */
53491592Smarkm			}
53591592Smarkm			if (arg[2])
53691592Smarkm				appcstrg(list, arg + 2);
53791592Smarkm			else if (argc > 1) {
53891592Smarkm				argc--;
53991592Smarkm				appcstrg(list, *++argv);
54091592Smarkm			} else
54191592Smarkm				usage();
54291592Smarkm		} else {
54312099Sjoerg			/* filename */
54491592Smarkm			fname(arg);
54512099Sjoerg			first = 0;
54612099Sjoerg		}
54791592Smarkm		argc--;
54891592Smarkm		argv++;
54912099Sjoerg	}
55012099Sjoerg
55112099Sjoerg	if (first)
55212099Sjoerg		usage();
55312099Sjoerg
55412099Sjoerg	if (iflag)
55512099Sjoerg		terminate(0);
55612099Sjoerg
55712099Sjoerg	if (!oflag) {
55812099Sjoerg		if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
55991818Smarkm			s = PATH_LINTLIB;
56012099Sjoerg		appcstrg(&libsrchpath, s);
56112099Sjoerg		findlibs(libs);
56212099Sjoerg		findlibs(deflibs);
56312099Sjoerg	}
56412099Sjoerg
56512099Sjoerg	(void)printf("Lint pass2:\n");
56612099Sjoerg	lint2();
56712099Sjoerg
56812099Sjoerg	if (oflag)
56912099Sjoerg		cat(p2in, outputfn);
57012099Sjoerg
57112099Sjoerg	if (Cflag)
57212099Sjoerg		p2out = NULL;
57312099Sjoerg
57412099Sjoerg	terminate(0);
57512099Sjoerg	/* NOTREACHED */
57612099Sjoerg}
57712099Sjoerg
57812099Sjoerg/*
57912099Sjoerg * Read a file name from the command line
58012099Sjoerg * and pass it through lint1 if it is a C source.
58112099Sjoerg */
58212099Sjoergstatic void
58391592Smarkmfname(const char *name)
58412099Sjoerg{
58512099Sjoerg	const	char *bn, *suff;
58612099Sjoerg	char	**args, *ofn, *path;
58712099Sjoerg	size_t	len;
58891592Smarkm	int is_stdin;
58975710Sasmodai	int	fd;
59012099Sjoerg
59191592Smarkm	is_stdin = (strcmp(name, "-") == 0);
59291592Smarkm	bn = lbasename(name, '/');
59391592Smarkm	suff = lbasename(bn, '.');
59412099Sjoerg
59512099Sjoerg	if (strcmp(suff, "ln") == 0) {
59612099Sjoerg		/* only for lint2 */
59712099Sjoerg		if (!iflag)
59812099Sjoerg			appcstrg(&p2in, name);
59912099Sjoerg		return;
60012099Sjoerg	}
60112099Sjoerg
60291592Smarkm	if (!is_stdin && strcmp(suff, "c") != 0 &&
60312099Sjoerg	    (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
60412099Sjoerg		warnx("unknown file type: %s\n", name);
60512099Sjoerg		return;
60612099Sjoerg	}
60712099Sjoerg
60891592Smarkm	if (!iflag || !first)
60991592Smarkm		(void)printf("%s:\n",
61091592Smarkm		    is_stdin ? "{standard input}" : Fflag ? name : bn);
61112099Sjoerg
61212099Sjoerg	/* build the name of the output file of lint1 */
61312099Sjoerg	if (oflag) {
61412099Sjoerg		ofn = outputfn;
61512099Sjoerg		outputfn = NULL;
61612099Sjoerg		oflag = 0;
61712099Sjoerg	} else if (iflag) {
61891592Smarkm		if (is_stdin) {
61991592Smarkm			warnx("-i not supported without -o for standard input");
62091592Smarkm			return;
62191592Smarkm		}
62291592Smarkm		ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
62312099Sjoerg		len = bn == suff ? strlen(bn) : (suff - 1) - bn;
62412099Sjoerg		(void)sprintf(ofn, "%.*s", (int)len, bn);
62512099Sjoerg		(void)strcat(ofn, ".ln");
62612099Sjoerg	} else {
62791818Smarkm		ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
62812099Sjoerg		(void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
62975710Sasmodai		fd = mkstemp(ofn);
63075710Sasmodai		if (fd == -1) {
63112099Sjoerg			warn("can't make temp");
63212099Sjoerg			terminate(-1);
63312099Sjoerg		}
63475710Sasmodai		close(fd);
63512099Sjoerg	}
63612099Sjoerg	if (!iflag)
63712099Sjoerg		appcstrg(&p1out, ofn);
63812099Sjoerg
63991818Smarkm	args = xcalloc(1, sizeof (char *));
64012099Sjoerg
64175710Sasmodai	/* run cc */
64212099Sjoerg
64391592Smarkm	if (getenv("CC") == NULL) {
64491592Smarkm		path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc"));
64591592Smarkm		(void)sprintf(path, "%s/cc", PATH_USRBIN);
64691592Smarkm	} else {
64791592Smarkm		path = strdup(getenv("CC"));
64891592Smarkm	}
64912099Sjoerg
65012099Sjoerg	appcstrg(&args, path);
65175710Sasmodai	applst(&args, cflags);
65275710Sasmodai	applst(&args, lcflags);
65312099Sjoerg	appcstrg(&args, name);
65412099Sjoerg
65575710Sasmodai	/* we reuse the same tmp file for cpp output, so rewind and truncate */
65675710Sasmodai	if (lseek(cppoutfd, SEEK_SET, (off_t)0) != 0) {
65775710Sasmodai		warn("lseek");
65875710Sasmodai		terminate(-1);
65975710Sasmodai	}
66075710Sasmodai	if (ftruncate(cppoutfd, (off_t)0) != 0) {
66175710Sasmodai		warn("ftruncate");
66275710Sasmodai		terminate(-1);
66375710Sasmodai	}
66475710Sasmodai
66575710Sasmodai	runchild(path, args, cppout, cppoutfd);
66612099Sjoerg	free(path);
66712099Sjoerg	freelst(&args);
66812099Sjoerg
66912099Sjoerg	/* run lint1 */
67012099Sjoerg
67191592Smarkm	if (!Bflag) {
67291592Smarkm		path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") +
67391592Smarkm		    strlen(target_prefix));
67491592Smarkm		(void)sprintf(path, "%s/%slint1", PATH_LIBEXEC,
67591592Smarkm		    target_prefix);
67691592Smarkm	} else {
67791592Smarkm		/*
67891592Smarkm		 * XXX Unclear whether we should be using target_prefix
67991592Smarkm		 * XXX here.  --thorpej@wasabisystems.com
68091592Smarkm		 */
68191592Smarkm		path = xmalloc(strlen(libexec_path) + sizeof ("/lint1"));
68291592Smarkm		(void)sprintf(path, "%s/lint1", libexec_path);
68391592Smarkm	}
68412099Sjoerg
68512099Sjoerg	appcstrg(&args, path);
68612099Sjoerg	applst(&args, l1flags);
68712099Sjoerg	appcstrg(&args, cppout);
68812099Sjoerg	appcstrg(&args, ofn);
68912099Sjoerg
69075710Sasmodai	runchild(path, args, ofn, -1);
69112099Sjoerg	free(path);
69212099Sjoerg	freelst(&args);
69312099Sjoerg
69412099Sjoerg	appcstrg(&p2in, ofn);
69512099Sjoerg	free(ofn);
69612099Sjoerg
69712099Sjoerg	free(args);
69812099Sjoerg}
69912099Sjoerg
70012099Sjoergstatic void
70191592Smarkmrunchild(const char *path, char *const *args, const char *crfn, int fdout)
70212099Sjoerg{
70312099Sjoerg	int	status, rv, signo, i;
70412099Sjoerg
70512099Sjoerg	if (Vflag) {
70612099Sjoerg		for (i = 0; args[i] != NULL; i++)
70712099Sjoerg			(void)printf("%s ", args[i]);
70812099Sjoerg		(void)printf("\n");
70912099Sjoerg	}
71012099Sjoerg
71112099Sjoerg	currfn = crfn;
71212099Sjoerg
71312099Sjoerg	(void)fflush(stdout);
71412099Sjoerg
71575710Sasmodai	switch (vfork()) {
71612099Sjoerg	case -1:
71712099Sjoerg		warn("cannot fork");
71812099Sjoerg		terminate(-1);
71912099Sjoerg		/* NOTREACHED */
72012099Sjoerg	default:
72112099Sjoerg		/* parent */
72212099Sjoerg		break;
72312099Sjoerg	case 0:
72412099Sjoerg		/* child */
72575710Sasmodai
72675710Sasmodai		/* setup the standard output if necessary */
72775710Sasmodai		if (fdout != -1) {
72875710Sasmodai			dup2(fdout, STDOUT_FILENO);
72975710Sasmodai			close(fdout);
73075710Sasmodai		}
73191592Smarkm		(void)execvp(path, args);
73212099Sjoerg		warn("cannot exec %s", path);
73375710Sasmodai		_exit(1);
73412099Sjoerg		/* NOTREACHED */
73512099Sjoerg	}
73612099Sjoerg
73712099Sjoerg	while ((rv = wait(&status)) == -1 && errno == EINTR) ;
73812099Sjoerg	if (rv == -1) {
73912099Sjoerg		warn("wait");
74012099Sjoerg		terminate(-1);
74112099Sjoerg	}
74212099Sjoerg	if (WIFSIGNALED(status)) {
74312099Sjoerg		signo = WTERMSIG(status);
74491592Smarkm#if HAVE_DECL_SYS_SIGNAME
74512099Sjoerg		warnx("%s got SIG%s", path, sys_signame[signo]);
74691592Smarkm#else
74791592Smarkm		warnx("%s got signal %d", path, signo);
74891592Smarkm#endif
74912099Sjoerg		terminate(-1);
75012099Sjoerg	}
75112099Sjoerg	if (WEXITSTATUS(status) != 0)
75212099Sjoerg		terminate(-1);
75312099Sjoerg	currfn = NULL;
75412099Sjoerg}
75512099Sjoerg
75612099Sjoergstatic void
75791592Smarkmfindlibs(char *const *liblst)
75812099Sjoerg{
75912099Sjoerg	int	i, k;
76012099Sjoerg	const	char *lib, *path;
76112099Sjoerg	char	*lfn;
76212099Sjoerg	size_t	len;
76312099Sjoerg
76412099Sjoerg	lfn = NULL;
76512099Sjoerg
76612099Sjoerg	for (i = 0; (lib = liblst[i]) != NULL; i++) {
76712099Sjoerg		for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
76812099Sjoerg			len = strlen(path) + strlen(lib);
76991818Smarkm			lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
77012099Sjoerg			(void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
77112099Sjoerg			if (rdok(lfn))
77212099Sjoerg				break;
77391818Smarkm			lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
77412099Sjoerg			(void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
77512099Sjoerg			if (rdok(lfn))
77612099Sjoerg				break;
77712099Sjoerg		}
77812099Sjoerg		if (path != NULL) {
77912099Sjoerg			appstrg(&l2libs, concat2("-l", lfn));
78012099Sjoerg		} else {
78112099Sjoerg			warnx("cannot find llib-l%s.ln", lib);
78212099Sjoerg		}
78312099Sjoerg	}
78412099Sjoerg
78512099Sjoerg	free(lfn);
78612099Sjoerg}
78712099Sjoerg
78812099Sjoergstatic int
78991592Smarkmrdok(const char *path)
79012099Sjoerg{
79112099Sjoerg	struct	stat sbuf;
79212099Sjoerg
79312099Sjoerg	if (stat(path, &sbuf) == -1)
79412099Sjoerg		return (0);
79591592Smarkm	if (!S_ISREG(sbuf.st_mode))
79612099Sjoerg		return (0);
79712099Sjoerg	if (access(path, R_OK) == -1)
79812099Sjoerg		return (0);
79912099Sjoerg	return (1);
80012099Sjoerg}
80112099Sjoerg
80212099Sjoergstatic void
80391592Smarkmlint2(void)
80412099Sjoerg{
80512099Sjoerg	char	*path, **args;
80612099Sjoerg
80791818Smarkm	args = xcalloc(1, sizeof (char *));
80812099Sjoerg
80991592Smarkm	if (!Bflag) {
81091592Smarkm		path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") +
81191592Smarkm		    strlen(target_prefix));
81291592Smarkm		(void)sprintf(path, "%s/%slint2", PATH_LIBEXEC,
81391592Smarkm		    target_prefix);
81491592Smarkm	} else {
81591592Smarkm		/*
81691592Smarkm		 * XXX Unclear whether we should be using target_prefix
81791592Smarkm		 * XXX here.  --thorpej@wasabisystems.com
81891592Smarkm		 */
81991592Smarkm		path = xmalloc(strlen(libexec_path) + sizeof ("/lint2"));
82091592Smarkm		(void)sprintf(path, "%s/lint2", libexec_path);
82191592Smarkm	}
82291592Smarkm
82312099Sjoerg	appcstrg(&args, path);
82412099Sjoerg	applst(&args, l2flags);
82512099Sjoerg	applst(&args, l2libs);
82612099Sjoerg	applst(&args, p2in);
82712099Sjoerg
82875710Sasmodai	runchild(path, args, p2out, -1);
82912099Sjoerg	free(path);
83012099Sjoerg	freelst(&args);
83112099Sjoerg	free(args);
83212099Sjoerg}
83312099Sjoerg
83412099Sjoergstatic void
83591592Smarkmcat(char *const *srcs, const char *dest)
83612099Sjoerg{
83712099Sjoerg	int	ifd, ofd, i;
83812099Sjoerg	char	*src, *buf;
83912099Sjoerg	ssize_t	rlen;
84012099Sjoerg
84112099Sjoerg	if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
84212099Sjoerg		warn("cannot open %s", dest);
84312099Sjoerg		terminate(-1);
84412099Sjoerg	}
84512099Sjoerg
84691818Smarkm	buf = xmalloc(MBLKSIZ);
84712099Sjoerg
84812099Sjoerg	for (i = 0; (src = srcs[i]) != NULL; i++) {
84912099Sjoerg		if ((ifd = open(src, O_RDONLY)) == -1) {
85012099Sjoerg			free(buf);
85112099Sjoerg			warn("cannot open %s", src);
85212099Sjoerg			terminate(-1);
85312099Sjoerg		}
85412099Sjoerg		do {
85512099Sjoerg			if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
85612099Sjoerg				free(buf);
85712099Sjoerg				warn("read error on %s", src);
85812099Sjoerg				terminate(-1);
85912099Sjoerg			}
86012099Sjoerg			if (write(ofd, buf, (size_t)rlen) == -1) {
86112099Sjoerg				free(buf);
86212099Sjoerg				warn("write error on %s", dest);
86312099Sjoerg				terminate(-1);
86412099Sjoerg			}
86512099Sjoerg		} while (rlen == MBLKSIZ);
86612099Sjoerg		(void)close(ifd);
86712099Sjoerg	}
86812099Sjoerg	(void)close(ofd);
86912099Sjoerg	free(buf);
87012099Sjoerg}
871