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