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