]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/xlint/xlint/xlint.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / xlint / xlint / xlint.c
1 /* $NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv 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.27 2002/01/31 19:09:33 tv 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;
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 asyncron 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 [-abceghprvwxzHF] [-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 [-abceghprvwzHF] [-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         appcstrg(&cflags, "-Wp,-C");
349         appcstrg(&cflags, "-Wcomment");
350         appcstrg(&cflags, "-D__LINT__");
351         appcstrg(&cflags, "-Dlint");            /* XXX don't def. with -s */
352
353         appdef(&cflags, "lint");
354
355         appcstrg(&deflibs, "c");
356
357         if (signal(SIGHUP, terminate) == SIG_IGN)
358                 (void)signal(SIGHUP, SIG_IGN);
359         (void)signal(SIGINT, terminate);
360         (void)signal(SIGQUIT, terminate);
361         (void)signal(SIGTERM, terminate);
362
363         while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:U:VX:")) != -1) {
364                 switch (c) {
365
366                 case 'a':
367                 case 'b':
368                 case 'c':
369                 case 'e':
370                 case 'g':
371                 case 'r':
372                 case 'v':
373                 case 'w':
374                 case 'z':
375                         (void)sprintf(flgbuf, "-%c", c);
376                         appcstrg(&l1flags, flgbuf);
377                         break;
378
379                 case 'F':
380                         Fflag = 1;
381                         /* FALLTHROUGH */
382                 case 'u':
383                 case 'h':
384                         (void)sprintf(flgbuf, "-%c", c);
385                         appcstrg(&l1flags, flgbuf);
386                         appcstrg(&l2flags, flgbuf);
387                         break;
388
389                 case 'X':
390                         (void)sprintf(flgbuf, "-%c", c);
391                         appcstrg(&l1flags, flgbuf);
392                         appcstrg(&l1flags, optarg);
393                         break;
394
395                 case 'i':
396                         if (Cflag)
397                                 usage();
398                         iflag = 1;
399                         break;
400
401                 case 'n':
402                         freelst(&deflibs);
403                         break;
404
405                 case 'p':
406                         appcstrg(&lcflags, "-Wtraditional");
407                         appcstrg(&lcflags, "-Wno-system-headers");
408                         appcstrg(&l1flags, "-p");
409                         appcstrg(&l2flags, "-p");
410                         if (*deflibs != NULL) {
411                                 freelst(&deflibs);
412                                 appcstrg(&deflibs, "c");
413                         }
414                         break;
415
416                 case 's':
417                         if (tflag)
418                                 usage();
419                         freelst(&lcflags);
420                         appcstrg(&lcflags, "-trigraphs");
421                         appcstrg(&lcflags, "-Wtrigraphs");
422                         appcstrg(&lcflags, "-pedantic");
423                         appcstrg(&lcflags, "-D__STRICT_ANSI__");
424                         appcstrg(&l1flags, "-s");
425                         appcstrg(&l2flags, "-s");
426                         sflag = 1;
427                         break;
428
429 #if !HAVE_CONFIG_H
430                 case 't':
431                         if (sflag)
432                                 usage();
433                         freelst(&lcflags);
434                         appcstrg(&lcflags, "-traditional");
435                         appstrg(&lcflags, concat2("-D", MACHINE));
436                         appstrg(&lcflags, concat2("-D", MACHINE_ARCH));
437                         appcstrg(&l1flags, "-t");
438                         appcstrg(&l2flags, "-t");
439                         tflag = 1;
440                         break;
441 #endif
442
443                 case 'x':
444                         appcstrg(&l2flags, "-x");
445                         break;
446
447                 case 'C':
448                         if (Cflag || oflag || iflag)
449                                 usage();
450                         Cflag = 1;
451                         appstrg(&l2flags, concat2("-C", optarg));
452                         p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
453                         (void)sprintf(p2out, "llib-l%s.ln", optarg);
454                         freelst(&deflibs);
455                         break;
456
457                 case 'd':
458                         if (dflag)
459                                 usage();
460                         dflag = 1;
461                         appcstrg(&cflags, "-nostdinc");
462                         appcstrg(&cflags, "-idirafter");
463                         appcstrg(&cflags, optarg);
464                         break;
465
466                 case 'D':
467                 case 'I':
468                 case 'U':
469                         (void)sprintf(flgbuf, "-%c", c);
470                         appstrg(&cflags, concat2(flgbuf, optarg));
471                         break;
472
473                 case 'l':
474                         appcstrg(&libs, optarg);
475                         break;
476
477                 case 'o':
478                         if (Cflag || oflag)
479                                 usage();
480                         oflag = 1;
481                         outputfn = xstrdup(optarg);
482                         break;
483
484                 case 'L':
485                         appcstrg(&libsrchpath, optarg);
486                         break;
487
488                 case 'H':
489                         appcstrg(&l2flags, "-H");
490                         break;
491
492                 case 'B':
493                         Bflag = 1;
494                         libexec_path = xstrdup(optarg);
495                         break;
496
497                 case 'V':
498                         Vflag = 1;
499                         break;
500
501                 default:
502                         usage();
503                         /* NOTREACHED */
504                 }
505         }
506         argc -= optind;
507         argv += optind;
508
509         /*
510          * To avoid modifying getopt(3)'s state engine midstream, we
511          * explicitly accept just a few options after the first source file.
512          *
513          * In particular, only -l<lib> and -L<libdir> (and these with a space
514          * after -l or -L) are allowed.
515          */
516         while (argc > 0) {
517                 const char *arg = argv[0];
518
519                 if (arg[0] == '-') {
520                         char ***list;
521
522                         /* option */
523                         switch (arg[1]) {
524                         case 'l':
525                                 list = &libs;
526                                 break;
527
528                         case 'L':
529                                 list = &libsrchpath;
530                                 break;
531
532                         default:
533                                 usage();
534                                 /* NOTREACHED */
535                         }
536                         if (arg[2])
537                                 appcstrg(list, arg + 2);
538                         else if (argc > 1) {
539                                 argc--;
540                                 appcstrg(list, *++argv);
541                         } else
542                                 usage();
543                 } else {
544                         /* filename */
545                         fname(arg);
546                         first = 0;
547                 }
548                 argc--;
549                 argv++;
550         }
551
552         if (first)
553                 usage();
554
555         if (iflag)
556                 terminate(0);
557
558         if (!oflag) {
559                 if ((tmp = getenv("LIBDIR")) == NULL || strlen(tmp) == 0)
560                         tmp = PATH_LINTLIB;
561                 appcstrg(&libsrchpath, tmp);
562                 findlibs(libs);
563                 findlibs(deflibs);
564         }
565
566         (void)printf("Lint pass2:\n");
567         lint2();
568
569         if (oflag)
570                 cat(p2in, outputfn);
571
572         if (Cflag)
573                 p2out = NULL;
574
575         terminate(0);
576         /* NOTREACHED */
577 }
578
579 /*
580  * Read a file name from the command line
581  * and pass it through lint1 if it is a C source.
582  */
583 static void
584 fname(const char *name)
585 {
586         const   char *bn, *suff;
587         char    **args, *ofn, *p, *pathname;
588         size_t  len;
589         int is_stdin;
590         int     fd;
591
592         is_stdin = (strcmp(name, "-") == 0);
593         bn = lbasename(name, '/');
594         suff = lbasename(bn, '.');
595
596         if (strcmp(suff, "ln") == 0) {
597                 /* only for lint2 */
598                 if (!iflag)
599                         appcstrg(&p2in, name);
600                 return;
601         }
602
603         if (!is_stdin && strcmp(suff, "c") != 0 &&
604             (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
605                 warnx("unknown file type: %s\n", name);
606                 return;
607         }
608
609         if (!iflag || !first)
610                 (void)printf("%s:\n",
611                     is_stdin ? "{standard input}" : Fflag ? name : bn);
612
613         /* build the name of the output file of lint1 */
614         if (oflag) {
615                 ofn = outputfn;
616                 outputfn = NULL;
617                 oflag = 0;
618         } else if (iflag) {
619                 if (is_stdin) {
620                         warnx("-i not supported without -o for standard input");
621                         return;
622                 }
623                 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
624                 len = bn == suff ? strlen(bn) : (size_t)((suff - 1) - bn);
625                 (void)sprintf(ofn, "%.*s", (int)len, bn);
626                 (void)strcat(ofn, ".ln");
627         } else {
628                 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
629                 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
630                 fd = mkstemp(ofn);
631                 if (fd == -1) {
632                         warn("can't make temp");
633                         terminate(-1);
634                 }
635                 close(fd);
636         }
637         if (!iflag)
638                 appcstrg(&p1out, ofn);
639
640         args = xcalloc(1, sizeof (char *));
641
642         /* run cc */
643
644         if (getenv("CC") == NULL) {
645                 pathname = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc"));
646                 (void)sprintf(pathname, "%s/cc", PATH_USRBIN);
647                 appcstrg(&args, pathname);
648         } else {
649                 pathname = strdup(getenv("CC"));
650                 for (p = strtok(pathname, " \t"); p; p = strtok(NULL, " \t"))
651                         appcstrg(&args, p);
652         }
653
654         applst(&args, cflags);
655         applst(&args, lcflags);
656         appcstrg(&args, name);
657
658         /* we reuse the same tmp file for cpp output, so rewind and truncate */
659         if (lseek(cppoutfd, (off_t)0, SEEK_SET) != 0) {
660                 warn("lseek");
661                 terminate(-1);
662         }
663         if (ftruncate(cppoutfd, (off_t)0) != 0) {
664                 warn("ftruncate");
665                 terminate(-1);
666         }
667
668         runchild(pathname, args, cppout, cppoutfd);
669         free(pathname);
670         freelst(&args);
671
672         /* run lint1 */
673
674         if (!Bflag) {
675                 pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") +
676                     strlen(target_prefix));
677                 (void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC,
678                     target_prefix);
679         } else {
680                 /*
681                  * XXX Unclear whether we should be using target_prefix
682                  * XXX here.  --thorpej@wasabisystems.com
683                  */
684                 pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1"));
685                 (void)sprintf(pathname, "%s/lint1", libexec_path);
686         }
687
688         appcstrg(&args, pathname);
689         applst(&args, l1flags);
690         appcstrg(&args, cppout);
691         appcstrg(&args, ofn);
692
693         runchild(pathname, args, ofn, -1);
694         free(pathname);
695         freelst(&args);
696
697         appcstrg(&p2in, ofn);
698         free(ofn);
699
700         free(args);
701 }
702
703 static void
704 runchild(const char *path, char *const *args, const char *crfn, int fdout)
705 {
706         int     status, rv, signo, i;
707
708         if (Vflag) {
709                 for (i = 0; args[i] != NULL; i++)
710                         (void)printf("%s ", args[i]);
711                 (void)printf("\n");
712         }
713
714         currfn = crfn;
715
716         (void)fflush(stdout);
717
718         switch (vfork()) {
719         case -1:
720                 warn("cannot fork");
721                 terminate(-1);
722                 /* NOTREACHED */
723         default:
724                 /* parent */
725                 break;
726         case 0:
727                 /* child */
728
729                 /* setup the standard output if necessary */
730                 if (fdout != -1) {
731                         dup2(fdout, STDOUT_FILENO);
732                         close(fdout);
733                 }
734                 (void)execvp(path, args);
735                 warn("cannot exec %s", path);
736                 _exit(1);
737                 /* NOTREACHED */
738         }
739
740         while ((rv = wait(&status)) == -1 && errno == EINTR) ;
741         if (rv == -1) {
742                 warn("wait");
743                 terminate(-1);
744         }
745         if (WIFSIGNALED(status)) {
746                 signo = WTERMSIG(status);
747 #if HAVE_DECL_SYS_SIGNAME
748                 warnx("%s got SIG%s", path, sys_signame[signo]);
749 #else
750                 warnx("%s got signal %d", path, signo);
751 #endif
752                 terminate(-1);
753         }
754         if (WEXITSTATUS(status) != 0)
755                 terminate(-1);
756         currfn = NULL;
757 }
758
759 static void
760 findlibs(char *const *liblst)
761 {
762         int     i, k;
763         const   char *lib, *path;
764         char    *lfn;
765         size_t  len;
766
767         lfn = NULL;
768
769         for (i = 0; (lib = liblst[i]) != NULL; i++) {
770                 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
771                         len = strlen(path) + strlen(lib);
772                         lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
773                         (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
774                         if (rdok(lfn))
775                                 break;
776                         lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
777                         (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
778                         if (rdok(lfn))
779                                 break;
780                 }
781                 if (path != NULL) {
782                         appstrg(&l2libs, concat2("-l", lfn));
783                 } else {
784                         warnx("cannot find llib-l%s.ln", lib);
785                 }
786         }
787
788         free(lfn);
789 }
790
791 static int
792 rdok(const char *path)
793 {
794         struct  stat sbuf;
795
796         if (stat(path, &sbuf) == -1)
797                 return (0);
798         if (!S_ISREG(sbuf.st_mode))
799                 return (0);
800         if (access(path, R_OK) == -1)
801                 return (0);
802         return (1);
803 }
804
805 static void
806 lint2(void)
807 {
808         char    *path, **args;
809
810         args = xcalloc(1, sizeof (char *));
811
812         if (!Bflag) {
813                 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") +
814                     strlen(target_prefix));
815                 (void)sprintf(path, "%s/%slint2", PATH_LIBEXEC,
816                     target_prefix);
817         } else {
818                 /*
819                  * XXX Unclear whether we should be using target_prefix
820                  * XXX here.  --thorpej@wasabisystems.com
821                  */
822                 path = xmalloc(strlen(libexec_path) + sizeof ("/lint2"));
823                 (void)sprintf(path, "%s/lint2", libexec_path);
824         }
825
826         appcstrg(&args, path);
827         applst(&args, l2flags);
828         applst(&args, l2libs);
829         applst(&args, p2in);
830
831         runchild(path, args, p2out, -1);
832         free(path);
833         freelst(&args);
834         free(args);
835 }
836
837 static void
838 cat(char *const *srcs, const char *dest)
839 {
840         int     ifd, ofd, i;
841         char    *src, *buf;
842         ssize_t rlen;
843
844         if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
845                 warn("cannot open %s", dest);
846                 terminate(-1);
847         }
848
849         buf = xmalloc(MBLKSIZ);
850
851         for (i = 0; (src = srcs[i]) != NULL; i++) {
852                 if ((ifd = open(src, O_RDONLY)) == -1) {
853                         free(buf);
854                         warn("cannot open %s", src);
855                         terminate(-1);
856                 }
857                 do {
858                         if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
859                                 free(buf);
860                                 warn("read error on %s", src);
861                                 terminate(-1);
862                         }
863                         if (write(ofd, buf, (size_t)rlen) == -1) {
864                                 free(buf);
865                                 warn("write error on %s", dest);
866                                 terminate(-1);
867                         }
868                 } while (rlen == MBLKSIZ);
869                 (void)close(ifd);
870         }
871         (void)close(ofd);
872         free(buf);
873 }