forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
824 lines
18 KiB
824 lines
18 KiB
/* $Id: hsum.c 243 2010-06-21 17:13:32Z tp $ */ |
|
/* |
|
* Command-line utility to compute hash functions over files. This is |
|
* intended to work similarly to the usual "md5sum" utility, but for |
|
* all hash functions implemented by sphlib. |
|
* |
|
* Usage is the following: |
|
* <pre> |
|
* sphsum function [ options ] [ file... ] |
|
* </pre> |
|
* where <code>function</code> is the hash function name (short internal |
|
* name, such as <code>md5</code> or <code>whirlpool0</code>). Options |
|
* specify whether the file must be read as text or binary (it makes no |
|
* difference on Unix systems); moreover, with the <code>"-c"</code> option, |
|
* a list of checksums can be verified. If no file name is specified, then |
|
* standard input is used; the special file name <code>"-"</code> (a single |
|
* minus sign) is also an alias for standard input. |
|
* |
|
* Alternatively, the executable binary may be named after the hash |
|
* function itself. In that situation, the <code>function</code> parameter |
|
* must be omitted. For function name recognition, suffixes <code>".exe"</code> |
|
* and <code>"sum"</code> are suppressed; thus, the executable may be named |
|
* <code>"md5sum"</code> or <code>"md5sum.exe"</code>, and will then behave |
|
* as the standard Linux utility <code>"md5sum"</code>. |
|
* |
|
* ==========================(LICENSE BEGIN)============================ |
|
* |
|
* Copyright (c) 2007-2010 Projet RNRT SAPHIR |
|
* |
|
* Permission is hereby granted, free of charge, to any person obtaining |
|
* a copy of this software and associated documentation files (the |
|
* "Software"), to deal in the Software without restriction, including |
|
* without limitation the rights to use, copy, modify, merge, publish, |
|
* distribute, sublicense, and/or sell copies of the Software, and to |
|
* permit persons to whom the Software is furnished to do so, subject to |
|
* the following conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be |
|
* included in all copies or substantial portions of the Software. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
* |
|
* ===========================(LICENSE END)============================= |
|
* |
|
* @author Thomas Pornin <[email protected]> |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
|
|
#include "sph_blake.h" |
|
#include "sph_bmw.h" |
|
#include "sph_cubehash.h" |
|
#include "sph_echo.h" |
|
#include "sph_fugue.h" |
|
#include "sph_groestl.h" |
|
#include "sph_hamsi.h" |
|
#include "sph_haval.h" |
|
#include "sph_jh.h" |
|
#include "sph_keccak.h" |
|
#include "sph_luffa.h" |
|
#include "sph_md2.h" |
|
#include "sph_md4.h" |
|
#include "sph_md5.h" |
|
#include "sph_panama.h" |
|
#include "sph_radiogatun.h" |
|
#include "sph_ripemd.h" |
|
#include "sph_sha0.h" |
|
#include "sph_sha1.h" |
|
#include "sph_sha2.h" |
|
#include "sph_shabal.h" |
|
#include "sph_shavite.h" |
|
#include "sph_simd.h" |
|
#include "sph_skein.h" |
|
#include "sph_tiger.h" |
|
#include "sph_whirlpool.h" |
|
|
|
/** |
|
* The program name, as extracted from the invocation name. |
|
*/ |
|
static char *program_name; |
|
|
|
/** |
|
* Extract the program name from the invocation name. |
|
* |
|
* @param fullname the invocation name |
|
*/ |
|
static void |
|
make_program_name(char *fullname) |
|
{ |
|
char *c, *d; |
|
|
|
if (fullname == NULL) { |
|
program_name = "hsum"; |
|
return; |
|
} |
|
for (c = d = fullname; *d != 0; d ++) |
|
if (*d == '/' || *d == '\\') |
|
c = d + 1; |
|
program_name = c; |
|
} |
|
|
|
/** |
|
* Print out usage and exit. |
|
* |
|
* @param genf non-zero if generic executable |
|
* @param fail non-zero to exit with a failure status |
|
*/ |
|
static void |
|
usage(int genf, int fail) |
|
{ |
|
fprintf(stderr, |
|
"usage: %s%s [options] [file...]\n" |
|
"options:\n" |
|
" -b, --binary\n" |
|
" read in binary mode\n" |
|
" -c, --check\n" |
|
" read sums from the files and check them\n" |
|
" -t, --text\n" |
|
" read in text mode (default)\n" |
|
" --status\n" |
|
" output is discarded; success or failure is shown by the exit code\n" |
|
" -w, --warn\n" |
|
" warn about improperly formatted checksum lines (which are ignored)\n" |
|
" -h, --help\n" |
|
" display this help and exit\n" |
|
" -v, --version\n" |
|
" display version information and exit\n", |
|
program_name, genf ? " function" : ""); |
|
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS); |
|
} |
|
|
|
/** |
|
* Print out version information and exit with a success status. |
|
*/ |
|
static void |
|
version(void) |
|
{ |
|
fprintf(stderr, |
|
"sphlib: version 2.1\n" |
|
"Copyright (c) 2007-2010 Projet RNRT SAPHIR\n" |
|
"This software is provided WITHOUT ANY WARRANTY, to the extent\n" |
|
"permitted by law.\n"); |
|
exit(EXIT_SUCCESS); |
|
} |
|
|
|
#define MAKECC(name) sph_ ## name ## _context cc_ ## name |
|
|
|
/** |
|
* The hash function context is static; this union ensures that we have |
|
* a properly sized and aligned context for all functions (but not |
|
* simultaneously, of course). |
|
*/ |
|
static union { |
|
MAKECC(blake224); |
|
MAKECC(blake256); |
|
#if SPH_64 |
|
MAKECC(blake384); |
|
MAKECC(blake512); |
|
#endif |
|
MAKECC(bmw224); |
|
MAKECC(bmw256); |
|
#if SPH_64 |
|
MAKECC(bmw384); |
|
MAKECC(bmw512); |
|
#endif |
|
MAKECC(cubehash224); |
|
MAKECC(cubehash256); |
|
MAKECC(cubehash384); |
|
MAKECC(cubehash512); |
|
MAKECC(echo224); |
|
MAKECC(echo256); |
|
MAKECC(echo384); |
|
MAKECC(echo512); |
|
MAKECC(fugue224); |
|
MAKECC(fugue256); |
|
MAKECC(fugue384); |
|
MAKECC(fugue512); |
|
MAKECC(groestl224); |
|
MAKECC(groestl256); |
|
MAKECC(groestl384); |
|
MAKECC(groestl512); |
|
MAKECC(hamsi224); |
|
MAKECC(hamsi256); |
|
MAKECC(hamsi384); |
|
MAKECC(hamsi512); |
|
MAKECC(haval128_3); |
|
MAKECC(haval128_4); |
|
MAKECC(haval128_5); |
|
MAKECC(haval160_3); |
|
MAKECC(haval160_4); |
|
MAKECC(haval160_5); |
|
MAKECC(haval192_3); |
|
MAKECC(haval192_4); |
|
MAKECC(haval192_5); |
|
MAKECC(haval224_3); |
|
MAKECC(haval224_4); |
|
MAKECC(haval224_5); |
|
MAKECC(haval256_3); |
|
MAKECC(haval256_4); |
|
MAKECC(haval256_5); |
|
MAKECC(jh224); |
|
MAKECC(jh256); |
|
MAKECC(jh384); |
|
MAKECC(jh512); |
|
MAKECC(keccak224); |
|
MAKECC(keccak256); |
|
MAKECC(keccak384); |
|
MAKECC(keccak512); |
|
MAKECC(luffa224); |
|
MAKECC(luffa256); |
|
MAKECC(luffa384); |
|
MAKECC(luffa512); |
|
MAKECC(md2); |
|
MAKECC(md4); |
|
MAKECC(md5); |
|
MAKECC(panama); |
|
MAKECC(radiogatun32); |
|
#if SPH_64 |
|
MAKECC(radiogatun64); |
|
#endif |
|
MAKECC(ripemd128); |
|
MAKECC(ripemd160); |
|
MAKECC(ripemd); |
|
MAKECC(sha0); |
|
MAKECC(sha1); |
|
MAKECC(sha224); |
|
MAKECC(sha256); |
|
#if SPH_64 |
|
MAKECC(sha384); |
|
MAKECC(sha512); |
|
#endif |
|
MAKECC(shabal224); |
|
MAKECC(shabal256); |
|
MAKECC(shabal384); |
|
MAKECC(shabal512); |
|
MAKECC(shavite224); |
|
MAKECC(shavite256); |
|
MAKECC(shavite384); |
|
MAKECC(shavite512); |
|
MAKECC(simd224); |
|
MAKECC(simd256); |
|
MAKECC(simd384); |
|
MAKECC(simd512); |
|
#if SPH_64 |
|
MAKECC(skein224); |
|
MAKECC(skein256); |
|
MAKECC(skein384); |
|
MAKECC(skein512); |
|
#endif |
|
MAKECC(tiger2); |
|
MAKECC(tiger); |
|
MAKECC(whirlpool0); |
|
MAKECC(whirlpool1); |
|
MAKECC(whirlpool); |
|
} hcontext; |
|
|
|
/** |
|
* File data will come through this buffer. Using the union ensures |
|
* proper alignment. Eight kilobytes are used for the buffer: this |
|
* should be enough to get near-optimal speed. |
|
*/ |
|
static union { |
|
unsigned char buf[8192]; |
|
long l; |
|
void *p; |
|
sph_u32 w32; |
|
#if SPH_64 |
|
sph_u64 w64; |
|
#endif |
|
} ubuf; |
|
|
|
#define MAKEFFGEN(id, name, len) { \ |
|
&sph_ ## id ## _init, &sph_ ## id, \ |
|
&sph_ ## id ## _close, #name, len \ |
|
} |
|
|
|
#define MAKEFF(id) MAKEFFGEN(id, id, SPH_SIZE_ ## id / 8) |
|
|
|
/** |
|
* This array contains the callbacks to the hash function implementation. |
|
*/ |
|
static struct known_function { |
|
void (*ff_init)(void *cc); |
|
void (*ff_update)(void *cc, const void *data, size_t len); |
|
void (*ff_close)(void *cc, void *dst); |
|
char *name; |
|
size_t out_len; |
|
} known_functions[] = { |
|
MAKEFF(blake224), |
|
MAKEFF(blake256), |
|
#if SPH_64 |
|
MAKEFF(blake384), |
|
MAKEFF(blake512), |
|
#endif |
|
MAKEFF(bmw224), |
|
MAKEFF(bmw256), |
|
#if SPH_64 |
|
MAKEFF(bmw384), |
|
MAKEFF(bmw512), |
|
#endif |
|
MAKEFF(cubehash224), |
|
MAKEFF(cubehash256), |
|
MAKEFF(cubehash384), |
|
MAKEFF(cubehash512), |
|
MAKEFF(echo224), |
|
MAKEFF(echo256), |
|
MAKEFF(echo384), |
|
MAKEFF(echo512), |
|
MAKEFF(fugue224), |
|
MAKEFF(fugue256), |
|
MAKEFF(fugue384), |
|
MAKEFF(fugue512), |
|
MAKEFF(groestl224), |
|
MAKEFF(groestl256), |
|
MAKEFF(groestl384), |
|
MAKEFF(groestl512), |
|
MAKEFF(hamsi224), |
|
MAKEFF(hamsi256), |
|
MAKEFF(hamsi384), |
|
MAKEFF(hamsi512), |
|
MAKEFF(haval128_3), |
|
MAKEFF(haval128_4), |
|
MAKEFF(haval128_5), |
|
MAKEFF(haval160_3), |
|
MAKEFF(haval160_4), |
|
MAKEFF(haval160_5), |
|
MAKEFF(haval192_3), |
|
MAKEFF(haval192_4), |
|
MAKEFF(haval192_5), |
|
MAKEFF(haval224_3), |
|
MAKEFF(haval224_4), |
|
MAKEFF(haval224_5), |
|
MAKEFF(haval256_3), |
|
MAKEFF(haval256_4), |
|
MAKEFF(haval256_5), |
|
MAKEFF(jh224), |
|
MAKEFF(jh256), |
|
MAKEFF(jh384), |
|
MAKEFF(jh512), |
|
MAKEFF(keccak224), |
|
MAKEFF(keccak256), |
|
MAKEFF(keccak384), |
|
MAKEFF(keccak512), |
|
MAKEFF(luffa224), |
|
MAKEFF(luffa256), |
|
MAKEFF(luffa384), |
|
MAKEFF(luffa512), |
|
MAKEFF(md2), |
|
MAKEFF(md4), |
|
MAKEFF(md5), |
|
MAKEFF(panama), |
|
MAKEFF(radiogatun32), |
|
#if SPH_64 |
|
MAKEFF(radiogatun64), |
|
#endif |
|
MAKEFF(ripemd128), |
|
MAKEFF(ripemd160), |
|
MAKEFF(ripemd), |
|
MAKEFFGEN(ripemd128, rmd128, 16), |
|
MAKEFFGEN(ripemd160, rmd160, 20), |
|
MAKEFFGEN(ripemd, rmd, 16), |
|
MAKEFF(sha0), |
|
MAKEFF(sha1), |
|
MAKEFF(sha224), |
|
MAKEFF(sha256), |
|
#if SPH_64 |
|
MAKEFF(sha384), |
|
MAKEFF(sha512), |
|
#endif |
|
MAKEFF(shabal224), |
|
MAKEFF(shabal256), |
|
MAKEFF(shabal384), |
|
MAKEFF(shabal512), |
|
MAKEFF(shavite224), |
|
MAKEFF(shavite256), |
|
MAKEFF(shavite384), |
|
MAKEFF(shavite512), |
|
MAKEFF(simd224), |
|
MAKEFF(simd256), |
|
MAKEFF(simd384), |
|
MAKEFF(simd512), |
|
#if SPH_64 |
|
MAKEFF(skein224), |
|
MAKEFF(skein256), |
|
MAKEFF(skein384), |
|
MAKEFF(skein512), |
|
#endif |
|
MAKEFF(tiger2), |
|
MAKEFF(tiger), |
|
MAKEFF(whirlpool0), |
|
MAKEFF(whirlpool1), |
|
MAKEFF(whirlpool), |
|
|
|
{ 0, 0, 0, 0, 0 } |
|
}; |
|
|
|
/** |
|
* Compare two strings, case insensitive. Note: this function assumes |
|
* an architecture which operates with an ASCII-compatible charset. |
|
* |
|
* @param s1 the first string |
|
* @param s2 the second string |
|
* @return non-zero on string equality |
|
*/ |
|
static int |
|
equals_string_nocase(char *s1, char *s2) |
|
{ |
|
while (*s1 || *s2) { |
|
int c1, c2; |
|
|
|
c1 = *s1 ++; |
|
c2 = *s2 ++; |
|
if (c1 >= 'A' && c1 <= 'Z') |
|
c1 += 'a' - 'A'; |
|
if (c2 >= 'A' && c2 <= 'Z') |
|
c2 += 'a' - 'A'; |
|
if (c1 != c2) |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
/** |
|
* Recognize the function name. |
|
* |
|
* @param name the name to match |
|
* @return the function index, of -1 |
|
*/ |
|
static int |
|
get_function_name(char *name) |
|
{ |
|
int i; |
|
size_t u, v, w, len; |
|
char name_ext[30]; |
|
|
|
len = strlen(name); |
|
v = 0; |
|
for (u = 0; u < len; u ++) |
|
if (name[u] == '/' || name[u] == '\\') |
|
v = u + 1; |
|
w = len; |
|
if (w > (v + 4) && equals_string_nocase(name + (w - 4), ".exe")) |
|
w -= 3; |
|
if (w > (v + 3) && equals_string_nocase(name + (w - 3), "sum")) |
|
w -= 3; |
|
if ((w - v) >= sizeof name_ext) |
|
return -1; |
|
memcpy(name_ext, name + v, w - v); |
|
name_ext[w - v] = 0; |
|
for (i = 0; known_functions[i].name != NULL; i ++) |
|
if (equals_string_nocase(name_ext, known_functions[i].name)) |
|
return i; |
|
return -1; |
|
} |
|
|
|
/* |
|
* Static state: options, counts for computations and failures, and |
|
* the function to use. |
|
*/ |
|
|
|
static int function_id, binary, check, nostatus, nowarn; |
|
static int has_failed; |
|
static long mismatch_count, computed_count; |
|
static struct known_function kf; |
|
|
|
/** |
|
* Print out a file hash. |
|
* |
|
* @param buf the hash output |
|
* @param len the hash output length |
|
* @param fname the hashed file name |
|
*/ |
|
static void |
|
print_hash(unsigned char *buf, size_t len, char *fname) |
|
{ |
|
while (len -- > 0) |
|
printf("%02x", (unsigned)*buf ++); |
|
printf(" %s%s\n", binary ? "*" : " ", fname); |
|
} |
|
|
|
/** |
|
* Print out the file status (when checking). A <code>NULL</code> file name |
|
* means "standard input". |
|
* |
|
* @param fname the file name (may be <code>NULL</code>) |
|
* @param ok zero for a failure |
|
*/ |
|
static void |
|
print_status(char *fname, int ok) |
|
{ |
|
if (nostatus) |
|
return; |
|
if (fname == NULL) |
|
fname = "-"; |
|
printf("%s: %s\n", fname, ok ? "OK" : "FAILED"); |
|
} |
|
|
|
/** |
|
* Hash some data |
|
* |
|
* @param in the data input stream |
|
* @param fname the file name (for error reporting), or <code>NULL</code> |
|
* @param dst the output buffer for the hash result |
|
* @return 0 on success, -1 on error (I/O error) |
|
*/ |
|
static int |
|
hash_file(FILE *in, char *fname, void *dst) |
|
{ |
|
for (;;) { |
|
size_t len; |
|
|
|
len = fread(ubuf.buf, 1, sizeof ubuf.buf, in); |
|
kf.ff_update(&hcontext, ubuf.buf, len); |
|
if (len < sizeof ubuf.buf) |
|
break; |
|
} |
|
if (ferror(in)) { |
|
fprintf(stderr, "%s: %s: ", program_name, |
|
fname == NULL ? "<stdin>" : fname); |
|
perror("fread"); |
|
return -1; |
|
} |
|
kf.ff_close(&hcontext, dst); |
|
return 0; |
|
} |
|
|
|
/** |
|
* Get the numerical value of an hexadecimal digit. |
|
* |
|
* @param c the character value |
|
* @return the numerical value, or -1 on error |
|
*/ |
|
static int |
|
hexnum(int c) |
|
{ |
|
if (c >= '0' && c <= '9') |
|
return c - '0'; |
|
switch (c) { |
|
case 'a': case 'A': return 10; |
|
case 'b': case 'B': return 11; |
|
case 'c': case 'C': return 12; |
|
case 'd': case 'D': return 13; |
|
case 'e': case 'E': return 14; |
|
case 'f': case 'F': return 15; |
|
} |
|
return -1; |
|
} |
|
|
|
/** |
|
* Parse a line from a checksum file. The terminating newline must have |
|
* been removed from the line. |
|
* |
|
* @param line the read line |
|
* @param line_num the file line number (for error reporting) |
|
* @param out the output buffer for the expected hash result |
|
* @param rbin set to 1 if the "binary" flag is set in the line |
|
* @return pointer to the file name (within the line), or <code>NULL</code> |
|
*/ |
|
static char * |
|
parse_line(char *line, long line_num, unsigned char *out, int *rbin) |
|
{ |
|
char *c; |
|
size_t u; |
|
|
|
for (c = line; *c == ' ' || *c == '\t'; c ++); |
|
for (u = 0; u < kf.out_len; u ++) { |
|
int z1, z2; |
|
|
|
z1 = hexnum(*c ++); |
|
if (z1 < 0) |
|
goto error; |
|
z2 = hexnum(*c ++); |
|
if (z2 < 0) |
|
goto error; |
|
out[u] = (z1 << 4) | z2; |
|
} |
|
if (*c ++ != ' ') |
|
goto error; |
|
switch (*c ++) { |
|
case ' ': |
|
*rbin = 0; |
|
break; |
|
case '*': |
|
*rbin = 1; |
|
break; |
|
default: |
|
goto error; |
|
} |
|
return c; |
|
|
|
error: |
|
if (!nowarn) |
|
fprintf(stderr, "%s: warning: improperly formatted" |
|
" checksum file line %ld, skipping.\n", |
|
program_name, line_num); |
|
return NULL; |
|
} |
|
|
|
/** |
|
* Process the provided file name. |
|
* |
|
* @param fname the file name (<code>NULL</code> for standard input) |
|
*/ |
|
static void |
|
process_file(char *fname) |
|
{ |
|
FILE *in; |
|
|
|
if (fname == NULL) { |
|
in = stdin; |
|
} else { |
|
in = fopen(fname, (binary && !check) ? "rb" : "r"); |
|
if (in == NULL) { |
|
fprintf(stderr, "%s: %s: ", program_name, fname); |
|
perror("fopen"); |
|
has_failed = 1; |
|
if (check) |
|
mismatch_count ++; |
|
return; |
|
} |
|
} |
|
if (check) { |
|
char line[4096]; |
|
long line_num; |
|
|
|
line_num = 0; |
|
while (fgets(line, sizeof line, in) != NULL) { |
|
size_t n; |
|
char *fname2; |
|
int rbin; |
|
FILE *in2; |
|
unsigned char buf[128]; |
|
unsigned char exp_res[128]; |
|
int good; |
|
|
|
line_num ++; |
|
n = strlen(line); |
|
if (n > 0 && line[n - 1] == '\n') |
|
line[-- n] = 0; |
|
if (n == 1 + sizeof line) { |
|
int quit; |
|
|
|
if (!nowarn) |
|
fprintf(stderr, "%s: warning: checksum" |
|
" file line %ld too long," |
|
" skipping.\n", |
|
program_name, line_num); |
|
quit = 0; |
|
for (;;) { |
|
if (fgets(line, |
|
sizeof line, in) == NULL) { |
|
quit = 1; |
|
break; |
|
} |
|
n = strlen(line); |
|
if (n > 0 && line[n - 1] == '\n') |
|
break; |
|
} |
|
if (quit) |
|
break; |
|
} |
|
fname2 = parse_line(line, line_num, exp_res, &rbin); |
|
if (fname2 == NULL) |
|
continue; |
|
if (strcmp(fname2, "-") == 0) { |
|
if (fname == NULL) { |
|
fprintf(stderr, "%s: error: stdin" |
|
" double use (checksum file" |
|
" line %ld), skipping.\n", |
|
program_name, line_num); |
|
has_failed = 1; |
|
mismatch_count ++; |
|
continue; |
|
} |
|
fname2 = NULL; |
|
in2 = stdin; |
|
} else { |
|
in2 = fopen(fname2, rbin ? "rb" : "r"); |
|
if (in2 == NULL) { |
|
fprintf(stderr, "%s: %s: ", |
|
program_name, fname2); |
|
perror("fopen"); |
|
has_failed = 1; |
|
mismatch_count ++; |
|
} |
|
} |
|
computed_count ++; |
|
if (hash_file(in2, fname2, buf) < 0) { |
|
has_failed = 1; |
|
mismatch_count ++; |
|
} else { |
|
good = (memcmp(buf, exp_res, kf.out_len) == 0); |
|
print_status(fname2, good); |
|
if (!good) { |
|
has_failed = 1; |
|
mismatch_count ++; |
|
} |
|
} |
|
if (fname2 != NULL) |
|
fclose(in2); |
|
} |
|
if (ferror(in)) { |
|
fprintf(stderr, "%s: error: read error on checksum" |
|
" file\n", program_name); |
|
has_failed = 1; |
|
} |
|
} else { |
|
unsigned char buf[128]; |
|
|
|
if (hash_file(in, fname, buf) < 0) { |
|
has_failed = 1; |
|
if (check) |
|
mismatch_count ++; |
|
} else { |
|
print_hash(buf, kf.out_len, |
|
fname == NULL ? "-" : fname); |
|
} |
|
} |
|
if (fname != NULL) |
|
fclose(in); |
|
} |
|
|
|
/** |
|
* Main function. See <code>usage()</code> for options. |
|
* |
|
* @param argc the argument count |
|
* @param argv the program arguments |
|
* @return the exit status |
|
*/ |
|
int |
|
main(int argc, char *argv[]) |
|
{ |
|
int i; |
|
int fid, skip, ff; |
|
|
|
binary = 0; |
|
check = 0; |
|
nostatus = 0; |
|
nowarn = 0; |
|
make_program_name(argv[0]); |
|
if (argc <= 0) |
|
usage(1, 1); |
|
fid = get_function_name(program_name); |
|
if (fid < 0) { |
|
if (argc <= 1) |
|
usage(1, 1); |
|
fid = get_function_name(argv[1]); |
|
if (fid < 0) { |
|
if (!strcmp(argv[1], "-v") |
|
|| !strcmp(argv[1], "--version")) |
|
version(); |
|
usage(1, 1); |
|
} |
|
skip = 1; |
|
} else { |
|
skip = 0; |
|
} |
|
for (ff = 0, i = 1 + skip; i < argc; i ++) { |
|
char *opt; |
|
|
|
opt = argv[i]; |
|
if (!strcmp(opt, "-b") || !strcmp(opt, "--binary")) { |
|
binary = 1; |
|
} else if (!strcmp(opt, "-c") || !strcmp(opt, "--check")) { |
|
check = 1; |
|
} else if (!strcmp(opt, "-t") || !strcmp(opt, "--text")) { |
|
binary = 0; |
|
} else if (!strcmp(opt, "--status")) { |
|
nostatus = 1; |
|
} else if (!strcmp(opt, "-w") || !strcmp(opt, "--warn")) { |
|
nowarn = 1; |
|
} else if (!strcmp(opt, "-h") || !strcmp(opt, "--help")) { |
|
usage(skip, 0); |
|
} else if (!strcmp(opt, "-v") || !strcmp(opt, "--version")) { |
|
version(); |
|
} else if (!strcmp(opt, "--")) { |
|
if ((i + 1) < argc) |
|
ff = 1; |
|
argv[i] = NULL; |
|
break; |
|
} else { |
|
ff = 1; |
|
continue; |
|
} |
|
argv[i] = NULL; |
|
} |
|
if ((nostatus || nowarn) && !check) |
|
usage(skip, 1); |
|
has_failed = 0; |
|
mismatch_count = 0; |
|
computed_count = 0; |
|
function_id = fid; |
|
kf = known_functions[fid]; |
|
kf.ff_init(&hcontext); |
|
if (ff) { |
|
for (i = 1 + skip; i < argc; i ++) { |
|
char *fname; |
|
|
|
fname = argv[i]; |
|
if (fname == NULL) |
|
continue; |
|
if (!strcmp(fname, "-")) |
|
fname = NULL; |
|
process_file(fname); |
|
} |
|
} else { |
|
process_file(NULL); |
|
} |
|
if (check && mismatch_count > 0 && !nostatus) { |
|
fprintf(stderr, "%s: WARNING: %ld of %ld computed checksum%s" |
|
" did NOT match\n", |
|
program_name, mismatch_count, computed_count, |
|
computed_count > 1 ? "s" : ""); |
|
} |
|
return has_failed ? EXIT_FAILURE : EXIT_SUCCESS; |
|
}
|
|
|