[BACK]Return to file.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / file

Annotation of src/usr.bin/file/file.c, Revision 1.25

1.25    ! doug        1: /*     $OpenBSD: file.c,v 1.24 2015/01/16 05:46:44 deraadt Exp $ */
1.1       deraadt     2: /*
1.11      ian         3:  * Copyright (c) Ian F. Darwin 1986-1995.
                      4:  * Software written by Ian F. Darwin and others;
                      5:  * maintained 1995-present by Christos Zoulas and others.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice immediately at the beginning of the file, without modification,
                     12:  *    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:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     21:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
1.1       deraadt    28:  */
1.14      tedu       29: /*
                     30:  * file - find type of a file or files - main program.
                     31:  */
1.11      ian        32:
1.20      deraadt    33: #include <sys/types.h>
                     34: #include <sys/stat.h>
                     35:
1.14      tedu       36: #include "file.h"
                     37: #include "magic.h"
1.1       deraadt    38:
                     39: #include <stdio.h>
                     40: #include <stdlib.h>
1.14      tedu       41: #include <unistd.h>
1.1       deraadt    42: #include <string.h>
1.14      tedu       43: #ifdef RESTORE_TIME
                     44: # if (__COHERENT__ >= 0x420)
                     45: #  include <sys/utime.h>
1.5       millert    46: # else
1.14      tedu       47: #  ifdef USE_UTIMES
                     48: #   include <sys/time.h>
                     49: #  else
                     50: #   include <utime.h>
                     51: #  endif
1.5       millert    52: # endif
1.1       deraadt    53: #endif
1.14      tedu       54: #ifdef HAVE_UNISTD_H
1.1       deraadt    55: #include <unistd.h>    /* for read() */
1.14      tedu       56: #endif
                     57: #ifdef HAVE_LOCALE_H
                     58: #include <locale.h>
                     59: #endif
                     60: #ifdef HAVE_WCHAR_H
                     61: #include <wchar.h>
                     62: #endif
                     63:
1.19      chl        64: #include <getopt.h>
                     65: #ifndef HAVE_GETOPT_LONG
                     66: int getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex);
1.14      tedu       67: #endif
1.1       deraadt    68:
1.5       millert    69: #include <netinet/in.h>                /* for byte swapping */
1.1       deraadt    70:
                     71: #include "patchlevel.h"
1.14      tedu       72:
1.1       deraadt    73:
                     74: #ifdef S_IFLNK
1.18      chl        75: #define SYMLINKFLAG "Lh"
1.1       deraadt    76: #else
1.14      tedu       77: #define SYMLINKFLAG ""
1.1       deraadt    78: #endif
                     79:
1.21      ajacouto   80: # define USAGE  "Usage: %s [-bcik" SYMLINKFLAG "nNprsvz0] [-e test] [-f namefile] [-F separator] [-m magicfiles] file...\n" \
                     81:                "       %s -C -m magicfiles\n"
1.14      tedu       82:
1.25    ! doug       83: #ifndef PATH_MAX
        !            84: #define        PATH_MAX        1024
1.1       deraadt    85: #endif
                     86:
1.14      tedu       87: private int            /* Global command-line options          */
                     88:        bflag = 0,      /* brief output format                  */
                     89:        nopad = 0,      /* Don't pad output                     */
1.18      chl        90:        nobuffer = 0,   /* Do not buffer stdout                 */
                     91:        nulsep = 0;     /* Append '\0' to the separator         */
1.14      tedu       92:
                     93: private const char *magicfile = 0;     /* where the magic is   */
                     94: private const char *default_magicfile = MAGIC;
1.18      chl        95: private const char *separator = ":";   /* Default field separator      */
1.14      tedu       96:
1.19      chl        97: extern char *__progname;               /* used throughout              */
                     98:
1.14      tedu       99: private struct magic_set *magic;
                    100:
                    101: private void unwrap(char *);
                    102: private void usage(void);
                    103: private void help(void);
