xlint.c revision 100364
1192067Snwhitehorn/* $NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv Exp $ */
2192067Snwhitehorn
3192067Snwhitehorn/*
4192067Snwhitehorn * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
5192067Snwhitehorn * Copyright (c) 1994, 1995 Jochen Pohl
6192067Snwhitehorn * All Rights Reserved.
7192067Snwhitehorn *
8192067Snwhitehorn * Redistribution and use in source and binary forms, with or without
9192067Snwhitehorn * modification, are permitted provided that the following conditions
10192067Snwhitehorn * are met:
11192067Snwhitehorn * 1. Redistributions of source code must retain the above copyright
12192067Snwhitehorn *    notice, this list of conditions and the following disclaimer.
13192067Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
14192067Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
15192067Snwhitehorn *    documentation and/or other materials provided with the distribution.
16192067Snwhitehorn * 3. All advertising materials mentioning features or use of this software
17192067Snwhitehorn *    must display the following acknowledgement:
18192067Snwhitehorn *      This product includes software developed by Jochen Pohl for
19192067Snwhitehorn *	The NetBSD Project.
20192067Snwhitehorn * 4. The name of the author may not be used to endorse or promote products
21192067Snwhitehorn *    derived from this software without specific prior written permission.
22192067Snwhitehorn *
23192067Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24192067Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25192067Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26192067Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27192067Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28192067Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29192067Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30192067Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31192067Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32192067Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33192067Snwhitehorn */
34192067Snwhitehorn
35192067Snwhitehorn#include <sys/cdefs.h>
36192067Snwhitehorn#if defined(__RCSID) && !defined(lint)
37192067Snwhitehorn__RCSID("$NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv Exp $");
38198212Snwhitehorn#endif
39198212Snwhitehorn__FBSDID("$FreeBSD: head/usr.bin/xlint/xlint/xlint.c 100364 2002-07-19 16:38:21Z markm $");
40192067Snwhitehorn
41262675Sjhibbits#include <sys/param.h>
42192067Snwhitehorn#include <sys/wait.h>
43192067Snwhitehorn#include <sys/stat.h>
44262675Sjhibbits#include <sys/utsname.h>
45192067Snwhitehorn#include <errno.h>
46192067Snwhitehorn#include <fcntl.h>
47198212Snwhitehorn#include <paths.h>
48262675Sjhibbits#include <signal.h>
49192067Snwhitehorn#include <stdio.h>
50192067Snwhitehorn#include <stdlib.h>
51192067Snwhitehorn#include <string.h>
52192067Snwhitehorn#include <unistd.h>
53192067Snwhitehorn
54192067Snwhitehorn#include "lint.h"
55192067Snwhitehorn#include "pathnames.h"
56192067Snwhitehorn
57192067Snwhitehorn#define DEFAULT_PATH		_PATH_DEFPATH
58192067Snwhitehorn
59212054Snwhitehornint main(int, char *[]);
60255910Snwhitehorn
61266020Sian/* directory for temporary files */
62266020Sianstatic	const	char *tmpdir;
63212054Snwhitehorn
64212054Snwhitehorn/* path name for cpp output */
65212054Snwhitehornstatic	char	*cppout;
66212054Snwhitehorn
67212054Snwhitehorn/* file descriptor for cpp output */
68212054Snwhitehornstatic	int	cppoutfd = -1;
69262675Sjhibbits
70192067Snwhitehorn/* files created by 1st pass */
71212054Snwhitehornstatic	char	**p1out;
72212054Snwhitehorn
73255910Snwhitehorn/* input files for 2nd pass (without libraries) */
74212054Snwhitehornstatic	char	**p2in;
75212054Snwhitehorn
76192067Snwhitehorn/* library which will be created by 2nd pass */
77212054Snwhitehornstatic	char	*p2out;
78212054Snwhitehorn
79212054Snwhitehorn/* flags always passed to cc(1) */
80212054Snwhitehornstatic	char	**cflags;
81192067Snwhitehorn
82212054Snwhitehorn/* flags for cc(1), controled by sflag/tflag */
83262675Sjhibbitsstatic	char	**lcflags;
84212054Snwhitehorn
85246732Srpaulo/* flags for lint1 */
86192067Snwhitehornstatic	char	**l1flags;
87192067Snwhitehorn
88212054Snwhitehorn/* flags for lint2 */
89212054Snwhitehornstatic	char	**l2flags;
90212054Snwhitehorn
91192067Snwhitehorn/* libraries for lint2 */
92192067Snwhitehornstatic	char	**l2libs;
93192067Snwhitehorn
94212054Snwhitehorn/* default libraries */
95192067Snwhitehornstatic	char	**deflibs;
96192067Snwhitehorn
97212054Snwhitehorn/* additional libraries */
98192067Snwhitehornstatic	char	**libs;
99255420Snwhitehorn
100255420Snwhitehorn/* search path for libraries */
101255420Snwhitehornstatic	char	**libsrchpath;
102255420Snwhitehorn
103192067Snwhitehornstatic  char	*libexec_path;
104255420Snwhitehorn
105255420Snwhitehorn/* flags */
106255420Snwhitehornstatic	int	iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag;
107255420Snwhitehorn
108255420Snwhitehorn/* print the commands executed to run the stages of compilation */
109255420Snwhitehornstatic	int	Vflag;
110255420Snwhitehorn
111255420Snwhitehorn/* filename for oflag */
112255420Snwhitehornstatic	char	*outputfn;
113255420Snwhitehorn
114255420Snwhitehorn/* reset after first .c source has been processed */
115255420Snwhitehornstatic	int	first = 1;
116192067Snwhitehorn
117192067Snwhitehorn/*
118192067Snwhitehorn * name of a file which is currently written by a child and should
119192067Snwhitehorn * be removed after abnormal termination of the child
120266020Sian */
121266020Sianstatic	const	char *currfn;
122192067Snwhitehorn
123266020Sian#if !defined(TARGET_PREFIX)
124266020Sian#define	TARGET_PREFIX	""
125266020Sian#endif
126266020Sianstatic const char target_prefix[] = TARGET_PREFIX;
127266020Sian
128266020Sianstatic	void	appstrg(char ***, char *);
129266020Sianstatic	void	appcstrg(char ***, const char *);
130266020Sianstatic	void	applst(char ***, char *const *);
131266020Sianstatic	void	freelst(char ***);
132266020Sianstatic	char	*concat2(const char *, const char *);
133266020Sianstatic	char	*concat3(const char *, const char *, const char *);
134266020Sianstatic	void	terminate(int) __attribute__((__noreturn__));
135266020Sianstatic	const	char *lbasename(const char *, int);
136266020Sianstatic	void	appdef(char ***, const char *);
137266020Sianstatic	void	usage(void);
138266020Sianstatic	void	fname(const char *);
139266020Sianstatic	void	runchild(const char *, char *const *, const char *, int);
140266020Sianstatic	void	findlibs(char *const *);
141266020Sianstatic	int	rdok(const char *);
142266020Sianstatic	void	lint2(void);
143266020Sianstatic	void	cat(char *const *, const char *);
144266020Sian
145266020Sian/*
146266020Sian * Some functions to deal with lists of strings.
147266020Sian * Take care that we get no surprises in case of asyncron signals.
148266020Sian */
149266020Sianstatic void
150266020Sianappstrg(char ***lstp, char *s)
151266020Sian{
152266020Sian	char	**lst, **olst;
153266020Sian	int	i;
154266020Sian
155266020Sian	olst = *lstp;
156266020Sian	for (i = 0; olst[i] != NULL; i++)
157266020Sian		continue;
158266020Sian	lst = xrealloc(olst, (i + 2) * sizeof (char *));
159266020Sian	lst[i] = s;
160266020Sian	lst[i + 1] = NULL;
161266020Sian	*lstp = lst;
162266020Sian}
163266020Sian
164266020Sianstatic void
165266020Sianappcstrg(char ***lstp, const char *s)
166266020Sian{
167266020Sian
168266020Sian	appstrg(lstp, xstrdup(s));
169266020Sian}
170266020Sian
171266020Sianstatic void
172266020Sianapplst(char ***destp, char *const *src)
173266020Sian{
174192067Snwhitehorn	int	i, k;
175192067Snwhitehorn	char	**dest, **odest;
176255910Snwhitehorn
177255910Snwhitehorn	odest = *destp;
178255910Snwhitehorn	for (i = 0; odest[i] != NULL; i++)
179255910Snwhitehorn		continue;
180255910Snwhitehorn	for (k = 0; src[k] != NULL; k++)
181255910Snwhitehorn		continue;
182255910Snwhitehorn	dest = xrealloc(odest, (i + k + 1) * sizeof (char *));
183255910Snwhitehorn	for (k = 0; src[k] != NULL; k++)
184255910Snwhitehorn		dest[i + k] = xstrdup(src[k]);
185255910Snwhitehorn	dest[i + k] = NULL;
186255910Snwhitehorn	*destp = dest;
187255910Snwhitehorn}
188255910Snwhitehorn
189255910Snwhitehornstatic void
190255910Snwhitehornfreelst(char ***lstp)
191255910Snwhitehorn{
192255910Snwhitehorn	char	*s;
193255910Snwhitehorn	int	i;
194255910Snwhitehorn
195255910Snwhitehorn	for (i = 0; (*lstp)[i] != NULL; i++)
196255910Snwhitehorn		continue;
197255910Snwhitehorn	while (i-- > 0) {
198255910Snwhitehorn		s = (*lstp)[i];
199255910Snwhitehorn		(*lstp)[i] = NULL;
200255910Snwhitehorn		free(s);
201255910Snwhitehorn	}
202255910Snwhitehorn}
203255910Snwhitehorn
204255910Snwhitehornstatic char *
205192067Snwhitehornconcat2(const char *s1, const char *s2)
206212054Snwhitehorn{
207192067Snwhitehorn	char	*s;
208192067Snwhitehorn
209209851Snwhitehorn	s = xmalloc(strlen(s1) + strlen(s2) + 1);
210192067Snwhitehorn	(void)strcpy(s, s1);
211192067Snwhitehorn	(void)strcat(s, s2);
212192067Snwhitehorn
213192067Snwhitehorn	return (s);
214192067Snwhitehorn}
215192067Snwhitehorn
216192067Snwhitehornstatic char *
217192067Snwhitehornconcat3(const char *s1, const char *s2, const char *s3)
218192067Snwhitehorn{
219192067Snwhitehorn	char	*s;
220192067Snwhitehorn
221192067Snwhitehorn	s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
222192067Snwhitehorn	(void)strcpy(s, s1);
223212054Snwhitehorn	(void)strcat(s, s2);
224192067Snwhitehorn	(void)strcat(s, s3);
225260673Sjhibbits
226260673Sjhibbits	return (s);
227192067Snwhitehorn}
228192067Snwhitehorn
229192067Snwhitehorn/*
230192067Snwhitehorn * Clean up after a signal.
231193909Sgrehan */
232193909Sgrehanstatic void
233193909Sgrehanterminate(int signo)
234193909Sgrehan{
235193909Sgrehan	int	i;
236193909Sgrehan
237193909Sgrehan	if (cppoutfd != -1)
238193909Sgrehan		(void)close(cppoutfd);
239192067Snwhitehorn	if (cppout != NULL)
240192067Snwhitehorn		(void)remove(cppout);
241192067Snwhitehorn
242192067Snwhitehorn	if (p1out != NULL) {
243192067Snwhitehorn		for (i = 0; p1out[i] != NULL; i++)
244212054Snwhitehorn			(void)remove(p1out[i]);
245192067Snwhitehorn	}
246192067Snwhitehorn
247192067Snwhitehorn	if (p2out != NULL)
248192067Snwhitehorn		(void)remove(p2out);
249192067Snwhitehorn
250192067Snwhitehorn	if (currfn != NULL)
251192067Snwhitehorn		(void)remove(currfn);
252192067Snwhitehorn
253192067Snwhitehorn	exit(signo != 0 ? 1 : 0);
254192067Snwhitehorn}
255192067Snwhitehorn
256192067Snwhitehorn/*
257192067Snwhitehorn * Returns a pointer to the last component of strg after delim.
258192067Snwhitehorn * Returns strg if the string does not contain delim.
259193909Sgrehan */
260193909Sgrehanstatic const char *
261193909Sgrehanlbasename(const char *strg, int delim)
262193909Sgrehan{
263193909Sgrehan	const	char *cp, *cp1, *cp2;
264193909Sgrehan
265228201Sjchandra	cp = cp1 = cp2 = strg;
266193909Sgrehan	while (*cp != '\0') {
267193909Sgrehan		if (*cp++ == delim) {
268192067Snwhitehorn			cp2 = cp1;
269192067Snwhitehorn			cp1 = cp;
270193909Sgrehan		}
271192067Snwhitehorn	}
272192067Snwhitehorn	return (*cp1 == '\0' ? cp2 : cp1);
273192067Snwhitehorn}
274192067Snwhitehorn
275192067Snwhitehornstatic void
276192067Snwhitehornappdef(char ***lstp, const char *def)
277192067Snwhitehorn{
278192067Snwhitehorn
279192067Snwhitehorn	appstrg(lstp, concat2("-D__", def));
280212054Snwhitehorn	appstrg(lstp, concat3("-D__", def, "__"));
281192067Snwhitehorn}
282192067Snwhitehorn
283192067Snwhitehornstatic void
284212054Snwhitehornusage(void)
285192067Snwhitehorn{
286192067Snwhitehorn
287192067Snwhitehorn	(void)fprintf(stderr,
288192067Snwhitehorn	    "usage: lint [-abceghprvwxzHF] [-s|-t] [-i|-nu] [-Dname[=def]]"
289192067Snwhitehorn	    " [-Uname] [-X <id>[,<id>]...\n");
290192067Snwhitehorn	(void)fprintf(stderr,
291192067Snwhitehorn	    "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
292192067Snwhitehorn	    " file...\n");
293192067Snwhitehorn	(void)fprintf(stderr,
294192067Snwhitehorn	    "       lint [-abceghprvwzHF] [-s|-t] -Clibrary [-Dname[=def]]\n"
295192067Snwhitehorn	    " [-X <id>[,<id>]...\n");
296192067Snwhitehorn	(void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file"
297192067Snwhitehorn	    " ...\n");
298192067Snwhitehorn	terminate(-1);
299192067Snwhitehorn}
300212054Snwhitehorn
301192067Snwhitehorn
302192067Snwhitehornint
303192067Snwhitehornmain(int argc, char *argv[])
304212054Snwhitehorn{
305192067Snwhitehorn	int	c;
306192067Snwhitehorn	char	flgbuf[3], *tmp, *s;
307192067Snwhitehorn	size_t	len;
308192067Snwhitehorn
309192067Snwhitehorn	if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
310192067Snwhitehorn		tmpdir = xstrdup(_PATH_TMP);
311228201Sjchandra	} else {
312192067Snwhitehorn		s = xmalloc(len + 2);
313192067Snwhitehorn		(void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
314192067Snwhitehorn		tmpdir = s;
315192067Snwhitehorn	}
316192067Snwhitehorn
317192067Snwhitehorn	cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
318192067Snwhitehorn	(void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
319212054Snwhitehorn	cppoutfd = mkstemp(cppout);
320192067Snwhitehorn	if (cppoutfd == -1) {
321192067Snwhitehorn		warn("can't make temp");
322192067Snwhitehorn		terminate(-1);
323212054Snwhitehorn	}
324192067Snwhitehorn
325192067Snwhitehorn	p1out = xcalloc(1, sizeof (char *));
326192067Snwhitehorn	p2in = xcalloc(1, sizeof (char *));
327192067Snwhitehorn	cflags = xcalloc(1, sizeof (char *));
328198212Snwhitehorn	lcflags = xcalloc(1, sizeof (char *));
329192067Snwhitehorn	l1flags = xcalloc(1, sizeof (char *));
330192067Snwhitehorn	l2flags = xcalloc(1, sizeof (char *));
331192067Snwhitehorn	l2libs = xcalloc(1, sizeof (char *));
332192067Snwhitehorn	deflibs = xcalloc(1, sizeof (char *));
333209114Snwhitehorn	libs = xcalloc(1, sizeof (char *));
334209114Snwhitehorn	libsrchpath = xcalloc(1, sizeof (char *));
335192067Snwhitehorn
336209114Snwhitehorn	appcstrg(&cflags, "-E");
337209114Snwhitehorn	appcstrg(&cflags, "-x");
338209114Snwhitehorn	appcstrg(&cflags, "c");
339209114Snwhitehorn#if 0
340209114Snwhitehorn	appcstrg(&cflags, "-D__attribute__(x)=");
341209114Snwhitehorn	appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0");
342209114Snwhitehorn#else
343209114Snwhitehorn	appcstrg(&cflags, "-U__GNUC__");
344209114Snwhitehorn	appcstrg(&cflags, "-undef");
345209114Snwhitehorn#endif
346209853Snwhitehorn	appcstrg(&cflags, "-Wp,-$");
347209114Snwhitehorn	appcstrg(&cflags, "-Wp,-C");
348209114Snwhitehorn	appcstrg(&cflags, "-Wcomment");
349209114Snwhitehorn	appcstrg(&cflags, "-D__LINT__");
350209114Snwhitehorn	appcstrg(&cflags, "-Dlint");		/* XXX don't def. with -s */
351209114Snwhitehorn
352209114Snwhitehorn	appdef(&cflags, "lint");
353209114Snwhitehorn
354192067Snwhitehorn	appcstrg(&lcflags, "-Wtraditional");
355192067Snwhitehorn
356198212Snwhitehorn	appcstrg(&deflibs, "c");
357198212Snwhitehorn
358192067Snwhitehorn	if (signal(SIGHUP, terminate) == SIG_IGN)
359198212Snwhitehorn		(void)signal(SIGHUP, SIG_IGN);
360198212Snwhitehorn	(void)signal(SIGINT, terminate);
361192067Snwhitehorn	(void)signal(SIGQUIT, terminate);
362209114Snwhitehorn	(void)signal(SIGTERM, terminate);
363198378Snwhitehorn
364192067Snwhitehorn	while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:U:VX:")) != -1) {
365192067Snwhitehorn		switch (c) {
366192067Snwhitehorn
367209114Snwhitehorn		case 'a':
368198378Snwhitehorn		case 'b':
369192067Snwhitehorn		case 'c':
370192067Snwhitehorn		case 'e':
371198378Snwhitehorn		case 'g':
372192067Snwhitehorn		case 'r':
373192067Snwhitehorn		case 'v':
374192067Snwhitehorn		case 'w':
375192067Snwhitehorn		case 'z':
376192067Snwhitehorn			(void)sprintf(flgbuf, "-%c", c);
377192067Snwhitehorn			appcstrg(&l1flags, flgbuf);
378192067Snwhitehorn			break;
379192067Snwhitehorn
380192067Snwhitehorn		case 'F':
381192067Snwhitehorn			Fflag = 1;
382212054Snwhitehorn			/* FALLTHROUGH */
383212054Snwhitehorn		case 'u':
384212054Snwhitehorn		case 'h':
385212054Snwhitehorn			(void)sprintf(flgbuf, "-%c", c);
386212054Snwhitehorn			appcstrg(&l1flags, flgbuf);
387212054Snwhitehorn			appcstrg(&l2flags, flgbuf);
388262675Sjhibbits			break;
389262675Sjhibbits
390262675Sjhibbits		case 'X':
391262675Sjhibbits			(void)sprintf(flgbuf, "-%c", c);
392262675Sjhibbits			appcstrg(&l1flags, flgbuf);
393262675Sjhibbits			appcstrg(&l1flags, optarg);
394262675Sjhibbits			break;
395262675Sjhibbits
396		case 'i':
397			if (Cflag)
398				usage();
399			iflag = 1;
400			break;
401
402		case 'n':
403			freelst(&deflibs);
404			break;
405
406		case 'p':
407			appcstrg(&l1flags, "-p");
408			appcstrg(&l2flags, "-p");
409			if (*deflibs != NULL) {
410				freelst(&deflibs);
411				appcstrg(&deflibs, "c");
412			}
413			break;
414
415		case 's':
416			if (tflag)
417				usage();
418			freelst(&lcflags);
419			appcstrg(&lcflags, "-trigraphs");
420			appcstrg(&lcflags, "-Wtrigraphs");
421			appcstrg(&lcflags, "-pedantic");
422			appcstrg(&lcflags, "-D__STRICT_ANSI__");
423			appcstrg(&l1flags, "-s");
424			appcstrg(&l2flags, "-s");
425			sflag = 1;
426			break;
427
428#if !HAVE_CONFIG_H
429		case 't':
430			if (sflag)
431				usage();
432			freelst(&lcflags);
433			appcstrg(&lcflags, "-traditional");
434			appstrg(&lcflags, concat2("-D", MACHINE));
435			appstrg(&lcflags, concat2("-D", MACHINE_ARCH));
436			appcstrg(&l1flags, "-t");
437			appcstrg(&l2flags, "-t");
438			tflag = 1;
439			break;
440#endif
441
442		case 'x':
443			appcstrg(&l2flags, "-x");
444			break;
445
446		case 'C':
447			if (Cflag || oflag || iflag)
448				usage();
449			Cflag = 1;
450			appstrg(&l2flags, concat2("-C", optarg));
451			p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
452			(void)sprintf(p2out, "llib-l%s.ln", optarg);
453			freelst(&deflibs);
454			break;
455
456		case 'd':
457			if (dflag)
458				usage();
459			dflag = 1;
460			appcstrg(&cflags, "-nostdinc");
461			appcstrg(&cflags, "-idirafter");
462			appcstrg(&cflags, optarg);
463			break;
464
465		case 'D':
466		case 'I':
467		case 'U':
468			(void)sprintf(flgbuf, "-%c", c);
469			appstrg(&cflags, concat2(flgbuf, optarg));
470			break;
471
472		case 'l':
473			appcstrg(&libs, optarg);
474			break;
475
476		case 'o':
477			if (Cflag || oflag)
478				usage();
479			oflag = 1;
480			outputfn = xstrdup(optarg);
481			break;
482
483		case 'L':
484			appcstrg(&libsrchpath, optarg);
485			break;
486
487		case 'H':
488			appcstrg(&l2flags, "-H");
489			break;
490
491		case 'B':
492			Bflag = 1;
493			libexec_path = xstrdup(optarg);
494			break;
495
496		case 'V':
497			Vflag = 1;
498			break;
499
500		default:
501			usage();
502			/* NOTREACHED */
503		}
504	}
505	argc -= optind;
506	argv += optind;
507
508	/*
509	 * To avoid modifying getopt(3)'s state engine midstream, we
510	 * explicitly accept just a few options after the first source file.
511	 *
512	 * In particular, only -l<lib> and -L<libdir> (and these with a space
513	 * after -l or -L) are allowed.
514	 */
515	while (argc > 0) {
516		const char *arg = argv[0];
517
518		if (arg[0] == '-') {
519			char ***list;
520
521			/* option */
522			switch (arg[1]) {
523			case 'l':
524				list = &libs;
525				break;
526
527			case 'L':
528				list = &libsrchpath;
529				break;
530
531			default:
532				usage();
533				/* NOTREACHED */
534			}
535			if (arg[2])
536				appcstrg(list, arg + 2);
537			else if (argc > 1) {
538				argc--;
539				appcstrg(list, *++argv);
540			} else
541				usage();
542		} else {
543			/* filename */
544			fname(arg);
545			first = 0;
546		}
547		argc--;
548		argv++;
549	}
550
551	if (first)
552		usage();
553
554	if (iflag)
555		terminate(0);
556
557	if (!oflag) {
558		if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
559			s = PATH_LINTLIB;
560		appcstrg(&libsrchpath, s);
561		findlibs(libs);
562		findlibs(deflibs);
563	}
564
565	(void)printf("Lint pass2:\n");
566	lint2();
567
568	if (oflag)
569		cat(p2in, outputfn);
570
571	if (Cflag)
572		p2out = NULL;
573
574	terminate(0);
575	/* NOTREACHED */
576}
577
578/*
579 * Read a file name from the command line
580 * and pass it through lint1 if it is a C source.
581 */
582static void
583fname(const char *name)
584{
585	const	char *bn, *suff;
586	char	**args, *ofn, *pathname, *CC;
587	size_t	len;
588	int is_stdin;
589	int	fd;
590
591	is_stdin = (strcmp(name, "-") == 0);
592	bn = lbasename(name, '/');
593	suff = lbasename(bn, '.');
594
595	if (strcmp(suff, "ln") == 0) {
596		/* only for lint2 */
597		if (!iflag)
598			appcstrg(&p2in, name);
599		return;
600	}
601
602	if (!is_stdin && strcmp(suff, "c") != 0 &&
603	    (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
604		warnx("unknown file type: %s\n", name);
605		return;
606	}
607
608	if (!iflag || !first)
609		(void)printf("%s:\n",
610		    is_stdin ? "{standard input}" : Fflag ? name : bn);
611
612	/* build the name of the output file of lint1 */
613	if (oflag) {
614		ofn = outputfn;
615		outputfn = NULL;
616		oflag = 0;
617	} else if (iflag) {
618		if (is_stdin) {
619			warnx("-i not supported without -o for standard input");
620			return;
621		}
622		ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
623		len = bn == suff ? strlen(bn) : (suff - 1) - bn;
624		(void)sprintf(ofn, "%.*s", (int)len, bn);
625		(void)strcat(ofn, ".ln");
626	} else {
627		ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
628		(void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
629		fd = mkstemp(ofn);
630		if (fd == -1) {
631			warn("can't make temp");
632			terminate(-1);
633		}
634		close(fd);
635	}
636	if (!iflag)
637		appcstrg(&p1out, ofn);
638
639	args = xcalloc(1, sizeof (char *));
640
641	/* run cc */
642
643	if (getenv("CC") == NULL) {
644		pathname = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc"));
645		(void)sprintf(pathname, "%s/cc", PATH_USRBIN);
646	} else
647		pathname = strdup(getenv("CC"));
648
649	appcstrg(&args, pathname);
650	applst(&args, cflags);
651	applst(&args, lcflags);
652	appcstrg(&args, name);
653
654	/* we reuse the same tmp file for cpp output, so rewind and truncate */
655	if (lseek(cppoutfd, SEEK_SET, (off_t)0) != 0) {
656		warn("lseek");
657		terminate(-1);
658	}
659	if (ftruncate(cppoutfd, (off_t)0) != 0) {
660		warn("ftruncate");
661		terminate(-1);
662	}
663
664	runchild(pathname, args, cppout, cppoutfd);
665	free(pathname);
666	freelst(&args);
667
668	/* run lint1 */
669
670	if (!Bflag) {
671		pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") +
672		    strlen(target_prefix));
673		(void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC,
674		    target_prefix);
675	} else {
676		/*
677		 * XXX Unclear whether we should be using target_prefix
678		 * XXX here.  --thorpej@wasabisystems.com
679		 */
680		pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1"));
681		(void)sprintf(pathname, "%s/lint1", libexec_path);
682	}
683
684	appcstrg(&args, pathname);
685	applst(&args, l1flags);
686	appcstrg(&args, cppout);
687	appcstrg(&args, ofn);
688
689	runchild(pathname, args, ofn, -1);
690	free(pathname);
691	freelst(&args);
692
693	appcstrg(&p2in, ofn);
694	free(ofn);
695
696	free(args);
697}
698
699static void
700runchild(const char *path, char *const *args, const char *crfn, int fdout)
701{
702	int	status, rv, signo, i;
703
704	if (Vflag) {
705		for (i = 0; args[i] != NULL; i++)
706			(void)printf("%s ", args[i]);
707		(void)printf("\n");
708	}
709
710	currfn = crfn;
711
712	(void)fflush(stdout);
713
714	switch (vfork()) {
715	case -1:
716		warn("cannot fork");
717		terminate(-1);
718		/* NOTREACHED */
719	default:
720		/* parent */
721		break;
722	case 0:
723		/* child */
724
725		/* setup the standard output if necessary */
726		if (fdout != -1) {
727			dup2(fdout, STDOUT_FILENO);
728			close(fdout);
729		}
730		(void)execvp(path, args);
731		warn("cannot exec %s", path);
732		_exit(1);
733		/* NOTREACHED */
734	}
735
736	while ((rv = wait(&status)) == -1 && errno == EINTR) ;
737	if (rv == -1) {
738		warn("wait");
739		terminate(-1);
740	}
741	if (WIFSIGNALED(status)) {
742		signo = WTERMSIG(status);
743#if HAVE_DECL_SYS_SIGNAME
744		warnx("%s got SIG%s", path, sys_signame[signo]);
745#else
746		warnx("%s got signal %d", path, signo);
747#endif
748		terminate(-1);
749	}
750	if (WEXITSTATUS(status) != 0)
751		terminate(-1);
752	currfn = NULL;
753}
754
755static void
756findlibs(char *const *liblst)
757{
758	int	i, k;
759	const	char *lib, *path;
760	char	*lfn;
761	size_t	len;
762
763	lfn = NULL;
764
765	for (i = 0; (lib = liblst[i]) != NULL; i++) {
766		for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
767			len = strlen(path) + strlen(lib);
768			lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
769			(void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
770			if (rdok(lfn))
771				break;
772			lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
773			(void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
774			if (rdok(lfn))
775				break;
776		}
777		if (path != NULL) {
778			appstrg(&l2libs, concat2("-l", lfn));
779		} else {
780			warnx("cannot find llib-l%s.ln", lib);
781		}
782	}
783
784	free(lfn);
785}
786
787static int
788rdok(const char *path)
789{
790	struct	stat sbuf;
791
792	if (stat(path, &sbuf) == -1)
793		return (0);
794	if (!S_ISREG(sbuf.st_mode))
795		return (0);
796	if (access(path, R_OK) == -1)
797		return (0);
798	return (1);
799}
800
801static void
802lint2(void)
803{
804	char	*path, **args;
805
806	args = xcalloc(1, sizeof (char *));
807
808	if (!Bflag) {
809		path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") +
810		    strlen(target_prefix));
811		(void)sprintf(path, "%s/%slint2", PATH_LIBEXEC,
812		    target_prefix);
813	} else {
814		/*
815		 * XXX Unclear whether we should be using target_prefix
816		 * XXX here.  --thorpej@wasabisystems.com
817		 */
818		path = xmalloc(strlen(libexec_path) + sizeof ("/lint2"));
819		(void)sprintf(path, "%s/lint2", libexec_path);
820	}
821
822	appcstrg(&args, path);
823	applst(&args, l2flags);
824	applst(&args, l2libs);
825	applst(&args, p2in);
826
827	runchild(path, args, p2out, -1);
828	free(path);
829	freelst(&args);
830	free(args);
831}
832
833static void
834cat(char *const *srcs, const char *dest)
835{
836	int	ifd, ofd, i;
837	char	*src, *buf;
838	ssize_t	rlen;
839
840	if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
841		warn("cannot open %s", dest);
842		terminate(-1);
843	}
844
845	buf = xmalloc(MBLKSIZ);
846
847	for (i = 0; (src = srcs[i]) != NULL; i++) {
848		if ((ifd = open(src, O_RDONLY)) == -1) {
849			free(buf);
850			warn("cannot open %s", src);
851			terminate(-1);
852		}
853		do {
854			if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
855				free(buf);
856				warn("read error on %s", src);
857				terminate(-1);
858			}
859			if (write(ofd, buf, (size_t)rlen) == -1) {
860				free(buf);
861				warn("write error on %s", dest);
862				terminate(-1);
863			}
864		} while (rlen == MBLKSIZ);
865		(void)close(ifd);
866	}
867	(void)close(ofd);
868	free(buf);
869}
870