Annotation of src/usr.bin/file/file.c, Revision 1.70
1.70 ! claudio 1: /* $OpenBSD: file.c,v 1.69 2019/11/30 14:01:45 mestre 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.67 tedu 170:
171: if (pledge("stdio rpath getpw recvfd sendfd id proc", NULL) == -1)
172: err(1, "pledge");
1.1 deraadt 173:
1.66 brynet 174: magicfp = NULL;
1.32 nicm 175: if (geteuid() != 0 && !issetugid()) {
176: home = getenv("HOME");
177: if (home == NULL || *home == '\0') {
178: pw = getpwuid(getuid());
179: if (pw != NULL)
180: home = pw->pw_dir;
181: else
182: home = NULL;
183: }
184: if (home != NULL) {
1.35 nicm 185: xasprintf(&magicpath, "%s/.magic", home);
186: magicfp = fopen(magicpath, "r");
187: if (magicfp == NULL)
188: free(magicpath);
1.32 nicm 189: }
1.27 nicm 190: }
1.35 nicm 191: if (magicfp == NULL) {
192: magicpath = xstrdup("/etc/magic");
193: magicfp = fopen(magicpath, "r");
194: }
195: if (magicfp == NULL)
196: err(1, "%s", magicpath);
197:
1.66 brynet 198: parent = getpid();
199: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
200: err(1, "socketpair");
201: switch (pid = fork()) {
202: case -1:
203: err(1, "fork");
204: case 0:
205: close(pair[0]);
206: child(pair[1], parent, argc, argv);
1.35 nicm 207: }
1.66 brynet 208: close(pair[1]);
1.69 mestre 209:
210: if (pledge("stdio rpath sendfd", NULL) == -1)
211: err(1, "pledge");
1.61 deraadt 212:
1.66 brynet 213: fclose(magicfp);
214: magicfp = NULL;
1.35 nicm 215:
1.66 brynet 216: if (cflag)
217: goto wait_for_child;
1.35 nicm 218:
1.66 brynet 219: imsg_init(&ibuf, pair[0]);
220: for (idx = 0; idx < argc; idx++) {
221: fd = prepare_message(&msg, idx, argv[idx]);
222: send_message(&ibuf, &msg, sizeof msg, fd);
1.35 nicm 223:
1.66 brynet 224: if (read_message(&ibuf, &imsg, pid) == 0)
225: break;
226: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *ack)
227: errx(1, "message too small");
228: ack = imsg.data;
229: if (ack->idx != idx)
230: errx(1, "index not expected");
231: imsg_free(&imsg);
1.1 deraadt 232: }
233:
1.66 brynet 234: wait_for_child:
235: close(pair[0]);
236: while (wait(NULL) == -1 && errno != ECHILD) {
237: if (errno != EINTR)
238: err(1, "wait");
1.30 nicm 239: }
1.66 brynet 240: _exit(0); /* let the child flush */
1.55 nicm 241: }
242:
1.66 brynet 243: static int
244: prepare_message(struct input_msg *msg, int idx, const char *path)
1.55 nicm 245: {
246: int fd, mode, error;
247:
1.66 brynet 248: memset(msg, 0, sizeof *msg);
249: msg->idx = idx;
1.63 brynet 250:
1.55 nicm 251: if (strcmp(path, "-") == 0) {
1.66 brynet 252: if (fstat(STDIN_FILENO, &msg->sb) == -1) {
253: msg->error = errno;
254: return (-1);
1.55 nicm 255: }
1.66 brynet 256: return (STDIN_FILENO);
1.55 nicm 257: }
258:
259: if (Lflag)
1.66 brynet 260: error = stat(path, &msg->sb);
1.55 nicm 261: else
1.66 brynet 262: error = lstat(path, &msg->sb);
1.55 nicm 263: if (error == -1) {
1.66 brynet 264: msg->error = errno;
265: return (-1);
1.55 nicm 266: }
267:
1.66 brynet 268: /*
269: * pledge(2) doesn't let us pass directory file descriptors around -
270: * but in fact we don't need them, so just don't open directories or
271: * symlinks (which could be to directories).
272: */
273: mode = msg->sb.st_mode;
1.55 nicm 274: if (!S_ISDIR(mode) && !S_ISLNK(mode)) {
275: fd = open(path, O_RDONLY|O_NONBLOCK);
276: if (fd == -1 && (errno == ENFILE || errno == EMFILE))
277: err(1, "open");
278: } else
279: fd = -1;
280: if (S_ISLNK(mode))
1.66 brynet 281: read_link(msg, path);
282: return (fd);
283:
1.27 nicm 284: }
285:
286: static void
1.66 brynet 287: send_message(struct imsgbuf *ibuf, void *msg, size_t msglen, int fd)
288: {
289: if (imsg_compose(ibuf, -1, -1, 0, fd, msg, msglen) != 1)
290: err(1, "imsg_compose");
291: if (imsg_flush(ibuf) != 0)
292: err(1, "imsg_flush");
293: }
294:
295: static int
296: read_message(struct imsgbuf *ibuf, struct imsg *imsg, pid_t from)
297: {
298: int n;
299:
300: while ((n = imsg_read(ibuf)) == -1 && errno == EAGAIN)
301: /* nothing */ ;
302: if (n == -1)
303: err(1, "imsg_read");
304: if (n == 0)
305: return (0);
306:
307: if ((n = imsg_get(ibuf, imsg)) == -1)
308: err(1, "imsg_get");
309: if (n == 0)
310: return (0);
311:
312: if ((pid_t)imsg->hdr.pid != from)
313: errx(1, "PIDs don't match");
314:
315: return (n);
316:
317: }
318:
319: static void
320: read_link(struct input_msg *msg, const char *path)
1.14 tedu 321: {
1.27 nicm 322: struct stat sb;
1.35 nicm 323: char lpath[PATH_MAX];
1.27 nicm 324: char *copy, *root;
325: int used;
326: ssize_t size;
327:
1.47 tobias 328: size = readlink(path, lpath, sizeof lpath - 1);
1.27 nicm 329: if (size == -1) {
1.66 brynet 330: msg->link_error = errno;
1.14 tedu 331: return;
1.27 nicm 332: }
1.35 nicm 333: lpath[size] = '\0';
1.27 nicm 334:
1.35 nicm 335: if (*lpath == '/')
1.66 brynet 336: strlcpy(msg->link_path, lpath, sizeof msg->link_path);
1.27 nicm 337: else {
1.35 nicm 338: copy = xstrdup(path);
1.27 nicm 339:
340: root = dirname(copy);
341: if (*root == '\0' || strcmp(root, ".") == 0 ||
342: strcmp (root, "/") == 0)
1.66 brynet 343: strlcpy(msg->link_path, lpath, sizeof msg->link_path);
1.27 nicm 344: else {
1.66 brynet 345: used = snprintf(msg->link_path, sizeof msg->link_path,
1.35 nicm 346: "%s/%s", root, lpath);
1.66 brynet 347: if (used < 0 || (size_t)used >= sizeof msg->link_path) {
348: msg->link_error = ENAMETOOLONG;
1.37 lteo 349: free(copy);
1.27 nicm 350: return;
351: }
352: }
353:
354: free(copy);
355: }
356:
1.54 nicm 357: if (!Lflag && stat(path, &sb) == -1)
1.66 brynet 358: msg->link_target = errno;
359: }
360:
361: static __dead void
362: child(int fd, pid_t parent, int argc, char **argv)
363: {
364: struct passwd *pw;
365: struct magic *m;
366: struct imsgbuf ibuf;
367: struct imsg imsg;
368: struct input_msg *msg;
369: struct input_ack ack;
370: struct input_file inf;
371: int i, idx;
372: size_t len, width = 0;
373:
374: if (pledge("stdio getpw recvfd id", NULL) == -1)
375: err(1, "pledge");
376:
377: if (geteuid() == 0) {
378: pw = getpwnam(FILE_USER);
379: if (pw == NULL)
380: errx(1, "unknown user %s", FILE_USER);
381: if (setgroups(1, &pw->pw_gid) != 0)
382: err(1, "setgroups");
383: if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
384: err(1, "setresgid");
385: if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
386: err(1, "setresuid");
387: }
388:
389: if (pledge("stdio recvfd", NULL) == -1)
390: err(1, "pledge");
391:
392: m = magic_load(magicfp, magicpath, cflag || Wflag);
393: if (cflag) {
394: magic_dump(m);
395: exit(0);
396: }
397:
398: for (i = 0; i < argc; i++) {
399: len = strlen(argv[i]) + 1;
400: if (len > width)
401: width = len;
402: }
403:
404: imsg_init(&ibuf, fd);
405: for (;;) {
406: if (read_message(&ibuf, &imsg, parent) == 0)
407: break;
408: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *msg)
409: errx(1, "message too small");
410: msg = imsg.data;
411:
412: idx = msg->idx;
413: if (idx < 0 || idx >= argc)
414: errx(1, "index out of range");
415:
416: memset(&inf, 0, sizeof inf);
417: inf.m = m;
418: inf.msg = msg;
419:
420: inf.path = argv[idx];
1.70 ! claudio 421: inf.fd = imsg_get_fd(&imsg);
1.66 brynet 422:
423: test_file(&inf, width);
424:
1.70 ! claudio 425: if (inf.fd != -1)
! 426: close(inf.fd);
1.66 brynet 427: imsg_free(&imsg);
428:
429: ack.idx = idx;
430: send_message(&ibuf, &ack, sizeof ack, -1);
431: }
432: exit(0);
1.35 nicm 433: }
434:
1.27 nicm 435: static void *
1.42 nicm 436: fill_buffer(int fd, size_t size, size_t *used)
1.1 deraadt 437: {
1.27 nicm 438: static void *buffer;
439: ssize_t got;
440: size_t left;
441: void *next;
442:
443: if (buffer == NULL)
444: buffer = xmalloc(FILE_READ_SIZE);
445:
446: next = buffer;
1.42 nicm 447: left = size;
1.27 nicm 448: while (left != 0) {
1.42 nicm 449: got = read(fd, next, left);
1.27 nicm 450: if (got == -1) {
451: if (errno == EINTR)
452: continue;
1.59 nicm 453: return (NULL);
1.5 millert 454: }
1.27 nicm 455: if (got == 0)
456: break;
1.30 nicm 457: next = (char *)next + got;
1.27 nicm 458: left -= got;
459: }
1.42 nicm 460: *used = size - left;
1.59 nicm 461: return (buffer);
1.27 nicm 462: }
463:
464: static int
465: load_file(struct input_file *inf)
466: {
1.42 nicm 467: size_t used;
468:
1.66 brynet 469: if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode))
1.43 nicm 470: return (0); /* empty file */
1.66 brynet 471: if (inf->msg->sb.st_size == 0 || inf->msg->sb.st_size > FILE_READ_SIZE)
1.27 nicm 472: inf->size = FILE_READ_SIZE;
1.46 tobias 473: else
1.66 brynet 474: inf->size = inf->msg->sb.st_size;
1.43 nicm 475:
1.66 brynet 476: if (!S_ISREG(inf->msg->sb.st_mode))
1.43 nicm 477: goto try_read;
1.27 nicm 478:
479: inf->base = mmap(NULL, inf->size, PROT_READ, MAP_PRIVATE, inf->fd, 0);
1.43 nicm 480: if (inf->base == MAP_FAILED)
481: goto try_read;
482: inf->mapped = 1;
483: return (0);
484:
485: try_read:
486: inf->base = fill_buffer(inf->fd, inf->size, &used);
487: if (inf->base == NULL) {
488: xasprintf(&inf->result, "cannot read '%s' (%s)", inf->path,
489: strerror(errno));
490: return (1);
491: }
492: inf->size = used;
1.27 nicm 493: return (0);
494: }
1.5 millert 495:
1.27 nicm 496: static int
497: try_stat(struct input_file *inf)
498: {
1.66 brynet 499: if (inf->msg->error != 0) {
1.27 nicm 500: xasprintf(&inf->result, "cannot stat '%s' (%s)", inf->path,
1.66 brynet 501: strerror(inf->msg->error));
1.27 nicm 502: return (1);
503: }
1.45 nicm 504: if (sflag || strcmp(inf->path, "-") == 0) {
1.66 brynet 505: switch (inf->msg->sb.st_mode & S_IFMT) {
1.45 nicm 506: case S_IFIFO:
507: if (strcmp(inf->path, "-") != 0)
508: break;
1.27 nicm 509: case S_IFBLK:
510: case S_IFCHR:
511: case S_IFREG:
512: return (0);
1.5 millert 513: }
1.27 nicm 514: }
1.1 deraadt 515:
1.66 brynet 516: if (iflag && (inf->msg->sb.st_mode & S_IFMT) != S_IFREG) {
1.27 nicm 517: xasprintf(&inf->result, "application/x-not-regular-file");
518: return (1);
1.1 deraadt 519: }
520:
1.66 brynet 521: switch (inf->msg->sb.st_mode & S_IFMT) {
1.27 nicm 522: case S_IFDIR:
523: xasprintf(&inf->result, "directory");
524: return (1);
525: case S_IFLNK:
1.66 brynet 526: if (inf->msg->link_error != 0) {
1.27 nicm 527: xasprintf(&inf->result, "unreadable symlink '%s' (%s)",
1.66 brynet 528: inf->path, strerror(inf->msg->link_error));
1.27 nicm 529: return (1);
530: }
1.66 brynet 531: if (inf->msg->link_target == ELOOP)
1.27 nicm 532: xasprintf(&inf->result, "symbolic link in a loop");
1.66 brynet 533: else if (inf->msg->link_target != 0) {
1.27 nicm 534: xasprintf(&inf->result, "broken symbolic link to '%s'",
1.66 brynet 535: inf->msg->link_path);
1.27 nicm 536: } else {
537: xasprintf(&inf->result, "symbolic link to '%s'",
1.66 brynet 538: inf->msg->link_path);
1.27 nicm 539: }
540: return (1);
541: case S_IFSOCK:
542: xasprintf(&inf->result, "socket");
543: return (1);
544: case S_IFBLK:
1.68 deraadt 545: xasprintf(&inf->result, "block special (%lu/%lu)",
1.66 brynet 546: (long)major(inf->msg->sb.st_rdev),
547: (long)minor(inf->msg->sb.st_rdev));
1.27 nicm 548: return (1);
549: case S_IFCHR:
1.68 deraadt 550: xasprintf(&inf->result, "character special (%lu/%lu)",
1.66 brynet 551: (long)major(inf->msg->sb.st_rdev),
552: (long)minor(inf->msg->sb.st_rdev));
1.27 nicm 553: return (1);
554: case S_IFIFO:
555: xasprintf(&inf->result, "fifo (named pipe)");
556: return (1);
1.1 deraadt 557: }
1.27 nicm 558: return (0);
559: }
560:
561: static int
562: try_empty(struct input_file *inf)
563: {
564: if (inf->size != 0)
565: return (0);
566:
567: if (iflag)
568: xasprintf(&inf->result, "application/x-empty");
569: else
570: xasprintf(&inf->result, "empty");
571: return (1);
572: }
573:
574: static int
575: try_access(struct input_file *inf)
576: {
577: char tmp[256] = "";
578:
1.66 brynet 579: if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode))
1.49 nicm 580: return (0); /* empty file */
1.27 nicm 581: if (inf->fd != -1)
582: return (0);
1.1 deraadt 583:
1.66 brynet 584: if (inf->msg->sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
1.27 nicm 585: strlcat(tmp, "writable, ", sizeof tmp);
1.66 brynet 586: if (inf->msg->sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
1.27 nicm 587: strlcat(tmp, "executable, ", sizeof tmp);
1.66 brynet 588: if (S_ISREG(inf->msg->sb.st_mode))
1.27 nicm 589: strlcat(tmp, "regular file, ", sizeof tmp);
590: strlcat(tmp, "no read permission", sizeof tmp);
591:
592: inf->result = xstrdup(tmp);
593: return (1);
1.1 deraadt 594: }
595:
1.27 nicm 596: static int
597: try_text(struct input_file *inf)
1.14 tedu 598: {
1.27 nicm 599: const char *type, *s;
600: int flags;
601:
602: flags = MAGIC_TEST_TEXT;
603: if (iflag)
604: flags |= MAGIC_TEST_MIME;
605:
606: type = text_get_type(inf->base, inf->size);
607: if (type == NULL)
608: return (0);
1.14 tedu 609:
1.27 nicm 610: s = magic_test(inf->m, inf->base, inf->size, flags);
611: if (s != NULL) {
612: inf->result = xstrdup(s);
613: return (1);
614: }
615:
616: s = text_try_words(inf->base, inf->size, flags);
617: if (s != NULL) {
618: if (iflag)
619: inf->result = xstrdup(s);
1.18 chl 620: else
1.27 nicm 621: xasprintf(&inf->result, "%s %s text", type, s);
622: return (1);
1.18 chl 623: }
1.14 tedu 624:
1.27 nicm 625: if (iflag)
626: inf->result = xstrdup("text/plain");
1.14 tedu 627: else
1.27 nicm 628: xasprintf(&inf->result, "%s text", type);
629: return (1);
1.14 tedu 630: }
631:
1.27 nicm 632: static int
633: try_magic(struct input_file *inf)
1.1 deraadt 634: {
1.27 nicm 635: const char *s;
636: int flags;
1.1 deraadt 637:
1.27 nicm 638: flags = 0;
639: if (iflag)
640: flags |= MAGIC_TEST_MIME;
641:
642: s = magic_test(inf->m, inf->base, inf->size, flags);
643: if (s != NULL) {
644: inf->result = xstrdup(s);
645: return (1);
1.1 deraadt 646: }
1.27 nicm 647: return (0);
1.14 tedu 648: }
1.1 deraadt 649:
1.27 nicm 650: static int
651: try_unknown(struct input_file *inf)
1.14 tedu 652: {
1.27 nicm 653: if (iflag)
1.65 bentley 654: xasprintf(&inf->result, "application/octet-stream");
1.27 nicm 655: else
656: xasprintf(&inf->result, "data");
657: return (1);
1.1 deraadt 658: }
659:
1.27 nicm 660: static void
1.35 nicm 661: test_file(struct input_file *inf, size_t width)
1.1 deraadt 662: {
1.35 nicm 663: char *label;
664: int stop;
1.27 nicm 665:
666: stop = 0;
667: if (!stop)
668: stop = try_stat(inf);
669: if (!stop)
670: stop = try_access(inf);
671: if (!stop)
672: stop = load_file(inf);
673: if (!stop)
674: stop = try_empty(inf);
675: if (!stop)
676: stop = try_magic(inf);
677: if (!stop)
678: stop = try_text(inf);
679: if (!stop)
680: stop = try_unknown(inf);
681:
682: if (bflag)
683: printf("%s\n", inf->result);
1.35 nicm 684: else {
1.45 nicm 685: if (strcmp(inf->path, "-") == 0)
686: xasprintf(&label, "/dev/stdin:");
687: else
688: xasprintf(&label, "%s:", inf->path);
1.35 nicm 689: printf("%-*s %s\n", (int)width, label, inf->result);
690: free(label);
691: }
1.30 nicm 692: free(inf->result);
1.27 nicm 693:
694: if (inf->mapped && inf->base != NULL)
695: munmap(inf->base, inf->size);
1.1 deraadt 696: }