1.1       deraadt   104:
1.14      tedu      105: int main(int, char *[]);
                    106: private void process(const char *, int);
                    107: private void load(const char *, int);
1.1       deraadt   108:
                    109:
                    110: /*
                    111:  * main - parse arguments and handle options
                    112:  */
                    113: int
1.13      deraadt   114: main(int argc, char *argv[])
1.1       deraadt   115: {
1.19      chl       116:        int c;
                    117:        size_t i;
1.14      tedu      118:        int action = 0, didsomefiles = 0, errflg = 0;
                    119:        int flags = 0;
                    120:        char *home, *usermagic;
                    121:        struct stat sb;
1.18      chl       122:        static const char hmagic[] = "/.magic";
1.19      chl       123: #define OPTSTRING      "bcCde:f:F:hikLm:nNprsvz0"
1.14      tedu      124:        int longindex;
1.18      chl       125:        static const struct option long_options[] =
1.14      tedu      126:        {
1.19      chl       127: #define OPT(shortname, longname, opt, doc)      \
                    128:     {longname, opt, NULL, shortname},
                    129: #define OPT_LONGONLY(longname, opt, doc)        \
                    130:     {longname, opt, NULL, 0},
                    131: #include "file_opts.h"
                    132: #undef OPT
                    133: #undef OPT_LONGONLY
                    134:     {0, 0, NULL, 0}
                    135: };
1.14      tedu      136:
1.18      chl       137:        static const struct {
                    138:                const char *name;
                    139:                int value;
                    140:        } nv[] = {
                    141:                { "apptype",    MAGIC_NO_CHECK_APPTYPE },
                    142:                { "ascii",      MAGIC_NO_CHECK_ASCII },
                    143:                { "compress",   MAGIC_NO_CHECK_COMPRESS },
                    144:                { "elf",        MAGIC_NO_CHECK_ELF },
                    145:                { "soft",       MAGIC_NO_CHECK_SOFT },
                    146:                { "tar",        MAGIC_NO_CHECK_TAR },
                    147:                { "tokens",     MAGIC_NO_CHECK_TOKENS },
                    148:        };
                    149:
                    150:        /* makes islower etc work for other langs */
                    151:        (void)setlocale(LC_CTYPE, "");
1.1       deraadt   152:
1.14      tedu      153: #ifdef __EMX__
                    154:        /* sh-like wildcard expansion! Shouldn't hurt at least ... */
                    155:        _wildcard(&argc, &argv);
                    156: #endif
1.1       deraadt   157:
1.14      tedu      158:        magicfile = default_magicfile;
                    159:        if ((usermagic = getenv("MAGIC")) != NULL)
                    160:                magicfile = usermagic;
                    161:        else
                    162:                if ((home = getenv("HOME")) != NULL) {
1.18      chl       163:                        size_t len = strlen(home) + sizeof(hmagic);
1.14      tedu      164:                        if ((usermagic = malloc(len)) != NULL) {
                    165:                                (void)strlcpy(usermagic, home, len);
1.18      chl       166:                                (void)strlcat(usermagic, hmagic, len);
1.14      tedu      167:                                if (stat(usermagic, &sb)<0)
                    168:                                        free(usermagic);
                    169:                                else
                    170:                                        magicfile = usermagic;
                    171:                        }
                    172:                }
                    173:
1.18      chl       174: #ifdef S_IFLNK
                    175:        flags |= getenv("POSIXLY_CORRECT") ? MAGIC_SYMLINK : 0;
                    176: #endif
1.14      tedu      177:        while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
                    178:            &longindex)) != -1)
