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