]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.bin/xlint/xlint/xlint.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.bin / xlint / xlint / xlint.c
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
60 int main(int, char *[]);
61
62 /* directory for temporary files */
63 static  const   char *tmpdir;
64
65 /* path name for cpp output */
66 static  char    *cppout;
67
68 /* file descriptor for cpp output */
69 static  int     cppoutfd = -1;
70
71 /* files created by 1st pass */
72 static  char    **p1out;
73
74 /* input files for 2nd pass (without libraries) */
75 static  char    **p2in;
76
77 /* library which will be created by 2nd pass */
78 static  char    *p2out;
79
80 /* flags always passed to cc(1) */
81 static  char    **cflags;
82
83 /* flags for cc(1), controlled by sflag/tflag */
84 static  char    **lcflags;
85
86 /* flags for lint1 */
87 static  char    **l1flags;
88
89 /* flags for lint2 */
90 static  char    **l2flags;
91
92 /* libraries for lint2 */
93 static  char    **l2libs;
94
95 /* default libraries */
96 static  char    **deflibs;
97
98 /* additional libraries */
99 static  char    **libs;
100
101 /* search path for libraries */
102 static  char    **libsrchpath;
103
104 static  char    *libexec_path;
105
106 /* flags */
107 static  int     iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag, Sflag;
108
109 /* print the commands executed to run the stages of compilation */
110 static  int     Vflag;
111
112 /* filename for oflag */
113 static  char    *outputfn;
114
115 /* reset after first .c source has been processed */
116 static  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  */
122 static  const   char *currfn;
123
124 #if !defined(TARGET_PREFIX)
125 #define TARGET_PREFIX   ""
126 #endif
127 static const char target_prefix[] = TARGET_PREFIX;
128
129 static  void    appstrg(char ***, char *);
130 static  void    appcstrg(char ***, const char *);
131 static  void    applst(char ***, char *const *);
132 static  void    freelst(char ***);
133 static  char    *concat2(const char *, const char *);
134 static  char    *concat3(const char *, const char *, const char *);
135 static  void    terminate(int) __attribute__((__noreturn__));
136 static  const   char *lbasename(const char *, int);
137 static  void    appdef(char ***, const char *);
138 static  void    usage(void) __dead2;
139 static  void    fname(const char *);
140 static  void    runchild(const char *, char *const *, const char *, int);
141 static  void    findlibs(char *const *);
142 static  int     rdok(const char *);
143 static  void    lint2(void);
144 static  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  */
150 static void
151 appstrg(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
165 static void
166 appcstrg(char ***lstp, const char *s)
167 {
168
169         appstrg(lstp, xstrdup(s));
170 }
171
172 static void
173 applst(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
190 static void
191 freelst(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
205 static char *
206 concat2(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
217 static char *
218 concat3(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  */
233 static void
234 terminate(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  */
261 static const char *
262 lbasename(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
276 static void
277 appdef(char ***lstp, const char *def)
278 {
279
280         appstrg(lstp, concat2("-D__", def));
281         appstrg(lstp, concat3("-D__", def, "__"));
282 }
283
284 static void
285 usage(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
303 int
304 main(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  */
593 static void
594 fname(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
713 static void
714 runchild(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
769 static void
770 findlibs(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
801 static int
802 rdok(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
815 static void
816 lint2(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
847 static void
848 cat(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 }