1.1       deraadt   179:                switch (c) {
1.14      tedu      180:                case 0 :
1.19      chl       181:                        switch (longindex) {
                    182:                        case 0:
1.14      tedu      183:                                help();
1.19      chl       184:                                break;
                    185:                        case 10:
                    186:                                flags |= MAGIC_MIME_TYPE;
                    187:                                break;
                    188:                        case 11:
                    189:                                flags |= MAGIC_MIME_ENCODING;
                    190:                                break;
                    191:                        }
1.14      tedu      192:                        break;
1.18      chl       193:                case '0':
                    194:                        nulsep = 1;
                    195:                        break;
1.9       millert   196:                case 'b':
1.19      chl       197:                        bflag++;
1.9       millert   198:                        break;
1.1       deraadt   199:                case 'c':
1.14      tedu      200:                        action = FILE_CHECK;
                    201:                        break;
                    202:                case 'C':
                    203:                        action = FILE_COMPILE;
1.1       deraadt   204:                        break;
                    205:                case 'd':
1.14      tedu      206:                        flags |= MAGIC_DEBUG|MAGIC_CHECK;
1.1       deraadt   207:                        break;
1.18      chl       208:                case 'e':
                    209:                        for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++)
                    210:                                if (strcmp(nv[i].name, optarg) == 0)
                    211:                                        break;
                    212:
                    213:                        if (i == sizeof(nv) / sizeof(nv[0]))
                    214:                                errflg++;
                    215:                        else
                    216:                                flags |= nv[i].value;
                    217:                        break;
                    218:
1.1       deraadt   219:                case 'f':
1.14      tedu      220:                        if(action)
                    221:                                usage();
                    222:                        load(magicfile, flags);
1.1       deraadt   223:                        unwrap(optarg);
                    224:                        ++didsomefiles;
                    225:                        break;
1.14      tedu      226:                case 'F':
                    227:                        separator = optarg;
                    228:                        break;
1.19      chl       229:                case 'i':
                    230:                        flags |= MAGIC_MIME;
                    231:                        break;
1.14      tedu      232:                case 'k':
                    233:                        flags |= MAGIC_CONTINUE;
1.1       deraadt   234:                        break;
                    235:                case 'm':
                    236:                        magicfile = optarg;
                    237:                        break;
1.14      tedu      238:                case 'n':
                    239:                        ++nobuffer;
                    240:                        break;
                    241:                case 'N':
                    242:                        ++nopad;
                    243:                        break;
                    244: #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
                    245:                case 'p':
                    246:                        flags |= MAGIC_PRESERVE_ATIME;
                    247:                        break;
                    248: #endif
                    249:                case 'r':
                    250:                        flags |= MAGIC_RAW;
                    251:                        break;
                    252:                case 's':
                    253:                        flags |= MAGIC_DEVICES;
                    254:                        break;
                    255:                case 'v':
1.19      chl       256:                        (void)fprintf(stderr, "%s-%d.%.2d\n", __progname,
1.14      tedu      257:                                       FILE_VERSION_MAJOR, patchlevel);
1.19      chl       258:                        (void)fprintf(stderr, "magic file from %s\n",
1.14      tedu      259:                                       magicfile);
                    260:                        return 1;
1.1       deraadt   261:                case 'z':
1.14      tedu      262:                        flags |= MAGIC_COMPRESS;
1.1       deraadt   263:                        break;
1.14      tedu      264: #ifdef S_IFLNK
                    265:                case 'L':
                    266:                        flags |= MAGIC_SYMLINK;
                    267:                        break;
1.18      chl       268:                case 'h':
                    269:                        flags &= ~MAGIC_SYMLINK;
                    270:                        break;
1.14      tedu      271: #endif
1.1       deraadt   272:                case '?':
                    273:                default:
                    274:                        errflg++;
                    275:                        break;
                    276:                }
                    277:
                    278:        if (errflg) {
1.14      tedu      279:                usage();
1.1       deraadt   280:        }
                    281:
