1 /** $MirOS: src/usr.bin/xlint/xlint/xlint.c,v 1.8 2014/03/23 20:57:15 tg Exp $ */
2 /* $OpenBSD: xlint.c,v 1.36 2011/09/21 18:08:07 jsg Exp $ */
3 /* $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $ */
4
5 /*
6 * Copyright (c) 1994, 1995 Jochen Pohl
7 * All Rights Reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Jochen Pohl for
20 * The NetBSD Project.
21 * 4. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <sys/param.h>
37 #include <sys/wait.h>
38 #include <sys/stat.h>
39 #include <sys/utsname.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <signal.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <paths.h>
49
50 #include "lint.h"
51 #include "pathnames.h"
52
53 __RCSID("$MirOS: src/usr.bin/xlint/xlint/xlint.c,v 1.8 2014/03/23 20:57:15 tg Exp $");
54
55 /* directory for temporary files */
56 static const char *tmpdir;
57
58 /* path name for cpp output */
59 static char *cppout;
60
61 /* files created by 1st pass */
62 static char **p1out;
63
64 /* input files for 2nd pass (without libraries) */
65 static char **p2in;
66
67 /* library which will be created by 2nd pass */
68 static char *p2out;
69
70 /* flags always passed to cpp */
71 static char **cppflags;
72
73 /* flags for cpp, controled by sflag/tflag */
74 static char **lcppflgs;
75
76 /* flags for lint1 */
77 static char **l1flags;
78
79 /* flags for lint2 */
80 static char **l2flags;
81
82 /* libraries for lint2 */
83 static char **l2libs;
84
85 /* default libraries */
86 static char **deflibs;
87
88 /* additional libraries */
89 static char **libs;
90
91 /* search path for libraries */
92 static char **libsrchpath;
93
94 /* flags */
95 static int iflag, oflag, Cflag, sflag, tflag, Fflag = 1;
96
97 /* print the commands executed to run the stages of compilation */
98 static int Vflag;
99
100 /* filename for oflag */
101 static char *outputfn;
102
103 /* reset after first .c source has been processed */
104 static int first = 1;
105
106 /*
107 * name of a file which is currently written by a child and should
108 * be removed after abnormal termination of the child
109 */
110 static const char *currfn;
111
112 static void appstrg(char ***, char *);
113 static void appcstrg(char ***, const char *);
114 static void applst(char ***, char *const *);
115 static void freelst(char ***);
116 static char *concat2(const char *, const char *);
117 static char *concat3(const char *, const char *, const char *);
118 static void terminate(int);
119 static const char *lbasename(const char *, int);
120 static void appdef(char ***, const char *);
121 static void usage(void);
122 static void fname(const char *);
123 static int runchild(const char *, char *const *, const char *);
124 static void findlibs(char *const *);
125 static int rdok(const char *);
126 static void lint2(void);
127 static void cat(char *const *, const char *);
128
129 /*
130 * Some functions to deal with lists of strings.
131 * Take care that we get no surprises in case of asynchronous signals.
132 */
133 static void
appstrg(char *** lstp,char * s)134 appstrg(char ***lstp, char *s)
135 {
136 char **lst, **olst;
137 int i;
138
139 olst = *lstp;
140 for (i = 0; olst[i] != NULL; i++) ;
141 lst = xmalloc((i + 2) * sizeof (char *));
142 (void)memcpy(lst, olst, i * sizeof (char *));
143 lst[i] = s;
144 lst[i + 1] = NULL;
145 *lstp = lst;
146 }
147
148 static void
appcstrg(char *** lstp,const char * s)149 appcstrg(char ***lstp, const char *s)
150 {
151 appstrg(lstp, xstrdup(s));
152 }
153
154 static void
applst(char *** destp,char * const * src)155 applst(char ***destp, char *const *src)
156 {
157 int i, k;
158 char **dest, **odest;
159
160 odest = *destp;
161 for (i = 0; odest[i] != NULL; i++) ;
162 for (k = 0; src[k] != NULL; k++) ;
163 dest = xmalloc((i + k + 1) * sizeof (char *));
164 (void)memcpy(dest, odest, i * sizeof (char *));
165 for (k = 0; src[k] != NULL; k++)
166 dest[i + k] = xstrdup(src[k]);
167 dest[i + k] = NULL;
168 *destp = dest;
169 free(odest);
170 }
171
172 static void
freelst(char *** lstp)173 freelst(char ***lstp)
174 {
175 char *s;
176 int i;
177
178 for (i = 0; (*lstp)[i] != NULL; i++) ;
179 while (i-- > 0) {
180 s = (*lstp)[i];
181 (*lstp)[i] = NULL;
182 free(s);
183 }
184 }
185
186 static char *
concat2(const char * s1,const char * s2)187 concat2(const char *s1, const char *s2)
188 {
189 char *s;
190 size_t len = strlen(s1) + strlen(s2) + 1;
191
192 s = xmalloc(len);
193 (void)strlcpy(s, s1, len);
194 (void)strlcat(s, s2, len);
195
196 return (s);
197 }
198
199 static char *
concat3(const char * s1,const char * s2,const char * s3)200 concat3(const char *s1, const char *s2, const char *s3)
201 {
202 char *s;
203 size_t len = strlen(s1) + strlen(s2) + strlen(s3) + 1;
204
205 s = xmalloc(len);
206 (void)strlcpy(s, s1, len);
207 (void)strlcat(s, s2, len);
208 (void)strlcat(s, s3, len);
209
210 return (s);
211 }
212
213 /*
214 * Clean up after a signal.
215 */
216 static void
terminate(int signo)217 terminate(int signo)
218 {
219 int i;
220
221 if (cppout != NULL)
222 (void)remove(cppout);
223
224 if (p1out != NULL) {
225 for (i = 0; p1out[i] != NULL; i++)
226 (void)remove(p1out[i]);
227 }
228
229 if (p2out != NULL)
230 (void)remove(p2out);
231
232 if (currfn != NULL)
233 (void)remove(currfn);
234
235 _exit(signo != 0 ? 1 : 0);
236 }
237
238 /*
239 * Returns a pointer to the last component of strg after delim.
240 * Returns strg if the string does not contain delim.
241 */
242 static const char *
lbasename(const char * strg,int delim)243 lbasename(const char *strg, int delim)
244 {
245 const char *cp, *cp1, *cp2;
246
247 cp = cp1 = cp2 = strg;
248 while (*cp != '\0') {
249 if (*cp++ == delim) {
250 cp2 = cp1;
251 cp1 = cp;
252 }
253 }
254 return (*cp1 == '\0' ? cp2 : cp1);
255 }
256
257 static void
appdef(char *** lstp,const char * def)258 appdef(char ***lstp, const char *def)
259 {
260 appstrg(lstp, concat2("-D__", def));
261 appstrg(lstp, concat3("-D__", def, "__"));
262 }
263
264 static void
usage()265 usage()
266 {
267 (void)printf("usage: lint [-ceFfgHhprsVvxz] [-i | -nu] [-Dname[=def]] [-Idirectory]\n");
268 (void)printf("\t[-Ldirectory] [-llibrary] [-ooutputfile] [-MD] [-Uname] file ...\n");
269 (void)printf(" lint [-ceFfgHhprsVvz] -Clibrary [-Dname[=def]]\n");
270 (void)printf("\t[-Idirectory] [-MD] [-Uname] file ...\n");
271 terminate(-1);
272 }
273
274 int
main(int argc,char * argv[])275 main(int argc, char *argv[])
276 {
277 int c;
278 int fd;
279 char flgbuf[3], *tmp, *s;
280 size_t len;
281 struct utsname un;
282
283 if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
284 tmpdir = xstrdup(_PATH_TMP);
285 } else {
286 s = xmalloc(len + 2);
287 (void)snprintf(s, len + 2, "%s%s",
288 tmp, tmp[len - 1] == '/' ? "" : "/");
289 tmpdir = s;
290 }
291
292 if (asprintf(&cppout, "%slint0.XXXXXXXXXX", tmpdir) == -1)
293 err(1, NULL);
294 if ((fd = mkstemp(cppout)) == -1) {
295 warn("can't make temp");
296 terminate(-1);
297 }
298 close(fd);
299
300 p1out = xcalloc(1, sizeof (char *));
301 p2in = xcalloc(1, sizeof (char *));
302 cppflags = xcalloc(1, sizeof (char *));
303 lcppflgs = xcalloc(1, sizeof (char *));
304 l1flags = xcalloc(1, sizeof (char *));
305 l2flags = xcalloc(1, sizeof (char *));
306 l2libs = xcalloc(1, sizeof (char *));
307 deflibs = xcalloc(1, sizeof (char *));
308 libs = xcalloc(1, sizeof (char *));
309 libsrchpath = xcalloc(1, sizeof (char *));
310
311 appcstrg(&cppflags, "-CC");
312 #ifdef __OpenBSD__
313 appcstrg(&cppflags, "-D__OpenBSD__");
314 #endif
315 #ifdef __MirBSD__
316 appcstrg(&cppflags, "-D__MirBSD__");
317 #endif
318 appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */
319 appdef(&cppflags, "lint");
320 appdef(&cppflags, "unix");
321
322 if (uname(&un) == -1)
323 err(1, "uname");
324 appdef(&cppflags, un.machine);
325 appstrg(&lcppflgs, concat2("-D", un.machine));
326
327 #ifdef MACHINE_ARCH
328 #ifdef MACHINE_CPU
329 if (strcmp(MACHINE_ARCH, MACHINE_CPU) != 0) {
330 appdef(&cppflags, MACHINE_CPU);
331 appstrg(&lcppflgs, concat2("-D", MACHINE_CPU));
332 }
333 #endif
334 if (strcmp(un.machine, MACHINE_ARCH) != 0) {
335 appdef(&cppflags, MACHINE_ARCH);
336 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
337 }
338 #endif
339
340 appcstrg(&deflibs, "c");
341
342 if (signal(SIGHUP, terminate) == SIG_IGN)
343 (void)signal(SIGHUP, SIG_IGN);
344 (void)signal(SIGINT, terminate);
345 (void)signal(SIGQUIT, terminate);
346 (void)signal(SIGTERM, terminate);
347
348 while (argc > optind) {
349 c = getopt(argc, argv, "abcefghil:no:prstuvxyzC:D:FHI:L:M:U:V");
350
351 switch (c) {
352
353 case 'a':
354 case 'b':
355 case 'c':
356 case 'e':
357 case 'f':
358 case 'g':
359 case 'r':
360 case 'v':
361 case 'y':
362 case 'z':
363 (void)snprintf(flgbuf, sizeof flgbuf, "-%c", c);
364 appcstrg(&l1flags, flgbuf);
365 break;
366
367 case 'F':
368 Fflag = 1;
369 /* FALLTHROUGH */
370 case 'u':
371 case 'h':
372 (void)snprintf(flgbuf, sizeof flgbuf, "-%c", c);
373 appcstrg(&l1flags, flgbuf);
374 appcstrg(&l2flags, flgbuf);
375 break;
376
377 case 'i':
378 if (Cflag)
379 usage();
380 iflag = 1;
381 break;
382
383 case 'n':
384 freelst(&deflibs);
385 break;
386
387 case 'p':
388 appcstrg(&l1flags, "-p");
389 appcstrg(&l2flags, "-p");
390 if (*deflibs != NULL) {
391 freelst(&deflibs);
392 appcstrg(&deflibs, "c");
393 }
394 break;
395
396 case 's':
397 if (tflag)
398 usage();
399 freelst(&lcppflgs);
400 appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
401 appcstrg(&l1flags, "-s");
402 appcstrg(&l2flags, "-s");
403 sflag = 1;
404 break;
405
406 case 't':
407 if (sflag)
408 usage();
409 freelst(&lcppflgs);
410 appcstrg(&lcppflgs, "-t");
411 appstrg(&lcppflgs, concat2("-D", MACHINE));
412 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
413 appcstrg(&l1flags, "-t");
414 appcstrg(&l2flags, "-t");
415 tflag = 1;
416 break;
417
418 case 'x':
419 appcstrg(&l2flags, "-x");
420 break;
421
422 case 'C':
423 if (Cflag || oflag || iflag)
424 usage();
425 Cflag = 1;
426 appstrg(&l2flags, concat2("-C", optarg));
427 if (asprintf(&p2out, "llib-l%s.ln", optarg) == -1)
428 err(1, NULL);
429 freelst(&deflibs);
430 break;
431
432 case 'D':
433 case 'I':
434 case 'U':
435 (void)snprintf(flgbuf, sizeof flgbuf, "-%c", c);
436 appstrg(&cppflags, concat2(flgbuf, optarg));
437 break;
438
439 case 'l':
440 appcstrg(&libs, optarg);
441 break;
442
443 case 'o':
444 if (Cflag || oflag)
445 usage();
446 oflag = 1;
447 outputfn = xstrdup(optarg);
448 break;
449
450 case 'L':
451 appcstrg(&libsrchpath, optarg);
452 break;
453
454 case 'M':
455 break;
456
457 case 'H':
458 appcstrg(&l2flags, "-H");
459 break;
460
461 case 'V':
462 Vflag = 1;
463 break;
464
465 case '?':
466 usage();
467 /* NOTREACHED */
468
469 case -1:
470 /* filename */
471 if (argv[optind] == NULL)
472 break;
473 fname(argv[optind++]);
474 first = 0;
475 }
476
477 }
478 argc -= optind;
479 argv += optind;
480
481 if (first)
482 usage();
483
484 if (iflag)
485 terminate(0);
486
487 if (!oflag) {
488 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
489 s = PATH_LINTLIB;
490 appcstrg(&libsrchpath, s);
491 findlibs(libs);
492 findlibs(deflibs);
493 }
494
495 (void)printf("Lint pass2:\n");
496 lint2();
497
498 if (oflag)
499 cat(p2in, outputfn);
500
501 if (Cflag)
502 p2out = NULL;
503
504 terminate(0);
505 /* NOTREACHED */
506 }
507
508 /*
509 * Read a file name from the command line
510 * and pass it through lint1 if it is a C source.
511 */
512 static void
fname(const char * name)513 fname(const char *name)
514 {
515 const char *bn, *suff;
516 char **args, *ofn, *path;
517 size_t len;
518 int error;
519 int fd;
520
521 bn = lbasename(name, '/');
522 suff = lbasename(bn, '.');
523
524 if (strcmp(suff, "ln") == 0) {
525 /* only for lint2 */
526 if (!iflag)
527 appcstrg(&p2in, name);
528 return;
529 }
530
531 if (strcmp(suff, "c") != 0 &&
532 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
533 warnx("unknown file type: %s", name);
534 return;
535 }
536
537 /* build the name of the output file of lint1 */
538 if (oflag) {
539 ofn = outputfn;
540 outputfn = NULL;
541 oflag = 0;
542 } else if (iflag) {
543 len = strlen(bn) + (bn == suff ? 4 : 2);
544 ofn = xmalloc(len);
545 (void)snprintf(ofn, len, "%.*s",
546 (int)(bn == suff ? strlen(bn) : (suff - 1) - bn), bn);
547 (void)strlcat(ofn, ".ln", len);
548 } else {
549 if (asprintf(&ofn, "%slint1.XXXXXXXXXX", tmpdir) == -1)
550 err(1, NULL);
551 if ((fd = mkstemp(ofn)) == -1) {
552 warn("can't make temp");
553 terminate(-1);
554 }
555 close(fd);
556 }
557 if (!iflag)
558 appcstrg(&p1out, ofn);
559
560 args = xcalloc(1, sizeof (char *));
561
562 /* run cpp */
563
564 path = strdup("env");
565 appcstrg(&args, path);
566
567 if ((path = getenv("CC")) == NULL || *path == '\0') {
568 path = NULL;
569 appcstrg(&args, strdup("/usr/libexec/cpp"));
570 } else {
571 appcstrg(&args, strdup(path));
572 appcstrg(&args, strdup("-E"));
573 if ((path = strrchr(name, '.')) != NULL &&
574 strcasecmp(name, ".c") && strcmp(name, ".m") &&
575 strcasecmp(name, ".h") && strcmp(name, ".cxx") &&
576 strcasecmp(name, ".cpp") && strcmp(name, ".cc") &&
577 strcasecmp(name, ".fpp") && strcmp(name, ".hh") &&
578 strcmp(name, ".S") && strcmp(name, ".F")) {
579 appcstrg(&args, strdup("-x"));
580 appcstrg(&args, strdup("c"));
581 }
582 appcstrg(&args, strdup("-o"));
583 appcstrg(&args, cppout);
584 }
585
586 applst(&args, cppflags);
587 applst(&args, lcppflgs);
588 appcstrg(&args, name);
589 if (path == NULL)
590 appcstrg(&args, cppout);
591
592 error = runchild("/usr/bin/env", args, cppout);
593 freelst(&args);
594 if (error)
595 return;
596
597 /* run lint1 */
598
599 if (asprintf(&path, "%s/lint1", PATH_LIBEXEC) == -1)
600 err(1, NULL);
601
602 appcstrg(&args, path);
603 applst(&args, l1flags);
604 appcstrg(&args, cppout);
605 appcstrg(&args, ofn);
606
607 error = runchild(path, args, ofn);
608 free(path);
609 freelst(&args);
610 if (error)
611 return;
612
613 appcstrg(&p2in, ofn);
614 free(ofn);
615
616 free(args);
617 }
618
619 static int
runchild(const char * path,char * const * args,const char * crfn)620 runchild(const char *path, char *const *args, const char *crfn)
621 {
622 int status, signo, i;
623 pid_t rv;
624
625 if (Vflag) {
626 for (i = 0; args[i] != NULL; i++)
627 (void)printf("%s ", args[i]);
628 (void)printf("\n");
629 }
630
631 currfn = crfn;
632
633 (void)fflush(stdout);
634
635 switch (fork()) {
636 case -1:
637 warn("cannot fork");
638 terminate(-1);
639 /* NOTREACHED */
640 default:
641 /* parent */
642 break;
643 case 0:
644 /* child */
645 (void)execv(path, args);
646 warn("cannot exec %s", path);
647 exit(1);
648 /* NOTREACHED */
649 }
650 currfn = NULL;
651
652 while ((rv = wait(&status)) == -1 && errno == EINTR) ;
653 if (rv == -1) {
654 warn("wait");
655 return(-1);
656 }
657 if (WIFSIGNALED(status)) {
658 signo = WTERMSIG(status);
659 warnx("%s got SIG%s", path, sys_signame[signo]);
660 return(-1);
661 }
662 if (WEXITSTATUS(status) != 0)
663 return(-1);
664 return(0);
665 }
666
667 static void
findlibs(char * const * liblst)668 findlibs(char *const *liblst)
669 {
670 int i, k;
671 const char *lib, *path;
672 char *lfn;
673 size_t len, l;
674
675 lfn = NULL;
676
677 for (i = 0; (lib = liblst[i]) != NULL; i++) {
678 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
679 len = strlen(path) + strlen(lib);
680 l = len + sizeof ("/llib-l.ln");
681 lfn = xrealloc(lfn, l);
682 (void)snprintf(lfn, l, "%s/llib-l%s.ln", path, lib);
683 if (rdok(lfn))
684 break;
685 l = len + sizeof ("/lint/llib-l.ln");
686 lfn = xrealloc(lfn, l);
687 (void)snprintf(lfn, l, "%s/lint/llib-l%s.ln", path, lib);
688 if (rdok(lfn))
689 break;
690 }
691 if (path != NULL) {
692 appstrg(&l2libs, concat2("-l", lfn));
693 } else {
694 warnx("cannot find llib-l%s.ln", lib);
695 }
696 }
697
698 free(lfn);
699 }
700
701 static int
rdok(const char * path)702 rdok(const char *path)
703 {
704 struct stat sbuf;
705
706 if (stat(path, &sbuf) == -1)
707 return (0);
708 if ((sbuf.st_mode & S_IFMT) != S_IFREG)
709 return (0);
710 if (access(path, R_OK) == -1)
711 return (0);
712 return (1);
713 }
714
715 static void
lint2()716 lint2()
717 {
718 char *path, **args;
719
720 args = xcalloc(1, sizeof (char *));
721
722 if (asprintf(&path, "%s/lint2", PATH_LIBEXEC) == -1)
723 err(1, NULL);
724
725 appcstrg(&args, path);
726 applst(&args, l2flags);
727 applst(&args, l2libs);
728 applst(&args, p2in);
729
730 (void)runchild(path, args, p2out);
731 free(path);
732 freelst(&args);
733 free(args);
734 }
735
736 static void
cat(char * const * srcs,const char * dest)737 cat(char *const *srcs, const char *dest)
738 {
739 int ifd, ofd, i;
740 char *src, *buf;
741 ssize_t rlen;
742
743 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
744 warn("cannot open %s", dest);
745 terminate(-1);
746 }
747
748 buf = xmalloc(MBLKSIZ);
749
750 for (i = 0; (src = srcs[i]) != NULL; i++) {
751 if ((ifd = open(src, O_RDONLY)) == -1) {
752 free(buf);
753 warn("cannot open %s", src);
754 terminate(-1);
755 }
756 do {
757 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
758 free(buf);
759 warn("read error on %s", src);
760 terminate(-1);
761 }
762 if (write(ofd, buf, (size_t)rlen) == -1) {
763 free(buf);
764 warn("write error on %s", dest);
765 terminate(-1);
766 }
767 } while (rlen == MBLKSIZ);
768 (void)close(ifd);
769 }
770 (void)close(ofd);
771 free(buf);
772 }
773