1/* $NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $ */
2
3/*
4 * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
5 * Copyright (c) 1994, 1995 Jochen Pohl
6 * All Rights Reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *      This product includes software developed by Jochen Pohl for
19 *	The NetBSD Project.
20 * 4. The name of the author may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#if defined(__RCSID) && !defined(lint)
37__RCSID("$NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $");
38#endif
39__FBSDID("$FreeBSD$");
40
41#include <sys/param.h>
42#include <sys/wait.h>
43#include <sys/stat.h>
44#include <sys/utsname.h>
45#include <err.h>
46#include <errno.h>
47#include <fcntl.h>
48#include <paths.h>
49#include <signal.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54
55#include "lint.h"
56#include "pathnames.h"
57
58#define DEFAULT_PATH		_PATH_DEFPATH
59
60int main(int, char *[]);
61
62/* directory for temporary files */
63static	const	char *tmpdir;
64
65/* path name for cpp output */
66static	char	*cppout;
67
68/* file descriptor for cpp output */
69static	int	cppoutfd = -1;
70
71/* files created by 1st pass */
72static	char	**p1out;
73
74/* input files for 2nd pass (without libraries) */
75static	char	**p2in;
76
77/* library which will be created by 2nd pass */
78static	char	*p2out;
79
80/* flags always passed to cc(1) */
81static	char	**cflags;
82
83/* flags for cc(1), controlled by sflag/tflag */
84static	char	**lcflags;
85
86/* flags for lint1 */
87static	char	**l1flags;
88
89/* flags for lint2 */
90static	char	**l2flags;
91
92/* libraries for lint2 */
93static	char	**l2libs;
94
95/* default libraries */
96static	char	**deflibs;
97
98/* additional libraries */
99static	char	**libs;
100
101/* search path for libraries */
102static	char	**libsrchpath;
103
104static  char	*libexec_path;
105
106/* flags */
107static	int	iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag, Sflag;
108
109/* print the commands executed to run the stages of compilation */
110static	int	Vflag;
111
112/* filename for oflag */
113static	char	*outputfn;
114
115/* reset after first .c source has been processed */
116static	int	first = 1;
117
118/*
119 * name of a file which is currently written by a child and should
120 * be removed after abnormal termination of the child
121 */
122static	const	char *currfn;
123
124#if !defined(TARGET_PREFIX)
125#define	TARGET_PREFIX	""
126#endif
127static const char target_prefix[] = TARGET_PREFIX;
128
129static	void	appstrg(char ***, char *);
130static	void	appcstrg(char ***, const char *);
131static	void	applst(char ***, char *const *);
132static	void	freelst(char ***);
133static	char	*concat2(const char *, const char *);
134static	char	*concat3(const char *, const char *, const char *);
135static	void	terminate(int) __attribute__((__noreturn__));
136static	const	char *lbasename(const char *, int);
137static	void	appdef(char ***, const char *);
138static	void	usage(void) __dead2;
139static	void	fname(const char *);
140static	void	runchild(const char *, char *const *, const char *, int);
141static	void	findlibs(char *const *);
142static	int	rdok(const char *);
143static	void	lint2(void);
144static	void	cat(char *const *, const char *);
145
146/*
147 * Some functions to deal with lists of strings.
148 * Take care that we get no surprises in case of asynchronous signals.
149 */
150static void
151appstrg(char ***lstp, char *s)
152{
153	char	**lst, **olst;
154	int	i;
155
156	olst = *lstp;
157	for (i = 0; olst[i] != NULL; i++)
158		continue;
159	lst = xrealloc(olst, (i + 2) * sizeof (char *));
160	lst[i] = s;
161	lst[i + 1] = NULL;
162	*lstp = lst;
163}
164
165static void
166appcstrg(char ***lstp, const char *s)
167{
168
169	appstrg(lstp, xstrdup(s));
170}
171
172static void
173applst(char ***destp, char *const *src)
174{
175	int	i, k;
176	char	**dest, **odest;
177
178	odest = *destp;
179	for (i = 0; odest[i] != NULL; i++)
180		continue;
181	for (k = 0; src[k] != NULL; k++)
182		continue;
183	dest = xrealloc(odest, (i + k + 1) * sizeof (char *));
184	for (k = 0; src[k] != NULL; k++)
185		dest[i + k] = xstrdup(src[k]);
186	dest[i + k] = NULL;
187	*destp = dest;
188}
189
190static void
191freelst(char ***lstp)
192{
193	char	*s;
194	int	i;
195
196	for (i = 0; (*lstp)[i] != NULL; i++)
197		continue;
198	while (i-- > 0) {
199		s = (*lstp)[i];
200		(*lstp)[i] = NULL;
201		free(s);
202	}
203}
204
205static char *
206concat2(const char *s1, const char *s2)
207{
208	char	*s;
209
210	s = xmalloc(strlen(s1) + strlen(s2) + 1);
211	(void)strcpy(s, s1);
212	(void)strcat(s, s2);
213
214	return (s);
215}
216
217static char *
218concat3(const char *s1, const char *s2, const char *s3)
219{
220	char	*s;
221
222	s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
223	(void)strcpy(s, s1);
224	(void)strcat(s, s2);
225	(void)strcat(s, s3);
226
227	return (s);
228}
229
230/*
231 * Clean up after a signal.
232 */
233static void
234terminate(int signo)
235{
236	int	i;
237
238	if (cppoutfd != -1)
239		(void)close(cppoutfd);
240	if (cppout != NULL)
241		(void)remove(cppout);
242
243	if (p1out != NULL) {
244		for (i = 0; p1out[i] != NULL; i++)
245			(void)remove(p1out[i]);
246	}
247
248	if (p2out != NULL)
249		(void)remove(p2out);
250
251	if (currfn != NULL)
252		(void)remove(currfn);
253
254	exit(signo != 0 ? 1 : 0);
255}
256
257/*
258 * Returns a pointer to the last component of strg after delim.
259 * Returns strg if the string does not contain delim.
260 */
261static const char *
262lbasename(const char *strg, int delim)
263{
264	const	char *cp, *cp1, *cp2;
265
266	cp = cp1 = cp2 = strg;
267	while (*cp != '\0') {
268		if (*cp++ == delim) {
269			cp2 = cp1;
270			cp1 = cp;
271		}
272	}
273	return (*cp1 == '\0' ? cp2 : cp1);
274}
275
276static void
277appdef(char ***lstp, const char *def)
278{
279
280	appstrg(lstp, concat2("-D__", def));
281	appstrg(lstp, concat3("-D__", def, "__"));
282}
283
284static void
285usage(void)
286{
287
288	(void)fprintf(stderr,
289	    "usage: lint [-abceghprvwxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]]"
290	    " [-Uname] [-X <id>[,<id>]...\n");
291	(void)fprintf(stderr,
292	    "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
293	    " file...\n");
294	(void)fprintf(stderr,
295	    "       lint [-abceghprvwzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n"
296	    " [-X <id>[,<id>]...\n");
297	(void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file"
298	    " ...\n");
299	terminate(-1);
300}
301
302
303int
304main(int argc, char *argv[])
305{
306	int	c;
307	char	flgbuf[3], *s;
308	const char *tmp;
309	size_t	len;
310
311	if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
312		tmpdir = _PATH_TMP;
313	} else {
314		s = xmalloc(len + 2);
315		(void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
316		tmpdir = s;
317	}
318
319	cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
320	(void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
321	cppoutfd = mkstemp(cppout);
322	if (cppoutfd == -1) {
323		warn("can't make temp");
324		terminate(-1);
325	}
326
327	p1out = xcalloc(1, sizeof (char *));
328	p2in = xcalloc(1, sizeof (char *));
329	cflags = xcalloc(1, sizeof (char *));
330	lcflags = xcalloc(1, sizeof (char *));
331	l1flags = xcalloc(1, sizeof (char *));
332	l2flags = xcalloc(1, sizeof (char *));
333	l2libs = xcalloc(1, sizeof (char *));
334	deflibs = xcalloc(1, sizeof (char *));
335	libs = xcalloc(1, sizeof (char *));
336	libsrchpath = xcalloc(1, sizeof (char *));
337
338	appcstrg(&cflags, "-E");
339	appcstrg(&cflags, "-x");
340	appcstrg(&cflags, "c");
341#if 0
342	appcstrg(&cflags, "-D__attribute__(x)=");
343	appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0");
344#else
345	appcstrg(&cflags, "-U__GNUC__");
346	appcstrg(&cflags, "-undef");
347#endif
348#if 0
349	appcstrg(&cflags, "-Wp,-$");
350#endif
351	appcstrg(&cflags, "-Wp,-C");
352	appcstrg(&cflags, "-Wcomment");
353	appcstrg(&cflags, "-D__LINT__");
354	appcstrg(&cflags, "-Dlint");		/* XXX don't def. with -s */
355
356	appdef(&cflags, "lint");
357
358	appcstrg(&deflibs, "c");
359
360	if (signal(SIGHUP, terminate) == SIG_IGN)
361		(void)signal(SIGHUP, SIG_IGN);
362	(void)signal(SIGINT, terminate);
363	(void)signal(SIGQUIT, terminate);
364	(void)signal(SIGTERM, terminate);
365	while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:M:SU:VX:")) != -1) {
366		switch (c) {
367
368		case 'a':
369		case 'b':
370		case 'c':
371		case 'e':
372		case 'g':
373		case 'r':
374		case 'v':
375		case 'w':
376		case 'z':
377			(void)sprintf(flgbuf, "-%c", c);
378			appcstrg(&l1flags, flgbuf);
379			break;
380
381		case 'F':
382			Fflag = 1;
383			/* FALLTHROUGH */
384		case 'u':
385		case 'h':
386			(void)sprintf(flgbuf, "-%c", c);
387			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