diff options
author | Ian Jackson <ian@chiark.chu.cam.ac.uk> | 1996-04-04 01:58:40 +0100 |
---|---|---|
committer | Ian Jackson <ian@chiark.chu.cam.ac.uk> | 1996-04-04 01:58:40 +0100 |
commit | 1b80fb16c22db72457d7a456ffbf1f70a8dfc0a5 (patch) | |
tree | c0ee53eba4e71f4c246ee9e45fbd90e931bbd1f9 /md5sum | |
download | dpkg-1b80fb16c22db72457d7a456ffbf1f70a8dfc0a5.tar.gz |
dpkg (1.1.4); priority=MEDIUM
* Allow overwriting of conflicting packages being removed. (Bug#2614.)
* a.out control file says Pre-Depends: libc4 | libc. (Bug#2640.)
* ELF control file and libc dependencies changed to use finalised scheme.
* ELF control file and libc dependencies for i386 only. (Bug#2617.)
* Guidelines say use only released libraries and compilers.
* Install wishlist as /usr/doc/dpkg/WISHLIST.
* Remove spurious entries for Guidelines in info dir file.
* dpkg-deb --build checks permissions on control (DEBIAN) directory.
* Spaces in control file fields not copied by dpkg-split. (Bug#2633.)
* Spaces in split file part control data ignore. (Bug#2633.)
* Portability fixes, including patch from Richard Kettlewell.
* Fixed minor configure.in bug causing mangled GCC -W options.
-- Ian Jackson <ian@chiark.chu.cam.ac.uk> Thu, 4 Apr 1996 01:58:40 +0100
Diffstat (limited to 'md5sum')
-rw-r--r-- | md5sum/Makefile.in | 44 | ||||
-rw-r--r-- | md5sum/md5.c | 241 | ||||
-rw-r--r-- | md5sum/md5.h | 39 | ||||
-rw-r--r-- | md5sum/md5sum.1 | 70 | ||||
-rw-r--r-- | md5sum/md5sum.c | 246 |
5 files changed, 640 insertions, 0 deletions
diff --git a/md5sum/Makefile.in b/md5sum/Makefile.in new file mode 100644 index 000000000..0cd7f852c --- /dev/null +++ b/md5sum/Makefile.in @@ -0,0 +1,44 @@ +# (-*- Fundamental -*-) + +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +mandir = $(prefix)/man/man1 + +SRC = md5.c md5sum.c +OBJ = md5.o md5sum.o +HDR = md5.h + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ + +CFLAGS = @CFLAGS@ $(XCFLAGS) +LDFLAGS = $(XLDFLAGS) +LIBS = -L../lib $(XLIBS) +ALL_CFLAGS = -I../lib -I.. @DEFS@ $(CFLAGS) + +.SUFFIXES: .c .o + +.c.o: + $(CC) $(ALL_CFLAGS) -c $< + +all: md5sum + +md5sum: md5.o md5sum.o + $(CC) $(LDFLAGS) -o md5sum md5.o md5sum.o + +clean: + rm -f *.o core md5sum + +distclean: clean + rm -f Makefile *.orig *~ *.~* ./#*# + +install: all + $(INSTALL_PROGRAM) -s md5sum $(bindir)/md5sum + $(INSTALL_DATA) md5sum.1 $(mandir)/md5sum.1 diff --git a/md5sum/md5.c b/md5sum/md5.c new file mode 100644 index 000000000..0ac9d192d --- /dev/null +++ b/md5sum/md5.c @@ -0,0 +1,241 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson <ijackson@nyx.cs.du.edu>. + * Still in the public domain. + */ + +#include <string.h> /* for memcpy() */ +#include <sys/types.h> /* for stupid systems */ +#include <netinet/in.h> /* for ntohl() */ + +#include "config.h" +#include "md5.h" + +#ifdef WORDS_BIGENDIAN +void +byteSwap(UWORD32 *buf, unsigned words) +{ + md5byte *p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) +{ + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(md5byte digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) +{ + register UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/md5sum/md5.h b/md5sum/md5.h new file mode 100644 index 000000000..021766c17 --- /dev/null +++ b/md5sum/md5.h @@ -0,0 +1,39 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson <ijackson@nyx.cs.du.edu>. + * Still in the public domain. + */ + +#ifndef MD5_H +#define MD5_H + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +#endif /* !MD5_H */ diff --git a/md5sum/md5sum.1 b/md5sum/md5sum.1 new file mode 100644 index 000000000..c5d5943cd --- /dev/null +++ b/md5sum/md5sum.1 @@ -0,0 +1,70 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.TH MD5SUM 1 "29th November 1995" "Lankester et al" "Debian GNU/Linux" +.SH NAME +md5sum \- generates or checks MD5 message digests + +.SH SYNOPSIS +.B md5sum +[-bv] [-c [file]] | [file...] + +.SH DESCRIPTION +.B md5sum +generates or checks MD5 checksums. The algorithm to generate the +checksum is reasonably fast and strong enough for most cases. Exact +specification of the algorithm is in +.I RFC 1321. + +Normally +.B md5sum +generates checksums of all files given to it as a parameter and prints +the checksums followed by the filenames. If, however, +.B -c +is specified, only one filename parameter is allowed. This file should +contain checksums and filenames to which these checksums refer to, and +the files listed in that file are checked against the checksums listed +there. See option +.B -c +for more information. + +.SS OPTIONS +.TP +.B -b +Use binary mode. In unix environment, only difference between this and +the normal mode is an asterix preceding the filename in the output. +.TP +.B -c +Check md5sum of all files listed in +.I file +against the checksum listed in the same file. The actual format of that +file is the same as output of +.B md5sum. +That is, each line in the file describes a file. A line looks like: + +.B <MD5 checksum> <filename> + +So, for example, a file containing checksum for this manpage would look +like(don't worry, if the checkusum doesn't match, there is a minor +problem in keeping it up to date): + +.B c6514f34ffe6e1ce146e1f17db2c0f90 md5sum.1 +.TP +.B -v +Be more verbose. Print filenames when checking (with -c). + +.SH BUGS +The related MD4 message digest algorithm was broken in October 1995. +MD5 isn't looking as secure as it used to. + +This manpage is not quite accurate and has formatting inconsistent +with other manpages. + +.B md5sum +does not accept standard options like +.BR -\-\help . + +.SH AUTHOR + +.B md5sum +was originally written by Branko Lankester, and modified afterwards by +Colin Plumb and Ian Jackson (ijackson@gnu.ai.mit.edu). Manual page was +added by Juho Vuori (javuori@cc.helsinki.fi) diff --git a/md5sum/md5sum.c b/md5sum/md5sum.c new file mode 100644 index 000000000..cec2be761 --- /dev/null +++ b/md5sum/md5sum.c @@ -0,0 +1,246 @@ +/* + * md5sum.c - Generate/check MD5 Message Digests + * + * Compile and link with md5.c. If you don't have getopt() in your library + * also include getopt.c. For MSDOS you can also link with the wildcard + * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC) + * so that you can use wildcards on the commandline. + * + * Written March 1993 by Branko Lankester + * Modified June 1993 by Colin Plumb for altered md5.c. + * Modified Feburary 1995 by Ian Jackson for use with Colin Plumb's md5.c. + * This file is in the public domain. + */ +#include <stdio.h> +#include <string.h> +#include "config.h" +#include "md5.h" + +#ifdef UNIX +#define FOPRTXT "r" +#define FOPRBIN "r" +#else +#ifdef VMS +#define FOPRTXT "r","ctx=stm" +#define FOPRBIN "rb","ctx=stm" +#else +#define FOPRTXT "r" +#define FOPRBIN "rb" +#endif +#endif + +extern char *optarg; +extern int optind; + +void usage(); +void print_digest(); +int mdfile(FILE *fp, unsigned char *digest); +int do_check(FILE *chkf); + +char *progname; +int verbose = 0; +int bin_mode = 0; + +void +main(int argc, char **argv) +{ + int opt, rc = 0; + int check = 0; + FILE *fp; + unsigned char digest[16]; + + progname = *argv; + while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) { + switch (opt) { + case 'c': check = 1; break; + case 'v': verbose = 1; break; + case 'b': bin_mode = 1; break; + default: usage(); + } + } + argc -= optind; + argv += optind; + if (check) { + switch (argc) { + case 0: fp = stdin; break; + case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) { + perror(*argv); + exit(2); + } + break; + default: usage(); + } + exit(do_check(fp)); + } + if (argc == 0) { + if (mdfile(stdin, digest)) { + fprintf(stderr, "%s: read error on stdin\n", progname); + exit(2); + } + print_digest(digest); + printf("\n"); + exit(0); + } + for ( ; argc > 0; --argc, ++argv) { + if (bin_mode) + fp = fopen(*argv, FOPRBIN); + else + fp = fopen(*argv, FOPRTXT); + if (fp == NULL) { + perror(*argv); + rc = 2; + continue; + } + if (mdfile(fp, digest)) { + fprintf(stderr, "%s: error reading %s\n", progname, *argv); + rc = 2; + } else { + print_digest(digest); + printf(" %c%s\n", bin_mode ? '*' : ' ', *argv); + } + fclose(fp); + } + exit(rc); +} + +void +usage() +{ + fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n"); + fprintf(stderr, "Generates or checks MD5 Message Digests\n"); + fprintf(stderr, " -c check message digests (default is generate)\n"); + fprintf(stderr, " -v verbose, print file names when checking\n"); + fprintf(stderr, " -b read files in binary mode\n"); + fprintf(stderr, "The input for -c should be the list of message digests and file names\n"); + fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n"); + exit(2); +} + +int +mdfile(FILE *fp, unsigned char *digest) +{ + unsigned char buf[1024]; + struct MD5Context ctx; + int n; + + MD5Init(&ctx); + while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) + MD5Update(&ctx, buf, n); + MD5Final(digest, &ctx); + if (ferror(fp)) + return -1; + return 0; +} + +void +print_digest(unsigned char *p) +{ + int i; + + for (i = 0; i < 16; ++i) + printf("%02x", *p++); +} + +int +hex_digit(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return -1; +} + +int +get_md5_line(FILE *fp, unsigned char *digest, char *file) +{ + char buf[1024]; + int i, d1, d2, rc; + char *p = buf; + + if (fgets(buf, sizeof(buf), fp) == NULL) + return -1; + + for (i = 0; i < 16; ++i) { + if ((d1 = hex_digit(*p++)) == -1) + return 0; + if ((d2 = hex_digit(*p++)) == -1) + return 0; + *digest++ = d1*16 + d2; + } + if (*p++ != ' ') + return 0; + /* + * next char is an attribute char, space means text file + * if it's a '*' the file should be checked in binary mode. + */ + if (*p == ' ') + rc = 1; + else if (*p == '*') + rc = 2; + else { + fprintf(stderr, "%s: unrecognized line: %s", progname, buf); + return 0; + } + ++p; + i = strlen(p); + if (i < 2 || i > 255) + return 0; + p[i-1] = '\0'; + strcpy(file, p); + return rc; +} + +int +do_check(FILE *chkf) +{ + int rc, ex = 0, failed = 0, checked = 0; + unsigned char chk_digest[16], file_digest[16]; + char filename[256]; + FILE *fp; + int flen = 14; + + while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) { + if (rc == 0) /* not an md5 line */ + continue; + if (verbose) { + if (strlen(filename) > flen) + flen = strlen(filename); + fprintf(stderr, "%-*s ", flen, filename); + } + if (bin_mode || rc == 2) + fp = fopen(filename, FOPRBIN); + else + fp = fopen(filename, FOPRTXT); + if (fp == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, filename); + ex = 2; + continue; + } + if (mdfile(fp, file_digest)) { + fprintf(stderr, "%s: error reading %s\n", progname, filename); + ex = 2; + fclose(fp); + continue; + } + fclose(fp); + if (memcmp(chk_digest, file_digest, 16) != 0) { + if (verbose) + fprintf(stderr, "FAILED\n"); + else + fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename); + ++failed; + } else if (verbose) + fprintf(stderr, "OK\n"); + ++checked; + } + if (verbose && failed) + fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked); + if (!checked) { + fprintf(stderr, "%s: no files checked\n", progname); + return 3; + } + if (!ex && failed) + ex = 1; + return ex; +} |