Annotation of src/usr.bin/file/file.c, Revision 1.66
1.66 ! brynet 1: /* $OpenBSD: file.c,v 1.65 2017/11/30 11:10:07 bentley Exp $ */
1.27 nicm 2:
1.14 tedu 3: /*
1.27 nicm 4: * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.14 tedu 17: */
1.11 ian 18:
1.20 deraadt 19: #include <sys/types.h>
1.66 ! brynet 20: #include <sys/ioctl.h>
1.27 nicm 21: #include <sys/mman.h>
1.66 ! brynet 22: #include <sys/queue.h>
! 23: #include <sys/socket.h>
1.58 nicm 24: #include <sys/stat.h>
1.66 ! brynet 25: #include <sys/uio.h>
! 26: #include <sys/wait.h>
1.20 deraadt 27:
1.58 nicm 28: #include <err.h>
1.27 nicm 29: #include <errno.h>
1.58 nicm 30: #include <fcntl.h>
31: #include <getopt.h>
1.66 ! brynet 32: #include <imsg.h>
1.27 nicm 33: #include <libgen.h>
1.58 nicm 34: #include <limits.h>
1.27 nicm 35: #include <pwd.h>
1.1 deraadt 36: #include <stdlib.h>
1.58 nicm 37: #include <string.h>
1.44 nicm 38: #include <time.h>
1.14 tedu 39: #include <unistd.h>
40:
1.27 nicm 41: #include "file.h"
42: #include "magic.h"
43: #include "xmalloc.h"
1.1 deraadt 44:
1.66 ! brynet 45: struct input_msg {
! 46: int idx;
! 47:
! 48: struct stat sb;
! 49: int error;
! 50:
! 51: char link_path[PATH_MAX];
! 52: int link_error;
! 53: int link_target;
! 54: };
! 55:
! 56: struct input_ack {
! 57: int idx;
! 58: };
! 59:
1.59 nicm 60: struct input_file {
1.66 ! brynet 61: struct magic *m;
! 62: struct input_msg *msg;
1.1 deraadt 63:
1.66 ! brynet 64: const char *path;
! 65: int fd;
1.14 tedu 66:
1.66 ! brynet 67: void *base;
! 68: size_t size;
! 69: int mapped;
! 70: char *result;
1.27 nicm 71: };
1.1 deraadt 72:
1.27 nicm 73: extern char *__progname;
1.1 deraadt 74:
1.27 nicm 75: __dead void usage(void);
1.1 deraadt 76:
1.66 ! brynet 77: static int prepare_message(struct input_msg *, int, const char *);
! 78: static void send_message(struct imsgbuf *, void *, size_t, int);
! 79: static int read_message(struct imsgbuf *, struct imsg *, pid_t);
! 80:
! 81: static void read_link(struct input_msg *, const char *);
1.35 nicm 82:
1.66 ! brynet 83: static __dead void child(int, pid_t, int, char **);
1.35 nicm 84:
85: static void test_file(struct input_file *, size_t);
1.27 nicm 86:
87: static int try_stat(struct input_file *);
88: static int try_empty(struct input_file *);
89: static int try_access(struct input_file *);
90: static int try_text(struct input_file *);
91: static int try_magic(struct input_file *);
92: static int try_unknown(struct input_file *);
93:
94: static int bflag;
95: static int cflag;
96: static int iflag;
97: static int Lflag;
98: static int sflag;
99: static int Wflag;
100:
1.66 ! brynet 101: static char *magicpath;
! 102: static FILE *magicfp;
! 103:
1.27 nicm 104: static struct option longopts[] = {
1.57 jca 105: { "brief", no_argument, NULL, 'b' },
106: { "dereference", no_argument, NULL, 'L' },
107: { "mime", no_argument, NULL, 'i' },
108: { "mime-type", no_argument, NULL, 'i' },
109: { NULL, 0, NULL, 0 }
1.27 nicm 110: };
1.14 tedu 111:
1.27 nicm 112: __dead void
113: usage(void)
114: {
1.39 jmc 115: fprintf(stderr, "usage: %s [-bchiLsW] file ...\n", __progname);
1.27 nicm 116: exit(1);
117: }
1.14 tedu 118:
1.1 deraadt 119: int
1.27 nicm 120: main(int argc, char **argv)
1.1 deraadt 121: {
1.66 ! brynet 122: int opt, pair[2], fd, idx;
! 123: char *home;
1.27 nicm 124: struct passwd *pw;
1.66 ! brynet 125: struct imsgbuf ibuf;
! 126: struct imsg imsg;
! 127: struct input_msg msg;
! 128: struct input_ack *ack;
! 129: pid_t pid, parent;
1.44 nicm 130:
1.66 ! brynet 131: tzset();
1.27 nicm 132:
133: for (;;) {
134: opt = getopt_long(argc, argv, "bchiLsW", longopts, NULL);
135: if (opt == -1)
1.18 chl 136: break;
1.27 nicm 137: switch (opt) {
1.9 millert 138: case 'b':
1.27 nicm 139: bflag = 1;
1.9 millert 140: break;
1.1 deraadt 141: case 'c':
1.27 nicm 142: cflag = 1;
1.14 tedu 143: break;
1.27 nicm 144: case 'h':
145: Lflag = 0;
1.14 tedu 146: break;
1.19 chl 147: case 'i':
1.27 nicm 148: iflag = 1;
1.19 chl 149: break;
1.27 nicm 150: case 'L':
151: Lflag = 1;
1.14 tedu 152: break;
153: case 's':
1.27 nicm 154: sflag = 1;
1.14 tedu 155: break;
1.27 nicm 156: case 'W':
157: Wflag = 1;
1.18 chl 158: break;
1.1 deraadt 159: default:
1.27 nicm 160: usage();
1.1 deraadt 161: }
1.27 nicm 162: }
163: argc -= optind;
164: argv += optind;
165: if (cflag) {
166: if (argc != 0)
167: usage();
168: } else if (argc == 0)
169: usage();
1.1 deraadt 170:
1.66 ! brynet 171: magicfp = NULL;
1.32 nicm 172: if (geteuid() != 0 && !issetugid()) {
173: home = getenv("HOME");
174: if (home == NULL || *home == '\0') {
175: pw = getpwuid(getuid());
176: if (pw != NULL)
177: home = pw->pw_dir;
178: else
179: home = NULL;
180: }
181: if (home != NULL) {
1.35 nicm 182: xasprintf(&magicpath, "%s/.magic", home);
183: magicfp = fopen(magicpath, "r");
184: if (magicfp == NULL)
185: free(magicpath);
1.32 nicm 186: }
1.27 nicm 187: }
1.35 nicm 188: if (magicfp == NULL) {
189: magicpath = xstrdup("/etc/magic");
190: magicfp = fopen(magicpath, "r");
191: }
192: if (magicfp == NULL)
193: err(1, "%s", magicpath);
194:
1.66 ! brynet 195: parent = getpid();
! 196: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
! 197: err(1, "socketpair");
! 198: switch (pid = fork()) {
! 199: case -1:
! 200: err(1, "fork");
! 201: case 0:
! 202: close(pair[0]);
! 203: child(pair[1], parent, argc, argv);
1.35 nicm 204: }
1.66 ! brynet 205: close(pair[1]);
1.61 deraadt 206:
1.66 ! brynet 207: fclose(magicfp);
! 208: magicfp = NULL;
1.35 nicm 209:
1.66 ! brynet 210: if (cflag)
! 211: goto wait_for_child;
1.35 nicm 212:
1.66 ! brynet 213: imsg_init(&ibuf, pair[0]);
! 214: for (idx = 0; idx < argc; idx++) {
! 215: fd = prepare_message(&msg, idx, argv[idx]);
! 216: send_message(&ibuf, &msg, sizeof msg, fd);
1.35 nicm 217:
1.66 ! brynet 218: if (read_message(&ibuf, &imsg, pid) == 0)
! 219: break;
! 220: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *ack)
! 221: errx(1, "message too small");
! 222: ack = imsg.data;
! 223: if (ack->idx != idx)
! 224: errx(1, "index not expected");
! 225: imsg_free(&imsg);
1.1 deraadt 226: }
227:
1.66 ! brynet 228: wait_for_child:
! 229: close(pair[0]);
! 230: while (wait(NULL) == -1 && errno != ECHILD) {
! 231: if (errno != EINTR)
! 232: err(1, "wait");
1.30 nicm 233: }
1.66 ! brynet 234: _exit(0); /* let the child flush */
1.55 nicm 235: }
236:
1.66 ! brynet 237: static int
! 238: prepare_message(struct input_msg *msg, int idx, const char *path)
1.55 nicm 239: {
240: int fd, mode, error;
241:
1.66 ! brynet 242: memset(msg, 0, sizeof *msg);
! 243: msg->idx = idx;
1.63 brynet 244:
1.55 nicm 245: if (strcmp(path, "-") == 0) {
1.66 ! brynet 246: if (fstat(STDIN_FILENO, &msg->sb) == -1) {
! 247: msg->error = errno;
! 248: return (-1);
1.55 nicm 249: }
1.66 ! brynet 250: return (STDIN_FILENO);
1.55 nicm 251: }
252:
253: if (Lflag)
1.66 ! brynet 254: error = stat(path, &msg->sb);
1.55 nicm 255: else
1.66 ! brynet 256: error = lstat(path, &msg->sb);
1.55 nicm 257: if (error == -1) {
1.66 ! brynet 258: msg->error = errno;
! 259: return (-1);
1.55 nicm 260: }
261:
1.66 ! brynet 262: /*
! 263: * pledge(2) doesn't let us pass directory file descriptors around -
! 264: * but in fact we don't need them, so just don't open directories or
! 265: * symlinks (which could be to directories).
! 266: */
! 267: mode = msg->sb.st_mode;
1.55 nicm 268: if (!S_ISDIR(mode) && !S_ISLNK(mode)) {
269: fd = open(path, O_RDONLY|O_NONBLOCK);
270: if (fd == -1 && (errno == ENFILE || errno == EMFILE))
271: err(1, "open");
272: } else
273: fd = -1;
274: if (S_ISLNK(mode))
1.66 ! brynet 275: read_link(msg, path);
! 276: return (fd);
! 277:
1.27 nicm 278: }
279:
280: static void
1.66 ! brynet 281: send_message(struct imsgbuf *ibuf, void *msg, size_t msglen, int fd)
! 282: {
! 283: if (imsg_compose(ibuf, -1, -1, 0, fd, msg, msglen) != 1)
! 284: err(1, "imsg_compose");
! 285: if (imsg_flush(ibuf) != 0)
! 286: err(1, "imsg_flush");
! 287: }
! 288:
! 289: static int
! 290: read_message(struct imsgbuf *ibuf, struct imsg *imsg, pid_t from)
! 291: {
! 292: int n;
! 293:
! 294: while ((n = imsg_read(ibuf)) == -1 && errno == EAGAIN)
! 295: /* nothing */ ;
! 296: if (n == -1)
! 297: err(1, "imsg_read");
! 298: if (n == 0)
! 299: return (0);
! 300:
! 301: if ((n = imsg_get(ibuf, imsg)) == -1)
! 302: err(1, "imsg_get");
! 303: if (n == 0)
! 304: return (0);
! 305:
! 306: if ((pid_t)imsg->hdr.pid != from)
! 307: errx(1, "PIDs don't match");
! 308:
! 309: return (n);
! 310:
! 311: }
! 312:
! 313: static void
! 314: read_link(struct input_msg *msg, const char *path)
1.14 tedu 315: {
1.27 nicm 316: struct stat sb;
1.35 nicm 317: char lpath[PATH_MAX];
1.27 nicm 318: char *copy, *root;
319: int used;
320: ssize_t size;
321:
1.47 tobias 322: size = readlink(path, lpath, sizeof lpath - 1);
1.27 nicm 323: if (size == -1) {
1.66 ! brynet 324: msg->link_error = errno;
1.14 tedu 325: return;
1.27 nicm 326: }
1.35 nicm 327: lpath[size] = '\0';
1.27 nicm 328:
1.35 nicm 329: if (*lpath == '/')
1.66 ! brynet 330: strlcpy(msg->link_path, lpath, sizeof msg->link_path);
1.27 nicm 331: else {
1.35 nicm 332: copy = xstrdup(path);
1.27 nicm 333:
334: root = dirname(copy);
335: if (*root == '\0' || strcmp(root, ".") == 0 ||
336: strcmp (root, "/") == 0)
1.66 ! brynet 337: strlcpy(msg->link_path, lpath, sizeof msg->link_path);
1.27 nicm 338: else {
1.66 ! brynet 339: used = snprintf(msg->link_path, sizeof msg->link_path,
1.35 nicm 340: "%s/%s", root, lpath);
1.66 ! brynet 341: if (used < 0 || (size_t)used >= sizeof msg->link_path) {
! 342: msg->link_error = ENAMETOOLONG;
1.37 lteo 343: free(copy);
1.27 nicm 344: return;
345: }
346: }
347:
348: free(copy);
349: }
350:
1.54 nicm 351: if (!Lflag && stat(path, &sb) == -1)
1.66 ! brynet 352: msg->link_target = errno;
! 353: }
! 354:
! 355: static __dead void
! 356: child(int fd, pid_t parent, int argc, char **argv)
! 357: {
! 358: struct passwd *pw;
! 359: struct magic *m;
! 360: struct imsgbuf ibuf;
! 361: struct imsg imsg;
! 362: struct input_msg *msg;
! 363: struct input_ack ack;
! 364: struct input_file inf;
! 365: int i, idx;
! 366: size_t len, width = 0;
! 367:
! 368: if (pledge("stdio getpw recvfd id", NULL) == -1)
! 369: err(1, "pledge");
! 370:
! 371: if (geteuid() == 0) {
! 372: pw = getpwnam(FILE_USER);
! 373: if (pw == NULL)
! 374: errx(1, "unknown user %s", FILE_USER);
! 375: if (setgroups(1, &pw->pw_gid) != 0)
! 376: err(1, "setgroups");
! 377: if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
! 378: err(1, "setresgid");
! 379: if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
! 380: err(1, "setresuid");
! 381: }
! 382:
! 383: if (pledge("stdio recvfd", NULL) == -1)
! 384: err(1, "pledge");
! 385:
! 386: m = magic_load(magicfp, magicpath, cflag || Wflag);
! 387: if (cflag) {
! 388: magic_dump(m);
! 389: exit(0);
! 390: }
! 391:
! 392: for (i = 0; i < argc; i++) {
! 393: len = strlen(argv[i]) + 1;
! 394: if (len > width)
! 395: width = len;
! 396: }
! 397:
! 398: imsg_init(&ibuf, fd);
! 399: for (;;) {
! 400: if (read_message(&ibuf, &imsg, parent) == 0)
! 401: break;
! 402: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *msg)
! 403: errx(1, "message too small");
! 404: msg = imsg.data;
! 405:
! 406: idx = msg->idx;
! 407: if (idx < 0 || idx >= argc)
! 408: errx(1, "index out of range");
! 409:
! 410: memset(&inf, 0, sizeof inf);
! 411: inf.m = m;
! 412: inf.msg = msg;
! 413:
! 414: inf.path = argv[idx];
! 415: inf.fd = imsg.fd;
! 416:
! 417: test_file(&inf, width);
! 418:
! 419: if (imsg.fd != -1)
! 420: close(imsg.fd);
! 421: imsg_free(&imsg);
! 422:
! 423: ack.idx = idx;
! 424: send_message(&ibuf, &ack, sizeof ack, -1);
! 425: }
! 426: exit(0);
1.35 nicm 427: }
428:
1.27 nicm 429: static void *
1.42 nicm 430: fill_buffer(int fd, size_t size, size_t *used)
1.1 deraadt 431: {
1.27 nicm 432: static void *buffer;
433: ssize_t got;
434: size_t left;
435: void *next;
436:
437: if (buffer == NULL)
438: buffer = xmalloc(FILE_READ_SIZE);
439:
440: next = buffer;
1.42 nicm 441: left = size;
1.27 nicm 442: while (left != 0) {
1.42 nicm 443: got = read(fd, next, left);
1.27 nicm 444: if (got == -1) {
445: if (errno == EINTR)
446: continue;
1.59 nicm 447: return (NULL);
1.5 millert 448: }
1.27 nicm 449: if (got == 0)
450: break;
1.30 nicm 451: next = (char *)next + got;
1.27 nicm 452: left -= got;
453: }
1.42 nicm 454: *used = size - left;
1.59 nicm 455: return (buffer);
1.27 nicm 456: }
457:
458: static int
459: load_file(struct input_file *inf)
460: {
1.42 nicm 461: size_t used;
462:
1.66 ! brynet 463: if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode))
1.43 nicm 464: return (0); /* empty file */
1.66 ! brynet 465: if (inf->msg->sb.st_size == 0 || inf->msg->sb.st_size > FILE_READ_SIZE)
1.27 nicm 466: inf->size = FILE_READ_SIZE;
1.46 tobias 467: else
1.66 ! brynet 468: inf->size = inf->msg->sb.st_size;
1.43 nicm 469:
1.66 ! brynet 470: if (!S_ISREG(inf->msg->sb.st_mode))
1.43 nicm 471: goto try_read;
1.27 nicm 472:
473: inf->base = mmap(NULL, inf->size, PROT_READ, MAP_PRIVATE, inf->fd, 0);
1.43 nicm 474: if (inf->base == MAP_FAILED)
475: goto try_read;
476: inf->mapped = 1;
477: return (0);
478:
479: try_read:
480: inf->base = fill_buffer(inf->fd, inf->size, &used);
481: if (inf->base == NULL) {
482: xasprintf(&inf->result, "cannot read '%s' (%s)", inf->path,
483: strerror(errno));
484: return (1);
485: }
486: inf->size = used;
1.27 nicm 487: return (0);
488: }
1.5 millert 489:
1.27 nicm 490: static int
491: try_stat(struct input_file *inf)
492: {
1.66 ! brynet 493: if (inf->msg->error != 0) {
1.27 nicm 494: xasprintf(&inf->result, "cannot stat '%s' (%s)", inf->path,
1.66 ! brynet 495: strerror(inf->msg->error));
1.27 nicm 496: return (1);
497: }
1.45 nicm 498: if (sflag || strcmp(inf->path, "-") == 0) {
1.66 ! brynet 499: switch (inf->msg->sb.st_mode & S_IFMT) {
1.45 nicm 500: case S_IFIFO:
501: if (strcmp(inf->path, "-") != 0)
502: break;
1.27 nicm 503: case S_IFBLK:
504: case S_IFCHR:
505: case S_IFREG:
506: return (0);
1.5 millert 507: }
1.27 nicm 508: }
1.1 deraadt 509:
1.66 ! brynet 510: if (iflag && (inf->msg->sb.st_mode & S_IFMT) != S_IFREG) {
1.27 nicm 511: xasprintf(&inf->result, "application/x-not-regular-file");
512: return (1);
1.1 deraadt 513: }
514:
1.66 ! brynet 515: switch (inf->msg->sb.st_mode & S_IFMT) {
1.27 nicm 516: case S_IFDIR:
517: xasprintf(&inf->result, "directory");
518: return (1);
519: case S_IFLNK:
1.66 ! brynet 520: if (inf->msg->link_error != 0) {
1.27 nicm 521: xasprintf(&inf->result, "unreadable symlink '%s' (%s)",
1.66 ! brynet 522: inf->path, strerror(inf->msg->link_error));
1.27 nicm 523: return (1);
524: }
1.66 ! brynet 525: if (inf->msg->link_target == ELOOP)
1.27 nicm 526: xasprintf(&inf->result, "symbolic link in a loop");
1.66 ! brynet 527: else if (inf->msg->link_target != 0) {
1.27 nicm 528: xasprintf(&inf->result, "broken symbolic link to '%s'",
1.66 ! brynet 529: inf->msg->link_path);
1.27 nicm 530: } else {
531: xasprintf(&inf->result, "symbolic link to '%s'",
1.66 ! brynet 532: inf->msg->link_path);
1.27 nicm 533: }
534: return (1);
535: case S_IFSOCK:
536: xasprintf(&inf->result, "socket");
537: return (1);
538: case S_IFBLK:
539: xasprintf(&inf->result, "block special (%ld/%ld)",
1.66 ! brynet 540: (long)major(inf->msg->sb.st_rdev),
! 541: (long)minor(inf->msg->sb.st_rdev));
1.27 nicm 542: return (1);
543: case S_IFCHR:
544: xasprintf(&inf->result, "character special (%ld/%ld)",
1.66 ! brynet 545: (long)major(inf->msg->sb.st_rdev),
! 546: (long)minor(inf->msg->sb.st_rdev));
1.27 nicm 547: return (1);
548: case S_IFIFO:
549: xasprintf(&inf->result, "fifo (named pipe)");
550: return (1);
1.1 deraadt 551: }
1.27 nicm 552: return (0);
553: }
554:
555: static int
556: try_empty(struct input_file *inf)
557: {
558: if (inf->size != 0)
559: return (0);
560:
561: if (iflag)
562: xasprintf(&inf->result, "application/x-empty");
563: else
564: xasprintf(&inf->result, "empty");
565: return (1);
566: }
567:
568: static int
569: try_access(struct input_file *inf)
570: {
571: char tmp[256] = "";
572:
1.66 ! brynet 573: if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode))
1.49 nicm 574: return (0); /* empty file */
1.27 nicm 575: if (inf->fd != -1)
576: return (0);
1.1 deraadt 577:
1.66 ! brynet 578: if (inf->msg->sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
1.27 nicm 579: strlcat(tmp, "writable, ", sizeof tmp);
1.66 ! brynet 580: if (inf->msg->sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
1.27 nicm 581: strlcat(tmp, "executable, ", sizeof tmp);
1.66 ! brynet 582: if (S_ISREG(inf->msg->sb.st_mode))
1.27 nicm 583: strlcat(tmp, "regular file, ", sizeof tmp);
584: strlcat(tmp, "no read permission", sizeof tmp);
585:
586: inf->result = xstrdup(tmp);
587: return (1);
1.1 deraadt 588: }
589:
1.27 nicm 590: static int
591: try_text(struct input_file *inf)
1.14 tedu 592: {
1.27 nicm 593: const char *type, *s;
594: int flags;
595:
596: flags = MAGIC_TEST_TEXT;
597: if (iflag)
598: flags |= MAGIC_TEST_MIME;
599:
600: type = text_get_type(inf->base, inf->size);
601: if (type == NULL)
602: return (0);
1.14 tedu 603:
1.27 nicm 604: s = magic_test(inf->m, inf->base, inf->size, flags);
605: if (s != NULL) {
606: inf->result = xstrdup(s);
607: return (1);
608: }
609:
610: s = text_try_words(inf->base, inf->size, flags);
611: if (s != NULL) {
612: if (iflag)
613: inf->result = xstrdup(s);
1.18 chl 614: else
1.27 nicm 615: xasprintf(&inf->result, "%s %s text", type, s);
616: return (1);
1.18 chl 617: }
1.14 tedu 618:
1.27 nicm 619: if (iflag)
620: inf->result = xstrdup("text/plain");
1.14 tedu 621: else
1.27 nicm 622: xasprintf(&inf->result, "%s text", type);
623: return (1);
1.14 tedu 624: }
625:
1.27 nicm 626: static int
627: try_magic(struct input_file *inf)
1.1 deraadt 628: {
1.27 nicm 629: const char *s;
630: int flags;
1.1 deraadt 631:
1.27 nicm 632: flags = 0;
633: if (iflag)
634: flags |= MAGIC_TEST_MIME;
635:
636: s = magic_test(inf->m, inf->base, inf->size, flags);
637: if (s != NULL) {
638: inf->result = xstrdup(s);
639: return (1);
1.1 deraadt 640: }
1.27 nicm 641: return (0);
1.14 tedu 642: }
1.1 deraadt 643:
1.27 nicm 644: static int
645: try_unknown(struct input_file *inf)
1.14 tedu 646: {
1.27 nicm 647: if (iflag)
1.65 bentley 648: xasprintf(&inf->result, "application/octet-stream");
1.27 nicm 649: else
650: xasprintf(&inf->result, "data");
651: return (1);
1.1 deraadt 652: }
653:
1.27 nicm 654: static void
1.35 nicm 655: test_file(struct input_file *inf, size_t width)
1.1 deraadt 656: {
1.35 nicm 657: char *label;
658: int stop;
1.27 nicm 659:
660: stop = 0;
661: if (!stop)
662: stop = try_stat(inf);
663: if (!stop)
664: stop = try_access(inf);
665: if (!stop)
666: stop = load_file(inf);
667: if (!stop)
668: stop = try_empty(inf);
669: if (!stop)
670: stop = try_magic(inf);
671: if (!stop)
672: stop = try_text(inf);
673: if (!stop)
674: stop = try_unknown(inf);
675:
676: if (bflag)
677: printf("%s\n", inf->result);
1.35 nicm 678: else {
1.45 nicm 679: if (strcmp(inf->path, "-") == 0)
680: xasprintf(&label, "/dev/stdin:");
681: else
682: xasprintf(&label, "%s:", inf->path);
1.35 nicm 683: printf("%-*s %s\n", (int)width, label, inf->result);
684: free(label);
685: }
1.30 nicm 686: free(inf->result);
1.27 nicm 687:
688: if (inf->mapped && inf->base != NULL)
689: munmap(inf->base, inf->size);
1.1 deraadt 690: }