[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.23

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