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

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