diff --git a/file/Makefile.am b/file/Makefile.am index 99a97644d..1ce7704de 100644 --- a/file/Makefile.am +++ b/file/Makefile.am @@ -1,32 +1,34 @@ AUTOMAKE_OPTIONS = 1.4 foreign -noinst_HEADERS = debug.h system.h - -bin_PROGRAMS = file - -data_DATA = magic magic.mime magic.mgc magic.mime.mgc - -MAGIC = @datadir@/magic -CPPFLAGS = -DMAGIC='"$(MAGIC)"' - -if FSECT5 -man_MAGIC = magic.5 -else -man_MAGIC = magic.4 -endif -fsect = @fsect@ -man_MANS = file.1 $(man_MAGIC) - -file_SOURCES = file.c apprentice.c fsmagic.c softmagic.c ascmagic.c \ - compress.c is_tar.c readelf.c print.c \ - file.h names.h patchlevel.h readelf.h tar.h -#file_LDFLAGS = -all-static - EXTRA_DIST = LEGAL.NOTICE MAINT Makefile.std magic2mime \ Localstuff Header $(magic_FRAGMENTS) file.man magic.man BUILT_SOURCES = $(man_MANS) magic magic.mgc magic.mime.mgc +pkgincdir = @includedir@/fmagic +pkginc_HEADERS = file.h + +noinst_HEADERS = debug.h names.h patchlevel.h readelf.h system.h tar.h + +lib_LTLIBRARIES = libfmagic.la +libfmagic_la_SOURCES = \ + apprentice.c ascmagic.c fsmagic.c compress.c is_tar.c \ + print.c readelf.c softmagic.c + +bin_PROGRAMS = file +file_SOURCES = file.c +file_LDADD = libfmagic.la + +data_DATA = magic magic.mime magic.mgc magic.mime.mgc + +man_MAGIC = magic.@fsect@ +man_MANS = file.1 $(man_MAGIC) + +MAGIC = @datadir@/magic +CPPFLAGS = -DMAGIC='"$(MAGIC)"' + +fsect = @fsect@ + magic: Header Localstuff $(magic_FRAGMENTS) cat $(srcdir)/Header $(srcdir)/Localstuff > $@ for frag in $(magic_FRAGMENTS); do \ @@ -217,5 +219,5 @@ Magdir/zyxel .PHONY: lclint lclint: - lclint $(DEFS) $(INCLUDES) $(file_SOURCES) + lclint $(DEFS) $(INCLUDES) $(file_SOURCES) $(libfmagic_la_SOURCES) $(pkginc_HEADERS) $(noinst_HEADERS) diff --git a/file/apprentice.c b/file/apprentice.c index b525833d7..8e59db4fe 100644 --- a/file/apprentice.c +++ b/file/apprentice.c @@ -763,8 +763,7 @@ byteswap(struct magic *m, uint32_t nmagic) */ static char * mkdbname(const char *fn) - /*@globals fileSystem @*/ - /*@modifies fileSystem @*/ + /*@*/ { static const char ext[] = ".mgc"; /*@only@*/ diff --git a/file/file.c b/file/file.c index f4e94865a..f82c0e21b 100644 --- a/file/file.c +++ b/file/file.c @@ -32,7 +32,6 @@ FILE_RCSID("@(#)Id: file.c,v 1.66 2002/07/03 19:00:41 christos Exp ") - #ifdef S_IFLNK # define USAGE "Usage: %s [-bciknsvzL] [-f namefile] [-m magicfiles] file...\n" #else @@ -56,19 +55,20 @@ int os2_apptype (const char *fn, char *buf, int nb); /*@unchecked@*/ int debug = 0; /* debugging */ /*@unchecked@*/ - int lflag = 0; /* follow Symlinks (BSD only) */ -/*@unchecked@*/ -static int bflag = 0; /* brief output format */ -/*@unchecked@*/ - int zflag = 0; /* follow (uncompress) compressed files */ -/*@unchecked@*/ - int sflag = 0; /* read block special files */ + int bflag = 0; /* brief output format */ /*@unchecked@*/ int iflag = 0; -/*@unchecked@*/ -static int nobuffer = 0; /* Do not buffer stdout */ /*@unchecked@*/ int kflag = 0; /* Keep going after the first match */ +/*@unchecked@*/ + int lflag = 0; /* follow Symlinks (BSD only) */ +/*@unchecked@*/ + int sflag = 0; /* read block special files */ +/*@unchecked@*/ + int zflag = 0; /* follow (uncompress) compressed files */ + +/*@unchecked@*/ +static int nobuffer = 0; /* Do not buffer stdout */ /*@unchecked@*/ /*@null@*/ const char *magicfile = 0; /* where the magic is */ @@ -80,142 +80,6 @@ char *progname; /* used throughout */ /*@unchecked@*/ int lineno; /* line number in the magic file */ -int -tryit(const char *fn, unsigned char *buf, int nb, int zfl) -{ - - /* - * The main work is done here! - * We have the file name and/or the data buffer to be identified. - */ - -#ifdef __EMX__ - /* - * Ok, here's the right place to add a call to some os-specific - * routine, e.g. - */ - if (os2_apptype(fn, buf, nb) == 1) - return 'o'; -#endif - /* try compression stuff */ - if (zfl && zmagic(fn, buf, nb)) - return 'z'; - - /* try tests in /etc/magic (or surrogate magic file) */ - if (softmagic(buf, nb)) - return 's'; - - /* try known keywords, check whether it is ASCII */ - if (ascmagic(buf, nb)) - return 'a'; - - /* abandon hope, all ye who remain here */ - ckfputs(iflag ? "application/octet-stream" : "data", stdout); - return '\0'; -} - -/* - * process - process input file - */ -void -process(const char *inname, int wid) -{ - int fd = 0; - static const char stdname[] = "standard input"; - unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */ - struct stat sb; - int nbytes = 0; /* number of bytes read from a datafile */ - char match = '\0'; - - if (strcmp("-", inname) == 0) { - if (fstat(0, &sb)<0) { - error("cannot fstat `%s' (%s).\n", stdname, - strerror(errno)); - /*@notreached@*/ - } - inname = stdname; - } - - if (wid > 0 && !bflag) - (void) printf("%s:%*s ", inname, - (int) (wid - strlen(inname)), ""); - - if (inname != stdname) { - /* - * first try judging the file based on its filesystem status - */ - if (fsmagic(inname, &sb) != 0) { - (void) putchar('\n'); - return; - } - - if ((fd = open(inname, O_RDONLY)) < 0) { - /* We can't open it, but we were able to stat it. */ - if (sb.st_mode & 0002) ckfputs("writeable, ", stdout); - if (sb.st_mode & 0111) ckfputs("executable, ", stdout); - ckfprintf(stdout, "can't read `%s' (%s).\n", - inname, strerror(errno)); - return; - } - } - - - /* - * try looking at the first HOWMANY bytes - */ - if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { - error("read failed (%s).\n", strerror(errno)); - /*@notreached@*/ - } - - if (nbytes == 0) - ckfputs(iflag ? "application/x-empty" : "empty", stdout); - else { - buf[nbytes++] = '\0'; /* null-terminate it */ - match = tryit(inname, buf, nbytes, zflag); - } - -#ifdef BUILTIN_ELF - if (match == 's' && nbytes > 5) { - /* - * We matched something in the file, so this *might* - * be an ELF file, and the file is at least 5 bytes long, - * so if it's an ELF file it has at least one byte - * past the ELF magic number - try extracting information - * from the ELF headers that can't easily be extracted - * with rules in the magic file. - */ - tryelf(fd, buf, nbytes); - } -#endif - - if (inname != stdname) { -#ifdef RESTORE_TIME - /* - * Try to restore access, modification times if read it. - * This is really *bad* because it will modify the status - * time of the file... And of course this will affect - * backup programs - */ -# ifdef USE_UTIMES - struct timeval utsbuf[2]; - utsbuf[0].tv_sec = sb.st_atime; - utsbuf[1].tv_sec = sb.st_mtime; - - (void) utimes(inname, utsbuf); /* don't care if loses */ -# else - struct utimbuf utbuf; - - utbuf.actime = sb.st_atime; - utbuf.modtime = sb.st_mtime; - (void) utime(inname, &utbuf); /* don't care if loses */ -# endif -#endif - (void) close(fd); - } - (void) putchar('\n'); -} - /* * unwrap -- read a file of filenames, do each one. */ @@ -320,7 +184,7 @@ main(int argc, char **argv) struct stat sb; #define OPTSTRING "bcdf:ikm:nsvzCL" #ifdef HAVE_GETOPT_H - int longindex; + int longindex = 0; /*@-nullassign -readonlytrans@*/ static struct option long_options[] = { @@ -372,7 +236,8 @@ main(int argc, char **argv) magicfile = usermagic; else { if ((home = getenv("HOME")) != NULL) { - usermagic = xmalloc(strlen(home) + 8); + size_t nb = strlen(home) + 8; + usermagic = xmalloc(nb); (void)strcpy(usermagic, home); (void)strcat(usermagic, "/.magic"); if (stat(usermagic, &sb)<0) @@ -385,10 +250,8 @@ main(int argc, char **argv) #ifndef HAVE_GETOPT_H while ((c = getopt(argc, argv, OPTSTRING)) != -1) #else -/*@-compdef @*/ while ((c = getopt_long(argc, argv, OPTSTRING, long_options, &longindex)) != -1) -/*@=compdef @*/ #endif { switch (c) { diff --git a/file/file.h b/file/file.h index de861e595..2c0388394 100644 --- a/file/file.h +++ b/file/file.h @@ -128,15 +128,17 @@ extern struct mlist mlist; /* list of arrays of magic entries */ /*@unchecked@*/ extern int debug; /* enable debugging? */ /*@unchecked@*/ -extern int zflag; /* process compressed files? */ +extern int bflag; /* brief output format */ +/*@unchecked@*/ +extern int iflag; /* Output types as mime-types */ +/*@unchecked@*/ +extern int kflag; /* Keep going after the first match */ /*@unchecked@*/ extern int lflag; /* follow symbolic links? */ /*@unchecked@*/ extern int sflag; /* read/analyze block special files? */ /*@unchecked@*/ -extern int iflag; /* Output types as mime-types */ -/*@unchecked@*/ -extern int kflag; /* Keep going after the first match */ +extern int zflag; /* process compressed files? */ /*@=exportlocal@*/ /*@mayexit@*/ @@ -180,6 +182,19 @@ extern int softmagic(unsigned char *buf, int nbytes) extern int tryit(const char *fn, unsigned char *buf, int nb, int zfl) /*@globals fileSystem, internalState @*/ /*@modifies buf, fileSystem, internalState @*/; +/** + */ +/*@unused@*/ /*@exits@*/ /*@only@*/ +static inline void * vmefail(/*@unused@*/ size_t nb) + /*@globals fileSystem @*/ + /*@modifies fileSystem @*/ +{ + error("out of memory"); + /*@notreached@*/ +/*@-nullret@*/ + return NULL; +/*@=nullret@*/ +} extern int zmagic(const char *fname, unsigned char *buf, int nbytes) /*@globals fileSystem, internalState @*/ /*@modifies buf, fileSystem, internalState @*/; diff --git a/file/fsmagic.c b/file/fsmagic.c index 3dae1028d..7b8780d72 100644 --- a/file/fsmagic.c +++ b/file/fsmagic.c @@ -224,3 +224,139 @@ fsmagic(const char *fn, struct stat *sb) } return 0; } + +int +tryit(const char *fn, unsigned char *buf, int nb, int zfl) +{ + + /* + * The main work is done here! + * We have the file name and/or the data buffer to be identified. + */ + +#ifdef __EMX__ + /* + * Ok, here's the right place to add a call to some os-specific + * routine, e.g. + */ + if (os2_apptype(fn, buf, nb) == 1) + return 'o'; +#endif + /* try compression stuff */ + if (zfl && zmagic(fn, buf, nb)) + return 'z'; + + /* try tests in /etc/magic (or surrogate magic file) */ + if (softmagic(buf, nb)) + return 's'; + + /* try known keywords, check whether it is ASCII */ + if (ascmagic(buf, nb)) + return 'a'; + + /* abandon hope, all ye who remain here */ + ckfputs(iflag ? "application/octet-stream" : "data", stdout); + return '\0'; +} + +/* + * process - process input file + */ +void +process(const char *inname, int wid) +{ + int fd = 0; + static const char stdname[] = "standard input"; + unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */ + struct stat sb; + int nbytes = 0; /* number of bytes read from a datafile */ + char match = '\0'; + + if (strcmp("-", inname) == 0) { + if (fstat(0, &sb)<0) { + error("cannot fstat `%s' (%s).\n", stdname, + strerror(errno)); + /*@notreached@*/ + } + inname = stdname; + } + + if (wid > 0 && !bflag) + (void) printf("%s:%*s ", inname, + (int) (wid - strlen(inname)), ""); + + if (inname != stdname) { + /* + * first try judging the file based on its filesystem status + */ + if (fsmagic(inname, &sb) != 0) { + (void) putchar('\n'); + return; + } + + if ((fd = open(inname, O_RDONLY)) < 0) { + /* We can't open it, but we were able to stat it. */ + if (sb.st_mode & 0002) ckfputs("writeable, ", stdout); + if (sb.st_mode & 0111) ckfputs("executable, ", stdout); + ckfprintf(stdout, "can't read `%s' (%s).\n", + inname, strerror(errno)); + return; + } + } + + + /* + * try looking at the first HOWMANY bytes + */ + if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { + error("read failed (%s).\n", strerror(errno)); + /*@notreached@*/ + } + + if (nbytes == 0) + ckfputs(iflag ? "application/x-empty" : "empty", stdout); + else { + buf[nbytes++] = '\0'; /* null-terminate it */ + match = tryit(inname, buf, nbytes, zflag); + } + +#ifdef BUILTIN_ELF + if (match == 's' && nbytes > 5) { + /* + * We matched something in the file, so this *might* + * be an ELF file, and the file is at least 5 bytes long, + * so if it's an ELF file it has at least one byte + * past the ELF magic number - try extracting information + * from the ELF headers that can't easily be extracted + * with rules in the magic file. + */ + tryelf(fd, buf, nbytes); + } +#endif + + if (inname != stdname) { +#ifdef RESTORE_TIME + /* + * Try to restore access, modification times if read it. + * This is really *bad* because it will modify the status + * time of the file... And of course this will affect + * backup programs + */ +# ifdef USE_UTIMES + struct timeval utsbuf[2]; + utsbuf[0].tv_sec = sb.st_atime; + utsbuf[1].tv_sec = sb.st_mtime; + + (void) utimes(inname, utsbuf); /* don't care if loses */ +# else + struct utimbuf utbuf; + + utbuf.actime = sb.st_atime; + utbuf.modtime = sb.st_mtime; + (void) utime(inname, &utbuf); /* don't care if loses */ +# endif +#endif + (void) close(fd); + } + (void) putchar('\n'); +} diff --git a/file/softmagic.c b/file/softmagic.c index acf84b9b5..4f0e7a3df 100644 --- a/file/softmagic.c +++ b/file/softmagic.c @@ -1031,7 +1031,7 @@ sm_match(struct magic *m, uint32_t nmagic, unsigned char *s, int nbytes) /* and any continuations that match */ while (m[magindex+1].cont_level != 0 && ++magindex < nmagic) { if (cont_level < m[magindex].cont_level) - continue; + /*@innercontinue@*/ continue; if (cont_level > m[magindex].cont_level) { /* * We're at the end of the level diff --git a/file/system.h b/file/system.h index e7fe901fe..c06a21331 100644 --- a/file/system.h +++ b/file/system.h @@ -190,7 +190,7 @@ extern char *sys_errlist[]; #define strtoul(a, b, c) strtol(a, b, c) #endif -/*@-declundef -incondefs @*/ +/*@-declundef -exportfcn -incondefs @*/ /** */ /*@mayexit@*/ /*@only@*/ /*@out@*/ @@ -216,10 +216,12 @@ void * xrealloc (/*@null@*/ /*@only@*/ void * ptr, size_t size) /** */ +/*@-fcnuse@*/ /*@mayexit@*/ /*@only@*/ char * xstrdup (const char *str) /*@*/; -/*@=declundef =incondefs @*/ +/*@=fcnuse@*/ +/*@=declundef =exportfcn=incondefs @*/ #if HAVE_MCHECK_H #include @@ -247,11 +249,13 @@ extern void muntrace (void) __THROW #endif /* defined(__LCLINT__) */ #endif /* HAVE_MCHECK_H */ +#if !defined(__LCLINT__) /* Memory allocation via macro defs to get meaningful locations from mtrace() */ -#define xmalloc(_size) (malloc(_size) ? : (error("out of memory"), NULL)) -#define xcalloc(_nmemb, _size) (calloc((_nmemb), (_size)) ? : (error("out of memory"), NULL)) -#define xrealloc(_ptr, _size) (realloc((_ptr), (_size)) ? : (error("out of memory"), NULL)) +#define xmalloc(_size) (malloc(_size) ? : vmefail(0)) +#define xcalloc(_nmemb, _size) (calloc((_nmemb), (_size)) ? : vmefail(0)) +#define xrealloc(_ptr, _size) (realloc((_ptr), (_size)) ? : vmefail(0)) #define xstrdup(_str) (strcpy(xmalloc(strlen(_str)+1), (_str))) +#endif #if HAVE_LOCALE_H # include