Changeset View
Changeset View
Standalone View
Standalone View
contrib/file/src/file.c
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | "] [--apple] [--extension] [--mime-encoding] [--mime-type]\n" \ | ||||
" %s [--help]\n" | " %s [--help]\n" | ||||
private int /* Global command-line options */ | private int /* Global command-line options */ | ||||
bflag = 0, /* brief output format */ | bflag = 0, /* brief output format */ | ||||
nopad = 0, /* Don't pad output */ | nopad = 0, /* Don't pad output */ | ||||
nobuffer = 0, /* Do not buffer stdout */ | nobuffer = 0, /* Do not buffer stdout */ | ||||
nulsep = 0; /* Append '\0' to the separator */ | nulsep = 0; /* Append '\0' to the separator */ | ||||
#ifdef HAVE_CAPSICUM | |||||
private int *ifds = NULL; | |||||
private int fcnt = 0; | |||||
private char **fnames = NULL; | |||||
#endif | |||||
private const char *separator = ":"; /* Default field separator */ | private const char *separator = ":"; /* Default field separator */ | ||||
private const struct option long_options[] = { | private const struct option long_options[] = { | ||||
#define OPT_HELP 1 | #define OPT_HELP 1 | ||||
#define OPT_APPLE 2 | #define OPT_APPLE 2 | ||||
#define OPT_EXTENSIONS 3 | #define OPT_EXTENSIONS 3 | ||||
#define OPT_MIME_TYPE 4 | #define OPT_MIME_TYPE 4 | ||||
#define OPT_MIME_ENCODING 5 | #define OPT_MIME_ENCODING 5 | ||||
#define OPT(shortname, longname, opt, def, doc) \ | #define OPT(shortname, longname, opt, def, doc) \ | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
private void usage(void); | private void usage(void); | ||||
private void docprint(const char *, int); | private void docprint(const char *, int); | ||||
#ifdef __dead | #ifdef __dead | ||||
__dead | __dead | ||||
#endif | #endif | ||||
private void help(void); | private void help(void); | ||||
private int unwrap(struct magic_set *, const char *); | private int unwrap(struct magic_set * __unused, const char *, size_t *); | ||||
private int process(struct magic_set *ms, const char *, int); | private int process(struct magic_set *ms, const char *, int, int); | ||||
private struct magic_set *load(const char *, int); | private struct magic_set *load(const char *, int); | ||||
private void setparam(const char *); | private void setparam(const char *); | ||||
private void applyparam(magic_t); | private void applyparam(magic_t); | ||||
/* | /* | ||||
* main - parse arguments and handle options | * main - parse arguments and handle options | ||||
*/ | */ | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
int c; | int c; | ||||
size_t i; | size_t i, wid = 0; | ||||
int action = 0, didsomefiles = 0, errflg = 0; | int action = 0, didsomefiles = 0, errflg = 0; | ||||
int flags = 0, e = 0; | int flags = 0, e = 0; | ||||
struct magic_set *magic = NULL; | struct magic_set *magic = NULL; | ||||
int longindex; | int longindex; | ||||
const char *magicfile = NULL; /* where the magic is */ | const char *magicfile = NULL; /* where the magic is */ | ||||
#ifdef HAVE_CAPSICUM | |||||
cap_rights_t rights_ro; | |||||
#endif | |||||
/* makes islower etc work for other langs */ | /* makes islower etc work for other langs */ | ||||
#ifdef HAVE_SETLOCALE | #ifdef HAVE_SETLOCALE | ||||
(void)setlocale(LC_CTYPE, ""); | (void)setlocale(LC_CTYPE, ""); | ||||
#endif | #endif | ||||
#ifdef __EMX__ | #ifdef __EMX__ | ||||
/* sh-like wildcard expansion! Shouldn't hurt at least ... */ | /* sh-like wildcard expansion! Shouldn't hurt at least ... */ | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | case 'e': | ||||
errflg++; | errflg++; | ||||
else | else | ||||
flags |= nv[i].value; | flags |= nv[i].value; | ||||
break; | break; | ||||
case 'f': | case 'f': | ||||
if(action) | if(action) | ||||
usage(); | usage(); | ||||
#ifdef HAVE_CAPSICUM | |||||
e |= unwrap(NULL, optarg, &wid); | |||||
#else | |||||
if (magic == NULL) | if (magic == NULL) | ||||
if ((magic = load(magicfile, flags)) == NULL) | if ((magic = load(magicfile, flags)) == NULL) | ||||
return 1; | return 1; | ||||
applyparam(magic); | applyparam(magic); | ||||
e |= unwrap(magic, optarg); | e |= unwrap(magic, optarg, &wid); | ||||
#endif | |||||
++didsomefiles; | ++didsomefiles; | ||||
break; | break; | ||||
case 'F': | case 'F': | ||||
separator = optarg; | separator = optarg; | ||||
break; | break; | ||||
case 'i': | case 'i': | ||||
flags |= MAGIC_MIME; | flags |= MAGIC_MIME; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | if (magic == NULL) | ||||
if ((magic = load(magicfile, flags)) == NULL) | if ((magic = load(magicfile, flags)) == NULL) | ||||
return 1; | return 1; | ||||
applyparam(magic); | applyparam(magic); | ||||
} | } | ||||
if (optind == argc) { | if (optind == argc) { | ||||
if (!didsomefiles) | if (!didsomefiles) | ||||
usage(); | usage(); | ||||
#ifdef HAVE_CAPSICUM | |||||
if (cap_enter() < 0 && errno != ENOSYS) { | |||||
(void)fprintf(stderr, "%s: Error: failed to enter " | |||||
"sandbox\n", progname); | |||||
return 1; | |||||
} | } | ||||
/* Process file descriptions we opened earlier in unwrap_open */ | |||||
for (c = 0; c < fcnt; c++) { | |||||
e |= process(magic, fnames[c], wid, ifds[c]); | |||||
if(nobuffer) | |||||
(void)fflush(stdout); | |||||
} | |||||
#endif | |||||
} | |||||
else { | else { | ||||
size_t j, wid, nw; | size_t j, nw; | ||||
for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) { | for (j = (size_t)optind; j < (size_t)argc; j++) { | ||||
nw = file_mbswidth(argv[j]); | nw = file_mbswidth(argv[j]); | ||||
if (nw > wid) | if (nw > wid) | ||||
wid = nw; | wid = nw; | ||||
} | } | ||||
/* | /* | ||||
* If bflag is only set twice, set it depending on | * If bflag is only set twice, set it depending on | ||||
* number of files [this is undocumented, and subject to change] | * number of files [this is undocumented, and subject to change] | ||||
*/ | */ | ||||
if (bflag == 2) { | if (bflag == 2) { | ||||
bflag = optind >= argc - 1; | bflag = optind >= argc - 1; | ||||
} | } | ||||
for (; optind < argc; optind++) | |||||
e |= process(magic, argv[optind], wid); | #ifdef HAVE_CAPSICUM | ||||
cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); | |||||
ifds = realloc(ifds, sizeof(int) * (fcnt + argc)); | |||||
if (ifds == NULL) { | |||||
fprintf(stderr, "%s: failed to allocate memory: %s\n", | |||||
progname, strerror(errno)); | |||||
return 1; | |||||
} | } | ||||
for (c = optind; c < argc; c++) { | |||||
if (strcmp(argv[c], "-") == 0) { | |||||
ifds[c + fcnt] = STDIN_FILENO; | |||||
continue; | |||||
} | |||||
if ((ifds[c + fcnt] = open(argv[c], | |||||
O_RDONLY | O_BINARY)) == -1) | |||||
(void)fprintf(stderr, "%s: cannot open `%s': " | |||||
"%s\n", progname, argv[c], strerror(errno)); | |||||
if (cap_rights_limit(ifds[c + fcnt], &rights_ro) < 0 && | |||||
errno != ENOSYS) { | |||||
(void)fprintf(stderr, "%s: cap_rights_limit() " | |||||
"failed, could not restrict capabilities\n", | |||||
progname); | |||||
return 1; | |||||
} | |||||
} | |||||
if (cap_enter() < 0 && errno != ENOSYS) { | |||||
(void)fprintf(stderr, "%s: Error: failed to enter " | |||||
"sandbox\n", progname); | |||||
return 1; | |||||
} | |||||
/* Process file descriptions we opened earlier in unwrap_open */ | |||||
for (c = 0; c < fcnt; c++) { | |||||
e |= process(magic, fnames[c], wid, ifds[c]); | |||||
if(nobuffer) | |||||
(void)fflush(stdout); | |||||
} | |||||
/* Process files listed on the command line */ | |||||
for (; optind < argc; optind++) { | |||||
e |= process(magic, argv[optind], wid, | |||||
ifds[optind + fcnt]); | |||||
if(nobuffer) | |||||
(void)fflush(stdout); | |||||
} | |||||
#else | |||||
for (; optind < argc; optind++) { | |||||
e |= process(magic, argv[optind], wid, -1); | |||||
if(nobuffer) | |||||
(void)fflush(stdout); | |||||
} | |||||
#endif | |||||
} | |||||
out: | out: | ||||
#ifdef HAVE_CAPSICUM | |||||
if (ifds != NULL) | |||||
free(ifds); | |||||
if (fnames != NULL) { | |||||
for (c = 0; c < fcnt; c++) | |||||
if (fnames[c] != NULL) | |||||
free(fnames[c]); | |||||
free(fnames); | |||||
} | |||||
#endif | |||||
if (magic) | if (magic) | ||||
magic_close(magic); | magic_close(magic); | ||||
return e; | return e; | ||||
} | } | ||||
private void | private void | ||||
applyparam(magic_t magic) | applyparam(magic_t magic) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | load(const char *magicfile, int flags) | ||||
} | } | ||||
return magic; | return magic; | ||||
} | } | ||||
/* | /* | ||||
* unwrap -- read a file of filenames, do each one. | * unwrap -- read a file of filenames, do each one. | ||||
*/ | */ | ||||
private int | private int | ||||
unwrap(struct magic_set *ms, const char *fn) | unwrap(struct magic_set *ms __unused, const char *fn, size_t *wid) | ||||
{ | { | ||||
FILE *f; | FILE *f; | ||||
ssize_t len; | ssize_t len; | ||||
char *line = NULL; | char *line = NULL; | ||||
size_t llen = 0; | size_t llen = 0, cwid, linecnt = 0; | ||||
int wid = 0, cwid; | |||||
int e = 0; | int e = 0; | ||||
#ifdef HAVE_CAPSICUM | |||||
cap_rights_t rights_ro; | |||||
cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); | |||||
#endif | |||||
if (strcmp("-", fn) == 0) { | if (strcmp("-", fn) == 0) { | ||||
f = stdin; | f = stdin; | ||||
wid = 1; | *wid = 1; | ||||
} else { | } else { | ||||
if ((f = fopen(fn, "r")) == NULL) { | if ((f = fopen(fn, "r")) == NULL) { | ||||
(void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", | (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", | ||||
progname, fn, strerror(errno)); | progname, fn, strerror(errno)); | ||||
return 1; | return 1; | ||||
} | } | ||||
while ((len = getline(&line, &llen, f)) > 0) { | while ((len = getline(&line, &llen, f)) > 0) { | ||||
if (line[len - 1] == '\n') | if (line[len - 1] == '\n') | ||||
line[len - 1] = '\0'; | line[len - 1] = '\0'; | ||||
cwid = file_mbswidth(line); | cwid = file_mbswidth(line); | ||||
if (cwid > wid) | if (cwid > *wid) | ||||
wid = cwid; | *wid = cwid; | ||||
linecnt++; | |||||
} | } | ||||
rewind(f); | rewind(f); | ||||
} | } | ||||
#ifdef HAVE_CAPSICUM | |||||
ifds = realloc(ifds, sizeof(int) * (fcnt + linecnt)); | |||||
fnames = realloc(fnames, sizeof(char *) * (fcnt + linecnt)); | |||||
if (ifds == NULL || fnames == NULL) { | |||||
(void)fprintf(stderr, "%s: failed to allocate memory: %s\n", | |||||
progname, strerror(errno)); | |||||
exit(1); | |||||
} | |||||
#endif | |||||
while ((len = getline(&line, &llen, f)) > 0) { | while ((len = getline(&line, &llen, f)) > 0) { | ||||
if (line[len - 1] == '\n') | if (line[len - 1] == '\n') | ||||
line[len - 1] = '\0'; | line[len - 1] = '\0'; | ||||
e |= process(ms, line, wid); | #ifdef HAVE_CAPSICUM | ||||
if (strcmp(line, "-") == 0) { | |||||
ifds[fcnt] = STDIN_FILENO; | |||||
} else if ((ifds[fcnt] = open(line, O_RDONLY)) == -1) { | |||||
(void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", | |||||
progname, line, strerror(errno)); | |||||
e = 1; | |||||
break; | |||||
} | |||||
if ((fnames[fcnt] = strdup(line)) == NULL) { | |||||
(void)fprintf(stderr, "%s: failed to allocate memory: " | |||||
"%s\n", progname, strerror(errno)); | |||||
exit(1); | |||||
} | |||||
if (cap_rights_limit(ifds[fcnt], &rights_ro) < 0 && | |||||
errno != ENOSYS) { | |||||
(void)fprintf(stderr, "%s: cap_rights_limit() " | |||||
"failed, could not restrict capabilities\n", | |||||
progname); | |||||
exit(1); | |||||
} | |||||
fcnt++; | |||||
#else | |||||
e |= process(ms, line, wid, -1); | |||||
if(nobuffer) | if(nobuffer) | ||||
(void)fflush(stdout); | (void)fflush(stdout); | ||||
#endif | |||||
} | } | ||||
free(line); | free(line); | ||||
(void)fclose(f); | (void)fclose(f); | ||||
return e; | return e; | ||||
} | } | ||||
/* | /* | ||||
* Called for each input file on the command line (or in a list of files) | * Called for each input file on the command line (or in a list of files) | ||||
*/ | */ | ||||
private int | private int | ||||
process(struct magic_set *ms, const char *inname, int wid) | process(struct magic_set *ms, const char *inname, int wid, int ifd) | ||||
{ | { | ||||
const char *type, c = nulsep > 1 ? '\0' : '\n'; | const char *type, c = nulsep > 1 ? '\0' : '\n'; | ||||
int std_in = strcmp(inname, "-") == 0; | |||||
if (ifd == -1 && strcmp(inname, "-") == 0) | |||||
ifd = STDIN_FILENO; | |||||
if (wid > 0 && !bflag) { | if (wid > 0 && !bflag) { | ||||
(void)printf("%s", std_in ? "/dev/stdin" : inname); | (void)printf("%s", ifd == STDIN_FILENO ? "/dev/stdin" : inname); | ||||
if (nulsep) | if (nulsep) | ||||
(void)putc('\0', stdout); | (void)putc('\0', stdout); | ||||
if (nulsep < 2) { | if (nulsep < 2) { | ||||
(void)printf("%s", separator); | (void)printf("%s", separator); | ||||
(void)printf("%*s ", | (void)printf("%*s ", | ||||
(int) (nopad ? 0 : (wid - file_mbswidth(inname))), | (int) (nopad ? 0 : (wid - file_mbswidth(inname))), | ||||
""); | ""); | ||||
} | } | ||||
} | } | ||||
type = magic_file(ms, std_in ? NULL : inname); | type = magic_file(ms, ifd == STDIN_FILENO ? NULL : inname, ifd); | ||||
if (ifd > 0) | |||||
close(ifd); | |||||
if (type == NULL) { | if (type == NULL) { | ||||
(void)printf("ERROR: %s%c", magic_error(ms), c); | (void)printf("ERROR: %s%c", magic_error(ms), c); | ||||
return 1; | return 1; | ||||
} else { | } else { | ||||
(void)printf("%s%c", type, c); | (void)printf("%s%c", type, c); | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 106 Lines • Show Last 20 Lines |