diff options
Diffstat (limited to 'contrib/file/src/file.c')
-rw-r--r-- | contrib/file/src/file.c | 365 |
1 files changed, 231 insertions, 134 deletions
diff --git a/contrib/file/src/file.c b/contrib/file/src/file.c index aca585216373..31c1035ca0e4 100644 --- a/contrib/file/src/file.c +++ b/contrib/file/src/file.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: file.c,v 1.187 2020/06/07 17:38:30 christos Exp $") +FILE_RCSID("@(#)$File: file.c,v 1.215 2023/05/21 17:08:34 christos Exp $") #endif /* lint */ #include "magic.h" @@ -57,6 +57,15 @@ FILE_RCSID("@(#)$File: file.c,v 1.187 2020/06/07 17:38:30 christos Exp $") #ifdef HAVE_WCHAR_H #include <wchar.h> #endif +#ifdef HAVE_WCTYPE_H +#include <wctype.h> +#endif +#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) && \ + defined(HAVE_WCTYPE_H) +#define FILE_WIDE_SUPPORT +#else +#include <ctype.h> +#endif #if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION) # include <getopt.h> @@ -88,14 +97,14 @@ int getopt_long(int, char * const *, const char *, " %s -C [-m <magicfiles>]\n" \ " %s [--help]\n" -private int /* Global command-line options */ +file_private int /* Global command-line options */ bflag = 0, /* brief output format */ nopad = 0, /* Don't pad output */ nobuffer = 0, /* Do not buffer stdout */ nulsep = 0; /* Append '\0' to the separator */ -private const char *separator = ":"; /* Default field separator */ -private const struct option long_options[] = { +file_private const char *separator = ":"; /* Default field separator */ +file_private const struct option long_options[] = { #define OPT_HELP 1 #define OPT_APPLE 2 #define OPT_EXTENSIONS 3 @@ -112,7 +121,7 @@ private const struct option long_options[] = { {0, 0, NULL, 0} }; -private const struct { +file_private const struct { const char *name; int value; } nv[] = { @@ -126,51 +135,56 @@ private const struct { { "soft", MAGIC_NO_CHECK_SOFT }, { "tar", MAGIC_NO_CHECK_TAR }, { "json", MAGIC_NO_CHECK_JSON }, + { "simh", MAGIC_NO_CHECK_SIMH }, { "text", MAGIC_NO_CHECK_TEXT }, /* synonym for ascii */ { "tokens", MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */ }; -private struct { +file_private struct { const char *name; - int tag; size_t value; - int set; size_t def; const char *desc; + int tag; + int set; } pm[] = { - { "bytes", MAGIC_PARAM_BYTES_MAX, 0, 0, FILE_BYTES_MAX, - "max bytes to look inside file" }, - { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0, 0, FILE_ELF_NOTES_MAX, - "max ELF notes processed" }, - { "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0, 0, FILE_ELF_PHNUM_MAX, - "max ELF prog sections processed" }, - { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0, 0, FILE_ELF_SHNUM_MAX, - "max ELF sections processed" }, - { "indir", MAGIC_PARAM_INDIR_MAX, 0, 0, FILE_INDIR_MAX, - "recursion limit for indirection" }, - { "name", MAGIC_PARAM_NAME_MAX, 0, 0, FILE_NAME_MAX, - "use limit for name/use magic" }, - { "regex", MAGIC_PARAM_REGEX_MAX, 0, 0, FILE_REGEX_MAX, - "length limit for REGEX searches" }, + { "bytes", 0, FILE_BYTES_MAX, "max bytes to look inside file", + MAGIC_PARAM_BYTES_MAX, 0 }, + { "elf_notes", 0, FILE_ELF_NOTES_MAX, "max ELF notes processed", + MAGIC_PARAM_ELF_NOTES_MAX, 0 }, + { "elf_phnum", 0, FILE_ELF_PHNUM_MAX, "max ELF prog sections processed", + MAGIC_PARAM_ELF_PHNUM_MAX, 0 }, + { "elf_shnum", 0, FILE_ELF_SHNUM_MAX, "max ELF sections processed", + MAGIC_PARAM_ELF_SHNUM_MAX, 0 }, + { "elf_shsize", 0, FILE_ELF_SHSIZE_MAX, "max ELF section size", + MAGIC_PARAM_ELF_SHSIZE_MAX, 0 }, + { "encoding", 0, FILE_ENCODING_MAX, "max bytes to scan for encoding", + MAGIC_PARAM_ENCODING_MAX, 0 }, + { "indir", 0, FILE_INDIR_MAX, "recursion limit for indirection", + MAGIC_PARAM_INDIR_MAX, 0 }, + { "name", 0, FILE_NAME_MAX, "use limit for name/use magic", + MAGIC_PARAM_NAME_MAX, 0 }, + { "regex", 0, FILE_REGEX_MAX, "length limit for REGEX searches", + MAGIC_PARAM_REGEX_MAX, 0 }, }; -private int posixly; +file_private int posixly; #ifdef __dead __dead #endif -private void usage(void); -private void docprint(const char *, int); +file_private void usage(void); +file_private void docprint(const char *, int); #ifdef __dead __dead #endif -private void help(void); +file_private void help(void); -private int unwrap(struct magic_set *, const char *); -private int process(struct magic_set *ms, const char *, int); -private struct magic_set *load(const char *, int); -private void setparam(const char *); -private void applyparam(magic_t); +file_private int unwrap(struct magic_set *, const char *); +file_private int process(struct magic_set *ms, const char *, int); +file_private struct magic_set *load(const char *, int); +file_private void setparam(const char *); +file_private void applyparam(magic_t); /* @@ -180,7 +194,7 @@ int main(int argc, char *argv[]) { int c; - size_t i; + size_t i, j, wid, nw; int action = 0, didsomefiles = 0, errflg = 0; int flags = 0, e = 0; #ifdef HAVE_LIBSECCOMP @@ -355,6 +369,8 @@ main(int argc, char *argv[]) if (sandbox && enable_sandbox_full() == -1) #endif file_err(EXIT_FAILURE, "SECCOMP initialisation failed"); + if (sandbox) + flags |= MAGIC_NO_COMPRESS_FORK; #endif /* HAVE_LIBSECCOMP */ if (MAGIC_VERSION != magic_version()) @@ -406,33 +422,36 @@ main(int argc, char *argv[]) if (optind == argc) { if (!didsomefiles) usage(); + goto out; } - else { - size_t j, wid, nw; - for (wid = 0, j = CAST(size_t, optind); j < CAST(size_t, argc); - j++) { - nw = file_mbswidth(argv[j]); - if (nw > wid) - wid = nw; - } - /* - * If bflag is only set twice, set it depending on - * number of files [this is undocumented, and subject to change] - */ - if (bflag == 2) { - bflag = optind >= argc - 1; - } - for (; optind < argc; optind++) - e |= process(magic, argv[optind], wid); + + for (wid = 0, j = CAST(size_t, optind); j < CAST(size_t, argc); + j++) { + nw = file_mbswidth(magic, argv[j]); + if (nw > wid) + wid = nw; } + /* + * If bflag is only set twice, set it depending on + * number of files [this is undocumented, and subject to change] + */ + if (bflag == 2) { + bflag = optind >= argc - 1; + } + for (; optind < argc; optind++) + e |= process(magic, argv[optind], wid); + out: + if (!nobuffer) + e |= fflush(stdout) != 0; + if (magic) magic_close(magic); return e; } -private void +file_private void applyparam(magic_t magic) { size_t i; @@ -445,13 +464,13 @@ applyparam(magic_t magic) } } -private void +file_private void setparam(const char *p) { size_t i; char *s; - if ((s = strchr(p, '=')) == NULL) + if ((s = CCAST(char *, strchr(p, '='))) == NULL) goto badparm; for (i = 0; i < __arraycount(pm); i++) { @@ -465,7 +484,7 @@ badparm: file_errx(EXIT_FAILURE, "Unknown param %s", p); } -private struct magic_set * +file_private struct magic_set * /*ARGSUSED*/ load(const char *magicfile, int flags) { @@ -489,7 +508,7 @@ load(const char *magicfile, int flags) /* * unwrap -- read a file of filenames, do each one. */ -private int +file_private int unwrap(struct magic_set *ms, const char *fn) { FILE *f; @@ -498,109 +517,187 @@ unwrap(struct magic_set *ms, const char *fn) size_t llen = 0; int wid = 0, cwid; int e = 0; + size_t fi = 0, fimax = 0; + char **flist = NULL; - if (strcmp("-", fn) == 0) { + if (strcmp("-", fn) == 0) f = stdin; - wid = 1; - } else { + else { if ((f = fopen(fn, "r")) == NULL) { file_warn("Cannot open `%s'", fn); return 1; } - - while ((len = getline(&line, &llen, f)) > 0) { - if (line[len - 1] == '\n') - line[len - 1] = '\0'; - cwid = file_mbswidth(line); - if (cwid > wid) - wid = cwid; - } - - rewind(f); } while ((len = getline(&line, &llen, f)) > 0) { if (line[len - 1] == '\n') line[len - 1] = '\0'; - e |= process(ms, line, wid); - if(nobuffer) - (void)fflush(stdout); + cwid = file_mbswidth(ms, line); + if (nobuffer) { + e |= process(ms, line, cwid); + free(line); + line = NULL; + llen = 0; + continue; + } + if (cwid > wid) + wid = cwid; + if (fi >= fimax) { + fimax += 100; + char **nf = CAST(char **, + realloc(flist, fimax * sizeof(*flist))); + if (nf == NULL) { + file_err(EXIT_FAILURE, + "Cannot allocate memory for file list"); + } + flist = nf; + } + flist[fi++] = line; + line = NULL; + llen = 0; + } + + if (!nobuffer) { + fimax = fi; + for (fi = 0; fi < fimax; fi++) { + e |= process(ms, flist[fi], wid); + free(flist[fi]); + } } + free(flist); - free(line); - (void)fclose(f); + if (f != stdin) + (void)fclose(f); return e; } +file_private void +file_octal(unsigned char c) +{ + (void)putc('\\', stdout); + (void)putc(((c >> 6) & 7) + '0', stdout); + (void)putc(((c >> 3) & 7) + '0', stdout); + (void)putc(((c >> 0) & 7) + '0', stdout); +} + +file_private void +fname_print(const char *inname) +{ + size_t n = strlen(inname); +#ifdef FILE_WIDE_SUPPORT + mbstate_t state; + wchar_t nextchar; + size_t bytesconsumed; + + + (void)memset(&state, 0, sizeof(state)); + while (n > 0) { + bytesconsumed = mbrtowc(&nextchar, inname, n, &state); + if (bytesconsumed == CAST(size_t, -1) || + bytesconsumed == CAST(size_t, -2)) { + nextchar = *inname++; + n--; + (void)memset(&state, 0, sizeof(state)); + file_octal(CAST(unsigned char, nextchar)); + continue; + } + inname += bytesconsumed; + n -= bytesconsumed; + if (iswprint(nextchar)) { + printf("%lc", (wint_t)nextchar); + continue; + } + /* XXX: What if it is > 255? */ + file_octal(CAST(unsigned char, nextchar)); + } +#else + size_t i; + for (i = 0; i < n; i++) { + unsigned char c = CAST(unsigned char, inname[i]); + if (isprint(c)) { + (void)putc(c, stdout); + continue; + } + file_octal(c); + } +#endif +} + /* * Called for each input file on the command line (or in a list of files) */ -private int +file_private int process(struct magic_set *ms, const char *inname, int wid) { const char *type, c = nulsep > 1 ? '\0' : '\n'; int std_in = strcmp(inname, "-") == 0; + int haderror = 0; if (wid > 0 && !bflag) { - (void)printf("%s", std_in ? "/dev/stdin" : inname); + const char *pname = std_in ? "/dev/stdin" : inname; + if ((ms->flags & MAGIC_RAW) == 0) + fname_print(pname); + else + (void)printf("%s", pname); if (nulsep) (void)putc('\0', stdout); if (nulsep < 2) { (void)printf("%s", separator); (void)printf("%*s ", CAST(int, nopad ? 0 - : (wid - file_mbswidth(inname))), ""); + : (wid - file_mbswidth(ms, inname))), ""); } } type = magic_file(ms, std_in ? NULL : inname); if (type == NULL) { - (void)printf("ERROR: %s%c", magic_error(ms), c); - return 1; + haderror |= printf("ERROR: %s%c", magic_error(ms), c); } else { - (void)printf("%s%c", type, c); - return 0; + haderror |= printf("%s%c", type, c) < 0; } + if (nobuffer) + haderror |= fflush(stdout) != 0; + return haderror || type == NULL; } -protected size_t -file_mbswidth(const char *s) +file_protected size_t +file_mbswidth(struct magic_set *ms, const char *s) { -#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) - size_t bytesconsumed, old_n, n, width = 0; + size_t width = 0; +#ifdef FILE_WIDE_SUPPORT + size_t bytesconsumed, n; mbstate_t state; wchar_t nextchar; - (void)memset(&state, 0, sizeof(mbstate_t)); - old_n = n = strlen(s); + + (void)memset(&state, 0, sizeof(state)); + n = strlen(s); while (n > 0) { bytesconsumed = mbrtowc(&nextchar, s, n, &state); if (bytesconsumed == CAST(size_t, -1) || bytesconsumed == CAST(size_t, -2)) { - /* Something went wrong, return something reasonable */ - return old_n; - } - if (s[0] == '\n') { - /* - * do what strlen() would do, so that caller - * is always right - */ - width++; + nextchar = *s; + bytesconsumed = 1; + (void)memset(&state, 0, sizeof(state)); + width += 4; } else { int w = wcwidth(nextchar); - if (w > 0) - width += w; + width += ((ms->flags & MAGIC_RAW) != 0 + || iswprint(nextchar)) ? (w > 0 ? w : 1) : 4; } s += bytesconsumed, n -= bytesconsumed; } - return width; #else - return strlen(s); + for (; *s; s++) { + width += (ms->flags & MAGIC_RAW) != 0 + || isprint(CAST(unsigned char, *s)) ? 1 : 4; + } #endif + return width; } -private void +file_private void usage(void) { const char *pn = file_getprogname(); @@ -608,26 +705,26 @@ usage(void) exit(EXIT_FAILURE); } -private void +file_private void defprint(int def) { if (!def) return; if (((def & 1) && posixly) || ((def & 2) && !posixly)) - fprintf(stdout, " (default)"); - fputc('\n', stdout); + (void)fprintf(stdout, " (default)"); + (void)putc('\n', stdout); } -private void +file_private void docprint(const char *opts, int def) { size_t i; int comma, pad; char *sp, *p; - p = strchr(opts, '%'); + p = CCAST(char *, strchr(opts, '%')); if (p == NULL) { - fprintf(stdout, "%s", opts); + (void)fprintf(stdout, "%s", opts); defprint(def); return; } @@ -635,26 +732,26 @@ docprint(const char *opts, int def) for (sp = p - 1; sp > opts && *sp == ' '; sp--) continue; - fprintf(stdout, "%.*s", CAST(int, p - opts), opts); + (void)printf("%.*s", CAST(int, p - opts), opts); pad = (int)CAST(int, p - sp - 1); switch (*++p) { case 'e': comma = 0; for (i = 0; i < __arraycount(nv); i++) { - fprintf(stdout, "%s%s", comma++ ? ", " : "", nv[i].name); + (void)printf("%s%s", comma++ ? ", " : "", nv[i].name); if (i && i % 5 == 0 && i != __arraycount(nv) - 1) { - fprintf(stdout, ",\n%*s", pad, ""); + (void)printf(",\n%*s", pad, ""); comma = 0; } } break; case 'P': for (i = 0; i < __arraycount(pm); i++) { - fprintf(stdout, "%9s %7zu %s", pm[i].name, pm[i].def, + (void)printf("%9s %7zu %s", pm[i].name, pm[i].def, pm[i].desc); if (i != __arraycount(pm) - 1) - fprintf(stdout, "\n%*s", pad, ""); + (void)printf("\n%*s", pad, ""); } break; default: @@ -662,11 +759,11 @@ docprint(const char *opts, int def) *p); break; } - fprintf(stdout, "%s", opts + (p - opts) + 1); + (void)printf("%s", opts + (p - opts) + 1); } -private void +file_private void help(void) { (void)fputs( @@ -674,89 +771,89 @@ help(void) "Determine type of FILEs.\n" "\n", stdout); #define OPT(shortname, longname, opt, def, doc) \ - fprintf(stdout, " -%c, --" longname, shortname), \ + (void)printf(" -%c, --" longname, shortname), \ docprint(doc, def); #define OPT_LONGONLY(longname, opt, def, doc, id) \ - fprintf(stdout, " --" longname), \ + (void)printf(" --" longname), \ docprint(doc, def); #include "file_opts.h" #undef OPT #undef OPT_LONGONLY - fprintf(stdout, "\nReport bugs to https://bugs.astron.com/\n"); + (void)printf("\nReport bugs to https://bugs.astron.com/\n"); exit(EXIT_SUCCESS); } -private const char *file_progname; +file_private const char *file_progname; -protected void +file_protected void file_setprogname(const char *progname) { file_progname = progname; } -protected const char * +file_protected const char * file_getprogname(void) { return file_progname; } -protected void +file_protected void file_err(int e, const char *fmt, ...) { va_list ap; int se = errno; va_start(ap, fmt); - fprintf(stderr, "%s: ", file_progname); - vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "%s: ", file_progname); + (void)vfprintf(stderr, fmt, ap); va_end(ap); if (se) - fprintf(stderr, " (%s)\n", strerror(se)); + (void)fprintf(stderr, " (%s)\n", strerror(se)); else fputc('\n', stderr); exit(e); } -protected void +file_protected void file_errx(int e, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "%s: ", file_progname); - vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "%s: ", file_progname); + (void)vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, "\n"); + (void)fprintf(stderr, "\n"); exit(e); } -protected void +file_protected void file_warn(const char *fmt, ...) { va_list ap; int se = errno; va_start(ap, fmt); - fprintf(stderr, "%s: ", file_progname); - vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "%s: ", file_progname); + (void)vfprintf(stderr, fmt, ap); va_end(ap); if (se) - fprintf(stderr, " (%s)\n", strerror(se)); + (void)fprintf(stderr, " (%s)\n", strerror(se)); else fputc('\n', stderr); errno = se; } -protected void +file_protected void file_warnx(const char *fmt, ...) { va_list ap; int se = errno; va_start(ap, fmt); - fprintf(stderr, "%s: ", file_progname); - vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "%s: ", file_progname); + (void)vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, "\n"); + (void)fprintf(stderr, "\n"); errno = se; } |