xref: /netbsd/usr.bin/xlint/xlint/xlint.c (revision 6550d01e)
1 /* $NetBSD: xlint.c,v 1.43 2010/03/22 01:29:30 mrg 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 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
37 #endif
38 
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(lint)
41 __RCSID("$NetBSD: xlint.c,v 1.43 2010/03/22 01:29:30 mrg Exp $");
42 #endif
43 
44 #include <sys/param.h>
45 #include <sys/wait.h>
46 #include <sys/stat.h>
47 #include <sys/utsname.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <paths.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <util.h>
57 
58 #include "lint.h"
59 #include "pathnames.h"
60 #include "findcc.h"
61 
62 #define DEFAULT_PATH		_PATH_DEFPATH
63 
64 int main(int, char *[]);
65 
66 /* directory for temporary files */
67 static	const	char *tmpdir;
68 
69 /* path name for cpp output */
70 static	char	*cppout;
71 
72 /* file descriptor for cpp output */
73 static	int	cppoutfd = -1;
74 
75 /* files created by 1st pass */
76 static	char	**p1out;
77 
78 /* input files for 2nd pass (without libraries) */
79 static	char	**p2in;
80 
81 /* library which will be created by 2nd pass */
82 static	char	*p2out;
83 
84 /* flags always passed to cc(1) */
85 static	char	**cflags;
86 
87 /* flags for cc(1), controled by sflag/tflag */
88 static	char	**lcflags;
89 
90 /* flags for lint1 */
91 static	char	**l1flags;
92 
93 /* flags for lint2 */
94 static	char	**l2flags;
95 
96 /* libraries for lint2 */
97 static	char	**l2libs;
98 
99 /* default libraries */
100 static	char	**deflibs;
101 
102 /* additional libraries */
103 static	char	**libs;
104 
105 /* search path for libraries */
106 static	char	**libsrchpath;
107 
108 static  char	*libexec_path;
109 
110 /* flags */
111 static	int	iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag, Sflag;
112 
113 /* print the commands executed to run the stages of compilation */
114 static	int	Vflag;
115 
116 /* filename for oflag */
117 static	char	*outputfn;
118 
119 /* reset after first .c source has been processed */
120 static	int	first = 1;
121 
122 /*
123  * name of a file which is currently written by a child and should
124  * be removed after abnormal termination of the child
125  */
126 static	const	char *currfn;
127 
128 #if !defined(TARGET_PREFIX)
129 #define	TARGET_PREFIX	""
130 #endif
131 static const char target_prefix[] = TARGET_PREFIX;
132 
133 static	void	appstrg(char ***, char *);
134 static	void	appcstrg(char ***, const char *);
135 static	void	applst(char ***, char *const *);
136 static	void	freelst(char ***);
137 static	char	*concat2(const char *, const char *);
138 static	char	*concat3(const char *, const char *, const char *);
139 static	void	terminate(int) __attribute__((__noreturn__));
140 static	const	char *lbasename(const char *, int);
141 static	void	appdef(char ***, const char *);
142 static	void	usage(void);
143 static	void	fname(const char *);
144 static	void	runchild(const char *, char *const *, const char *, int);
145 static	void	findlibs(char *const *);
146 static	int	rdok(const char *);
147 static	void	lint2(void);
148 static	void	cat(char *const *, const char *);
149 
150 /*
151  * Some functions to deal with lists of strings.
152  * Take care that we get no surprises in case of asynchronous signals.
153  */
154 static void
155 appstrg(char ***lstp, char *s)
156 {
157 	char	**lst, **olst;
158 	int	i;
159 
160 	olst = *lstp;
161 	for (i = 0; olst[i] != NULL; i++)
162 		continue;
163 	lst = xrealloc(olst, (i + 2) * sizeof (char *));
164 	lst[i] = s;
165 	lst[i + 1] = NULL;
166 	*lstp = lst;
167 }
168 
169 static void
170 appcstrg(char ***lstp, const char *s)
171 {
172 
173 	appstrg(lstp, xstrdup(s));
174 }
175 
176 static void
177 applst(char ***destp, char *const *src)
178 {
179 	int	i, k;
180 	char	**dest, **odest;
181 
182 	odest = *destp;
183 	for (i = 0; odest[i] != NULL; i++)
184 		continue;
185 	for (k = 0; src[k] != NULL; k++)
186 		continue;
187 	dest = xrealloc(odest, (i + k + 1) * sizeof (char *));
188 	for (k = 0; src[k] != NULL; k++)
189 		dest[i + k] = xstrdup(src[k]);
190 	dest[i + k] = NULL;
191 	*destp = dest;
192 }
193 
194 static void
195 freelst(char ***lstp)
196 {
197 	char	*s;
198 	int	i;
199 
200 	for (i = 0; (*lstp)[i] != NULL; i++)
201 		continue;
202 	while (i-- > 0) {
203 		s = (*lstp)[i];
204 		(*lstp)[i] = NULL;
205 		free(s);
206 	}
207 }
208 
209 static char *
210 concat2(const char *s1, const char *s2)
211 {
212 	char	*s;
213 
214 	s = xmalloc(strlen(s1) + strlen(s2) + 1);
215 	(void)strcpy(s, s1);
216 	(void)strcat(s, s2);
217 
218 	return (s);
219 }
220 
221 static char *
222 concat3(const char *s1, const char *s2, const char *s3)
223 {
224 	char	*s;
225 
226 	s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
227 	(void)strcpy(s, s1);
228 	(void)strcat(s, s2);
229 	(void)strcat(s, s3);
230 
231 	return (s);
232 }
233 
234 /*
235  * Clean up after a signal.
236  */
237 static void
238 terminate(int signo)
239 {
240 	int	i;
241 
242 	if (cppoutfd != -1)
243 		(void)close(cppoutfd);
244 	if (cppout != NULL)
245 		(void)remove(cppout);
246 
247 	if (p1out != NULL) {
248 		for (i = 0; p1out[i] != NULL; i++)
249 			(void)remove(p1out[i]);
250 	}
251 
252 	if (p2out != NULL)
253 		(void)remove(p2out);
254 
255 	if (currfn != NULL)
256 		(void)remove(currfn);
257 
258 	if (signo != 0)
259 		(void)raise_default_signal(signo);
260 	exit(signo != 0 ? 1 : 0);
261 }
262 
263 /*
264  * Returns a pointer to the last component of strg after delim.
265  * Returns strg if the string does not contain delim.
266  */
267 static const char *
268 lbasename(const char *strg, int delim)
269 {
270 	const	char *cp, *cp1, *cp2;
271 
272 	cp = cp1 = cp2 = strg;
273 	while (*cp != '\0') {
274 		if (*cp++ == delim) {
275 			cp2 = cp1;
276 			cp1 = cp;
277 		}
278 	}
279 	return (*cp1 == '\0' ? cp2 : cp1);
280 }
281 
282 static void
283 appdef(char ***lstp, const char *def)
284 {
285 
286 	appstrg(lstp, concat2("-D__", def));
287 	appstrg(lstp, concat3("-D__", def, "__"));
288 }
289 
290 static void
291 usage(void)
292 {
293 
294 	(void)fprintf(stderr,
295 	    "Usage: %s [-abceghprvwxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]]"
296 	    " [-Uname] [-X <id>[,<id>]...\n", getprogname());
297 	(void)fprintf(stderr,
298 	    "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
299 	    " file...\n");
300 	(void)fprintf(stderr,
301 	    "       %s [-abceghprvwzHFS] [|-s|-t] -Clibrary [-Dname[=def]]\n"
302 	    " [-X <id>[,<id>]...\n", getprogname());
303 	(void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file"
304 	    " ...\n");
305 	terminate(-1);
306 }
307 
308 
309 int
310 main(int argc, char *argv[])
311 {
312 	int	c;
313 	char	flgbuf[3], *tmp;
314 	size_t	len;
315 	const char *ks;
316 
317 	setprogname(argv[0]);
318 
319 	if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
320 		tmpdir = xstrdup(_PATH_TMP);
321 	} else {
322 		char *p = xmalloc(len + 2);
323 		(void)sprintf(p, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
324 		tmpdir = p;
325 	}
326 
327 	cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
328 	(void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
329 	cppoutfd = mkstemp(cppout);
330 	if (cppoutfd == -1) {
331 		warn("can't make temp");
332 		terminate(-1);
333 	}
334 
335 	p1out = xcalloc(1, sizeof (char *));
336 	p2in = xcalloc(1, sizeof (char *));
337 	cflags = xcalloc(1, sizeof (char *));
338 	lcflags = xcalloc(1, sizeof (char *));
339 	l1flags = xcalloc(1, sizeof (char *));
340 	l2flags = xcalloc(1, sizeof (char *));
341 	l2libs = xcalloc(1, sizeof (char *));
342 	deflibs = xcalloc(1, sizeof (char *));
343 	libs = xcalloc(1, sizeof (char *));
344 	libsrchpath = xcalloc(1, sizeof (char *));
345 
346 	appcstrg(&cflags, "-E");
347 	appcstrg(&cflags, "-x");
348 	appcstrg(&cflags, "c");
349 #if 0
350 	appcstrg(&cflags, "-D__attribute__(x)=");
351 	appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0");
352 #else
353 	appcstrg(&cflags, "-U__GNUC__");
354 	appcstrg(&cflags, "-U__PCC__");
355 #endif
356 #if 0
357 	appcstrg(&cflags, "-Wp,-$");
358 #endif
359 	appcstrg(&cflags, "-Wp,-CC");
360 	appcstrg(&cflags, "-Wcomment");
361 	appcstrg(&cflags, "-D__LINT__");
362 	appcstrg(&cflags, "-Dlint");		/* XXX don't def. with -s */
363 
364 	appdef(&cflags, "lint");
365 
366 	appcstrg(&deflibs, "c");
367 
368 	if (signal(SIGHUP, terminate) == SIG_IGN)
369 		(void)signal(SIGHUP, SIG_IGN);
370 	(void)signal(SIGINT, terminate);
371 	(void)signal(SIGQUIT, terminate);
372 	(void)signal(SIGTERM, terminate);
373 	while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:M:PSU:VX:")) != -1) {
374 		switch (c) {
375 
376 		case 'a':
377 		case 'b':
378 		case 'c':
379 		case 'e':
380 		case 'g':
381 		case 'r':
382 		case 'v':
383 		case 'w':
384 		case 'z':
385 			(void)sprintf(flgbuf, "-%c", c);
386 			appcstrg(&l1flags, flgbuf);
387 			break;
388 
389 		case 'F':
390 			Fflag = 1;
391 			/* FALLTHROUGH */
392 		case 'u':
393 		case 'h':
394 			(void)sprintf(flgbuf, "-%c", c);
395 			appcstrg(&l1flags, flgbuf);
396 			appcstrg(&l2flags, flgbuf);
397 			break;
398 
399 		case 'X':
400 			(void)sprintf(flgbuf, "-%c", c);
401 			appcstrg(&l1flags, flgbuf);
402 			appcstrg(&l1flags, optarg);
403 			break;
404 
405 		case 'i':
406 			if (Cflag)
407 				usage();
408 			iflag = 1;
409 			break;
410 
411 		case 'n':
412 			freelst(&deflibs);
413 			break;
414 
415 		case 'p':
416 			appcstrg(&l1flags, "-p");
417 			appcstrg(&l2flags, "-p");
418 			if (*deflibs != NULL) {
419 				freelst(&deflibs);
420 				appcstrg(&deflibs, "c");
421 			}
422 			break;
423 
424 		case 'P':
425 			appcstrg(&l1flags, "-P");
426 			break;
427 
428 		case 's':
429 			if (tflag)
430 				usage();
431 			freelst(&lcflags);
432 			appcstrg(&lcflags, "-trigraphs");
433 			appcstrg(&lcflags, "-Wtrigraphs");
434 			appcstrg(&lcflags, "-pedantic");
435 			appcstrg(&lcflags, "-D__STRICT_ANSI__");
436 			appcstrg(&l1flags, "-s");
437 			appcstrg(&l2flags, "-s");
438 			sflag = 1;
439 			break;
440 
441 		case 'S':
442 			if (tflag)
443 				usage();
444 			appcstrg(&l1flags, "-S");
445 			Sflag = 1;
446 			break;
447 
448 #if ! HAVE_NBTOOL_CONFIG_H
449 		case 't':
450 			if (sflag)
451 				usage();
452 			freelst(&lcflags);
453 			appcstrg(&lcflags, "-traditional");
454 			appcstrg(&lcflags, "-Wtraditional");
455 			appstrg(&lcflags, concat2("-D", MACHINE));
456 			appstrg(&lcflags, concat2("-D", MACHINE_ARCH));
457 			appcstrg(&l1flags, "-t");
458 			appcstrg(&l2flags, "-t");
459 			tflag = 1;
460 			break;
461 #endif
462 
463 		case 'x':
464 			appcstrg(&l2flags, "-x");
465 			break;
466 
467 		case 'C':
468 			if (Cflag || oflag || iflag)
469 				usage();
470 			Cflag = 1;
471 			appstrg(&l2flags, concat2("-C", optarg));
472 			p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
473 			(void)sprintf(p2out, "llib-l%s.ln", optarg);
474 			freelst(&deflibs);
475 			break;
476 
477 		case 'd':
478 			if (dflag)
479 				usage();
480 			dflag = 1;
481 			appcstrg(&cflags, "-nostdinc");
482 			appcstrg(&cflags, "-isystem");
483 			appcstrg(&cflags, optarg);
484 			break;
485 
486 		case 'D':
487 		case 'I':
488 		case 'M':
489 		case 'U':
490 			(void)sprintf(flgbuf, "-%c", c);
491 			appstrg(&cflags, concat2(flgbuf, optarg));
492 			break;
493 
494 		case 'l':
495 			appcstrg(&libs, optarg);
496 			break;
497 
498 		case 'o':
499 			if (Cflag || oflag)
500 				usage();
501 			oflag = 1;
502 			outputfn = xstrdup(optarg);
503 			break;
504 
505 		case 'L':
506 			appcstrg(&libsrchpath, optarg);
507 			break;
508 
509 		case 'H':
510 			appcstrg(&l2flags, "-H");
511 			break;
512 
513 		case 'B':
514 			Bflag = 1;
515 			libexec_path = xstrdup(optarg);
516 			break;
517 
518 		case 'V':
519 			Vflag = 1;
520 			break;
521 
522 		default:
523 			usage();
524 			/* NOTREACHED */
525 		}
526 	}
527 	argc -= optind;
528 	argv += optind;
529 
530 	/*
531 	 * To avoid modifying getopt(3)'s state engine midstream, we
532 	 * explicitly accept just a few options after the first source file.
533 	 *
534 	 * In particular, only -l<lib> and -L<libdir> (and these with a space
535 	 * after -l or -L) are allowed.
536 	 */
537 	while (argc > 0) {
538 		const char *arg = argv[0];
539 
540 		if (arg[0] == '-') {
541 			char ***list;
542 
543 			list = NULL;	/* XXXGCC -Wuninitialized */
544 
545 			/* option */
546 			switch (arg[1]) {
547 			case 'l':
548 				list = &libs;
549 				break;
550 
551 			case 'L':
552 				list = &libsrchpath;
553 				break;
554 
555 			default:
556 				usage();
557 				/* NOTREACHED */
558 			}
559 			if (arg[2])
560 				appcstrg(list, arg + 2);
561 			else if (argc > 1) {
562 				argc--;
563 				appcstrg(list, *++argv);
564 			} else
565 				usage();
566 		} else {
567 			/* filename */
568 			fname(arg);
569 			first = 0;
570 		}
571 		argc--;
572 		argv++;
573 	}
574 
575 	if (first)
576 		usage();
577 
578 	if (iflag)
579 		terminate(0);
580 
581 	if (!oflag) {
582 		if ((ks = getenv("LIBDIR")) == NULL || strlen(ks) == 0)
583 			ks = PATH_LINTLIB;
584 		appcstrg(&libsrchpath, ks);
585 		findlibs(libs);
586 		findlibs(deflibs);
587 	}
588 
589 	(void)printf("Lint pass2:\n");
590 	lint2();
591 
592 	if (oflag)
593 		cat(p2in, outputfn);
594 
595 	if (Cflag)
596 		p2out = NULL;
597 
598 	terminate(0);
599 	/* NOTREACHED */
600 }
601 
602 /*
603  * Read a file name from the command line
604  * and pass it through lint1 if it is a C source.
605  */
606 static void
607 fname(const char *name)
608 {
609 	const	char *bn, *suff;
610 	char	**args, *ofn, *pathname;
611 	const char *CC;
612 	size_t	len;
613 	int is_stdin;
614 	int	fd;
615 
616 	is_stdin = (strcmp(name, "-") == 0);
617 	bn = lbasename(name, '/');
618 	suff = lbasename(bn, '.');
619 
620 	if (strcmp(suff, "ln") == 0) {
621 		/* only for lint2 */
622 		if (!iflag)
623 			appcstrg(&p2in, name);
624 		return;
625 	}
626 
627 	if (!is_stdin && strcmp(suff, "c") != 0 &&
628 	    (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
629 		warnx("unknown file type: %s", name);
630 		return;
631 	}
632 
633 	if (!iflag || !first)
634 		(void)printf("%s:\n",
635 		    is_stdin ? "{standard input}" : Fflag ? name : bn);
636 
637 	/* build the name of the output file of lint1 */
638 	if (oflag) {
639 		ofn = outputfn;
640 		outputfn = NULL;
641 		oflag = 0;
642 	} else if (iflag) {
643 		if (is_stdin) {
644 			warnx("-i not supported without -o for standard input");
645 			return;
646 		}
647 		ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
648 		len = bn == suff ? strlen(bn) : (size_t)((suff - 1) - bn);
649 		(void)sprintf(ofn, "%.*s", (int)len, bn);
650 		(void)strcat(ofn, ".ln");
651 	} else {
652 		ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
653 		(void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
654 		fd = mkstemp(ofn);
655 		if (fd == -1) {
656 			warn("can't make temp");
657 			terminate(-1);
658 		}
659 		close(fd);
660 	}
661 	if (!iflag)
662 		appcstrg(&p1out, ofn);
663 
664 	args = xcalloc(1, sizeof (char *));
665 
666 	/* run cc */
667 	if ((CC = getenv("CC")) == NULL)
668 		CC = DEFAULT_CC;
669 	if ((pathname = findcc(CC)) == NULL)
670 		if (!setenv("PATH", DEFAULT_PATH, 1))
671 			pathname = findcc(CC);
672 	if (pathname == NULL) {
673 		(void)fprintf(stderr, "%s: %s: not found\n", getprogname(), CC);
674 		exit(EXIT_FAILURE);
675 	}
676 
677 	appcstrg(&args, pathname);
678 	applst(&args, cflags);
679 	applst(&args, lcflags);
680 	appcstrg(&args, name);
681 
682 	/* we reuse the same tmp file for cpp output, so rewind and truncate */
683 	if (lseek(cppoutfd, SEEK_SET, (off_t)0) != 0) {
684 		warn("lseek");
685 		terminate(-1);
686 	}
687 	if (ftruncate(cppoutfd, (off_t)0) != 0) {
688 		warn("ftruncate");
689 		terminate(-1);
690 	}
691 
692 	runchild(pathname, args, cppout, cppoutfd);
693 	free(pathname);
694 	freelst(&args);
695 
696 	/* run lint1 */
697 
698 	if (!Bflag) {
699 		pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") +
700 		    strlen(target_prefix));
701 		(void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC,
702 		    target_prefix);
703 	} else {
704 		/*
705 		 * XXX Unclear whether we should be using target_prefix
706 		 * XXX here.  --thorpej@wasabisystems.com
707 		 */
708 		pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1"));
709 		(void)sprintf(pathname, "%s/lint1", libexec_path);
710 	}
711 
712 	appcstrg(&args, pathname);
713 	applst(&args, l1flags);
714 	appcstrg(&args, cppout);
715 	appcstrg(&args, ofn);
716 
717 	runchild(pathname, args, ofn, -1);
718 	free(pathname);
719 	freelst(&args);
720 
721 	appcstrg(&p2in, ofn);
722 	free(ofn);
723 
724 	free(args);
725 }
726 
727 static void
728 runchild(const char *path, char *const *args, const char *crfn, int fdout)
729 {
730 	int	status, rv, signo, i;
731 
732 	if (Vflag) {
733 		for (i = 0; args[i] != NULL; i++)
734 			(void)printf("%s ", args[i]);
735 		(void)printf("\n");
736 	}
737 
738 	currfn = crfn;
739 
740 	(void)fflush(stdout);
741 
742 	switch (vfork()) {
743 	case -1:
744 		warn("cannot fork");
745 		terminate(-1);
746 		/* NOTREACHED */
747 	default:
748 		/* parent */
749 		break;
750 	case 0:
751 		/* child */
752 
753 		/* setup the standard output if necessary */
754 		if (fdout != -1) {
755 			dup2(fdout, STDOUT_FILENO);
756 			close(fdout);
757 		}
758 		(void)execvp(path, args);
759 		warn("cannot exec %s", path);
760 		_exit(1);
761 		/* NOTREACHED */
762 	}
763 
764 	while ((rv = wait(&status)) == -1 && errno == EINTR) ;
765 	if (rv == -1) {
766 		warn("wait");
767 		terminate(-1);
768 	}
769 	if (WIFSIGNALED(status)) {
770 		signo = WTERMSIG(status);
771 #if HAVE_DECL_SYS_SIGNAME
772 		warnx("%s got SIG%s", path, sys_signame[signo]);
773 #else
774 		warnx("%s got signal %d", path, signo);
775 #endif
776 		terminate(-1);
777 	}
778 	if (WEXITSTATUS(status) != 0)
779 		terminate(-1);
780 	currfn = NULL;
781 }
782 
783 static void
784 findlibs(char *const *liblst)
785 {
786 	int	i, k;
787 	const	char *lib, *path;
788 	char	*lfn;
789 	size_t	len;
790 
791 	lfn = NULL;
792 
793 	for (i = 0; (lib = liblst[i]) != NULL; i++) {
794 		for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
795 			len = strlen(path) + strlen(lib);
796 			lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
797 			(void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
798 			if (rdok(lfn))
799 				break;
800 			lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
801 			(void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
802 			if (rdok(lfn))
803 				break;
804 		}
805 		if (path != NULL) {
806 			appstrg(&l2libs, concat2("-l", lfn));
807 		} else {
808 			warnx("cannot find llib-l%s.ln", lib);
809 		}
810 	}
811 
812 	free(lfn);
813 }
814 
815 static int
816 rdok(const char *path)
817 {
818 	struct	stat sbuf;
819 
820 	if (stat(path, &sbuf) == -1)
821 		return (0);
822 	if (!S_ISREG(sbuf.st_mode))
823 		return (0);
824 	if (access(path, R_OK) == -1)
825 		return (0);
826 	return (1);
827 }
828 
829 static void
830 lint2(void)
831 {
832 	char	*path, **args;
833 
834 	args = xcalloc(1, sizeof (char *));
835 
836 	if (!Bflag) {
837 		path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") +
838 		    strlen(target_prefix));
839 		(void)sprintf(path, "%s/%slint2", PATH_LIBEXEC,
840 		    target_prefix);
841 	} else {
842 		/*
843 		 * XXX Unclear whether we should be using target_prefix
844 		 * XXX here.  --thorpej@wasabisystems.com
845 		 */
846 		path = xmalloc(strlen(libexec_path) + sizeof ("/lint2"));
847 		(void)sprintf(path, "%s/lint2", libexec_path);
848 	}
849 
850 	appcstrg(&args, path);
851 	applst(&args, l2flags);
852 	applst(&args, l2libs);
853 	applst(&args, p2in);
854 
855 	runchild(path, args, p2out, -1);
856 	free(path);
857 	freelst(&args);
858 	free(args);
859 }
860 
861 static void
862 cat(char *const *srcs, const char *dest)
863 {
864 	int	ifd, ofd, i;
865 	char	*src, *buf;
866 	ssize_t	rlen;
867 
868 	if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
869 		warn("cannot open %s", dest);
870 		terminate(-1);
871 	}
872 
873 	buf = xmalloc(MBLKSIZ);
874 
875 	for (i = 0; (src = srcs[i]) != NULL; i++) {
876 		if ((ifd = open(src, O_RDONLY)) == -1) {
877 			free(buf);
878 			warn("cannot open %s", src);
879 			terminate(-1);
880 		}
881 		do {
882 			if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
883 				free(buf);
884 				warn("read error on %s", src);
885 				terminate(-1);
886 			}
887 			if (write(ofd, buf, (size_t)rlen) == -1) {
888 				free(buf);
889 				warn("write error on %s", dest);
890 				terminate(-1);
891 			}
892 		} while (rlen == MBLKSIZ);
893 		(void)close(ifd);
894 	}
895 	(void)close(ofd);
896 	free(buf);
897 }
898