Bring some important updates from NetBSD up to about 2008/04/25. The main feature is initial support for C99. This is a very basic update to make it easier to merge new compiler attirbutes but more updates are likely to follow. Obtained from: NetBSD MFC after: 2 weeks
884 lines
18 KiB
C
884 lines
18 KiB
C
/* $NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
|
|
* Copyright (c) 1994, 1995 Jochen Pohl
|
|
* All Rights Reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Jochen Pohl for
|
|
* The NetBSD Project.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#if defined(__RCSID) && !defined(lint)
|
|
__RCSID("$NetBSD: xlint.c,v 1.36 2005/02/09 21:24:48 dsl Exp $");
|
|
#endif
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/utsname.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <paths.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lint.h"
|
|
#include "pathnames.h"
|
|
|
|
#define DEFAULT_PATH _PATH_DEFPATH
|
|
|
|
int main(int, char *[]);
|
|
|
|
/* directory for temporary files */
|
|
static const char *tmpdir;
|
|
|
|
/* path name for cpp output */
|
|
static char *cppout;
|
|
|
|
/* file descriptor for cpp output */
|
|
static int cppoutfd = -1;
|
|
|
|
/* files created by 1st pass */
|
|
static char **p1out;
|
|
|
|
/* input files for 2nd pass (without libraries) */
|
|
static char **p2in;
|
|
|
|
/* library which will be created by 2nd pass */
|
|
static char *p2out;
|
|
|
|
/* flags always passed to cc(1) */
|
|
static char **cflags;
|
|
|
|
/* flags for cc(1), controlled by sflag/tflag */
|
|
static char **lcflags;
|
|
|
|
/* flags for lint1 */
|
|
static char **l1flags;
|
|
|
|
/* flags for lint2 */
|
|
static char **l2flags;
|
|
|
|
/* libraries for lint2 */
|
|
static char **l2libs;
|
|
|
|
/* default libraries */
|
|
static char **deflibs;
|
|
|
|
/* additional libraries */
|
|
static char **libs;
|
|
|
|
/* search path for libraries */
|
|
static char **libsrchpath;
|
|
|
|
static char *libexec_path;
|
|
|
|
/* flags */
|
|
static int iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag, Sflag;
|
|
|
|
/* print the commands executed to run the stages of compilation */
|
|
static int Vflag;
|
|
|
|
/* filename for oflag */
|
|
static char *outputfn;
|
|
|
|
/* reset after first .c source has been processed */
|
|
static int first = 1;
|
|
|
|
/*
|
|
* name of a file which is currently written by a child and should
|
|
* be removed after abnormal termination of the child
|
|
*/
|
|
static const char *currfn;
|
|
|
|
#if !defined(TARGET_PREFIX)
|
|
#define TARGET_PREFIX ""
|
|
#endif
|
|
static const char target_prefix[] = TARGET_PREFIX;
|
|
|
|
static void appstrg(char ***, char *);
|
|
static void appcstrg(char ***, const char *);
|
|
static void applst(char ***, char *const *);
|
|
static void freelst(char ***);
|
|
static char *concat2(const char *, const char *);
|
|
static char *concat3(const char *, const char *, const char *);
|
|
static void terminate(int) __attribute__((__noreturn__));
|
|
static const char *lbasename(const char *, int);
|
|
static void appdef(char ***, const char *);
|
|
static void usage(void) __dead2;
|
|
static void fname(const char *);
|
|
static void runchild(const char *, char *const *, const char *, int);
|
|
static void findlibs(char *const *);
|
|
static int rdok(const char *);
|
|
static void lint2(void);
|
|
static void cat(char *const *, const char *);
|
|
|
|
/*
|
|
* Some functions to deal with lists of strings.
|
|
* Take care that we get no surprises in case of asynchronous signals.
|
|
*/
|
|
static void
|
|
appstrg(char ***lstp, char *s)
|
|
{
|
|
char **lst, **olst;
|
|
int i;
|
|
|
|
olst = *lstp;
|
|
for (i = 0; olst[i] != NULL; i++)
|
|
continue;
|
|
lst = xrealloc(olst, (i + 2) * sizeof (char *));
|
|
lst[i] = s;
|
|
lst[i + 1] = NULL;
|
|
*lstp = lst;
|
|
}
|
|
|
|
static void
|
|
appcstrg(char ***lstp, const char *s)
|
|
{
|
|
|
|
appstrg(lstp, xstrdup(s));
|
|
}
|
|
|
|
static void
|
|
applst(char ***destp, char *const *src)
|
|
{
|
|
int i, k;
|
|
char **dest, **odest;
|
|
|
|
odest = *destp;
|
|
for (i = 0; odest[i] != NULL; i++)
|
|
continue;
|
|
for (k = 0; src[k] != NULL; k++)
|
|
continue;
|
|
dest = xrealloc(odest, (i + k + 1) * sizeof (char *));
|
|
for (k = 0; src[k] != NULL; k++)
|
|
dest[i + k] = xstrdup(src[k]);
|
|
dest[i + k] = NULL;
|
|
*destp = dest;
|
|
}
|
|
|
|
static void
|
|
freelst(char ***lstp)
|
|
{
|
|
char *s;
|
|
int i;
|
|
|
|
for (i = 0; (*lstp)[i] != NULL; i++)
|
|
continue;
|
|
while (i-- > 0) {
|
|
s = (*lstp)[i];
|
|
(*lstp)[i] = NULL;
|
|
free(s);
|
|
}
|
|
}
|
|
|
|
static char *
|
|
concat2(const char *s1, const char *s2)
|
|
{
|
|
char *s;
|
|
|
|
s = xmalloc(strlen(s1) + strlen(s2) + 1);
|
|
(void)strcpy(s, s1);
|
|
(void)strcat(s, s2);
|
|
|
|
return (s);
|
|
}
|
|
|
|
static char *
|
|
concat3(const char *s1, const char *s2, const char *s3)
|
|
{
|
|
char *s;
|
|
|
|
s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
|
|
(void)strcpy(s, s1);
|
|
(void)strcat(s, s2);
|
|
(void)strcat(s, s3);
|
|
|
|
return (s);
|
|
}
|
|
|
|
/*
|
|
* Clean up after a signal.
|
|
*/
|
|
static void
|
|
terminate(int signo)
|
|
{
|
|
int i;
|
|
|
|
if (cppoutfd != -1)
|
|
(void)close(cppoutfd);
|
|
if (cppout != NULL)
|
|
(void)remove(cppout);
|
|
|
|
if (p1out != NULL) {
|
|
for (i = 0; p1out[i] != NULL; i++)
|
|
(void)remove(p1out[i]);
|
|
}
|
|
|
|
if (p2out != NULL)
|
|
(void)remove(p2out);
|
|
|
|
if (currfn != NULL)
|
|
(void)remove(currfn);
|
|
|
|
exit(signo != 0 ? 1 : 0);
|
|
}
|
|
|
|
/*
|
|
* Returns a pointer to the last component of strg after delim.
|
|
* Returns strg if the string does not contain delim.
|
|
*/
|
|
static const char *
|
|
lbasename(const char *strg, int delim)
|
|
{
|
|
const char *cp, *cp1, *cp2;
|
|
|
|
cp = cp1 = cp2 = strg;
|
|
while (*cp != '\0') {
|
|
if (*cp++ == delim) {
|
|
cp2 = cp1;
|
|
cp1 = cp;
|
|
}
|
|
}
|
|
return (*cp1 == '\0' ? cp2 : cp1);
|
|
}
|
|
|
|
static void
|
|
appdef(char ***lstp, const char *def)
|
|
{
|
|
|
|
appstrg(lstp, concat2("-D__", def));
|
|
appstrg(lstp, concat3("-D__", def, "__"));
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
|
|
(void)fprintf(stderr,
|
|
"usage: lint [-abceghprvwxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]]"
|
|
" [-Uname] [-X <id>[,<id>]...\n");
|
|
(void)fprintf(stderr,
|
|
"\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
|
|
" file...\n");
|
|
(void)fprintf(stderr,
|
|
" lint [-abceghprvwzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n"
|
|
" [-X <id>[,<id>]...\n");
|
|
(void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file"
|
|
" ...\n");
|
|
terminate(-1);
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int c;
|
|
char flgbuf[3], *s;
|
|
const char *tmp;
|
|
size_t len;
|
|
|
|
if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
|
|
tmpdir = _PATH_TMP;
|
|
} else {
|
|
s = xmalloc(len + 2);
|
|
(void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
|
|
tmpdir = s;
|
|
}
|
|
|
|
cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
|
|
(void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
|
|
cppoutfd = mkstemp(cppout);
|
|
if (cppoutfd == -1) {
|
|
warn("can't make temp");
|
|
terminate(-1);
|
|
}
|
|
|
|
p1out = xcalloc(1, sizeof (char *));
|
|
p2in = xcalloc(1, sizeof (char *));
|
|
cflags = xcalloc(1, sizeof (char *));
|
|
lcflags = xcalloc(1, sizeof (char *));
|
|
l1flags = xcalloc(1, sizeof (char *));
|
|
l2flags = xcalloc(1, sizeof (char *));
|
|
l2libs = xcalloc(1, sizeof (char *));
|
|
deflibs = xcalloc(1, sizeof (char *));
|
|
libs = xcalloc(1, sizeof (char *));
|
|
libsrchpath = xcalloc(1, sizeof (char *));
|
|
|
|
appcstrg(&cflags, "-E");
|
|
appcstrg(&cflags, "-x");
|
|
appcstrg(&cflags, "c");
|
|
#if 0
|
|
appcstrg(&cflags, "-D__attribute__(x)=");
|
|
appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0");
|
|
#else
|
|
appcstrg(&cflags, "-U__GNUC__");
|
|
appcstrg(&cflags, "-undef");
|
|
#endif
|
|
#if 0
|
|
appcstrg(&cflags, "-Wp,-$");
|
|
#endif
|
|
appcstrg(&cflags, "-Wp,-C");
|
|
appcstrg(&cflags, "-Wcomment");
|
|
appcstrg(&cflags, "-D__LINT__");
|
|
appcstrg(&cflags, "-Dlint"); /* XXX don't def. with -s */
|
|
|
|
appdef(&cflags, "lint");
|
|
|
|
appcstrg(&deflibs, "c");
|
|
|
|
if (signal(SIGHUP, terminate) == SIG_IGN)
|
|
(void)signal(SIGHUP, SIG_IGN);
|
|
(void)signal(SIGINT, terminate);
|
|
(void)signal(SIGQUIT, terminate);
|
|
(void)signal(SIGTERM, terminate);
|
|
while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:M:SU:VX:")) != -1) {
|
|
switch (c) {
|
|
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'e':
|
|
case 'g':
|
|
case 'r':
|
|
case 'v':
|
|
case 'w':
|
|
case 'z':
|
|
(void)sprintf(flgbuf, "-%c", c);
|
|
appcstrg(&l1flags, flgbuf);
|
|
break;
|
|
|
|
case 'F':
|
|
Fflag = 1;
|
|
/* FALLTHROUGH */
|
|
case 'u':
|
|
case 'h':
|
|
(void)sprintf(flgbuf, "-%c", c);
|
|
appcstrg(&l1flags, flgbuf);
|
|
appcstrg(&l2flags, flgbuf);
|
|
break;
|
|
|
|
case 'X':
|
|
(void)sprintf(flgbuf, "-%c", c);
|
|
appcstrg(&l1flags, flgbuf);
|
|
appcstrg(&l1flags, optarg);
|
|
break;
|
|
|
|
case 'i':
|
|
if (Cflag)
|
|
usage();
|
|
iflag = 1;
|
|
break;
|
|
|
|
case 'n':
|
|
freelst(&deflibs);
|
|
break;
|
|
|
|
case 'p':
|
|
appcstrg(&lcflags, "-Wtraditional");
|
|
appcstrg(&lcflags, "-Wno-system-headers");
|
|
appcstrg(&l1flags, "-p");
|
|
appcstrg(&l2flags, "-p");
|
|
if (*deflibs != NULL) {
|
|
freelst(&deflibs);
|
|
appcstrg(&deflibs, "c");
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
if (tflag)
|
|
usage();
|
|
freelst(&lcflags);
|
|
appcstrg(&lcflags, "-trigraphs");
|
|
appcstrg(&lcflags, "-Wtrigraphs");
|
|
appcstrg(&lcflags, "-pedantic");
|
|
appcstrg(&lcflags, "-D__STRICT_ANSI__");
|
|
appcstrg(&l1flags, "-s");
|
|
appcstrg(&l2flags, "-s");
|
|
sflag = 1;
|
|
break;
|
|
|
|
case 'S':
|
|
if (tflag)
|
|
usage();
|
|
appcstrg(&l1flags, "-S");
|
|
Sflag = 1;
|
|
break;
|
|
|
|
#if !HAVE_CONFIG_H
|
|
case 't':
|
|
if (sflag)
|
|
usage();
|
|
freelst(&lcflags);
|
|
appcstrg(&lcflags, "-traditional");
|
|
appstrg(&lcflags, concat2("-D", MACHINE));
|
|
appstrg(&lcflags, concat2("-D", MACHINE_ARCH));
|
|
appcstrg(&l1flags, "-t");
|
|
appcstrg(&l2flags, "-t");
|
|
tflag = 1;
|
|
break;
|
|
#endif
|
|
|
|
case 'x':
|
|
appcstrg(&l2flags, "-x");
|
|
break;
|
|
|
|
case 'C':
|
|
if (Cflag || oflag || iflag)
|
|
usage();
|
|
Cflag = 1;
|
|
appstrg(&l2flags, concat2("-C", optarg));
|
|
p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
|
|
(void)sprintf(p2out, "llib-l%s.ln", optarg);
|
|
freelst(&deflibs);
|
|
break;
|
|
|
|
case 'd':
|
|
if (dflag)
|
|
usage();
|
|
dflag = 1;
|
|
appcstrg(&cflags, "-nostdinc");
|
|
appcstrg(&cflags, "-idirafter");
|
|
appcstrg(&cflags, optarg);
|
|
break;
|
|
|
|
case 'D':
|
|
case 'I':
|
|
case 'M':
|
|
case 'U':
|
|
(void)sprintf(flgbuf, "-%c", c);
|
|
appstrg(&cflags, concat2(flgbuf, optarg));
|
|
break;
|
|
|
|
case 'l':
|
|
appcstrg(&libs, optarg);
|
|
break;
|
|
|
|
case 'o':
|
|
if (Cflag || oflag)
|
|
usage();
|
|
oflag = 1;
|
|
outputfn = xstrdup(optarg);
|
|
break;
|
|
|
|
case 'L':
|
|
appcstrg(&libsrchpath, optarg);
|
|
break;
|
|
|
|
case 'H':
|
|
appcstrg(&l2flags, "-H");
|
|
break;
|
|
|
|
case 'B':
|
|
Bflag = 1;
|
|
libexec_path = xstrdup(optarg);
|
|
break;
|
|
|
|
case 'V':
|
|
Vflag = 1;
|
|
break;
|
|
|
|
default:
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
/*
|
|
* To avoid modifying getopt(3)'s state engine midstream, we
|
|
* explicitly accept just a few options after the first source file.
|
|
*
|
|
* In particular, only -l<lib> and -L<libdir> (and these with a space
|
|
* after -l or -L) are allowed.
|
|
*/
|
|
while (argc > 0) {
|
|
const char *arg = argv[0];
|
|
|
|
if (arg[0] == '-') {
|
|
char ***list;
|
|
|
|
/* option */
|
|
switch (arg[1]) {
|
|
case 'l':
|
|
list = &libs;
|
|
break;
|
|
|
|
case 'L':
|
|
list = &libsrchpath;
|
|
break;
|
|
|
|
default:
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
if (arg[2])
|
|
appcstrg(list, arg + 2);
|
|
else if (argc > 1) {
|
|
argc--;
|
|
appcstrg(list, *++argv);
|
|
} else
|
|
usage();
|
|
} else {
|
|
/* filename */
|
|
fname(arg);
|
|
first = 0;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if (first)
|
|
usage();
|
|
|
|
if (iflag)
|
|
terminate(0);
|
|
|
|
if (!oflag) {
|
|
if ((tmp = getenv("LIBDIR")) == NULL || strlen(tmp) == 0)
|
|
tmp = PATH_LINTLIB;
|
|
appcstrg(&libsrchpath, tmp);
|
|
findlibs(libs);
|
|
findlibs(deflibs);
|
|
}
|
|
|
|
(void)printf("Lint pass2:\n");
|
|
lint2();
|
|
|
|
if (oflag)
|
|
cat(p2in, outputfn);
|
|
|
|
if (Cflag)
|
|
p2out = NULL;
|
|
|
|
terminate(0);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/*
|
|
* Read a file name from the command line
|
|
* and pass it through lint1 if it is a C source.
|
|
*/
|
|
static void
|
|
fname(const char *name)
|
|
{
|
|
const char *bn, *suff;
|
|
char **args, *ofn, *p, *pathname;
|
|
size_t len;
|
|
int is_stdin;
|
|
int fd;
|
|
|
|
is_stdin = (strcmp(name, "-") == 0);
|
|
bn = lbasename(name, '/');
|
|
suff = lbasename(bn, '.');
|
|
|
|
if (strcmp(suff, "ln") == 0) {
|
|
/* only for lint2 */
|
|
if (!iflag)
|
|
appcstrg(&p2in, name);
|
|
return;
|
|
}
|
|
|
|
if (!is_stdin && strcmp(suff, "c") != 0 &&
|
|
(strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
|
|
warnx("unknown file type: %s\n", name);
|
|
return;
|
|
}
|
|
|
|
if (!iflag || !first)
|
|
(void)printf("%s:\n",
|
|
is_stdin ? "{standard input}" : Fflag ? name : bn);
|
|
|
|
/* build the name of the output file of lint1 */
|
|
if (oflag) {
|
|
ofn = outputfn;
|
|
outputfn = NULL;
|
|
oflag = 0;
|
|
} else if (iflag) {
|
|
if (is_stdin) {
|
|
warnx("-i not supported without -o for standard input");
|
|
return;
|
|
}
|
|
ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
|
|
len = bn == suff ? strlen(bn) : (size_t)((suff - 1) - bn);
|
|
(void)sprintf(ofn, "%.*s", (int)len, bn);
|
|
(void)strcat(ofn, ".ln");
|
|
} else {
|
|
ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
|
|
(void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
|
|
fd = mkstemp(ofn);
|
|
if (fd == -1) {
|
|
warn("can't make temp");
|
|
terminate(-1);
|
|
}
|
|
close(fd);
|
|
}
|
|
if (!iflag)
|
|
appcstrg(&p1out, ofn);
|
|
|
|
args = xcalloc(1, sizeof (char *));
|
|
|
|
/* run cc */
|
|
|
|
if (getenv("CC") == NULL) {
|
|
pathname = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc"));
|
|
(void)sprintf(pathname, "%s/cc", PATH_USRBIN);
|
|
appcstrg(&args, pathname);
|
|
} else {
|
|
pathname = strdup(getenv("CC"));
|
|
for (p = strtok(pathname, " \t"); p; p = strtok(NULL, " \t"))
|
|
appcstrg(&args, p);
|
|
}
|
|
|
|
applst(&args, cflags);
|
|
applst(&args, lcflags);
|
|
appcstrg(&args, name);
|
|
|
|
/* we reuse the same tmp file for cpp output, so rewind and truncate */
|
|
if (lseek(cppoutfd, (off_t)0, SEEK_SET) != 0) {
|
|
warn("lseek");
|
|
terminate(-1);
|
|
}
|
|
if (ftruncate(cppoutfd, (off_t)0) != 0) {
|
|
warn("ftruncate");
|
|
terminate(-1);
|
|
}
|
|
|
|
runchild(pathname, args, cppout, cppoutfd);
|
|
free(pathname);
|
|
freelst(&args);
|
|
|
|
/* run lint1 */
|
|
|
|
if (!Bflag) {
|
|
pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") +
|
|
strlen(target_prefix));
|
|
(void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC,
|
|
target_prefix);
|
|
} else {
|
|
/*
|
|
* XXX Unclear whether we should be using target_prefix
|
|
* XXX here. --thorpej@wasabisystems.com
|
|
*/
|
|
pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1"));
|
|
(void)sprintf(pathname, "%s/lint1", libexec_path);
|
|
}
|
|
|
|
appcstrg(&args, pathname);
|
|
applst(&args, l1flags);
|
|
appcstrg(&args, cppout);
|
|
appcstrg(&args, ofn);
|
|
|
|
runchild(pathname, args, ofn, -1);
|
|
free(pathname);
|
|
freelst(&args);
|
|
|
|
appcstrg(&p2in, ofn);
|
|
free(ofn);
|
|
|
|
free(args);
|
|
}
|
|
|
|
static void
|
|
runchild(const char *path, char *const *args, const char *crfn, int fdout)
|
|
{
|
|
int status, rv, signo, i;
|
|
|
|
if (Vflag) {
|
|
for (i = 0; args[i] != NULL; i++)
|
|
(void)printf("%s ", args[i]);
|
|
(void)printf("\n");
|
|
}
|
|
|
|
currfn = crfn;
|
|
|
|
(void)fflush(stdout);
|
|
|
|
switch (vfork()) {
|
|
case -1:
|
|
warn("cannot fork");
|
|
terminate(-1);
|
|
/* NOTREACHED */
|
|
default:
|
|
/* parent */
|
|
break;
|
|
case 0:
|
|
/* child */
|
|
|
|
/* setup the standard output if necessary */
|
|
if (fdout != -1) {
|
|
dup2(fdout, STDOUT_FILENO);
|
|
close(fdout);
|
|
}
|
|
(void)execvp(path, args);
|
|
warn("cannot exec %s", path);
|
|
_exit(1);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
while ((rv = wait(&status)) == -1 && errno == EINTR) ;
|
|
if (rv == -1) {
|
|
warn("wait");
|
|
terminate(-1);
|
|
}
|
|
if (WIFSIGNALED(status)) {
|
|
signo = WTERMSIG(status);
|
|
#if HAVE_DECL_SYS_SIGNAME
|
|
warnx("%s got SIG%s", path, sys_signame[signo]);
|
|
#else
|
|
warnx("%s got signal %d", path, signo);
|
|
#endif
|
|
terminate(-1);
|
|
}
|
|
if (WEXITSTATUS(status) != 0)
|
|
terminate(-1);
|
|
currfn = NULL;
|
|
}
|
|
|
|
static void
|
|
findlibs(char *const *liblst)
|
|
{
|
|
int i, k;
|
|
const char *lib, *path;
|
|
char *lfn;
|
|
size_t len;
|
|
|
|
lfn = NULL;
|
|
|
|
for (i = 0; (lib = liblst[i]) != NULL; i++) {
|
|
for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
|
|
len = strlen(path) + strlen(lib);
|
|
lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
|
|
(void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
|
|
if (rdok(lfn))
|
|
break;
|
|
lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
|
|
(void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
|
|
if (rdok(lfn))
|
|
break;
|
|
}
|
|
if (path != NULL) {
|
|
appstrg(&l2libs, concat2("-l", lfn));
|
|
} else {
|
|
warnx("cannot find llib-l%s.ln", lib);
|
|
}
|
|
}
|
|
|
|
free(lfn);
|
|
}
|
|
|
|
static int
|
|
rdok(const char *path)
|
|
{
|
|
struct stat sbuf;
|
|
|
|
if (stat(path, &sbuf) == -1)
|
|
return (0);
|
|
if (!S_ISREG(sbuf.st_mode))
|
|
return (0);
|
|
if (access(path, R_OK) == -1)
|
|
return (0);
|
|
return (1);
|
|
}
|
|
|
|
static void
|
|
lint2(void)
|
|
{
|
|
char *path, **args;
|
|
|
|
args = xcalloc(1, sizeof (char *));
|
|
|
|
if (!Bflag) {
|
|
path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") +
|
|
strlen(target_prefix));
|
|
(void)sprintf(path, "%s/%slint2", PATH_LIBEXEC,
|
|
target_prefix);
|
|
} else {
|
|
/*
|
|
* XXX Unclear whether we should be using target_prefix
|
|
* XXX here. --thorpej@wasabisystems.com
|
|
*/
|
|
path = xmalloc(strlen(libexec_path) + sizeof ("/lint2"));
|
|
(void)sprintf(path, "%s/lint2", libexec_path);
|
|
}
|
|
|
|
appcstrg(&args, path);
|
|
applst(&args, l2flags);
|
|
applst(&args, l2libs);
|
|
applst(&args, p2in);
|
|
|
|
runchild(path, args, p2out, -1);
|
|
free(path);
|
|
freelst(&args);
|
|
free(args);
|
|
}
|
|
|
|
static void
|
|
cat(char *const *srcs, const char *dest)
|
|
{
|
|
int ifd, ofd, i;
|
|
char *src, *buf;
|
|
ssize_t rlen;
|
|
|
|
if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
|
|
warn("cannot open %s", dest);
|
|
terminate(-1);
|
|
}
|
|
|
|
buf = xmalloc(MBLKSIZ);
|
|
|
|
for (i = 0; (src = srcs[i]) != NULL; i++) {
|
|
if ((ifd = open(src, O_RDONLY)) == -1) {
|
|
free(buf);
|
|
warn("cannot open %s", src);
|
|
terminate(-1);
|
|
}
|
|
do {
|
|
if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
|
|
free(buf);
|
|
warn("read error on %s", src);
|
|
terminate(-1);
|
|
}
|
|
if (write(ofd, buf, (size_t)rlen) == -1) {
|
|
free(buf);
|
|
warn("write error on %s", dest);
|
|
terminate(-1);
|
|
}
|
|
} while (rlen == MBLKSIZ);
|
|
(void)close(ifd);
|
|
}
|
|
(void)close(ofd);
|
|
free(buf);
|
|
}
|