1327e51cbSPeter Avalos /*
2327e51cbSPeter Avalos * Copyright (c) Ian F. Darwin 1986-1995.
3327e51cbSPeter Avalos * Software written by Ian F. Darwin and others;
4327e51cbSPeter Avalos * maintained 1995-present by Christos Zoulas and others.
5327e51cbSPeter Avalos *
6327e51cbSPeter Avalos * Redistribution and use in source and binary forms, with or without
7327e51cbSPeter Avalos * modification, are permitted provided that the following conditions
8327e51cbSPeter Avalos * are met:
9327e51cbSPeter Avalos * 1. Redistributions of source code must retain the above copyright
10327e51cbSPeter Avalos * notice immediately at the beginning of the file, without modification,
11327e51cbSPeter Avalos * this list of conditions, and the following disclaimer.
12327e51cbSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
13327e51cbSPeter Avalos * notice, this list of conditions and the following disclaimer in the
14327e51cbSPeter Avalos * documentation and/or other materials provided with the distribution.
15327e51cbSPeter Avalos *
16327e51cbSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17327e51cbSPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18327e51cbSPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19327e51cbSPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20327e51cbSPeter Avalos * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21327e51cbSPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22327e51cbSPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23327e51cbSPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24327e51cbSPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25327e51cbSPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26327e51cbSPeter Avalos * SUCH DAMAGE.
27327e51cbSPeter Avalos */
28327e51cbSPeter Avalos /*
29327e51cbSPeter Avalos * file - find type of a file or files - main program.
30327e51cbSPeter Avalos */
31327e51cbSPeter Avalos
32327e51cbSPeter Avalos #include "file.h"
3379343712SPeter Avalos
3479343712SPeter Avalos #ifndef lint
35*3b9cdfa3SAntonio Huete Jimenez FILE_RCSID("@(#)$File: file.c,v 1.204 2022/09/13 18:46:07 christos Exp $")
3679343712SPeter Avalos #endif /* lint */
3779343712SPeter Avalos
38327e51cbSPeter Avalos #include "magic.h"
39327e51cbSPeter Avalos
40327e51cbSPeter Avalos #include <stdlib.h>
41327e51cbSPeter Avalos #include <unistd.h>
42327e51cbSPeter Avalos #include <string.h>
43327e51cbSPeter Avalos #ifdef RESTORE_TIME
44327e51cbSPeter Avalos # if (__COHERENT__ >= 0x420)
45327e51cbSPeter Avalos # include <sys/utime.h>
46327e51cbSPeter Avalos # else
47327e51cbSPeter Avalos # ifdef USE_UTIMES
48327e51cbSPeter Avalos # include <sys/time.h>
49327e51cbSPeter Avalos # else
50327e51cbSPeter Avalos # include <utime.h>
51327e51cbSPeter Avalos # endif
52327e51cbSPeter Avalos # endif
53327e51cbSPeter Avalos #endif
54327e51cbSPeter Avalos #ifdef HAVE_UNISTD_H
55327e51cbSPeter Avalos #include <unistd.h> /* for read() */
56327e51cbSPeter Avalos #endif
57327e51cbSPeter Avalos #ifdef HAVE_WCHAR_H
58327e51cbSPeter Avalos #include <wchar.h>
59327e51cbSPeter Avalos #endif
60*3b9cdfa3SAntonio Huete Jimenez #ifdef HAVE_WCTYPE_H
61*3b9cdfa3SAntonio Huete Jimenez #include <wctype.h>
62*3b9cdfa3SAntonio Huete Jimenez #endif
63*3b9cdfa3SAntonio Huete Jimenez #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) && \
64*3b9cdfa3SAntonio Huete Jimenez defined(HAVE_WCTYPE_H)
65*3b9cdfa3SAntonio Huete Jimenez #define FILE_WIDE_SUPPORT
66*3b9cdfa3SAntonio Huete Jimenez #else
67*3b9cdfa3SAntonio Huete Jimenez #include <ctype.h>
68*3b9cdfa3SAntonio Huete Jimenez #endif
69327e51cbSPeter Avalos
7079343712SPeter Avalos #if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION)
7179343712SPeter Avalos # include <getopt.h>
7279343712SPeter Avalos # ifndef HAVE_GETOPT_LONG
736fca56fbSSascha Wildner int getopt_long(int, char * const *, const char *,
746fca56fbSSascha Wildner const struct option *, int *);
75327e51cbSPeter Avalos # endif
76f72f8299SJan Lentfer # else
77f72f8299SJan Lentfer # include "mygetopt.h"
78f72f8299SJan Lentfer #endif
79327e51cbSPeter Avalos
80327e51cbSPeter Avalos #ifdef S_IFLNK
816fca56fbSSascha Wildner # define IFLNK_h "h"
826fca56fbSSascha Wildner # define IFLNK_L "L"
83327e51cbSPeter Avalos #else
846fca56fbSSascha Wildner # define IFLNK_h ""
856fca56fbSSascha Wildner # define IFLNK_L ""
86327e51cbSPeter Avalos #endif
87327e51cbSPeter Avalos
886fca56fbSSascha Wildner #define FILE_FLAGS "bcCdE" IFLNK_h "ik" IFLNK_L "lNnprsSvzZ0"
896fca56fbSSascha Wildner #define OPTSTRING "bcCde:Ef:F:hiklLm:nNpP:rsSvzZ0"
906fca56fbSSascha Wildner
91f72f8299SJan Lentfer # define USAGE \
926fca56fbSSascha Wildner "Usage: %s [-" FILE_FLAGS "] [--apple] [--extension] [--mime-encoding]\n" \
936fca56fbSSascha Wildner " [--mime-type] [-e <testname>] [-F <separator>] " \
946fca56fbSSascha Wildner " [-f <namefile>]\n" \
95c990e5baSDaniel Fojt " [-m <magicfiles>] [-P <parameter=value>] [--exclude-quiet]\n" \
96c990e5baSDaniel Fojt " <file> ...\n" \
976fca56fbSSascha Wildner " %s -C [-m <magicfiles>]\n" \
98f72f8299SJan Lentfer " %s [--help]\n"
99327e51cbSPeter Avalos
100327e51cbSPeter Avalos private int /* Global command-line options */
101327e51cbSPeter Avalos bflag = 0, /* brief output format */
102327e51cbSPeter Avalos nopad = 0, /* Don't pad output */
103327e51cbSPeter Avalos nobuffer = 0, /* Do not buffer stdout */
104327e51cbSPeter Avalos nulsep = 0; /* Append '\0' to the separator */
105327e51cbSPeter Avalos
106327e51cbSPeter Avalos private const char *separator = ":"; /* Default field separator */
10779343712SPeter Avalos private const struct option long_options[] = {
108c30bd091SSascha Wildner #define OPT_HELP 1
109c30bd091SSascha Wildner #define OPT_APPLE 2
110c30bd091SSascha Wildner #define OPT_EXTENSIONS 3
111c30bd091SSascha Wildner #define OPT_MIME_TYPE 4
112c30bd091SSascha Wildner #define OPT_MIME_ENCODING 5
113c990e5baSDaniel Fojt #define OPT_EXCLUDE_QUIET 6
114c30bd091SSascha Wildner #define OPT(shortname, longname, opt, def, doc) \
11579343712SPeter Avalos {longname, opt, NULL, shortname},
116c30bd091SSascha Wildner #define OPT_LONGONLY(longname, opt, def, doc, id) \
117c30bd091SSascha Wildner {longname, opt, NULL, id},
11879343712SPeter Avalos #include "file_opts.h"
11979343712SPeter Avalos #undef OPT
12079343712SPeter Avalos #undef OPT_LONGONLY
12179343712SPeter Avalos {0, 0, NULL, 0}
12279343712SPeter Avalos };
12379343712SPeter Avalos
12479343712SPeter Avalos private const struct {
12579343712SPeter Avalos const char *name;
12679343712SPeter Avalos int value;
12779343712SPeter Avalos } nv[] = {
12879343712SPeter Avalos { "apptype", MAGIC_NO_CHECK_APPTYPE },
12979343712SPeter Avalos { "ascii", MAGIC_NO_CHECK_ASCII },
13079343712SPeter Avalos { "cdf", MAGIC_NO_CHECK_CDF },
13179343712SPeter Avalos { "compress", MAGIC_NO_CHECK_COMPRESS },
1326fca56fbSSascha Wildner { "csv", MAGIC_NO_CHECK_CSV },
13379343712SPeter Avalos { "elf", MAGIC_NO_CHECK_ELF },
13479343712SPeter Avalos { "encoding", MAGIC_NO_CHECK_ENCODING },
13579343712SPeter Avalos { "soft", MAGIC_NO_CHECK_SOFT },
13679343712SPeter Avalos { "tar", MAGIC_NO_CHECK_TAR },
1376fca56fbSSascha Wildner { "json", MAGIC_NO_CHECK_JSON },
138e4d4ce0cSPeter Avalos { "text", MAGIC_NO_CHECK_TEXT }, /* synonym for ascii */
1399f86ab30SPeter Avalos { "tokens", MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */
14079343712SPeter Avalos };
141327e51cbSPeter Avalos
14282c5fa3eSPeter Avalos private struct {
14382c5fa3eSPeter Avalos const char *name;
14482c5fa3eSPeter Avalos size_t value;
145c990e5baSDaniel Fojt size_t def;
146c990e5baSDaniel Fojt const char *desc;
147614728caSSascha Wildner int tag;
148614728caSSascha Wildner int set;
14982c5fa3eSPeter Avalos } pm[] = {
150614728caSSascha Wildner { "bytes", 0, FILE_BYTES_MAX, "max bytes to look inside file",
151614728caSSascha Wildner MAGIC_PARAM_BYTES_MAX, 0 },
152614728caSSascha Wildner { "elf_notes", 0, FILE_ELF_NOTES_MAX, "max ELF notes processed",
153614728caSSascha Wildner MAGIC_PARAM_ELF_NOTES_MAX, 0 },
154614728caSSascha Wildner { "elf_phnum", 0, FILE_ELF_PHNUM_MAX, "max ELF prog sections processed",
155614728caSSascha Wildner MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
156614728caSSascha Wildner { "elf_shnum", 0, FILE_ELF_SHNUM_MAX, "max ELF sections processed",
157614728caSSascha Wildner MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
158614728caSSascha Wildner { "encoding", 0, FILE_ENCODING_MAX, "max bytes to scan for encoding",
159614728caSSascha Wildner MAGIC_PARAM_ENCODING_MAX, 0 },
160614728caSSascha Wildner { "indir", 0, FILE_INDIR_MAX, "recursion limit for indirection",
161614728caSSascha Wildner MAGIC_PARAM_INDIR_MAX, 0 },
162614728caSSascha Wildner { "name", 0, FILE_NAME_MAX, "use limit for name/use magic",
163614728caSSascha Wildner MAGIC_PARAM_NAME_MAX, 0 },
164614728caSSascha Wildner { "regex", 0, FILE_REGEX_MAX, "length limit for REGEX searches",
165614728caSSascha Wildner MAGIC_PARAM_REGEX_MAX, 0 },
16682c5fa3eSPeter Avalos };
16782c5fa3eSPeter Avalos
168c30bd091SSascha Wildner private int posixly;
169327e51cbSPeter Avalos
170c30bd091SSascha Wildner #ifdef __dead
171c30bd091SSascha Wildner __dead
172c30bd091SSascha Wildner #endif
173327e51cbSPeter Avalos private void usage(void);
174c30bd091SSascha Wildner private void docprint(const char *, int);
175c30bd091SSascha Wildner #ifdef __dead
176c30bd091SSascha Wildner __dead
177c30bd091SSascha Wildner #endif
178327e51cbSPeter Avalos private void help(void);
17979343712SPeter Avalos
18079343712SPeter Avalos private int unwrap(struct magic_set *, const char *);
18179343712SPeter Avalos private int process(struct magic_set *ms, const char *, int);
18279343712SPeter Avalos private struct magic_set *load(const char *, int);
18382c5fa3eSPeter Avalos private void setparam(const char *);
18482c5fa3eSPeter Avalos private void applyparam(magic_t);
185327e51cbSPeter Avalos
186327e51cbSPeter Avalos
187327e51cbSPeter Avalos /*
188327e51cbSPeter Avalos * main - parse arguments and handle options
189327e51cbSPeter Avalos */
190327e51cbSPeter Avalos int
main(int argc,char * argv[])191327e51cbSPeter Avalos main(int argc, char *argv[])
192327e51cbSPeter Avalos {
193327e51cbSPeter Avalos int c;
194*3b9cdfa3SAntonio Huete Jimenez size_t i, j, wid, nw;
195327e51cbSPeter Avalos int action = 0, didsomefiles = 0, errflg = 0;
19679343712SPeter Avalos int flags = 0, e = 0;
1976fca56fbSSascha Wildner #ifdef HAVE_LIBSECCOMP
1986fca56fbSSascha Wildner int sandbox = 1;
1996fca56fbSSascha Wildner #endif
20079343712SPeter Avalos struct magic_set *magic = NULL;
201327e51cbSPeter Avalos int longindex;
202f72f8299SJan Lentfer const char *magicfile = NULL; /* where the magic is */
2036fca56fbSSascha Wildner char *progname;
204327e51cbSPeter Avalos
205327e51cbSPeter Avalos /* makes islower etc work for other langs */
206327e51cbSPeter Avalos (void)setlocale(LC_CTYPE, "");
207327e51cbSPeter Avalos
208327e51cbSPeter Avalos #ifdef __EMX__
209327e51cbSPeter Avalos /* sh-like wildcard expansion! Shouldn't hurt at least ... */
210327e51cbSPeter Avalos _wildcard(&argc, &argv);
211327e51cbSPeter Avalos #endif
212327e51cbSPeter Avalos
213327e51cbSPeter Avalos if ((progname = strrchr(argv[0], '/')) != NULL)
214327e51cbSPeter Avalos progname++;
215327e51cbSPeter Avalos else
216327e51cbSPeter Avalos progname = argv[0];
217327e51cbSPeter Avalos
2186fca56fbSSascha Wildner file_setprogname(progname);
2196fca56fbSSascha Wildner
2206fca56fbSSascha Wildner
221327e51cbSPeter Avalos #ifdef S_IFLNK
222c30bd091SSascha Wildner posixly = getenv("POSIXLY_CORRECT") != NULL;
223c30bd091SSascha Wildner flags |= posixly ? MAGIC_SYMLINK : 0;
224327e51cbSPeter Avalos #endif
225327e51cbSPeter Avalos while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
226327e51cbSPeter Avalos &longindex)) != -1)
227327e51cbSPeter Avalos switch (c) {
228c30bd091SSascha Wildner case OPT_HELP:
229327e51cbSPeter Avalos help();
230327e51cbSPeter Avalos break;
231c30bd091SSascha Wildner case OPT_APPLE:
23279343712SPeter Avalos flags |= MAGIC_APPLE;
233327e51cbSPeter Avalos break;
234c30bd091SSascha Wildner case OPT_EXTENSIONS:
235c30bd091SSascha Wildner flags |= MAGIC_EXTENSION;
236c30bd091SSascha Wildner break;
237c30bd091SSascha Wildner case OPT_MIME_TYPE:
23879343712SPeter Avalos flags |= MAGIC_MIME_TYPE;
23979343712SPeter Avalos break;
240c30bd091SSascha Wildner case OPT_MIME_ENCODING:
241327e51cbSPeter Avalos flags |= MAGIC_MIME_ENCODING;
242327e51cbSPeter Avalos break;
243327e51cbSPeter Avalos case '0':
244c30bd091SSascha Wildner nulsep++;
245327e51cbSPeter Avalos break;
246327e51cbSPeter Avalos case 'b':
247327e51cbSPeter Avalos bflag++;
248327e51cbSPeter Avalos break;
249327e51cbSPeter Avalos case 'c':
250327e51cbSPeter Avalos action = FILE_CHECK;
251327e51cbSPeter Avalos break;
252327e51cbSPeter Avalos case 'C':
253327e51cbSPeter Avalos action = FILE_COMPILE;
254327e51cbSPeter Avalos break;
255327e51cbSPeter Avalos case 'd':
256327e51cbSPeter Avalos flags |= MAGIC_DEBUG|MAGIC_CHECK;
257327e51cbSPeter Avalos break;
258e8af9738SPeter Avalos case 'E':
259e8af9738SPeter Avalos flags |= MAGIC_ERROR;
260e8af9738SPeter Avalos break;
261327e51cbSPeter Avalos case 'e':
262c990e5baSDaniel Fojt case OPT_EXCLUDE_QUIET:
2636fca56fbSSascha Wildner for (i = 0; i < __arraycount(nv); i++)
264327e51cbSPeter Avalos if (strcmp(nv[i].name, optarg) == 0)
265327e51cbSPeter Avalos break;
266327e51cbSPeter Avalos
267c990e5baSDaniel Fojt if (i == __arraycount(nv)) {
268c990e5baSDaniel Fojt if (c != OPT_EXCLUDE_QUIET)
269327e51cbSPeter Avalos errflg++;
270c990e5baSDaniel Fojt } else
271327e51cbSPeter Avalos flags |= nv[i].value;
272327e51cbSPeter Avalos break;
273327e51cbSPeter Avalos
274327e51cbSPeter Avalos case 'f':
275327e51cbSPeter Avalos if(action)
276327e51cbSPeter Avalos usage();
27779343712SPeter Avalos if (magic == NULL)
27879343712SPeter Avalos if ((magic = load(magicfile, flags)) == NULL)
27979343712SPeter Avalos return 1;
280c30bd091SSascha Wildner applyparam(magic);
28179343712SPeter Avalos e |= unwrap(magic, optarg);
282327e51cbSPeter Avalos ++didsomefiles;
283327e51cbSPeter Avalos break;
284327e51cbSPeter Avalos case 'F':
285327e51cbSPeter Avalos separator = optarg;
286327e51cbSPeter Avalos break;
287327e51cbSPeter Avalos case 'i':
288327e51cbSPeter Avalos flags |= MAGIC_MIME;
289327e51cbSPeter Avalos break;
290327e51cbSPeter Avalos case 'k':
291327e51cbSPeter Avalos flags |= MAGIC_CONTINUE;
292327e51cbSPeter Avalos break;
293e4d4ce0cSPeter Avalos case 'l':
294e4d4ce0cSPeter Avalos action = FILE_LIST;
295e4d4ce0cSPeter Avalos break;
296327e51cbSPeter Avalos case 'm':
297327e51cbSPeter Avalos magicfile = optarg;
298327e51cbSPeter Avalos break;
299327e51cbSPeter Avalos case 'n':
300327e51cbSPeter Avalos ++nobuffer;
301327e51cbSPeter Avalos break;
302327e51cbSPeter Avalos case 'N':
303327e51cbSPeter Avalos ++nopad;
304327e51cbSPeter Avalos break;
305327e51cbSPeter Avalos #if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
306327e51cbSPeter Avalos case 'p':
307327e51cbSPeter Avalos flags |= MAGIC_PRESERVE_ATIME;
308327e51cbSPeter Avalos break;
309327e51cbSPeter Avalos #endif
31082c5fa3eSPeter Avalos case 'P':
31182c5fa3eSPeter Avalos setparam(optarg);
31282c5fa3eSPeter Avalos break;
313327e51cbSPeter Avalos case 'r':
314327e51cbSPeter Avalos flags |= MAGIC_RAW;
315327e51cbSPeter Avalos break;
316327e51cbSPeter Avalos case 's':
317327e51cbSPeter Avalos flags |= MAGIC_DEVICES;
318327e51cbSPeter Avalos break;
3196fca56fbSSascha Wildner case 'S':
3206fca56fbSSascha Wildner #ifdef HAVE_LIBSECCOMP
3216fca56fbSSascha Wildner sandbox = 0;
3226fca56fbSSascha Wildner #endif
3236fca56fbSSascha Wildner break;
324327e51cbSPeter Avalos case 'v':
325f72f8299SJan Lentfer if (magicfile == NULL)
326f72f8299SJan Lentfer magicfile = magic_getpath(magicfile, action);
3276fca56fbSSascha Wildner (void)fprintf(stdout, "%s-%s\n", file_getprogname(),
3286fca56fbSSascha Wildner VERSION);
329ff91a668SPeter Avalos (void)fprintf(stdout, "magic file from %s\n",
330327e51cbSPeter Avalos magicfile);
3316fca56fbSSascha Wildner #ifdef HAVE_LIBSECCOMP
3326fca56fbSSascha Wildner (void)fprintf(stdout, "seccomp support included\n");
3336fca56fbSSascha Wildner #endif
334e8af9738SPeter Avalos return 0;
335327e51cbSPeter Avalos case 'z':
336327e51cbSPeter Avalos flags |= MAGIC_COMPRESS;
337327e51cbSPeter Avalos break;
338c30bd091SSascha Wildner
339c30bd091SSascha Wildner case 'Z':
340c30bd091SSascha Wildner flags |= MAGIC_COMPRESS|MAGIC_COMPRESS_TRANSP;
341c30bd091SSascha Wildner break;
342327e51cbSPeter Avalos #ifdef S_IFLNK
343327e51cbSPeter Avalos case 'L':
344327e51cbSPeter Avalos flags |= MAGIC_SYMLINK;
345327e51cbSPeter Avalos break;
346327e51cbSPeter Avalos case 'h':
347327e51cbSPeter Avalos flags &= ~MAGIC_SYMLINK;
348327e51cbSPeter Avalos break;
349327e51cbSPeter Avalos #endif
350327e51cbSPeter Avalos case '?':
351327e51cbSPeter Avalos default:
352327e51cbSPeter Avalos errflg++;
353327e51cbSPeter Avalos break;
354327e51cbSPeter Avalos }
355327e51cbSPeter Avalos
356327e51cbSPeter Avalos if (errflg) {
357327e51cbSPeter Avalos usage();
358327e51cbSPeter Avalos }
35979343712SPeter Avalos if (e)
36079343712SPeter Avalos return e;
361327e51cbSPeter Avalos
3626fca56fbSSascha Wildner #ifdef HAVE_LIBSECCOMP
3636fca56fbSSascha Wildner #if 0
3646fca56fbSSascha Wildner if (sandbox && enable_sandbox_basic() == -1)
3656fca56fbSSascha Wildner #else
3666fca56fbSSascha Wildner if (sandbox && enable_sandbox_full() == -1)
3676fca56fbSSascha Wildner #endif
3686fca56fbSSascha Wildner file_err(EXIT_FAILURE, "SECCOMP initialisation failed");
3696fca56fbSSascha Wildner #endif /* HAVE_LIBSECCOMP */
3706fca56fbSSascha Wildner
371e8af9738SPeter Avalos if (MAGIC_VERSION != magic_version())
3726fca56fbSSascha Wildner file_warnx("Compiled magic version [%d] "
373e8af9738SPeter Avalos "does not match with shared library magic version [%d]\n",
3746fca56fbSSascha Wildner MAGIC_VERSION, magic_version());
375e8af9738SPeter Avalos
376327e51cbSPeter Avalos switch(action) {
377327e51cbSPeter Avalos case FILE_CHECK:
378327e51cbSPeter Avalos case FILE_COMPILE:
379e4d4ce0cSPeter Avalos case FILE_LIST:
38079343712SPeter Avalos /*
38179343712SPeter Avalos * Don't try to check/compile ~/.magic unless we explicitly
38279343712SPeter Avalos * ask for it.
38379343712SPeter Avalos */
384327e51cbSPeter Avalos magic = magic_open(flags|MAGIC_CHECK);
385327e51cbSPeter Avalos if (magic == NULL) {
3866fca56fbSSascha Wildner file_warn("Can't create magic");
387327e51cbSPeter Avalos return 1;
388327e51cbSPeter Avalos }
38982c5fa3eSPeter Avalos
39082c5fa3eSPeter Avalos
391e4d4ce0cSPeter Avalos switch(action) {
392e4d4ce0cSPeter Avalos case FILE_CHECK:
393e4d4ce0cSPeter Avalos c = magic_check(magic, magicfile);
394e4d4ce0cSPeter Avalos break;
395e4d4ce0cSPeter Avalos case FILE_COMPILE:
396e4d4ce0cSPeter Avalos c = magic_compile(magic, magicfile);
397e4d4ce0cSPeter Avalos break;
398e4d4ce0cSPeter Avalos case FILE_LIST:
399e4d4ce0cSPeter Avalos c = magic_list(magic, magicfile);
400e4d4ce0cSPeter Avalos break;
401e4d4ce0cSPeter Avalos default:
402e4d4ce0cSPeter Avalos abort();
403e4d4ce0cSPeter Avalos }
404327e51cbSPeter Avalos if (c == -1) {
4056fca56fbSSascha Wildner file_warnx("%s", magic_error(magic));
406c30bd091SSascha Wildner e = 1;
407c30bd091SSascha Wildner goto out;
408327e51cbSPeter Avalos }
409c30bd091SSascha Wildner goto out;
410327e51cbSPeter Avalos default:
41179343712SPeter Avalos if (magic == NULL)
41279343712SPeter Avalos if ((magic = load(magicfile, flags)) == NULL)
41379343712SPeter Avalos return 1;
41482c5fa3eSPeter Avalos applyparam(magic);
415327e51cbSPeter Avalos }
416327e51cbSPeter Avalos
417327e51cbSPeter Avalos if (optind == argc) {
41879343712SPeter Avalos if (!didsomefiles)
419327e51cbSPeter Avalos usage();
420*3b9cdfa3SAntonio Huete Jimenez goto out;
421327e51cbSPeter Avalos }
422*3b9cdfa3SAntonio Huete Jimenez
4236fca56fbSSascha Wildner for (wid = 0, j = CAST(size_t, optind); j < CAST(size_t, argc);
4246fca56fbSSascha Wildner j++) {
425*3b9cdfa3SAntonio Huete Jimenez nw = file_mbswidth(magic, argv[j]);
426327e51cbSPeter Avalos if (nw > wid)
427327e51cbSPeter Avalos wid = nw;
428327e51cbSPeter Avalos }
429*3b9cdfa3SAntonio Huete Jimenez
430327e51cbSPeter Avalos /*
431327e51cbSPeter Avalos * If bflag is only set twice, set it depending on
432327e51cbSPeter Avalos * number of files [this is undocumented, and subject to change]
433327e51cbSPeter Avalos */
434327e51cbSPeter Avalos if (bflag == 2) {
435327e51cbSPeter Avalos bflag = optind >= argc - 1;
436327e51cbSPeter Avalos }
437327e51cbSPeter Avalos for (; optind < argc; optind++)
43879343712SPeter Avalos e |= process(magic, argv[optind], wid);
439327e51cbSPeter Avalos
440c30bd091SSascha Wildner out:
441*3b9cdfa3SAntonio Huete Jimenez if (!nobuffer)
442*3b9cdfa3SAntonio Huete Jimenez e |= fflush(stdout) != 0;
443*3b9cdfa3SAntonio Huete Jimenez
44479343712SPeter Avalos if (magic)
445327e51cbSPeter Avalos magic_close(magic);
44679343712SPeter Avalos return e;
447327e51cbSPeter Avalos }
448327e51cbSPeter Avalos
44982c5fa3eSPeter Avalos private void
applyparam(magic_t magic)45082c5fa3eSPeter Avalos applyparam(magic_t magic)
45182c5fa3eSPeter Avalos {
45282c5fa3eSPeter Avalos size_t i;
45382c5fa3eSPeter Avalos
45482c5fa3eSPeter Avalos for (i = 0; i < __arraycount(pm); i++) {
4556fca56fbSSascha Wildner if (!pm[i].set)
45682c5fa3eSPeter Avalos continue;
4576fca56fbSSascha Wildner if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1)
4586fca56fbSSascha Wildner file_err(EXIT_FAILURE, "Can't set %s", pm[i].name);
45982c5fa3eSPeter Avalos }
46082c5fa3eSPeter Avalos }
46182c5fa3eSPeter Avalos
46282c5fa3eSPeter Avalos private void
setparam(const char * p)46382c5fa3eSPeter Avalos setparam(const char *p)
46482c5fa3eSPeter Avalos {
46582c5fa3eSPeter Avalos size_t i;
46682c5fa3eSPeter Avalos char *s;
46782c5fa3eSPeter Avalos
468*3b9cdfa3SAntonio Huete Jimenez if ((s = CCAST(char *, strchr(p, '='))) == NULL)
46982c5fa3eSPeter Avalos goto badparm;
47082c5fa3eSPeter Avalos
47182c5fa3eSPeter Avalos for (i = 0; i < __arraycount(pm); i++) {
47282c5fa3eSPeter Avalos if (strncmp(p, pm[i].name, s - p) != 0)
47382c5fa3eSPeter Avalos continue;
47482c5fa3eSPeter Avalos pm[i].value = atoi(s + 1);
4756fca56fbSSascha Wildner pm[i].set = 1;
47682c5fa3eSPeter Avalos return;
47782c5fa3eSPeter Avalos }
47882c5fa3eSPeter Avalos badparm:
4796fca56fbSSascha Wildner file_errx(EXIT_FAILURE, "Unknown param %s", p);
48082c5fa3eSPeter Avalos }
481327e51cbSPeter Avalos
48279343712SPeter Avalos private struct magic_set *
483327e51cbSPeter Avalos /*ARGSUSED*/
load(const char * magicfile,int flags)48479343712SPeter Avalos load(const char *magicfile, int flags)
485327e51cbSPeter Avalos {
48679343712SPeter Avalos struct magic_set *magic = magic_open(flags);
487c30bd091SSascha Wildner const char *e;
488c30bd091SSascha Wildner
489327e51cbSPeter Avalos if (magic == NULL) {
4906fca56fbSSascha Wildner file_warn("Can't create magic");
49179343712SPeter Avalos return NULL;
492327e51cbSPeter Avalos }
493327e51cbSPeter Avalos if (magic_load(magic, magicfile) == -1) {
4946fca56fbSSascha Wildner file_warn("%s", magic_error(magic));
49579343712SPeter Avalos magic_close(magic);
49679343712SPeter Avalos return NULL;
497327e51cbSPeter Avalos }
498c30bd091SSascha Wildner if ((e = magic_error(magic)) != NULL)
4996fca56fbSSascha Wildner file_warn("%s", e);
50079343712SPeter Avalos return magic;
501327e51cbSPeter Avalos }
502327e51cbSPeter Avalos
503327e51cbSPeter Avalos /*
504327e51cbSPeter Avalos * unwrap -- read a file of filenames, do each one.
505327e51cbSPeter Avalos */
50679343712SPeter Avalos private int
unwrap(struct magic_set * ms,const char * fn)50779343712SPeter Avalos unwrap(struct magic_set *ms, const char *fn)
508327e51cbSPeter Avalos {
509327e51cbSPeter Avalos FILE *f;
510ff91a668SPeter Avalos ssize_t len;
511ff91a668SPeter Avalos char *line = NULL;
512ff91a668SPeter Avalos size_t llen = 0;
513327e51cbSPeter Avalos int wid = 0, cwid;
51479343712SPeter Avalos int e = 0;
515*3b9cdfa3SAntonio Huete Jimenez size_t fi = 0, fimax = 100;
516*3b9cdfa3SAntonio Huete Jimenez char **flist = CAST(char **, malloc(sizeof(*flist) * fimax));
517327e51cbSPeter Avalos
518*3b9cdfa3SAntonio Huete Jimenez if (flist == NULL)
519*3b9cdfa3SAntonio Huete Jimenez out: file_err(EXIT_FAILURE, "Cannot allocate memory for file list");
520*3b9cdfa3SAntonio Huete Jimenez
521*3b9cdfa3SAntonio Huete Jimenez if (strcmp("-", fn) == 0)
522327e51cbSPeter Avalos f = stdin;
523*3b9cdfa3SAntonio Huete Jimenez else {
524327e51cbSPeter Avalos if ((f = fopen(fn, "r")) == NULL) {
5256fca56fbSSascha Wildner file_warn("Cannot open `%s'", fn);
52679343712SPeter Avalos return 1;
527327e51cbSPeter Avalos }
528*3b9cdfa3SAntonio Huete Jimenez }
529327e51cbSPeter Avalos
530ff91a668SPeter Avalos while ((len = getline(&line, &llen, f)) > 0) {
531ff91a668SPeter Avalos if (line[len - 1] == '\n')
532ff91a668SPeter Avalos line[len - 1] = '\0';
533*3b9cdfa3SAntonio Huete Jimenez if (fi >= fimax) {
534*3b9cdfa3SAntonio Huete Jimenez fimax += 100;
535*3b9cdfa3SAntonio Huete Jimenez char **nf = CAST(char **,
536*3b9cdfa3SAntonio Huete Jimenez realloc(flist, fimax * sizeof(*flist)));
537*3b9cdfa3SAntonio Huete Jimenez if (nf == NULL)
538*3b9cdfa3SAntonio Huete Jimenez goto out;
539*3b9cdfa3SAntonio Huete Jimenez flist = nf;
540*3b9cdfa3SAntonio Huete Jimenez }
541*3b9cdfa3SAntonio Huete Jimenez flist[fi++] = line;
542*3b9cdfa3SAntonio Huete Jimenez cwid = file_mbswidth(ms, line);
543327e51cbSPeter Avalos if (cwid > wid)
544327e51cbSPeter Avalos wid = cwid;
545*3b9cdfa3SAntonio Huete Jimenez line = NULL;
546*3b9cdfa3SAntonio Huete Jimenez llen = 0;
547327e51cbSPeter Avalos }
548327e51cbSPeter Avalos
549*3b9cdfa3SAntonio Huete Jimenez fimax = fi;
550*3b9cdfa3SAntonio Huete Jimenez for (fi = 0; fi < fimax; fi++) {
551*3b9cdfa3SAntonio Huete Jimenez e |= process(ms, flist[fi], wid);
552*3b9cdfa3SAntonio Huete Jimenez free(flist[fi]);
553327e51cbSPeter Avalos }
554*3b9cdfa3SAntonio Huete Jimenez free(flist);
555327e51cbSPeter Avalos
556*3b9cdfa3SAntonio Huete Jimenez if (f != stdin)
557327e51cbSPeter Avalos (void)fclose(f);
55879343712SPeter Avalos return e;
559327e51cbSPeter Avalos }
560327e51cbSPeter Avalos
561*3b9cdfa3SAntonio Huete Jimenez private void
file_octal(unsigned char c)562*3b9cdfa3SAntonio Huete Jimenez file_octal(unsigned char c)
563*3b9cdfa3SAntonio Huete Jimenez {
564*3b9cdfa3SAntonio Huete Jimenez putc('\\', stdout);
565*3b9cdfa3SAntonio Huete Jimenez putc(((c >> 6) & 7) + '0', stdout);
566*3b9cdfa3SAntonio Huete Jimenez putc(((c >> 3) & 7) + '0', stdout);
567*3b9cdfa3SAntonio Huete Jimenez putc(((c >> 0) & 7) + '0', stdout);
568*3b9cdfa3SAntonio Huete Jimenez }
569*3b9cdfa3SAntonio Huete Jimenez
570*3b9cdfa3SAntonio Huete Jimenez private void
fname_print(const char * inname)571*3b9cdfa3SAntonio Huete Jimenez fname_print(const char *inname)
572*3b9cdfa3SAntonio Huete Jimenez {
573*3b9cdfa3SAntonio Huete Jimenez size_t n = strlen(inname);
574*3b9cdfa3SAntonio Huete Jimenez #ifdef FILE_WIDE_SUPPORT
575*3b9cdfa3SAntonio Huete Jimenez mbstate_t state;
576*3b9cdfa3SAntonio Huete Jimenez wchar_t nextchar;
577*3b9cdfa3SAntonio Huete Jimenez size_t bytesconsumed;
578*3b9cdfa3SAntonio Huete Jimenez
579*3b9cdfa3SAntonio Huete Jimenez
580*3b9cdfa3SAntonio Huete Jimenez (void)memset(&state, 0, sizeof(state));
581*3b9cdfa3SAntonio Huete Jimenez while (n > 0) {
582*3b9cdfa3SAntonio Huete Jimenez bytesconsumed = mbrtowc(&nextchar, inname, n, &state);
583*3b9cdfa3SAntonio Huete Jimenez if (bytesconsumed == CAST(size_t, -1) ||
584*3b9cdfa3SAntonio Huete Jimenez bytesconsumed == CAST(size_t, -2)) {
585*3b9cdfa3SAntonio Huete Jimenez nextchar = *inname++;
586*3b9cdfa3SAntonio Huete Jimenez n--;
587*3b9cdfa3SAntonio Huete Jimenez (void)memset(&state, 0, sizeof(state));
588*3b9cdfa3SAntonio Huete Jimenez file_octal(CAST(unsigned char, nextchar));
589*3b9cdfa3SAntonio Huete Jimenez continue;
590*3b9cdfa3SAntonio Huete Jimenez }
591*3b9cdfa3SAntonio Huete Jimenez inname += bytesconsumed;
592*3b9cdfa3SAntonio Huete Jimenez n -= bytesconsumed;
593*3b9cdfa3SAntonio Huete Jimenez if (iswprint(nextchar)) {
594*3b9cdfa3SAntonio Huete Jimenez printf("%lc", nextchar);
595*3b9cdfa3SAntonio Huete Jimenez continue;
596*3b9cdfa3SAntonio Huete Jimenez }
597*3b9cdfa3SAntonio Huete Jimenez /* XXX: What if it is > 255? */
598*3b9cdfa3SAntonio Huete Jimenez file_octal(CAST(unsigned char, nextchar));
599*3b9cdfa3SAntonio Huete Jimenez }
600*3b9cdfa3SAntonio Huete Jimenez #else
601*3b9cdfa3SAntonio Huete Jimenez size_t i;
602*3b9cdfa3SAntonio Huete Jimenez for (i = 0; i < n; i++) {
603*3b9cdfa3SAntonio Huete Jimenez unsigned char c = CAST(unsigned char, inname[i]);
604*3b9cdfa3SAntonio Huete Jimenez if (isprint(c)) {
605*3b9cdfa3SAntonio Huete Jimenez putc(c);
606*3b9cdfa3SAntonio Huete Jimenez continue;
607*3b9cdfa3SAntonio Huete Jimenez }
608*3b9cdfa3SAntonio Huete Jimenez file_octal(c);
609*3b9cdfa3SAntonio Huete Jimenez }
610*3b9cdfa3SAntonio Huete Jimenez #endif
611*3b9cdfa3SAntonio Huete Jimenez }
612*3b9cdfa3SAntonio Huete Jimenez
613327e51cbSPeter Avalos /*
614327e51cbSPeter Avalos * Called for each input file on the command line (or in a list of files)
615327e51cbSPeter Avalos */
61679343712SPeter Avalos private int
process(struct magic_set * ms,const char * inname,int wid)61779343712SPeter Avalos process(struct magic_set *ms, const char *inname, int wid)
618327e51cbSPeter Avalos {
619c30bd091SSascha Wildner const char *type, c = nulsep > 1 ? '\0' : '\n';
620327e51cbSPeter Avalos int std_in = strcmp(inname, "-") == 0;
621*3b9cdfa3SAntonio Huete Jimenez int haderror = 0;
622327e51cbSPeter Avalos
623327e51cbSPeter Avalos if (wid > 0 && !bflag) {
624*3b9cdfa3SAntonio Huete Jimenez const char *pname = std_in ? "/dev/stdin" : inname;
625*3b9cdfa3SAntonio Huete Jimenez if ((ms->flags & MAGIC_RAW) == 0)
626*3b9cdfa3SAntonio Huete Jimenez fname_print(pname);
627*3b9cdfa3SAntonio Huete Jimenez else
628*3b9cdfa3SAntonio Huete Jimenez (void)printf("%s", pname);
629327e51cbSPeter Avalos if (nulsep)
630327e51cbSPeter Avalos (void)putc('\0', stdout);
631c30bd091SSascha Wildner if (nulsep < 2) {
632327e51cbSPeter Avalos (void)printf("%s", separator);
6336fca56fbSSascha Wildner (void)printf("%*s ", CAST(int, nopad ? 0
634*3b9cdfa3SAntonio Huete Jimenez : (wid - file_mbswidth(ms, inname))), "");
635c30bd091SSascha Wildner }
636327e51cbSPeter Avalos }
637327e51cbSPeter Avalos
63879343712SPeter Avalos type = magic_file(ms, std_in ? NULL : inname);
639c30bd091SSascha Wildner
64079343712SPeter Avalos if (type == NULL) {
641*3b9cdfa3SAntonio Huete Jimenez haderror |= printf("ERROR: %s%c", magic_error(ms), c);
64279343712SPeter Avalos } else {
643*3b9cdfa3SAntonio Huete Jimenez haderror |= printf("%s%c", type, c) < 0;
644327e51cbSPeter Avalos }
645970935fdSSascha Wildner if (nobuffer)
646*3b9cdfa3SAntonio Huete Jimenez haderror |= fflush(stdout) != 0;
647*3b9cdfa3SAntonio Huete Jimenez return haderror || type == NULL;
648327e51cbSPeter Avalos }
649327e51cbSPeter Avalos
650e8af9738SPeter Avalos protected size_t
file_mbswidth(struct magic_set * ms,const char * s)651*3b9cdfa3SAntonio Huete Jimenez file_mbswidth(struct magic_set *ms, const char *s)
652327e51cbSPeter Avalos {
653*3b9cdfa3SAntonio Huete Jimenez size_t width = 0;
654*3b9cdfa3SAntonio Huete Jimenez #ifdef FILE_WIDE_SUPPORT
655*3b9cdfa3SAntonio Huete Jimenez size_t bytesconsumed, n;
656327e51cbSPeter Avalos mbstate_t state;
657327e51cbSPeter Avalos wchar_t nextchar;
658*3b9cdfa3SAntonio Huete Jimenez
659*3b9cdfa3SAntonio Huete Jimenez (void)memset(&state, 0, sizeof(state));
660*3b9cdfa3SAntonio Huete Jimenez n = strlen(s);
661327e51cbSPeter Avalos
662327e51cbSPeter Avalos while (n > 0) {
663327e51cbSPeter Avalos bytesconsumed = mbrtowc(&nextchar, s, n, &state);
6646fca56fbSSascha Wildner if (bytesconsumed == CAST(size_t, -1) ||
6656fca56fbSSascha Wildner bytesconsumed == CAST(size_t, -2)) {
666*3b9cdfa3SAntonio Huete Jimenez nextchar = *s;
667*3b9cdfa3SAntonio Huete Jimenez bytesconsumed = 1;
668*3b9cdfa3SAntonio Huete Jimenez (void)memset(&state, 0, sizeof(state));
669*3b9cdfa3SAntonio Huete Jimenez width += 4;
670e8af9738SPeter Avalos } else {
671e8af9738SPeter Avalos int w = wcwidth(nextchar);
672*3b9cdfa3SAntonio Huete Jimenez width += ((ms->flags & MAGIC_RAW) != 0
673*3b9cdfa3SAntonio Huete Jimenez || iswprint(nextchar)) ? (w > 0 ? w : 1) : 4;
674e8af9738SPeter Avalos }
675327e51cbSPeter Avalos
676327e51cbSPeter Avalos s += bytesconsumed, n -= bytesconsumed;
677327e51cbSPeter Avalos }
678327e51cbSPeter Avalos #else
679*3b9cdfa3SAntonio Huete Jimenez for (; *s; s++) {
680*3b9cdfa3SAntonio Huete Jimenez width += (ms->flags & MAGIC_RAW) != 0
681*3b9cdfa3SAntonio Huete Jimenez || isprint(CAST(unsigned char, *s)) ? 1 : 4;
682*3b9cdfa3SAntonio Huete Jimenez }
683327e51cbSPeter Avalos #endif
684*3b9cdfa3SAntonio Huete Jimenez return width;
685327e51cbSPeter Avalos }
686327e51cbSPeter Avalos
687327e51cbSPeter Avalos private void
usage(void)688327e51cbSPeter Avalos usage(void)
689327e51cbSPeter Avalos {
6906fca56fbSSascha Wildner const char *pn = file_getprogname();
6916fca56fbSSascha Wildner (void)fprintf(stderr, USAGE, pn, pn, pn);
6926fca56fbSSascha Wildner exit(EXIT_FAILURE);
693327e51cbSPeter Avalos }
694327e51cbSPeter Avalos
695327e51cbSPeter Avalos private void
defprint(int def)696c30bd091SSascha Wildner defprint(int def)
697c30bd091SSascha Wildner {
698c30bd091SSascha Wildner if (!def)
699c30bd091SSascha Wildner return;
700c30bd091SSascha Wildner if (((def & 1) && posixly) || ((def & 2) && !posixly))
701c30bd091SSascha Wildner fprintf(stdout, " (default)");
702c30bd091SSascha Wildner fputc('\n', stdout);
703c30bd091SSascha Wildner }
704c30bd091SSascha Wildner
705c30bd091SSascha Wildner private void
docprint(const char * opts,int def)706c30bd091SSascha Wildner docprint(const char *opts, int def)
707e8af9738SPeter Avalos {
708e8af9738SPeter Avalos size_t i;
709c990e5baSDaniel Fojt int comma, pad;
710e8af9738SPeter Avalos char *sp, *p;
711e8af9738SPeter Avalos
712*3b9cdfa3SAntonio Huete Jimenez p = CCAST(char *, strchr(opts, '%'));
713e8af9738SPeter Avalos if (p == NULL) {
714e8af9738SPeter Avalos fprintf(stdout, "%s", opts);
715c30bd091SSascha Wildner defprint(def);
716e8af9738SPeter Avalos return;
717e8af9738SPeter Avalos }
718e8af9738SPeter Avalos
719e8af9738SPeter Avalos for (sp = p - 1; sp > opts && *sp == ' '; sp--)
720e8af9738SPeter Avalos continue;
721e8af9738SPeter Avalos
7226fca56fbSSascha Wildner fprintf(stdout, "%.*s", CAST(int, p - opts), opts);
723c990e5baSDaniel Fojt pad = (int)CAST(int, p - sp - 1);
724e8af9738SPeter Avalos
725c990e5baSDaniel Fojt switch (*++p) {
726c990e5baSDaniel Fojt case 'e':
727e8af9738SPeter Avalos comma = 0;
728e8af9738SPeter Avalos for (i = 0; i < __arraycount(nv); i++) {
729e8af9738SPeter Avalos fprintf(stdout, "%s%s", comma++ ? ", " : "", nv[i].name);
7306fca56fbSSascha Wildner if (i && i % 5 == 0 && i != __arraycount(nv) - 1) {
731c990e5baSDaniel Fojt fprintf(stdout, ",\n%*s", pad, "");
732e8af9738SPeter Avalos comma = 0;
733e8af9738SPeter Avalos }
734e8af9738SPeter Avalos }
735c990e5baSDaniel Fojt break;
736c990e5baSDaniel Fojt case 'P':
737c990e5baSDaniel Fojt for (i = 0; i < __arraycount(pm); i++) {
738c990e5baSDaniel Fojt fprintf(stdout, "%9s %7zu %s", pm[i].name, pm[i].def,
739c990e5baSDaniel Fojt pm[i].desc);
740c990e5baSDaniel Fojt if (i != __arraycount(pm) - 1)
741c990e5baSDaniel Fojt fprintf(stdout, "\n%*s", pad, "");
742c990e5baSDaniel Fojt }
743c990e5baSDaniel Fojt break;
744c990e5baSDaniel Fojt default:
745c990e5baSDaniel Fojt file_errx(EXIT_FAILURE, "Unknown escape `%c' in long options",
746c990e5baSDaniel Fojt *p);
747c990e5baSDaniel Fojt break;
748c990e5baSDaniel Fojt }
749c990e5baSDaniel Fojt fprintf(stdout, "%s", opts + (p - opts) + 1);
750e8af9738SPeter Avalos
751e8af9738SPeter Avalos }
752e8af9738SPeter Avalos
753e8af9738SPeter Avalos private void
help(void)754327e51cbSPeter Avalos help(void)
755327e51cbSPeter Avalos {
756327e51cbSPeter Avalos (void)fputs(
757327e51cbSPeter Avalos "Usage: file [OPTION...] [FILE...]\n"
758327e51cbSPeter Avalos "Determine type of FILEs.\n"
759ff91a668SPeter Avalos "\n", stdout);
760c30bd091SSascha Wildner #define OPT(shortname, longname, opt, def, doc) \
761e8af9738SPeter Avalos fprintf(stdout, " -%c, --" longname, shortname), \
762c30bd091SSascha Wildner docprint(doc, def);
763c30bd091SSascha Wildner #define OPT_LONGONLY(longname, opt, def, doc, id) \
764e8af9738SPeter Avalos fprintf(stdout, " --" longname), \
765c30bd091SSascha Wildner docprint(doc, def);
766327e51cbSPeter Avalos #include "file_opts.h"
767327e51cbSPeter Avalos #undef OPT
768327e51cbSPeter Avalos #undef OPT_LONGONLY
7696fca56fbSSascha Wildner fprintf(stdout, "\nReport bugs to https://bugs.astron.com/\n");
7706fca56fbSSascha Wildner exit(EXIT_SUCCESS);
7716fca56fbSSascha Wildner }
7726fca56fbSSascha Wildner
7736fca56fbSSascha Wildner private const char *file_progname;
7746fca56fbSSascha Wildner
7756fca56fbSSascha Wildner protected void
file_setprogname(const char * progname)7766fca56fbSSascha Wildner file_setprogname(const char *progname)
7776fca56fbSSascha Wildner {
7786fca56fbSSascha Wildner file_progname = progname;
7796fca56fbSSascha Wildner }
7806fca56fbSSascha Wildner
7816fca56fbSSascha Wildner protected const char *
file_getprogname(void)7826fca56fbSSascha Wildner file_getprogname(void)
7836fca56fbSSascha Wildner {
7846fca56fbSSascha Wildner return file_progname;
7856fca56fbSSascha Wildner }
7866fca56fbSSascha Wildner
7876fca56fbSSascha Wildner protected void
file_err(int e,const char * fmt,...)7886fca56fbSSascha Wildner file_err(int e, const char *fmt, ...)
7896fca56fbSSascha Wildner {
7906fca56fbSSascha Wildner va_list ap;
7916fca56fbSSascha Wildner int se = errno;
7926fca56fbSSascha Wildner
7936fca56fbSSascha Wildner va_start(ap, fmt);
7946fca56fbSSascha Wildner fprintf(stderr, "%s: ", file_progname);
7956fca56fbSSascha Wildner vfprintf(stderr, fmt, ap);
7966fca56fbSSascha Wildner va_end(ap);
797c990e5baSDaniel Fojt if (se)
7986fca56fbSSascha Wildner fprintf(stderr, " (%s)\n", strerror(se));
799c990e5baSDaniel Fojt else
800c990e5baSDaniel Fojt fputc('\n', stderr);
8016fca56fbSSascha Wildner exit(e);
8026fca56fbSSascha Wildner }
8036fca56fbSSascha Wildner
8046fca56fbSSascha Wildner protected void
file_errx(int e,const char * fmt,...)8056fca56fbSSascha Wildner file_errx(int e, const char *fmt, ...)
8066fca56fbSSascha Wildner {
8076fca56fbSSascha Wildner va_list ap;
8086fca56fbSSascha Wildner
8096fca56fbSSascha Wildner va_start(ap, fmt);
8106fca56fbSSascha Wildner fprintf(stderr, "%s: ", file_progname);
8116fca56fbSSascha Wildner vfprintf(stderr, fmt, ap);
8126fca56fbSSascha Wildner va_end(ap);
8136fca56fbSSascha Wildner fprintf(stderr, "\n");
8146fca56fbSSascha Wildner exit(e);
8156fca56fbSSascha Wildner }
8166fca56fbSSascha Wildner
8176fca56fbSSascha Wildner protected void
file_warn(const char * fmt,...)8186fca56fbSSascha Wildner file_warn(const char *fmt, ...)
8196fca56fbSSascha Wildner {
8206fca56fbSSascha Wildner va_list ap;
8216fca56fbSSascha Wildner int se = errno;
8226fca56fbSSascha Wildner
8236fca56fbSSascha Wildner va_start(ap, fmt);
8246fca56fbSSascha Wildner fprintf(stderr, "%s: ", file_progname);
8256fca56fbSSascha Wildner vfprintf(stderr, fmt, ap);
8266fca56fbSSascha Wildner va_end(ap);
827c990e5baSDaniel Fojt if (se)
8286fca56fbSSascha Wildner fprintf(stderr, " (%s)\n", strerror(se));
829c990e5baSDaniel Fojt else
830c990e5baSDaniel Fojt fputc('\n', stderr);
8316fca56fbSSascha Wildner errno = se;
8326fca56fbSSascha Wildner }
8336fca56fbSSascha Wildner
8346fca56fbSSascha Wildner protected void
file_warnx(const char * fmt,...)8356fca56fbSSascha Wildner file_warnx(const char *fmt, ...)
8366fca56fbSSascha Wildner {
8376fca56fbSSascha Wildner va_list ap;
8386fca56fbSSascha Wildner int se = errno;
8396fca56fbSSascha Wildner
8406fca56fbSSascha Wildner va_start(ap, fmt);
8416fca56fbSSascha Wildner fprintf(stderr, "%s: ", file_progname);
8426fca56fbSSascha Wildner vfprintf(stderr, fmt, ap);
8436fca56fbSSascha Wildner va_end(ap);
8446fca56fbSSascha Wildner fprintf(stderr, "\n");
8456fca56fbSSascha Wildner errno = se;
846327e51cbSPeter Avalos }
847