00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "file.h"
00033 #include "magic.h"
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <sys/types.h>
00040 #include <sys/param.h>
00041 #include <sys/stat.h>
00042 #ifdef RESTORE_TIME
00043 # if (__COHERENT__ >= 0x420)
00044 # include <sys/utime.h>
00045 # else
00046 # ifdef USE_UTIMES
00047 # include <sys/time.h>
00048 # else
00049 # include <utime.h>
00050 # endif
00051 # endif
00052 #endif
00053 #ifdef HAVE_UNISTD_H
00054 #include <unistd.h>
00055 #endif
00056 #ifdef HAVE_LOCALE_H
00057 #include <locale.h>
00058 #endif
00059 #ifdef HAVE_WCHAR_H
00060 #include <wchar.h>
00061 #endif
00062
00063 #ifdef HAVE_GETOPT_H
00064 #include <getopt.h>
00065 #else
00066 #undef HAVE_GETOPT_LONG
00067 #endif
00068
00069 #include <netinet/in.h>
00070
00071 #include "patchlevel.h"
00072
00073 #ifndef lint
00074 FILE_RCSID("@(#)$File: file.c,v 1.111 2007/05/08 14:44:18 christos Exp $")
00075 #endif
00076
00077
00078 #ifdef S_IFLNK
00079 #define SYMLINKFLAG "Lh"
00080 #else
00081 #define SYMLINKFLAG ""
00082 #endif
00083
00084 # define USAGE "Usage: %s [-bcik" SYMLINKFLAG "nNrsvz0] [-e test] [-f namefile] [-F separator] [-m magicfiles] file...\n %s -C -m magicfiles\n"
00085
00086 #ifndef MAXPATHLEN
00087 #define MAXPATHLEN 512
00088 #endif
00089
00090
00091 private int
00092 bflag = 0,
00093 nopad = 0,
00094 nobuffer = 0,
00095 nulsep = 0;
00096
00097
00098 private const char *magicfile = 0;
00099
00100 private const char *default_magicfile = MAGIC;
00101
00102 private const char *separator = ":";
00103
00104
00105 private char *progname;
00106
00107
00108 private struct magic_set *magic;
00109
00110 private void unwrap(char *)
00111
00112 ;
00113
00114 private void usage(void)
00115
00116 ;
00117 #ifdef HAVE_GETOPT_LONG
00118
00119 private void help(void)
00120
00121 ;
00122 #endif
00123 #if 0
00124 private int byteconv4(int, int, int);
00125 private short byteconv2(int, int, int);
00126 #endif
00127
00128 int main(int argc, char *argv[])
00129
00130
00131
00132 ;
00133 private void process(const char *, int)
00134
00135 ;
00136 private void load(const char *m, int flags)
00137
00138 ;
00139
00140
00141
00142
00143 int
00144 main(int argc, char *argv[])
00145 {
00146 int c, i;
00147 int action = 0, didsomefiles = 0, errflg = 0;
00148 int flags = 0;
00149 char *home, *usermagic;
00150 struct stat sb;
00151
00152 static const char hmagic[] = "/.magic";
00153 #define OPTSTRING "bcCde:f:F:hikLm:nNprsvz0"
00154 #ifdef HAVE_GETOPT_LONG
00155 int longindex;
00156
00157
00158 static const struct option long_options[] =
00159 {
00160 {"version", 0, 0, 'v'},
00161 {"help", 0, 0, 0},
00162 {"brief", 0, 0, 'b'},
00163 {"checking-printout", 0, 0, 'c'},
00164 {"debug", 0, 0, 'd'},
00165 {"exclude", 1, 0, 'e' },
00166 {"files-from", 1, 0, 'f'},
00167 {"separator", 1, 0, 'F'},
00168 {"mime", 0, 0, 'i'},
00169 {"keep-going", 0, 0, 'k'},
00170 #ifdef S_IFLNK
00171 {"dereference", 0, 0, 'L'},
00172 {"no-dereference", 0, 0, 'h'},
00173 #endif
00174 {"magic-file", 1, 0, 'm'},
00175 #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
00176 {"preserve-date", 0, 0, 'p'},
00177 #endif
00178 {"uncompress", 0, 0, 'z'},
00179 {"raw", 0, 0, 'r'},
00180 {"no-buffer", 0, 0, 'n'},
00181 {"no-pad", 0, 0, 'N'},
00182 {"special-files", 0, 0, 's'},
00183 {"compile", 0, 0, 'C'},
00184 {"print0", 0, 0, '0'},
00185 {0, 0, 0, 0},
00186 };
00187 #endif
00188
00189
00190
00191 static const struct {
00192
00193 const char *name;
00194 int value;
00195 } nv[] = {
00196 { "apptype", MAGIC_NO_CHECK_APPTYPE },
00197 { "ascii", MAGIC_NO_CHECK_ASCII },
00198 { "compress", MAGIC_NO_CHECK_COMPRESS },
00199 { "elf", MAGIC_NO_CHECK_ELF },
00200 { "fortran", MAGIC_NO_CHECK_FORTRAN },
00201 { "soft", MAGIC_NO_CHECK_SOFT },
00202 { "tar", MAGIC_NO_CHECK_TAR },
00203 { "tokens", MAGIC_NO_CHECK_TOKENS },
00204 { "troff", MAGIC_NO_CHECK_TROFF },
00205 };
00206
00207 #ifdef LC_CTYPE
00208
00209 (void)setlocale(LC_CTYPE, "");
00210 #endif
00211
00212 #ifdef __EMX__
00213
00214 _wildcard(&argc, &argv);
00215 #endif
00216
00217 if ((progname = strrchr(argv[0], '/')) != NULL)
00218 progname++;
00219 else
00220 progname = argv[0];
00221
00222 magicfile = default_magicfile;
00223 if ((usermagic = getenv("MAGIC")) != NULL)
00224 magicfile = usermagic;
00225 else
00226 if ((home = getenv("HOME")) != NULL) {
00227 if ((usermagic = malloc(strlen(home)
00228 + sizeof(hmagic))) != NULL) {
00229 (void)strcpy(usermagic, home);
00230 (void)strcat(usermagic, hmagic);
00231 if (stat(usermagic, &sb)<0)
00232 free(usermagic);
00233 else
00234 magicfile = usermagic;
00235 }
00236 }
00237
00238 #ifdef S_IFLNK
00239 flags |= getenv("POSIXLY_CORRECT") ? MAGIC_SYMLINK : 0;
00240 #endif
00241 #ifndef HAVE_GETOPT_LONG
00242 while ((c = getopt(argc, argv, OPTSTRING)) != -1)
00243 #else
00244 while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
00245 &longindex)) != -1)
00246 #endif
00247 switch (c) {
00248 #ifdef HAVE_GETOPT_LONG
00249 case 0 :
00250 if (longindex == 1)
00251 help();
00252 break;
00253 #endif
00254 case '0':
00255 nulsep = 1;
00256 break;
00257 case 'b':
00258 ++bflag;
00259 break;
00260 case 'c':
00261 action = FILE_CHECK;
00262 break;
00263 case 'C':
00264 action = FILE_COMPILE;
00265 break;
00266 case 'd':
00267 flags |= MAGIC_DEBUG|MAGIC_CHECK;
00268 break;
00269 case 'e':
00270 for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++)
00271 if (strcmp(nv[i].name, optarg) == 0)
00272 break;
00273
00274 if (i == sizeof(nv) / sizeof(nv[0]))
00275 errflg++;
00276 else
00277 flags |= nv[i].value;
00278 break;
00279
00280 case 'f':
00281 if(action)
00282 usage();
00283 load(magicfile, flags);
00284 unwrap(optarg);
00285 ++didsomefiles;
00286 break;
00287 case 'F':
00288 separator = optarg;
00289 break;
00290 case 'i':
00291 flags |= MAGIC_MIME;
00292 break;
00293 case 'k':
00294 flags |= MAGIC_CONTINUE;
00295 break;
00296 case 'm':
00297 magicfile = optarg;
00298 break;
00299 case 'n':
00300 ++nobuffer;
00301 break;
00302 case 'N':
00303 ++nopad;
00304 break;
00305 #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
00306 case 'p':
00307 flags |= MAGIC_PRESERVE_ATIME;
00308 break;
00309 #endif
00310 case 'r':
00311 flags |= MAGIC_RAW;
00312 break;
00313 case 's':
00314 flags |= MAGIC_DEVICES;
00315 break;
00316 case 'v':
00317 (void)fprintf(stdout, "%s-%d.%.2d\n", progname,
00318 FILE_VERSION_MAJOR, patchlevel);
00319 (void)fprintf(stdout, "magic file from %s\n",
00320 magicfile);
00321 return 1;
00322 case 'z':
00323 flags |= MAGIC_COMPRESS;
00324 break;
00325 #ifdef S_IFLNK
00326 case 'L':
00327 flags |= MAGIC_SYMLINK;
00328 break;
00329 case 'h':
00330 flags &= ~MAGIC_SYMLINK;
00331 break;
00332 #endif
00333 case '?':
00334 default:
00335 errflg++;
00336 break;
00337 }
00338
00339 if (errflg) {
00340 usage();
00341 }
00342
00343 switch(action) {
00344 case FILE_CHECK:
00345 case FILE_COMPILE:
00346 magic = magic_open(flags|MAGIC_CHECK);
00347 if (magic == NULL) {
00348 (void)fprintf(stderr, "%s: %s\n", progname,
00349 strerror(errno));
00350 return 1;
00351 }
00352 c = action == FILE_CHECK ? magic_check(magic, magicfile) :
00353 magic_compile(magic, magicfile);
00354 if (c == -1) {
00355 (void)fprintf(stderr, "%s: %s\n", progname,
00356 magic_error(magic));
00357 return -1;
00358 }
00359 return 0;
00360 default:
00361 load(magicfile, flags);
00362 break;
00363 }
00364
00365 if (optind == argc) {
00366 if (!didsomefiles) {
00367 usage();
00368 }
00369 }
00370 else {
00371 int i, wid, nw;
00372 for (wid = 0, i = optind; i < argc; i++) {
00373 nw = file_mbswidth(argv[i]);
00374 if (nw > wid)
00375 wid = nw;
00376 }
00377 for (; optind < argc; optind++)
00378 process(argv[optind], wid);
00379 }
00380
00381 magic_close(magic);
00382 return 0;
00383 }
00384
00385
00386 private void
00387 load( const char *m f__unused, int flags)
00388 {
00389 if (magic)
00390 return;
00391 magic = magic_open(flags);
00392 if (magic == NULL) {
00393 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
00394 exit(EXIT_FAILURE);
00395 }
00396 if (magic_load(magic, magicfile) == -1) {
00397 (void)fprintf(stderr, "%s: %s\n",
00398 progname, magic_error(magic));
00399 exit(EXIT_FAILURE);
00400 }
00401 }
00402
00403
00404
00405
00406 private void
00407 unwrap(char *fn)
00408 {
00409 char buf[MAXPATHLEN];
00410 FILE *f;
00411 int wid = 0, cwid;
00412 size_t len;
00413
00414 if (strcmp("-", fn) == 0) {
00415 f = stdin;
00416 wid = 1;
00417 } else {
00418 if ((f = fopen(fn, "r")) == NULL) {
00419 (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n",
00420 progname, fn, strerror(errno));
00421 exit(EXIT_FAILURE);
00422 }
00423
00424 while (fgets(buf, MAXPATHLEN, f) != NULL) {
00425 len = strlen(buf);
00426 if (len > 0 && buf[len - 1] == '\n')
00427 buf[len - 1] = '\0';
00428 cwid = file_mbswidth(buf);
00429 if (cwid > wid)
00430 wid = cwid;
00431 }
00432
00433 rewind(f);
00434 }
00435
00436 while (fgets(buf, MAXPATHLEN, f) != NULL) {
00437 len = strlen(buf);
00438 if (len > 0 && buf[len - 1] == '\n')
00439 buf[len - 1] = '\0';
00440 process(buf, wid);
00441 if(nobuffer)
00442 (void)fflush(stdout);
00443 }
00444
00445 (void)fclose(f);
00446 }
00447
00448
00449
00450
00451 private void
00452 process(const char *inname, int wid)
00453 {
00454 const char *type;
00455 int std_in = strcmp(inname, "-") == 0;
00456
00457 if (wid > 0 && !bflag) {
00458 (void)printf("%s", std_in ? "/dev/stdin" : inname);
00459 if (nulsep)
00460 (void)putc('\0', stdout);
00461 else
00462 (void)printf("%s", separator);
00463 (void)printf("%*s ",
00464 (int) (nopad ? 0 : (wid - file_mbswidth(inname))), "");
00465 }
00466
00467 type = magic_file(magic, std_in ? NULL : inname);
00468 if (type == NULL)
00469 (void)printf("ERROR: %s\n", magic_error(magic));
00470 else
00471 (void)printf("%s\n", type);
00472 }
00473
00474
00475 #if 0
00476
00477
00478
00479
00480
00481
00482
00483 private int
00484 byteconv4(int from, int same, int big_endian)
00485 {
00486 if (same)
00487 return from;
00488 else if (big_endian) {
00489 union {
00490 int i;
00491 char c[4];
00492 } retval, tmpval;
00493
00494 tmpval.i = from;
00495 retval.c[0] = tmpval.c[3];
00496 retval.c[1] = tmpval.c[2];
00497 retval.c[2] = tmpval.c[1];
00498 retval.c[3] = tmpval.c[0];
00499
00500 return retval.i;
00501 }
00502 else
00503 return ntohl(from);
00504 }
00505
00506
00507
00508
00509
00510 private short
00511 byteconv2(int from, int same, int big_endian)
00512 {
00513 if (same)
00514 return from;
00515 else if (big_endian) {
00516 union {
00517 short s;
00518 char c[2];
00519 } retval, tmpval;
00520
00521 tmpval.s = (short) from;
00522 retval.c[0] = tmpval.c[1];
00523 retval.c[1] = tmpval.c[0];
00524
00525 return retval.s;
00526 }
00527 else
00528 return ntohs(from);
00529 }
00530 #endif
00531
00532 size_t
00533 file_mbswidth(const char *s)
00534 {
00535 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
00536 size_t bytesconsumed, old_n, n, width = 0;
00537 mbstate_t state;
00538 wchar_t nextchar;
00539 (void)memset(&state, 0, sizeof(mbstate_t));
00540 old_n = n = strlen(s);
00541
00542 while (n > 0) {
00543 bytesconsumed = mbrtowc(&nextchar, s, n, &state);
00544 if (bytesconsumed == (size_t)(-1) ||
00545 bytesconsumed == (size_t)(-2)) {
00546
00547 return old_n;
00548 }
00549 if (s[0] == '\n') {
00550
00551
00552
00553
00554 width++;
00555 } else
00556 width += wcwidth(nextchar);
00557
00558 s += bytesconsumed, n -= bytesconsumed;
00559 }
00560 return width;
00561 #else
00562 return strlen(s);
00563 #endif
00564 }
00565
00566 private void
00567 usage(void)
00568 {
00569 (void)fprintf(stderr, USAGE, progname, progname);
00570 #ifdef HAVE_GETOPT_LONG
00571 (void)fputs("Try `file --help' for more information.\n", stderr);
00572 #endif
00573 exit(EXIT_FAILURE);
00574 }
00575
00576 #ifdef HAVE_GETOPT_LONG
00577 private void
00578 help(void)
00579 {
00580 (void)puts(
00581 "Usage: file [OPTION]... [FILE]...\n"
00582 "Determine file type of FILEs.\n"
00583 "\n"
00584 " -m, --magic-file LIST use LIST as a colon-separated list of magic\n"
00585 " number files\n"
00586 " -z, --uncompress try to look inside compressed files\n"
00587 " -b, --brief do not prepend filenames to output lines\n"
00588 " -c, --checking-printout print the parsed form of the magic file, use in\n"
00589 " conjunction with -m to debug a new magic file\n"
00590 " before installing it\n"
00591 " -e, --exclude exclude test from the list of test to be\n"
00592 " performed for file. Valid tests are:\n"
00593 " ascii, apptype, elf, compress, soft, tar\n"
00594 " -f, --files-from FILE read the filenames to be examined from FILE\n"
00595 " -F, --separator string use string as separator instead of `:'\n"
00596 " -i, --mime output mime type strings\n"
00597 " -k, --keep-going don't stop at the first match\n"
00598 " -L, --dereference causes symlinks to be followed\n"
00599 " -n, --no-buffer do not buffer output\n"
00600 " -N, --no-pad do not pad output\n"
00601 " -p, --preserve-date preserve access times on files\n"
00602 " -r, --raw don't translate unprintable chars to \\ooo\n"
00603 " -s, --special-files treat special (block/char devices) files as\n"
00604 " ordinary ones\n"
00605 "or\n"
00606 " --help display this help and exit\n"
00607 "or\n"
00608 " --version output version information and exit\n"
00609 "or\n"
00610 " -C, --compile compile file specified by -m\n"
00611 );
00612 exit(EXIT_SUCCESS);
00613 }
00614 #endif