home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / file39a.zip / src / file.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  8KB  |  343 lines

  1. /*
  2.  * file - find type of a file or files - main program.
  3.  *
  4.  * Copyright (c) Ian F. Darwin, 1987.
  5.  * Written by Ian F. Darwin.
  6.  *
  7.  * This software is not subject to any license of the American Telephone
  8.  * and Telegraph Company or of the Regents of the University of California.
  9.  *
  10.  * Permission is granted to anyone to use this software for any purpose on
  11.  * any computer system, and to alter it and redistribute it freely, subject
  12.  * to the following restrictions:
  13.  *
  14.  * 1. The author is not responsible for the consequences of use of this
  15.  *    software, no matter how awful, even if they arise from flaws in it.
  16.  *
  17.  * 2. The origin of this software must not be misrepresented, either by
  18.  *    explicit claim or by omission.  Since few users ever read sources,
  19.  *    credits must appear in the documentation.
  20.  *
  21.  * 3. Altered versions must be plainly marked as such, and must not be
  22.  *    misrepresented as being the original software.  Since few users
  23.  *    ever read sources, credits must appear in the documentation.
  24.  *
  25.  * 4. This notice may not be removed or altered.
  26.  */
  27. #ifndef    lint
  28. static char *moduleid = 
  29.     "@(#)$Id: file.c,v 1.26 93/02/19 14:22:45 ian Exp $";
  30. #endif    /* lint */
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sys/types.h>
  36. #ifndef MSC
  37. #include <sys/param.h>    /* for MAXPATHLEN */
  38. #endif
  39. #include <sys/stat.h>
  40. #include <fcntl.h>    /* for open() */
  41. #ifdef OS2
  42. #include <io.h>
  43. #include <sys/utime.h>
  44. #else
  45. #include <utime.h>
  46. #endif
  47. #ifndef MSC
  48. #include <unistd.h>    /* for read() */
  49. #endif
  50.  
  51. #include "file.h"
  52.  
  53. #ifdef S_IFLNK
  54. # define USAGE  "Usage: %s [-czL] [-f namefile] [-m magicfile] file...\n"
  55. #else
  56. # define USAGE  "Usage: %s [-cz] [-f namefile] [-m magicfile] file...\n"
  57. #endif
  58.  
  59. #ifndef MAGIC
  60. # define MAGIC "/etc/magic"
  61. #endif
  62.  
  63. int             /* Global command-line options         */
  64.     debug = 0,     /* debugging                 */
  65.     lflag = 0,    /* follow Symlinks (BSD only)         */
  66.     zflag = 0;    /* follow (uncompress) compressed files */
  67.  
  68. int            /* Misc globals                */
  69.     nmagic = 0;    /* number of valid magic[]s         */
  70.  
  71. struct  magic *magic;    /* array of magic entries        */
  72.  
  73. char *magicfile = MAGIC;/* where magic be found         */
  74.  
  75. char *progname;        /* used throughout             */
  76. int lineno;        /* line number in the magic file    */
  77.  
  78.  
  79. static void unwrap    __P((char *fn));
  80.  
  81. /*
  82.  * main - parse arguments and handle options
  83.  */
  84. int
  85. main(argc, argv)
  86. int argc;
  87. char *argv[];
  88. {
  89.     int c;
  90.     int check = 0, didsomefiles = 0, errflg = 0, ret = 0;
  91. #ifdef OS2
  92.     char    path[_MAX_PATH], drive[_MAX_DRIVE], dir[_MAX_DIR], *p;
  93. #endif
  94.  
  95. #ifdef EMX
  96.     _wildcard(&argc, &argv);
  97. #endif
  98.  
  99. #ifdef OS2
  100.     progname = _getname(argv[0]);
  101. #else
  102.     if ((progname = strrchr(argv[0], '/')) != NULL)
  103.         progname++;
  104.     else
  105.         progname = argv[0];
  106. #endif
  107.  
  108.     while ((c = getopt(argc, argv, "cdf:Lm:z")) != EOF)
  109.         switch (c) {
  110.         case 'c':
  111.             ++check;
  112.             break;
  113.         case 'd':
  114.             ++debug;
  115.             break;
  116.         case 'f':
  117.             unwrap(optarg);
  118.             ++didsomefiles;
  119.             break;
  120. #ifdef S_IFLNK
  121.         case 'L':
  122.             ++lflag;
  123.             break;
  124. #endif
  125.         case 'm':
  126.             magicfile = optarg;
  127.             break;
  128.         case 'z':
  129.             zflag++;
  130.             break;
  131.         case '?':
  132.         default:
  133.             errflg++;
  134.             break;
  135.         }
  136.     if (errflg) {
  137.         (void) fprintf(stderr, USAGE, progname);
  138.         exit(2);
  139.     }
  140.  
  141. #ifdef OS2
  142.     if (access(magicfile, 4)) {
  143.         _splitpath(argv[0], drive, dir, NULL, NULL);     /* Try dir of exe */
  144.         sprintf(path, "%s%s%s", drive, dir, p = _getname(magicfile));
  145.         if (access(path, 4)) {       
  146.             _searchenv(p, "PATH", path);                    /* next, try PATH */
  147.             if (*path == '\0') 
  148.                 _searchenv(p, "DPATH", path);                 /* finally, try DPATH */
  149.         }
  150.         if (*path)
  151.             magicfile = path;
  152.     }
  153. #endif
  154.  
  155.     ret = apprentice(magicfile, check);
  156.     if (check)
  157.         exit(ret);
  158.  
  159.     if (optind == argc) {
  160. #ifdef OS2
  161.         if (!isatty(fileno(stdin))) {    /* Do stdin */
  162.             process("-", 1);
  163.             ++didsomefiles;
  164.         }
  165. #endif
  166.         if (!didsomefiles) {
  167.             (void)fprintf(stderr, USAGE, progname);
  168.             exit(2);
  169.         }
  170.     }
  171.     else {
  172.         int i, wid, nw;
  173.         for (wid = 0, i = optind; i < argc; i++) {
  174.             nw = strlen(argv[i]);
  175.             if (nw > wid)
  176.                 wid = nw;
  177.         }
  178.         for (; optind < argc; optind++)
  179.             process(argv[optind], wid);
  180.     }
  181.  
  182.     return 0;
  183. }
  184.  
  185.  
  186. /*
  187.  * unwrap -- read a file of filenames, do each one.
  188.  */
  189. static void
  190. unwrap(fn)
  191. char *fn;
  192. {
  193.     char buf[MAXPATHLEN];
  194.     FILE *f;
  195.     int wid = 0, cwid;
  196.  
  197.     if ((f = fopen(fn, "r")) == NULL) {
  198.         error("Cannot open `%s' (%s).\n", fn, strerror(errno));
  199.         /*NOTREACHED*/
  200.     }
  201.  
  202.     while (fgets(buf, MAXPATHLEN, f) != NULL) {
  203.         cwid = strlen(buf) - 1;
  204.         if (cwid > wid)
  205.             wid = cwid;
  206.     }
  207.  
  208.     rewind(f);
  209.  
  210.     while (fgets(buf, MAXPATHLEN, f) != NULL) {
  211.         buf[strlen(buf)-1] = '\0';
  212.         process(buf, wid);
  213.     }
  214.  
  215.     (void) fclose(f);
  216. }
  217.  
  218.  
  219. #ifdef OS2
  220. static    const char    *apptypeName;
  221. #endif
  222.  
  223. /*
  224.  * process - process input file
  225.  */
  226. void
  227. process(inname, wid)
  228. const char    *inname;
  229. int wid;
  230. {
  231.     int    fd = 0;
  232.     static  const char stdname[] = "standard input";
  233.     unsigned char    buf[HOWMANY+1];    /* one extra for terminating '\0' */
  234.     struct utimbuf  utbuf;
  235.     struct stat    sb;
  236.     int nbytes = 0;    /* number of bytes read from a datafile */
  237.  
  238. #ifdef OS2
  239.     apptypeName = inname;
  240. #endif
  241.  
  242.     if (strcmp("-", inname) == 0) {
  243.         if (fstat(0, &sb)<0) {
  244.             error("cannot fstat `%s' (%s).\n", stdname, 
  245.                   strerror(errno));
  246.             /*NOTREACHED*/
  247.         }
  248.         inname = stdname;
  249. #ifdef OS2
  250.         if (wid < strlen(inname))        /* bugfix (?), not OS/2-specific */
  251.             wid = strlen(inname);
  252.         apptypeName = NULL;
  253. #endif
  254.     }
  255.  
  256.     if (wid > 0)
  257.          (void) printf("%s:%*s ", inname, wid - strlen(inname), "");
  258.  
  259.     if (inname != stdname) {
  260.         /*
  261.          * first try judging the file based on its filesystem status
  262.          */
  263.         if (fsmagic(inname, &sb) != 0) {
  264.             putchar('\n');
  265.             return;
  266.         }
  267.         
  268.         if ((fd = open(inname, O_RDONLY)) < 0) {
  269.             /* We can't open it, but we were able to stat it. */
  270.             if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
  271.             if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
  272.             ckfprintf(stdout, "can't read `%s' (%s).\n",
  273.             inname, strerror(errno));
  274.             return;
  275.         }
  276.     }
  277.  
  278. #ifdef OS2
  279.     setmode(fd, O_BINARY);
  280. #endif
  281.  
  282.     /*
  283.      * try looking at the first HOWMANY bytes
  284.      */
  285.     if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
  286.         error("read failed (%s).\n", strerror(errno));
  287.         /*NOTREACHED*/
  288.     }
  289.  
  290.     if (nbytes == 0) 
  291.         ckfputs("empty", stdout);
  292.     else {
  293.         buf[nbytes] = '\0';    /* null-terminate it */
  294.         tryit(buf, nbytes);
  295.     }
  296.  
  297.     if (inname != stdname) {
  298.         /*
  299.          * Try to restore access, modification times if read it.
  300.          */
  301.         utbuf.actime = sb.st_atime;
  302.         utbuf.modtime = sb.st_mtime;
  303. #ifdef OS2    /* OS/2 wants file closed before utime. MSC utime is broken. */
  304.         close(fd);
  305.         (void) utime((char *) inname, &utbuf); /* don't care if loses */
  306. #else
  307.         (void) utime(inname, &utbuf); /* don't care if loses */
  308.         (void) close(fd);
  309. #endif
  310.     }
  311.     (void) putchar('\n');
  312. }
  313.  
  314.  
  315. void
  316. tryit(buf, nb)
  317. unsigned char *buf;
  318. int nb;
  319. {
  320. #ifdef OS2
  321.     /*
  322.      * try DosQueryAppType tests; best chances with complete file
  323.      */
  324.     const    char    *p = apptypeName;
  325.     apptypeName = NULL;
  326.     if (apptype(p, buf, nb) != 1)
  327. #endif
  328.  
  329.     /*
  330.      * try tests in /etc/magic (or surrogate magic file)
  331.      */
  332.     if (softmagic(buf, nb) != 1)
  333.         /*
  334.          * try known keywords, check for ascii-ness too.
  335.          */
  336.         if (ascmagic(buf, nb) != 1)
  337.         /*
  338.          * abandon hope, all ye who remain here
  339.          */
  340.         ckfputs("data", stdout);
  341. }
  342.  
  343.