1.14      tedu      282:        switch(action) {
                    283:        case FILE_CHECK:
                    284:        case FILE_COMPILE:
                    285:                magic = magic_open(flags|MAGIC_CHECK);
                    286:                if (magic == NULL) {
1.18      chl       287:                        (void)fprintf(stderr, "%s: %s\n", __progname,
1.14      tedu      288:                            strerror(errno));
                    289:                        return 1;
                    290:                }
                    291:                c = action == FILE_CHECK ? magic_check(magic, magicfile) :
                    292:                    magic_compile(magic, magicfile);
                    293:                if (c == -1) {
1.18      chl       294:                        (void)fprintf(stderr, "%s: %s\n", __progname,
1.14      tedu      295:                            magic_error(magic));
                    296:                        return -1;
                    297:                }
                    298:                return 0;
                    299:        default:
                    300:                load(magicfile, flags);
                    301:                break;
1.1       deraadt   302:        }
                    303:
                    304:        if (optind == argc) {
1.7       deraadt   305:                if (!didsomefiles) {
1.14      tedu      306:                        usage();
1.7       deraadt   307:                }
1.14      tedu      308:        }
                    309:        else {
1.19      chl       310:                size_t j, wid, nw;
                    311:                for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) {
                    312:                        nw = file_mbswidth(argv[j]);
1.1       deraadt   313:                        if (nw > wid)
                    314:                                wid = nw;
                    315:                }
1.19      chl       316:                /*
                    317:                 * If bflag is only set twice, set it depending on
                    318:                 * number of files [this is undocumented, and subject to change]
                    319:                 */
                    320:                if (bflag == 2) {
                    321:                        bflag = optind >= argc - 1;
                    322:                }
1.1       deraadt   323:                for (; optind < argc; optind++)
                    324:                        process(argv[optind], wid);
                    325:        }
                    326:
1.19      chl       327:        c = magic->haderr ? 1 : 0;
1.18      chl       328:        magic_close(magic);
1.19      chl       329:        return c;
1.1       deraadt   330: }
                    331:
                    332:
1.14      tedu      333: private void
1.18      chl       334: /*ARGSUSED*/
1.14      tedu      335: load(const char *m, int flags)
                    336: {
1.18      chl       337:        if (magic || m == NULL)
1.14      tedu      338:                return;
                    339:        magic = magic_open(flags);
                    340:        if (magic == NULL) {
1.18      chl       341:                (void)fprintf(stderr, "%s: %s\n", __progname, strerror(errno));
1.14      tedu      342:                exit(1);
                    343:        }
                    344:        if (magic_load(magic, magicfile) == -1) {
                    345:                (void)fprintf(stderr, "%s: %s\n",
1.18      chl       346:                    __progname, magic_error(magic));
1.14      tedu      347:                exit(1);
                    348:        }
                    349: }
                    350:
1.1       deraadt   351: /*
                    352:  * unwrap -- read a file of filenames, do each one.
                    353:  */
1.14      tedu      354: private void
                    355: unwrap(char *fn)
1.1       deraadt   356: {
1.25    ! doug      357:        char buf[PATH_MAX];
1.1       deraadt   358:        FILE *f;
                    359:        int wid = 0, cwid;
                    360:
1.5       millert   361:        if (strcmp("-", fn) == 0) {
                    362:                f = stdin;
                    363:                wid = 1;
                    364:        } else {
                    365:                if ((f = fopen(fn, "r")) == NULL) {
1.14      tedu      366:                        (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n",
1.18      chl       367:                            __progname, fn, strerror(errno));
1.14      tedu      368:                        exit(1);
1.5       millert   369:                }
                    370:
1.15      otto      371:                while (fgets(buf, sizeof(buf), f) != NULL) {
1.18      chl       372:                        buf[strcspn(buf, "\n")] = '\0';
                    373:                        cwid = file_mbswidth(buf);
1.5       millert   374:                        if (cwid > wid)
                    375:                                wid = cwid;
                    376:                }
1.1       deraadt   377:
1.5       millert   378:                rewind(f);
1.1       deraadt   379:        }
                    380:
1.15      otto      381:        while (fgets(buf, sizeof(buf), f) != NULL) {
1.18      chl       382:                buf[strcspn(buf, "\n")] = '\0';
1.1       deraadt   383:                process(buf, wid);
1.14      tedu      384:                if(nobuffer)
1.18      chl       385:                        (void)fflush(stdout);
1.1       deraadt   386:        }
                    387:
1.18      chl       388:        (void)fclose(f);
1.1       deraadt   389: }
                    390:
