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

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