1107484Speter/* $NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $ */
2107484Speter
381404Speter/*
4107484Speter * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
581404Speter * Copyright (c) 1994, 1995 Jochen Pohl
681404Speter * All Rights Reserved.
781404Speter *
881404Speter * Redistribution and use in source and binary forms, with or without
981404Speter * modification, are permitted provided that the following conditions
1081404Speter * are met:
1181404Speter * 1. Redistributions of source code must retain the above copyright
1281404Speter *    notice, this list of conditions and the following disclaimer.
1381404Speter * 2. Redistributions in binary form must reproduce the above copyright
1481404Speter *    notice, this list of conditions and the following disclaimer in the
1581404Speter *    documentation and/or other materials provided with the distribution.
1681404Speter * 3. All advertising materials mentioning features or use of this software
1717721Speter *    must display the following acknowledgement:
1817721Speter *      This product includes software developed by Jochen Pohl for
1917721Speter *	The NetBSD Project.
2017721Speter * 4. The name of the author may not be used to endorse or promote products
2117721Speter *    derived from this software without specific prior written permission.
2217721Speter *
2317721Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2417721Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2517721Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2617721Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2717721Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2817721Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2917721Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3081404Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3181404Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3281404Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3317721Speter */
3481404Speter
3517721Speter#include <sys/cdefs.h>
3617721Speter#if defined(__RCSID) && !defined(lint)
3717721Speter__RCSID("$NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $");
3866525Speter#endif
3981404Speter__FBSDID("$FreeBSD$");
4081404Speter
4181404Speter#include <sys/param.h>
4281404Speter#include <sys/wait.h>
4381404Speter#include <sys/stat.h>
4481404Speter#include <sys/utsname.h>
4566525Speter#include <err.h>
4681404Speter#include <errno.h>
4766525Speter#include <fcntl.h>
4881404Speter#include <paths.h>
4981404Speter#include <signal.h>
5081404Speter#include <stdio.h>
5181404Speter#include <stdlib.h>
5281404Speter#include <string.h>
5381404Speter#include <unistd.h>
5481404Speter
5581404Speter#include "lint.h"
5681404Speter#include "pathnames.h"
5781404Speter
5881404Speter#define DEFAULT_PATH		_PATH_DEFPATH
5981404Speter
60107484Speterint main(int, char *[]);
6117721Speter
6281404Speter/* directory for temporary files */
6317721Speterstatic	const	char *tmpdir;
64107484Speter
65107484Speter/* path name for cpp output */
66107484Speterstatic	char	*cppout;
6781404Speter
6881404Speter/* file descriptor for cpp output */
6981404Speterstatic	int	cppoutfd = -1;
7081404Speter
7181404Speter/* files created by 1st pass */
7281404Speterstatic	char	**p1out;
7381404Speter
7481404Speter/* input files for 2nd pass (without libraries) */
7581404Speterstatic	char	**p2in;
76107484Speter
77107484Speter/* library which will be created by 2nd pass */
78107484Speterstatic	char	*p2out;
79107484Speter
8081404Speter/* flags always passed to cc(1) */
8181404Speterstatic	char	**cflags;
8281404Speter
8381404Speter/* flags for cc(1), controlled by sflag/tflag */
8481404Speterstatic	char	**lcflags;
85107484Speter
8681404Speter/* flags for lint1 */
8781404Speterstatic	char	**l1flags;
8881404Speter
8981404Speter/* flags for lint2 */
9081404Speterstatic	char	**l2flags;
9181404Speter
9281404Speter/* libraries for lint2 */
9381404Speterstatic	char	**l2libs;
9481404Speter
95107484Speter/* default libraries */
9681404Speterstatic	char	**deflibs;
9781404Speter
9881404Speter/* additional libraries */
99102840Speterstatic	char	**libs;
100102840Speter
10181404Speter/* search path for libraries */
10281404Speterstatic	char	**libsrchpath;
10317721Speter
10481404Speterstatic  char	*libexec_path;
10517721Speter
10681404Speter/* flags */
107107484Speterstatic	int	iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag, Sflag;
10881404Speter
10981404Speter/* print the commands executed to run the stages of compilation */
11081404Speterstatic	int	Vflag;
11181404Speter
11281404Speter/* filename for oflag */
11381404Speterstatic	char	*outputfn;
11481404Speter
11581404Speter/* reset after first .c source has been processed */
11681404Speterstatic	int	first = 1;
11781404Speter
118102840Speter/*
11981404Speter * name of a file which is currently written by a child and should
12081404Speter * be removed after abnormal termination of the child
12181404Speter */
12281404Speterstatic	const	char *currfn;
12317721Speter
12417721Speter#if !defined(TARGET_PREFIX)
12581404Speter#define	TARGET_PREFIX	""
12681404Speter#endif
12781404Speterstatic const char target_prefix[] = TARGET_PREFIX;
12817721Speter
12917721Speterstatic	void	appstrg(char ***, char *);
13081404Speterstatic	void	appcstrg(char ***, const char *);
13181404Speterstatic	void	applst(char ***, char *const *);
13217721Speterstatic	void	freelst(char ***);
13317721Speterstatic	char	*concat2(const char *, const char *);
13481404Speterstatic	char	*concat3(const char *, const char *, const char *);
13581404Speterstatic	void	terminate(int) __attribute__((__noreturn__));
13681404Speterstatic	const	char *lbasename(const char *, int);
13781404Speterstatic	void	appdef(char ***, const char *);
13881404Speterstatic	void	usage(void) __dead2;
13981404Speterstatic	void	fname(const char *);
14081404Speterstatic	void	runchild(const char *, char *const *, const char *, int);
14181404Speterstatic	void	findlibs(char *const *);
14281404Speterstatic	int	rdok(const char *);
14381404Speterstatic	void	lint2(void);
14481404Speterstatic	void	cat(char *const *, const char *);
14581404Speter
14681404Speter/*
14781404Speter * Some functions to deal with lists of strings.
14881404Speter * Take care that we get no surprises in case of asynchronous signals.
14981404Speter */
15081404Speterstatic void
15181404Speterappstrg(char ***lstp, char *s)
15281404Speter{
15381404Speter	char	**lst, **olst;
15481404Speter	int	i;
15581404Speter
15681404Speter	olst = *lstp;
15781404Speter	for (i = 0; olst[i] != NULL; i++)
15881404Speter		continue;
159107484Speter	lst = xrealloc(olst, (i + 2) * sizeof (char *));
160107484Speter	lst[i] = s;
161107484Speter	lst[i + 1] = NULL;
16281404Speter	*lstp = lst;
16381404Speter}
16481404Speter
16581404Speterstatic void
16681404Speterappcstrg(char ***lstp, const char *s)
167107484Speter{
168107484Speter
169107484Speter	appstrg(lstp, xstrdup(s));
17081404Speter}
17181404Speter
17281404Speterstatic void
17381404Speterapplst(char ***destp, char *const *src)
17481404Speter{
17581404Speter	int	i, k;
17681404Speter	char	**dest, **odest;
17781404Speter
178107484Speter	odest = *destp;
179107484Speter	for (i = 0; odest[i] != NULL; i++)
180107484Speter		continue;
18181404Speter	for (k = 0; src[k] != NULL; k++)
182107484Speter		continue;
18381404Speter	dest = xrealloc(odest, (i + k + 1) * sizeof (char *));
184107484Speter	for (k = 0; src[k] != NULL; k++)
18581404Speter		dest[i + k] = xstrdup(src[k]);
186107484Speter	dest[i + k] = NULL;
18781404Speter	*destp = dest;
188107484Speter}
18981404Speter
190107484Speterstatic void
19181404Speterfreelst(char ***lstp)
192107484Speter{
19381404Speter	char	*s;
194107484Speter	int	i;
195102840Speter
196107484Speter	for (i = 0; (*lstp)[i] != NULL; i++)
19781404Speter		continue;
198107484Speter	while (i-- > 0) {
19981404Speter		s = (*lstp)[i];
200107484Speter		(*lstp)[i] = NULL;
201107484Speter		free(s);
20281404Speter	}
20381404Speter}
20481404Speter
20581404Speterstatic char *
206107484Speterconcat2(const char *s1, const char *s2)
207107484Speter{
208107484Speter	char	*s;
209107484Speter
210107484Speter	s = xmalloc(strlen(s1) + strlen(s2) + 1);
21181404Speter	(void)strcpy(s, s1);
21217721Speter	(void)strcat(s, s2);
21381404Speter
21481404Speter	return (s);
21581404Speter}
21681404Speter
217107484Speterstatic char *
21881404Speterconcat3(const char *s1, const char *s2, const char *s3)
21981404Speter{
22017721Speter	char	*s;
221102840Speter
222107484Speter	s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
22381404Speter	(void)strcpy(s, s1);
22481404Speter	(void)strcat(s, s2);
22581404Speter	(void)strcat(s, s3);
22681404Speter
22781404Speter	return (s);
22881404Speter}
229107484Speter
230107484Speter/*
23117721Speter * Clean up after a signal.
23217721Speter */
23381404Speterstatic void
23481404Speterterminate(int signo)
23581404Speter{
23681404Speter	int	i;
23781404Speter
23881404Speter	if (cppoutfd != -1)
23981404Speter		(void)close(cppoutfd);
24081404Speter	if (cppout != NULL)
24181404Speter		(void)remove(cppout);
24281404Speter
24381404Speter	if (p1out != NULL) {
24481404Speter		for (i = 0; p1out[i] != NULL; i++)
24581404Speter			(void)remove(p1out[i]);
24681404Speter	}
24781404Speter
24881404Speter	if (p2out != NULL)
249107484Speter		(void)remove(p2out);
250107484Speter
251102840Speter	if (currfn != NULL)
252102840Speter		(void)remove(currfn);
253107484Speter
254107484Speter	exit(signo != 0 ? 1 : 0);
255107484Speter}
256107484Speter
257102840Speter/*
25881404Speter * Returns a pointer to the last component of strg after delim.
259107484Speter * Returns strg if the string does not contain delim.
260107484Speter */
261107484Speterstatic const char *
262107484Speterlbasename(const char *strg, int delim)
26381404Speter{
26481404Speter	const	char *cp, *cp1, *cp2;
26581404Speter
26681404Speter	cp = cp1 = cp2 = strg;
26781404Speter	while (*cp != '\0') {
26881404Speter		if (*cp++ == delim) {
26981404Speter			cp2 = cp1;
27081404Speter			cp1 = cp;
27181404Speter		}
27281404Speter	}
27325839Speter	return (*cp1 == '\0' ? cp2 : cp1);
27481404Speter}
27517721Speter
27681404Speterstatic void
27781404Speterappdef(char ***lstp, const char *def)
27881404Speter{
27981404Speter
28017721Speter	appstrg(lstp, concat2("-D__", def));
28181404Speter	appstrg(lstp, concat3("-D__", def, "__"));
28281404Speter}
28317721Speter
28481404Speterstatic void
28581404Speterusage(void)
28681404Speter{
287107484Speter
288102840Speter	(void)fprintf(stderr,
289102840Speter	    "usage: lint [-abceghprvwxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]]"
29081404Speter	    " [-Uname] [-X <id>[,<id>]...\n");
29117721Speter	(void)fprintf(stderr,
29281404Speter	    "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
29381404Speter	    " file...\n");
29417721Speter	(void)fprintf(stderr,
29581404Speter	    "       lint [-abceghprvwzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n"
296107484Speter	    " [-X <id>[,<id>]...\n");
29781404Speter	(void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file"
29881404Speter	    " ...\n");
29981404Speter	terminate(-1);
30081404Speter}
30181404Speter
30281404Speter
30381404Speterint
30481404Spetermain(int argc, char *argv[])
30581404Speter{
30681404Speter	int	c;
30781404Speter	char	flgbuf[3], *s;
30881404Speter	const char *tmp;
309102840Speter	size_t	len;
31081404Speter
31181404Speter	if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
31281404Speter		tmpdir = _PATH_TMP;
313102840Speter	} else {
31481404Speter		s = xmalloc(len + 2);
31581404Speter		(void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
31681404Speter		tmpdir = s;
31781404Speter	}
31881404Speter
31981404Speter	cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
32081404Speter	(void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
32181404Speter	cppoutfd = mkstemp(cppout);
322102840Speter	if (cppoutfd == -1) {
32381404Speter		warn("can't make temp");
32481404Speter		terminate(-1);
32581404Speter	}
32681404Speter
32781404Speter	p1out = xcalloc(1, sizeof (char *));
32881404Speter	p2in = xcalloc(1, sizeof (char *));
32981404Speter	cflags = xcalloc(1, sizeof (char *));
33081404Speter	lcflags = xcalloc(1, sizeof (char *));
33181404Speter	l1flags = xcalloc(1, sizeof (char *));
33281404Speter	l2flags = xcalloc(1, sizeof (char *));
33381404Speter	l2libs = xcalloc(1, sizeof (char *));
33481404Speter	deflibs = xcalloc(1, sizeof (char *));
33581404Speter	libs = xcalloc(1, sizeof (char *));
33681404Speter	libsrchpath = xcalloc(1, sizeof (char *));
337102840Speter
33881404Speter	appcstrg(&cflags, "-E");
33981404Speter	appcstrg(&cflags, "-x");
34081404Speter	appcstrg(&cflags, "c");
34181404Speter#if 0
34281404Speter	appcstrg(&cflags, "-D__attribute__(x)=");
343102840Speter	appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0");
344102840Speter#else
345102840Speter	appcstrg(&cflags, "-U__GNUC__");
346102840Speter	appcstrg(&cflags, "-undef");
347102840Speter#endif
348102840Speter#if 0
34981404Speter	appcstrg(&cflags, "-Wp,-$");
35081404Speter#endif
35181404Speter	appcstrg(&cflags, "-Wp,-C");
35281404Speter	appcstrg(&cflags, "-Wcomment");
353102840Speter	appcstrg(&cflags, "-D__LINT__");
354102840Speter	appcstrg(&cflags, "-Dlint");		/* XXX don't def. with -s */
35581404Speter
35681404Speter	appdef(&cflags, "lint");
35781404Speter
35881404Speter	appcstrg(&deflibs, "c");
35981404Speter
36081404Speter	if (signal(SIGHUP, terminate) == SIG_IGN)
36181404Speter		(void)signal(SIGHUP, SIG_IGN);
36281404Speter	(void)signal(SIGINT, terminate);
36381404Speter	(void)signal(SIGQUIT, terminate);
36481404Speter	(void)signal(SIGTERM, terminate);
36581404Speter	while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:M:SU:VX:")) != -1) {
36681404Speter		switch (c) {
36781404Speter
36881404Speter		case 'a':
36917721Speter		case 'b':
37017721Speter		case 'c':
37181404Speter		case 'e':
37281404Speter		case 'g':
37381404Speter		case 'r':
37481404Speter		case 'v':
37581404Speter		case 'w':
37681404Speter		case 'z':
37781404Speter			(void)sprintf(flgbuf, "-%c", c);
37881404Speter			appcstrg(&l1flags, flgbuf);
37981404Speter			break;
38081404Speter
38181404Speter		case 'F':
38281404Speter			Fflag = 1;
38381404Speter			/* FALLTHROUGH */
38481404Speter		case 'u':
38581404Speter		case 'h':
38681404Speter			(void)sprintf(flgbuf, "-%c", c);
38781404Speter			appcstrg(&l1flags, flgbuf);
388			appcstrg(&l2flags, flgbuf);
389			break;
390
391		case 'X':
392			(void)sprintf(flgbuf, "-%c", c);
393			appcstrg(&l1flags, flgbuf);
394			appcstrg(&l1flags, optarg);
395			break;
396
397		case 'i':
398			if (Cflag)
399				usage();
400			iflag = 1;
401			break;
402
403		case 'n':
404			freelst(&deflibs);
405			break;
406
407		case 'p':
408			appcstrg(&lcflags, "-Wtraditional");
409			appcstrg(&lcflags, "-Wno-system-headers");
410			appcstrg(&l1flags, "-p");
411			appcstrg(&l2flags, "-p");
412			if (*deflibs != NULL) {
413				freelst(&deflibs);
414				appcstrg(&deflibs, "c");
415			}
416			break;
417
418		case 's':
419			if (tflag)
420				usage();
421			freelst(&lcflags);
422			appcstrg(&lcflags, "-trigraphs");
423			appcstrg(&lcflags, "-Wtrigraphs");
424			appcstrg(&lcflags, "-pedantic");
425			appcstrg(&lcflags, "-D__STRICT_ANSI__");
426			appcstrg(&l1flags, "-s");
427			appcstrg(&l2flags, "-s");
428			sflag = 1;
429			break;
430
431		case 'S':
432			if (tflag)
433				usage();
434			appcstrg(&l1flags, "-S");
435			Sflag = 1;
436			break;
437
438#if !HAVE_CONFIG_H
439		case 't':
440			if (sflag)
441				usage();
442			freelst(&lcflags);
443			appcstrg(&lcflags, "-traditional");
444			appstrg(&lcflags, concat2("-D", MACHINE));
445			appstrg(&lcflags, concat2("-D", MACHINE_ARCH));
446			appcstrg(&l1flags, "-t");
447			appcstrg(&l2flags, "-t");
448			tflag = 1;
449			break;
450#endif
451
452		case 'x':
453			appcstrg(&l2flags, "-x");
454			break;
455
456		case 'C':
457			if (Cflag || oflag || iflag)
458				usage();
459			Cflag = 1;
460			appstrg(&l2flags, concat2("-C", optarg));
461			p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
462			(void)sprintf(p2out, "llib-l%s.ln", optarg);
463			freelst(&deflibs);
464			break;
465
466		case 'd':
467			if (dflag)
468				usage();
469			dflag = 1;
470			appcstrg(&cflags, "-nostdinc");
471			appcstrg(&cflags, "-idirafter");
472			appcstrg(&cflags, optarg);
473			break;
474
475		case 'D':
476		case 'I':
477		case 'M':
478		case 'U':
479			(void)sprintf(flgbuf, "-%c", c);
480			appstrg(&cflags, concat2(flgbuf, optarg));
481			break;
482
483		case 'l':
484			appcstrg(&libs, optarg);
485			break;
486
487		case 'o':
488			if (Cflag || oflag)
489				usage();
490			oflag = 1;
491			outputfn = xstrdup(optarg);
492			break;
493
494		case 'L':
495			appcstrg(&libsrchpath, optarg);
496			break;
497
498		case 'H':
499			appcstrg(&l2flags, "-H");
500			break;
501
502		case 'B':
503			Bflag = 1;
504			libexec_path = xstrdup(optarg);
505			break;
506
507		case 'V':
508			Vflag = 1;
509			break;
510
511		default:
512			usage();
513			/* NOTREACHED */
514		}
515	}
516	argc -= optind;
517	argv += optind;
518
519	/*
520	 * To avoid modifying getopt(3)'s state engine midstream, we
521	 * explicitly accept just a few options after the first source file.
522	 *
523	 * In particular, only -l<lib> and -L<libdir> (and these with a space
524	 * after -l or -L) are allowed.
525	 */
526	while (argc > 0) {
527		const char *arg = argv[0];
528
529		if (arg[0] == '-') {
530			char ***list;
531
532			/* option */
533			switch (arg[1]) {
534			case 'l':
535				list = &libs;
536				break;
537
538			case 'L':
539				list = &libsrchpath;
540				break;
541
542			default:
543				usage();
544				/* NOTREACHED */
545			}
546			if (arg[2])
547				appcstrg(list, arg + 2);
548			else if (argc > 1) {
549				argc--;
550				appcstrg(list, *++argv);
551			} else
552				usage();
553		} else {
554			/* filename */
555			fname(arg);
556			first = 0;
557		}
558		argc--;
559		argv++;
560	}
561
562	if (first)
563		usage();
564
565	if (iflag)
566		terminate(0);
567
568	if (!oflag) {
569		if ((tmp = getenv("LIBDIR")) == NULL || strlen(tmp) == 0)
570			tmp = PATH_LINTLIB;
571		appcstrg(&libsrchpath, tmp);
572		findlibs(libs);
573		findlibs(deflibs);
574	}
575
576	(void)printf("Lint pass2:\n");
577	lint2();
578
579	if (oflag)
580		cat(p2in, outputfn);
581
582	if (Cflag)
583		p2out = NULL;
584
585	terminate(0);
586	/* NOTREACHED */
587}
588
589/*
590 * Read a file name from the command line
591 * and pass it through lint1 if it is a C source.
592 */
593static void
594fname(const char *name)
595{
596	const	char *bn, *suff;
597	char	**args, *ofn, *p, *pathname;
598	size_t	len;
599	int is_stdin;
600	int	fd;
601
602	is_stdin = (strcmp(name, "-") == 0);
603	bn = lbasename(name, '/');
604	suff = lbasename(bn, '.');
605
606	if (strcmp(suff, "ln") == 0) {
607		/* only for lint2 */
608		if (!iflag)
609			appcstrg(&p2in, name);
610		return;
611	}
612
613	if (!is_stdin && strcmp(suff, "c") != 0 &&
614	    (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
615		warnx("unknown file type: %s\n", name);
616		return;
617	}
618
619	if (!iflag || !first)
620		(void)printf("%s:\n",
621		    is_stdin ? "{standard input}" : Fflag ? name : bn);
622
623	/* build the name of the output file of lint1 */
624	if (oflag) {
625		ofn = outputfn;
626		outputfn = NULL;
627		oflag = 0;
628	} else if (iflag) {
629		if (is_stdin) {
630			warnx("-i not supported without -o for standard input");
631			return;
632		}
633		ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
634		len = bn == suff ? strlen(bn) : (size_t)((suff - 1) - bn);
635		(void)sprintf(ofn, "%.*s", (int)len, bn);
636		(void)strcat(ofn, ".ln");
637	} else {
638		ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
639		(void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
640		fd = mkstemp(ofn);
641		if (fd == -1) {
642			warn("can't make temp");
643			terminate(-1);
644		}
645		close(fd);
646	}
647	if (!iflag)
648		appcstrg(&p1out, ofn);
649
650	args = xcalloc(1, sizeof (char *));
651
652	/* run cc */
653
654	if (getenv("CC") == NULL) {
655		pathname = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc"));
656		(void)sprintf(pathname, "%s/cc", PATH_USRBIN);
657		appcstrg(&args, pathname);
658	} else {
659		pathname = strdup(getenv("CC"));
660		for (p = strtok(pathname, " \t"); p; p = strtok(NULL, " \t"))
661			appcstrg(&args, p);
662	}
663
664	applst(&args, cflags);
665	applst(&args, lcflags);
666	appcstrg(&args, name);
667
668	/* we reuse the same tmp file for cpp output, so rewind and truncate */
669	if (lseek(cppoutfd, (off_t)0, SEEK_SET) != 0) {
670		warn("lseek");
671		terminate(-1);
672	}
673	if (ftruncate(cppoutfd, (off_t)0) != 0) {
674		warn("ftruncate");
675		terminate(-1);
676	}
677
678	runchild(pathname, args, cppout, cppoutfd);
679	free(pathname);
680	freelst(&args);
681
682	/* run lint1 */
683
684	if (!Bflag) {
685		pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") +
686		    strlen(target_prefix));
687		(void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC,
688		    target_prefix);
689	} else {
690		/*
691		 * XXX Unclear whether we should be using target_prefix
692		 * XXX here.  --thorpej@wasabisystems.com
693		 */
694		pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1"));
695		(void)sprintf(pathname, "%s/lint1", libexec_path);
696	}
697
698	appcstrg(&args, pathname);
699	applst(&args, l1flags);
700	appcstrg(&args, cppout);
701	appcstrg(&args, ofn);
702
703	runchild(pathname, args, ofn, -1);
704	free(pathname);
705	freelst(&args);
706
707	appcstrg(&p2in, ofn);
708	free(ofn);
709
710	free(args);
711}
712
713static void
714runchild(const char *path, char *const *args, const char *crfn, int fdout)
715{
716	int	status, rv, signo, i;
717
718	if (Vflag) {
719		for (i = 0; args[i] != NULL; i++)
720			(void)printf("%s ", args[i]);
721		(void)printf("\n");
722	}
723
724	currfn = crfn;
725
726	(void)fflush(stdout);
727
728	switch (vfork()) {
729	case -1:
730		warn("cannot fork");
731		terminate(-1);
732		/* NOTREACHED */
733	default:
734		/* parent */
735		break;
736	case 0:
737		/* child */
738
739		/* setup the standard output if necessary */
740		if (fdout != -1) {
741			dup2(fdout, STDOUT_FILENO);
742			close(fdout);
743		}
744		(void)execvp(path, args);
745		warn("cannot exec %s", path);
746		_exit(1);
747		/* NOTREACHED */
748	}
749
750	while ((rv = wait(&status)) == -1 && errno == EINTR) ;
751	if (rv == -1) {
752		warn("wait");
753		terminate(-1);
754	}
755	if (WIFSIGNALED(status)) {
756		signo = WTERMSIG(status);
757#if HAVE_DECL_SYS_SIGNAME
758		warnx("%s got SIG%s", path, sys_signame[signo]);
759#else
760		warnx("%s got signal %d", path, signo);
761#endif
762		terminate(-1);
763	}
764	if (WEXITSTATUS(status) != 0)
765		terminate(-1);
766	currfn = NULL;
767}
768
769static void
770findlibs(char *const *liblst)
771{
772	int	i, k;
773	const	char *lib, *path;
774	char	*lfn;
775	size_t	len;
776
777	lfn = NULL;
778
779	for (i = 0; (lib = liblst[i]) != NULL; i++) {
780		for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
781			len = strlen(path) + strlen(lib);
782			lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
783			(void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
784			if (rdok(lfn))
785				break;
786			lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
787			(void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
788			if (rdok(lfn))
789				break;
790		}
791		if (path != NULL) {
792			appstrg(&l2libs, concat2("-l", lfn));
793		} else {
794			warnx("cannot find llib-l%s.ln", lib);
795		}
796	}
797
798	free(lfn);
799}
800
801static int
802rdok(const char *path)
803{
804	struct	stat sbuf;
805
806	if (stat(path, &sbuf) == -1)
807		return (0);
808	if (!S_ISREG(sbuf.st_mode))
809		return (0);
810	if (access(path, R_OK) == -1)
811		return (0);
812	return (1);
813}
814
815static void
816lint2(void)
817{
818	char	*path, **args;
819
820	args = xcalloc(1, sizeof (char *));
821
822	if (!Bflag) {
823		path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") +
824		    strlen(target_prefix));
825		(void)sprintf(path, "%s/%slint2", PATH_LIBEXEC,
826		    target_prefix);
827	} else {
828		/*
829		 * XXX Unclear whether we should be using target_prefix
830		 * XXX here.  --thorpej@wasabisystems.com
831		 */
832		path = xmalloc(strlen(libexec_path) + sizeof ("/lint2"));
833		(void)sprintf(path, "%s/lint2", libexec_path);
834	}
835
836	appcstrg(&args, path);
837	applst(&args, l2flags);
838	applst(&args, l2libs);
839	applst(&args, p2in);
840
841	runchild(path, args, p2out, -1);
842	free(path);
843	freelst(&args);
844	free(args);
845}
846
847static void
848cat(char *const *srcs, const char *dest)
849{
850	int	ifd, ofd, i;
851	char	*src, *buf;
852	ssize_t	rlen;
853
854	if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
855		warn("cannot open %s", dest);
856		terminate(-1);
857	}
858
859	buf = xmalloc(MBLKSIZ);
860
861	for (i = 0; (src = srcs[i]) != NULL; i++) {
862		if ((ifd = open(src, O_RDONLY)) == -1) {
863			free(buf);
864			warn("cannot open %s", src);
865			terminate(-1);
866		}
867		do {
868			if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
869				free(buf);
870				warn("read error on %s", src);
871				terminate(-1);
872			}
873			if (write(ofd, buf, (size_t)rlen) == -1) {
874				free(buf);
875				warn("write error on %s", dest);
876				terminate(-1);
877			}
878		} while (rlen == MBLKSIZ);
879		(void)close(ifd);
880	}
881	(void)close(ofd);
882	free(buf);
883}
884