1.18      chl       391: /*
                    392:  * Called for each input file on the command line (or in a list of files)
                    393:  */
1.14      tedu      394: private void
                    395: process(const char *inname, int wid)
                    396: {
                    397:        const char *type;
                    398:        int std_in = strcmp(inname, "-") == 0;
                    399:
1.18      chl       400:        if (wid > 0 && !bflag) {
                    401:                (void)printf("%s", std_in ? "/dev/stdin" : inname);
                    402:                if (nulsep)
                    403:                        (void)putc('\0', stdout);
                    404:                else
                    405:                        (void)printf("%s", separator);
                    406:                (void)printf("%*s ",
                    407:                    (int) (nopad ? 0 : (wid - file_mbswidth(inname))), "");
                    408:        }
1.14      tedu      409:
                    410:        type = magic_file(magic, std_in ? NULL : inname);
                    411:        if (type == NULL)
1.18      chl       412:                (void)printf("ERROR: %s\n", magic_error(magic));
1.14      tedu      413:        else
1.18      chl       414:                (void)printf("%s\n", type);
1.14      tedu      415: }
                    416:
                    417: size_t
                    418: file_mbswidth(const char *s)
1.1       deraadt   419: {
1.18      chl       420: #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
1.14      tedu      421:        size_t bytesconsumed, old_n, n, width = 0;
                    422:        mbstate_t state;
                    423:        wchar_t nextchar;
                    424:        (void)memset(&state, 0, sizeof(mbstate_t));
                    425:        old_n = n = strlen(s);
1.23      stsp      426:        int w;
1.14      tedu      427:
                    428:        while (n > 0) {
                    429:                bytesconsumed = mbrtowc(&nextchar, s, n, &state);
                    430:                if (bytesconsumed == (size_t)(-1) ||
                    431:                    bytesconsumed == (size_t)(-2)) {
                    432:                        /* Something went wrong, return something reasonable */
                    433:                        return old_n;
1.1       deraadt   434:                }
1.14      tedu      435:                if (s[0] == '\n') {
                    436:                        /*
                    437:                         * do what strlen() would do, so that caller
                    438:                         * is always right
                    439:                         */
                    440:                        width++;
1.23      stsp      441:                } else {
                    442:                        w = wcwidth(nextchar);
                    443:                        if (w > 0)
                    444:                                width += w;
                    445:                }
1.1       deraadt   446:
1.14      tedu      447:                s += bytesconsumed, n -= bytesconsumed;
1.1       deraadt   448:        }
1.14      tedu      449:        return width;
                    450: #else
                    451:        return strlen(s);
1.5       millert   452: #endif
1.14      tedu      453: }
1.1       deraadt   454:
1.14      tedu      455: private void
                    456: usage(void)
                    457: {
1.18      chl       458:        (void)fprintf(stderr, USAGE, __progname, __progname);
1.14      tedu      459:        (void)fputs("Try `file --help' for more information.\n", stderr);
                    460:        exit(1);
1.1       deraadt   461: }
                    462:
1.14      tedu      463: private void
                    464: help(void)
1.1       deraadt   465: {
1.19      chl       466:        (void)fputs(
                    467: "Usage: file [OPTION...] [FILE...]\n"
                    468: "Determine type of FILEs.\n"
                    469: "\n", stderr);
                    470: #define OPT(shortname, longname, opt, doc)      \
                    471:         fprintf(stderr, "  -%c, --" longname doc, shortname);
                    472: #define OPT_LONGONLY(longname, opt, doc)        \
                    473:         fprintf(stderr, "      --" longname doc);
                    474: #include "file_opts.h"
                    475: #undef OPT
                    476: #undef OPT_LONGONLY
1.14      tedu      477:        exit(0);
1.1       deraadt   478: }