blob: 643f8271d9989e13c617148220f1d4e7e22e297d [file] [log] [blame]
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001/* md5sum.c - Compute MD5 checksum of files or strings according to the
2 * definition of MD5 in RFC 1321 from April 1992.
3 * Copyright (C) 1995-1999 Free Software Foundation, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
21/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
22
Eric Andersendb15cb72001-06-29 20:44:51 +000023/*
24 * June 29, 2001 Manuel Novoa III
25 *
26 * Added MD5SUM_SIZE_VS_SPEED configuration option.
27 *
28 * Current valid values, with data from my system for comparison, are:
29 * (using uClibc and running on linux-2.4.4.tar.bz2)
30 * user times (sec) text size (386)
31 * 0 (fastest) 1.1 6144
32 * 1 1.4 5392
33 * 2 3.0 5088
34 * 3 (smallest) 5.1 4912
35 */
36
37#define MD5SUM_SIZE_VS_SPEED 2
38
39/**********************************************************************/
40
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000041#include <stdio.h>
42#include <errno.h>
43#include <ctype.h>
Eric Andersen999bf722000-07-09 06:59:58 +000044#include <getopt.h>
Eric Andersene0c07572001-06-23 13:49:14 +000045#include <stdlib.h>
46#include <string.h>
47#include <endian.h>
48#include <sys/types.h>
49#if defined HAVE_LIMITS_H
50# include <limits.h>
51#endif
Eric Andersencbe31da2001-02-20 06:14:08 +000052#include "busybox.h"
Eric Andersen999bf722000-07-09 06:59:58 +000053
Eric Andersene111d692000-12-20 23:19:42 +000054/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
55#undef TRUE
56#undef FALSE
57#define FALSE ((int) 1)
58#define TRUE ((int) 0)
59
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000060//----------------------------------------------------------------------------
61//--------md5.c
62//----------------------------------------------------------------------------
63
64/* md5.c - Functions to compute MD5 message digest of files or memory blocks
65 * according to the definition of MD5 in RFC 1321 from April 1992.
66 * Copyright (C) 1995, 1996 Free Software Foundation, Inc.
67 *
68 * NOTE: The canonical source of this file is maintained with the GNU C
69 * Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
70 *
71 * This program is free software; you can redistribute it and/or modify it
72 * under the terms of the GNU General Public License as published by the
73 * Free Software Foundation; either version 2, or (at your option) any
74 * later version.
75 *
76 * This program is distributed in the hope that it will be useful,
77 * but WITHOUT ANY WARRANTY; without even the implied warranty of
78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79 * GNU General Public License for more details.
80 *
81 * You should have received a copy of the GNU General Public License
82 * along with this program; if not, write to the Free Software Foundation,
83 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
84 */
85
86/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
87
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000088//----------------------------------------------------------------------------
89//--------md5.h
90//----------------------------------------------------------------------------
91
92/* md5.h - Declaration of functions and data types used for MD5 sum
93 computing library functions.
94 Copyright (C) 1995, 1996 Free Software Foundation, Inc.
95 NOTE: The canonical source of this file is maintained with the GNU C
96 Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
97
98 This program is free software; you can redistribute it and/or modify it
99 under the terms of the GNU General Public License as published by the
100 Free Software Foundation; either version 2, or (at your option) any
101 later version.
102
103 This program is distributed in the hope that it will be useful,
104 but WITHOUT ANY WARRANTY; without even the implied warranty of
105 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
106 GNU General Public License for more details.
107
108 You should have received a copy of the GNU General Public License
109 along with this program; if not, write to the Free Software Foundation,
110 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
111
112#ifndef _MD5_H
Mark Whitley59ab0252001-01-23 22:30:04 +0000113static const int _MD5_H = 1;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000114
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000115/* The following contortions are an attempt to use the C preprocessor
116 to determine an unsigned integral type that is 32 bits wide. An
117 alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
118 doing that would require that the configure script compile and *run*
119 the resulting executable. Locally running cross-compiled executables
120 is usually not possible. */
121
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000122typedef u_int32_t md5_uint32;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000123
124/* Structure to save state of computation between the single steps. */
125struct md5_ctx
126{
127 md5_uint32 A;
128 md5_uint32 B;
129 md5_uint32 C;
130 md5_uint32 D;
131
132 md5_uint32 total[2];
133 md5_uint32 buflen;
134 char buffer[128];
135};
136
137/*
138 * The following three functions are build up the low level used in
139 * the functions `md5_stream' and `md5_buffer'.
140 */
141
142/* Initialize structure containing state of computation.
143 (RFC 1321, 3.3: Step 3) */
144extern void md5_init_ctx __P ((struct md5_ctx *ctx));
145
146/* Starting with the result of former calls of this function (or the
147 initialization function update the context for the next LEN bytes
148 starting at BUFFER.
149 It is necessary that LEN is a multiple of 64!!! */
150extern void md5_process_block __P ((const void *buffer, size_t len,
151 struct md5_ctx *ctx));
152
153/* Starting with the result of former calls of this function (or the
154 initialization function update the context for the next LEN bytes
155 starting at BUFFER.
156 It is NOT required that LEN is a multiple of 64. */
157extern void md5_process_bytes __P ((const void *buffer, size_t len,
158 struct md5_ctx *ctx));
159
160/* Process the remaining bytes in the buffer and put result from CTX
161 in first 16 bytes following RESBUF. The result is always in little
162 endian byte order, so that a byte-wise output yields to the wanted
163 ASCII representation of the message digest.
164
165 IMPORTANT: On some systems it is required that RESBUF is correctly
166 aligned for a 32 bits value. */
167extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
168
169
170/* Put result from CTX in first 16 bytes following RESBUF. The result is
171 always in little endian byte order, so that a byte-wise output yields
172 to the wanted ASCII representation of the message digest.
173
174 IMPORTANT: On some systems it is required that RESBUF is correctly
175 aligned for a 32 bits value. */
176extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
177
178
179/* Compute MD5 message digest for bytes read from STREAM. The
180 resulting message digest number will be written into the 16 bytes
181 beginning at RESBLOCK. */
182extern int md5_stream __P ((FILE *stream, void *resblock));
183
184/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
185 result is always in little endian byte order, so that a byte-wise
186 output yields to the wanted ASCII representation of the message
187 digest. */
188extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
189
190#endif
191
192//----------------------------------------------------------------------------
193//--------end of md5.h
194//----------------------------------------------------------------------------
195
Eric Andersen4a2e4632001-04-14 03:33:33 +0000196/* Handle endian-ness */
197#if __BYTE_ORDER == __LITTLE_ENDIAN
198 #define SWAP(n) (n)
199#else
200 #define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
201#endif
202
203
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000204
Eric Andersendb15cb72001-06-29 20:44:51 +0000205#if MD5SUM_SIZE_VS_SPEED == 0
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000206/* This array contains the bytes used to pad the buffer to the next
207 64-byte boundary. (RFC 1321, 3.1: Step 1) */
208static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
Eric Andersendb15cb72001-06-29 20:44:51 +0000209#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000210
211/* Initialize structure containing state of computation.
212 (RFC 1321, 3.3: Step 3) */
213void md5_init_ctx(struct md5_ctx *ctx)
214{
215 ctx->A = 0x67452301;
216 ctx->B = 0xefcdab89;
217 ctx->C = 0x98badcfe;
218 ctx->D = 0x10325476;
219
220 ctx->total[0] = ctx->total[1] = 0;
221 ctx->buflen = 0;
222}
223
224/* Put result from CTX in first 16 bytes following RESBUF. The result
225 must be in little endian byte order.
226
227 IMPORTANT: On some systems it is required that RESBUF is correctly
228 aligned for a 32 bits value. */
229void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
230{
231 ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
232 ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
233 ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
234 ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
235
236 return resbuf;
237}
238
239/* Process the remaining bytes in the internal buffer and the usual
240 prolog according to the standard and write the result to RESBUF.
241
242 IMPORTANT: On some systems it is required that RESBUF is correctly
243 aligned for a 32 bits value. */
244void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
245{
246 /* Take yet unprocessed bytes into account. */
247 md5_uint32 bytes = ctx->buflen;
248 size_t pad;
249
250 /* Now count remaining bytes. */
251 ctx->total[0] += bytes;
252 if (ctx->total[0] < bytes)
253 ++ctx->total[1];
254
255 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
Eric Andersendb15cb72001-06-29 20:44:51 +0000256#if MD5SUM_SIZE_VS_SPEED > 0
257 memset(&ctx->buffer[bytes], 0, pad);
258 ctx->buffer[bytes] = 0x80;
259#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000260 memcpy(&ctx->buffer[bytes], fillbuf, pad);
Eric Andersendb15cb72001-06-29 20:44:51 +0000261#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000262
263 /* Put the 64-bit file length in *bits* at the end of the buffer. */
264 *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
265 *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
Eric Andersen5a9d4412001-05-24 14:16:28 +0000266 SWAP( ((ctx->total[1] << 3) | (ctx->total[0] >> 29)) );
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000267
268 /* Process last bytes. */
269 md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
270
271 return md5_read_ctx(ctx, resbuf);
272}
273
274/* Compute MD5 message digest for bytes read from STREAM. The
275 resulting message digest number will be written into the 16 bytes
276 beginning at RESBLOCK. */
277int md5_stream(FILE *stream, void *resblock)
278{
279 /* Important: BLOCKSIZE must be a multiple of 64. */
Mark Whitley59ab0252001-01-23 22:30:04 +0000280static const int BLOCKSIZE = 4096;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000281 struct md5_ctx ctx;
282 char buffer[BLOCKSIZE + 72];
283 size_t sum;
284
285 /* Initialize the computation context. */
286 md5_init_ctx(&ctx);
287
288 /* Iterate over full file contents. */
289 while (1) {
290 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
291 computation function processes the whole buffer so that with the
292 next round of the loop another block can be read. */
293 size_t n;
294 sum = 0;
295
296 /* Read block. Take care for partial reads. */
297 do {
298 n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
299
300 sum += n;
301 }
302 while (sum < BLOCKSIZE && n != 0);
303 if (n == 0 && ferror(stream))
304 return 1;
305
306 /* If end of file is reached, end the loop. */
307 if (n == 0)
308 break;
309
310 /* Process buffer with BLOCKSIZE bytes. Note that
311 BLOCKSIZE % 64 == 0
312 */
313 md5_process_block(buffer, BLOCKSIZE, &ctx);
314 }
315
316 /* Add the last bytes if necessary. */
317 if (sum > 0)
318 md5_process_bytes(buffer, sum, &ctx);
319
320 /* Construct result in desired memory. */
321 md5_finish_ctx(&ctx, resblock);
322 return 0;
323}
324
325/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
326 result is always in little endian byte order, so that a byte-wise
327 output yields to the wanted ASCII representation of the message
328 digest. */
329void *md5_buffer(const char *buffer, size_t len, void *resblock)
330{
331 struct md5_ctx ctx;
332
333 /* Initialize the computation context. */
334 md5_init_ctx(&ctx);
335
336 /* Process whole buffer but last len % 64 bytes. */
337 md5_process_bytes(buffer, len, &ctx);
338
339 /* Put result in desired memory area. */
340 return md5_finish_ctx(&ctx, resblock);
341}
342
343void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
344{
345 /* When we already have some bits in our internal buffer concatenate
346 both inputs first. */
347 if (ctx->buflen != 0) {
348 size_t left_over = ctx->buflen;
349 size_t add = 128 - left_over > len ? len : 128 - left_over;
350
351 memcpy(&ctx->buffer[left_over], buffer, add);
352 ctx->buflen += add;
353
354 if (left_over + add > 64) {
355 md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
356 /* The regions in the following copy operation cannot overlap. */
357 memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
358 (left_over + add) & 63);
359 ctx->buflen = (left_over + add) & 63;
360 }
361
362 buffer = (const char *) buffer + add;
363 len -= add;
364 }
365
366 /* Process available complete blocks. */
367 if (len > 64) {
368 md5_process_block(buffer, len & ~63, ctx);
369 buffer = (const char *) buffer + (len & ~63);
370 len &= 63;
371 }
372
373 /* Move remaining bytes in internal buffer. */
374 if (len > 0) {
375 memcpy(ctx->buffer, buffer, len);
376 ctx->buflen = len;
377 }
378}
379
380/* These are the four functions used in the four steps of the MD5 algorithm
381 and defined in the RFC 1321. The first function is a little bit optimized
382 (as found in Colin Plumbs public domain implementation). */
383/* #define FF(b, c, d) ((b & c) | (~b & d)) */
384#define FF(b, c, d) (d ^ (b & (c ^ d)))
385#define FG(b, c, d) FF (d, b, c)
386#define FH(b, c, d) (b ^ c ^ d)
387#define FI(b, c, d) (c ^ (b | ~d))
388
389/* Process LEN bytes of BUFFER, accumulating context into CTX.
390 It is assumed that LEN % 64 == 0. */
391void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
392{
393 md5_uint32 correct_words[16];
394 const md5_uint32 *words = buffer;
395 size_t nwords = len / sizeof(md5_uint32);
396 const md5_uint32 *endp = words + nwords;
Eric Andersendb15cb72001-06-29 20:44:51 +0000397#if MD5SUM_SIZE_VS_SPEED > 0
398 static const md5_uint32 C_array[] = {
399 /* round 1 */
400 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
401 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
402 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
403 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
404 /* round 2 */
405 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
406 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
407 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
408 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
409 /* round 3 */
410 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
411 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
412 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
413 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
414 /* round 4 */
415 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
416 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
417 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
418 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
419 };
420
421 static const char P_array[] = {
422#if MD5SUM_SIZE_VS_SPEED > 1
423 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
424#endif
425 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
426 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
427 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
428 };
429
430#if MD5SUM_SIZE_VS_SPEED > 1
431 static const char S_array[] = {
432 7, 12, 17, 22,
433 5, 9, 14, 20,
434 4, 11, 16, 23,
435 6, 10, 15, 21
436 };
437#endif
438#endif
439
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000440 md5_uint32 A = ctx->A;
441 md5_uint32 B = ctx->B;
442 md5_uint32 C = ctx->C;
443 md5_uint32 D = ctx->D;
444
445 /* First increment the byte count. RFC 1321 specifies the possible
446 length of the file up to 2^64 bits. Here we only compute the
447 number of bytes. Do a double word increment. */
448 ctx->total[0] += len;
449 if (ctx->total[0] < len)
450 ++ctx->total[1];
451
452 /* Process all bytes in the buffer with 64 bytes in each round of
453 the loop. */
454 while (words < endp) {
455 md5_uint32 *cwp = correct_words;
456 md5_uint32 A_save = A;
457 md5_uint32 B_save = B;
458 md5_uint32 C_save = C;
459 md5_uint32 D_save = D;
460
Eric Andersendb15cb72001-06-29 20:44:51 +0000461#if MD5SUM_SIZE_VS_SPEED > 1
462#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
463
464 const md5_uint32 *pc;
465 const char *pp;
466 const char *ps;
467 int i;
468 md5_uint32 temp;
469
470 for ( i=0 ; i < 16 ; i++ ) {
471 cwp[i] = SWAP(words[i]);
472 }
473 words += 16;
474
475#if MD5SUM_SIZE_VS_SPEED > 2
476 pc = C_array; pp = P_array; ps = S_array - 4;
477
478 for ( i = 0 ; i < 64 ; i++ ) {
479 if ((i&0x0f) == 0) ps += 4;
480 temp = A;
481 switch (i>>4) {
482 case 0:
483 temp += FF(B,C,D);
484 break;
485 case 1:
486 temp += FG(B,C,D);
487 break;
488 case 2:
489 temp += FH(B,C,D);
490 break;
491 case 3:
492 temp += FI(B,C,D);
493 break;
494 }
495 temp += cwp[(int)(*pp++)] + *pc++;
496 temp = CYCLIC (temp, ps[i&3]);
497 temp += B;
498 A = D; D = C; C = B; B = temp;
499 }
500#else
501 pc = C_array; pp = P_array; ps = S_array;
502
503 for ( i = 0 ; i < 16 ; i++ ) {
504 temp = A + FF(B,C,D) + cwp[(int)(*pp++)] + *pc++;
505 temp = CYCLIC (temp, ps[i&3]);
506 temp += B;
507 A = D; D = C; C = B; B = temp;
508 }
509
510 ps += 4;
511 for ( i = 0 ; i < 16 ; i++ ) {
512 temp = A + FG(B,C,D) + cwp[(int)(*pp++)] + *pc++;
513 temp = CYCLIC (temp, ps[i&3]);
514 temp += B;
515 A = D; D = C; C = B; B = temp;
516 }
517 ps += 4;
518 for ( i = 0 ; i < 16 ; i++ ) {
519 temp = A + FH(B,C,D) + cwp[(int)(*pp++)] + *pc++;
520 temp = CYCLIC (temp, ps[i&3]);
521 temp += B;
522 A = D; D = C; C = B; B = temp;
523 }
524 ps += 4;
525 for ( i = 0 ; i < 16 ; i++ ) {
526 temp = A + FI(B,C,D) + cwp[(int)(*pp++)] + *pc++;
527 temp = CYCLIC (temp, ps[i&3]);
528 temp += B;
529 A = D; D = C; C = B; B = temp;
530 }
531
532#endif
533#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000534 /* First round: using the given function, the context and a constant
535 the next context is computed. Because the algorithms processing
536 unit is a 32-bit word and it is determined to work on words in
537 little endian byte order we perhaps have to change the byte order
538 before the computation. To reduce the work for the next steps
539 we store the swapped words in the array CORRECT_WORDS. */
540
541#define OP(a, b, c, d, s, T) \
542 do \
543 { \
544 a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
545 ++words; \
546 CYCLIC (a, s); \
547 a += b; \
548 } \
549 while (0)
550
551 /* It is unfortunate that C does not provide an operator for
552 cyclic rotation. Hope the C compiler is smart enough. */
553#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
554
555 /* Before we start, one word to the strange constants.
556 They are defined in RFC 1321 as
557
558 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
559 */
560
Eric Andersendb15cb72001-06-29 20:44:51 +0000561#if MD5SUM_SIZE_VS_SPEED == 1
562 const md5_uint32 *pc;
563 const char *pp;
564 int i;
565#endif
566
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000567 /* Round 1. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000568#if MD5SUM_SIZE_VS_SPEED == 1
569 pc = C_array;
570 for ( i=0 ; i < 4 ; i++ ) {
571 OP(A, B, C, D, 7, *pc++);
572 OP(D, A, B, C, 12, *pc++);
573 OP(C, D, A, B, 17, *pc++);
574 OP(B, C, D, A, 22, *pc++);
575 }
576#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000577 OP(A, B, C, D, 7, 0xd76aa478);
578 OP(D, A, B, C, 12, 0xe8c7b756);
579 OP(C, D, A, B, 17, 0x242070db);
580 OP(B, C, D, A, 22, 0xc1bdceee);
581 OP(A, B, C, D, 7, 0xf57c0faf);
582 OP(D, A, B, C, 12, 0x4787c62a);
583 OP(C, D, A, B, 17, 0xa8304613);
584 OP(B, C, D, A, 22, 0xfd469501);
585 OP(A, B, C, D, 7, 0x698098d8);
586 OP(D, A, B, C, 12, 0x8b44f7af);
587 OP(C, D, A, B, 17, 0xffff5bb1);
588 OP(B, C, D, A, 22, 0x895cd7be);
589 OP(A, B, C, D, 7, 0x6b901122);
590 OP(D, A, B, C, 12, 0xfd987193);
591 OP(C, D, A, B, 17, 0xa679438e);
592 OP(B, C, D, A, 22, 0x49b40821);
Eric Andersendb15cb72001-06-29 20:44:51 +0000593#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000594
595 /* For the second to fourth round we have the possibly swapped words
596 in CORRECT_WORDS. Redefine the macro to take an additional first
597 argument specifying the function to use. */
598#undef OP
599#define OP(f, a, b, c, d, k, s, T) \
600 do \
601 { \
602 a += f (b, c, d) + correct_words[k] + T; \
603 CYCLIC (a, s); \
604 a += b; \
605 } \
606 while (0)
607
608 /* Round 2. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000609#if MD5SUM_SIZE_VS_SPEED == 1
610 pp = P_array;
611 for ( i=0 ; i < 4 ; i++ ) {
612 OP(FG, A, B, C, D, (int)(*pp++), 5, *pc++);
613 OP(FG, D, A, B, C, (int)(*pp++), 9, *pc++);
614 OP(FG, C, D, A, B, (int)(*pp++), 14, *pc++);
615 OP(FG, B, C, D, A, (int)(*pp++), 20, *pc++);
616 }
617#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000618 OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
619 OP(FG, D, A, B, C, 6, 9, 0xc040b340);
620 OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
621 OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
622 OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
623 OP(FG, D, A, B, C, 10, 9, 0x02441453);
624 OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
625 OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
626 OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
627 OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
628 OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
629 OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
630 OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
631 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
632 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
633 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
Eric Andersendb15cb72001-06-29 20:44:51 +0000634#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000635
636 /* Round 3. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000637#if MD5SUM_SIZE_VS_SPEED == 1
638 for ( i=0 ; i < 4 ; i++ ) {
639 OP(FH, A, B, C, D, (int)(*pp++), 4, *pc++);
640 OP(FH, D, A, B, C, (int)(*pp++), 11, *pc++);
641 OP(FH, C, D, A, B, (int)(*pp++), 16, *pc++);
642 OP(FH, B, C, D, A, (int)(*pp++), 23, *pc++);
643 }
644#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000645 OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
646 OP(FH, D, A, B, C, 8, 11, 0x8771f681);
647 OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
648 OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
649 OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
650 OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
651 OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
652 OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
653 OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
654 OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
655 OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
656 OP(FH, B, C, D, A, 6, 23, 0x04881d05);
657 OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
658 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
659 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
660 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
Eric Andersendb15cb72001-06-29 20:44:51 +0000661#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000662
663 /* Round 4. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000664#if MD5SUM_SIZE_VS_SPEED == 1
665 for ( i=0 ; i < 4 ; i++ ) {
666 OP(FI, A, B, C, D, (int)(*pp++), 6, *pc++);
667 OP(FI, D, A, B, C, (int)(*pp++), 10, *pc++);
668 OP(FI, C, D, A, B, (int)(*pp++), 15, *pc++);
669 OP(FI, B, C, D, A, (int)(*pp++), 21, *pc++);
670 }
671#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000672 OP(FI, A, B, C, D, 0, 6, 0xf4292244);
673 OP(FI, D, A, B, C, 7, 10, 0x432aff97);
674 OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
675 OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
676 OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
677 OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
678 OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
679 OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
680 OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
681 OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
682 OP(FI, C, D, A, B, 6, 15, 0xa3014314);
683 OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
684 OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
685 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
686 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
687 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
Eric Andersendb15cb72001-06-29 20:44:51 +0000688#endif
689#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000690
691 /* Add the starting values of the context. */
692 A += A_save;
693 B += B_save;
694 C += C_save;
695 D += D_save;
696 }
697
698 /* Put checksum in context given as argument. */
699 ctx->A = A;
700 ctx->B = B;
701 ctx->C = C;
702 ctx->D = D;
703}
704
705//----------------------------------------------------------------------------
706//--------end of md5.c
707//----------------------------------------------------------------------------
708
709#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
710#define IN_CTYPE_DOMAIN(c) 1
711#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
712#define STREQ(a, b) (strcmp ((a), (b)) == 0)
713#define TOLOWER(Ch) tolower (Ch)
714#define OPENOPTS(BINARY) "r"
715
716/* The minimum length of a valid digest line in a file produced
717 by `md5sum FILE' and read by `md5sum -c'. This length does
718 not include any newline character at the end of a line. */
Mark Whitley59ab0252001-01-23 22:30:04 +0000719static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000720 2 - blank and binary indicator
721 1 - minimum filename length */
722
723static int have_read_stdin; /* Nonzero if any of the files read were
724 the standard input. */
725
726static int status_only = 0; /* With -c, don't generate any output.
727 The exit code indicates success or failure */
728static int warn = 0; /* With -w, print a message to standard error warning
729 about each improperly formatted MD5 checksum line */
730
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000731static int split_3(char *s,
732 size_t s_len,
733 unsigned char **u,
734 int *binary,
735 char **w)
736{
737 size_t i = 0;
738 int escaped_filename = 0;
739
740 while (ISWHITE(s[i]))
741 ++i;
742
743 /* The line must have at least 35 (36 if the first is a backslash)
744 more characters to contain correct message digest information.
745 Ignore this line if it is too short. */
746 if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
747 || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
748 return FALSE;
749
750 if (s[i] == '\\') {
751 ++i;
752 escaped_filename = 1;
753 }
754 *u = (unsigned char *) &s[i];
755
756 /* The first field has to be the 32-character hexadecimal
757 representation of the message digest. If it is not followed
758 immediately by a white space it's an error. */
759 i += 32;
760 if (!ISWHITE(s[i]))
761 return FALSE;
762
763 s[i++] = '\0';
764
765 if (s[i] != ' ' && s[i] != '*')
766 return FALSE;
767 *binary = (s[i++] == '*');
768
769 /* All characters between the type indicator and end of line are
770 significant -- that includes leading and trailing white space. */
771 *w = &s[i];
772
773 if (escaped_filename) {
774 /* Translate each `\n' string in the file name to a NEWLINE,
775 and each `\\' string to a backslash. */
776
777 char *dst = &s[i];
778
779 while (i < s_len) {
780 switch (s[i]) {
781 case '\\':
782 if (i == s_len - 1) {
783 /* A valid line does not end with a backslash. */
784 return FALSE;
785 }
786 ++i;
787 switch (s[i++]) {
788 case 'n':
789 *dst++ = '\n';
790 break;
791 case '\\':
792 *dst++ = '\\';
793 break;
794 default:
795 /* Only `\' or `n' may follow a backslash. */
796 return FALSE;
797 }
798 break;
799
800 case '\0':
801 /* The file name may not contain a NUL. */
802 return FALSE;
803 break;
804
805 default:
806 *dst++ = s[i++];
807 break;
808 }
809 }
810 *dst = '\0';
811 }
812 return TRUE;
813}
814
815static int hex_digits(unsigned char const *s)
816{
817 while (*s) {
818 if (!ISXDIGIT(*s))
819 return TRUE;
820 ++s;
821 }
822 return FALSE;
823}
824
825/* An interface to md5_stream. Operate on FILENAME (it may be "-") and
826 put the result in *MD5_RESULT. Return non-zero upon failure, zero
827 to indicate success. */
828static int md5_file(const char *filename,
829 int binary,
830 unsigned char *md5_result)
831{
832 FILE *fp;
833
834 if (STREQ(filename, "-")) {
835 have_read_stdin = 1;
836 fp = stdin;
837 } else {
838 fp = fopen(filename, OPENOPTS(binary));
839 if (fp == NULL) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000840 perror_msg("%s", filename);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000841 return FALSE;
842 }
843 }
844
845 if (md5_stream(fp, md5_result)) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000846 perror_msg("%s", filename);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000847
848 if (fp != stdin)
849 fclose(fp);
850 return FALSE;
851 }
852
853 if (fp != stdin && fclose(fp) == EOF) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000854 perror_msg("%s", filename);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000855 return FALSE;
856 }
857
858 return TRUE;
859}
860
861static int md5_check(const char *checkfile_name)
862{
863 FILE *checkfile_stream;
864 int n_properly_formated_lines = 0;
865 int n_mismatched_checksums = 0;
866 int n_open_or_read_failures = 0;
867 unsigned char md5buffer[16];
868 size_t line_number;
Eric Andersen70da6a62000-12-20 22:59:16 +0000869 char line[BUFSIZ];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000870
871 if (STREQ(checkfile_name, "-")) {
872 have_read_stdin = 1;
873 checkfile_stream = stdin;
874 } else {
875 checkfile_stream = fopen(checkfile_name, "r");
876 if (checkfile_stream == NULL) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000877 perror_msg("%s", checkfile_name);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000878 return FALSE;
879 }
880 }
881
882 line_number = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000883
884 do {
885 char *filename;
886 int binary;
887 unsigned char *md5num;
888 int line_length;
889
890 ++line_number;
891
Eric Andersen70da6a62000-12-20 22:59:16 +0000892 fgets(line, BUFSIZ-1, checkfile_stream);
893 line_length = strlen(line);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000894
Eric Andersene111d692000-12-20 23:19:42 +0000895 if (line_length <= 0 || line==NULL)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000896 break;
897
898 /* Ignore comment lines, which begin with a '#' character. */
899 if (line[0] == '#')
900 continue;
901
902 /* Remove any trailing newline. */
903 if (line[line_length - 1] == '\n')
904 line[--line_length] = '\0';
905
906 if (split_3(line, line_length, &md5num, &binary, &filename)
907 || !hex_digits(md5num)) {
908 if (warn) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000909 error_msg("%s: %lu: improperly formatted MD5 checksum line",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000910 checkfile_name, (unsigned long) line_number);
911 }
912 } else {
913 static const char bin2hex[] = {
914 '0', '1', '2', '3',
915 '4', '5', '6', '7',
916 '8', '9', 'a', 'b',
917 'c', 'd', 'e', 'f'
918 };
919
920 ++n_properly_formated_lines;
921
922 if (md5_file(filename, binary, md5buffer)) {
923 ++n_open_or_read_failures;
924 if (!status_only) {
925 printf("%s: FAILED open or read\n", filename);
926 fflush(stdout);
927 }
928 } else {
929 size_t cnt;
930 /* Compare generated binary number with text representation
931 in check file. Ignore case of hex digits. */
932 for (cnt = 0; cnt < 16; ++cnt) {
933 if (TOLOWER(md5num[2 * cnt])
934 != bin2hex[md5buffer[cnt] >> 4]
935 || (TOLOWER(md5num[2 * cnt + 1])
936 != (bin2hex[md5buffer[cnt] & 0xf])))
937 break;
938 }
939 if (cnt != 16)
940 ++n_mismatched_checksums;
941
942 if (!status_only) {
943 printf("%s: %s\n", filename,
944 (cnt != 16 ? "FAILED" : "OK"));
945 fflush(stdout);
946 }
947 }
948 }
949 }
950
951 while (!feof(checkfile_stream) && !ferror(checkfile_stream));
952
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000953 if (ferror(checkfile_stream)) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000954 error_msg("%s: read error", checkfile_name);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000955 return FALSE;
956 }
957
958 if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000959 perror_msg("md5sum: %s", checkfile_name);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000960 return FALSE;
961 }
962
963 if (n_properly_formated_lines == 0) {
964 /* Warn if no tests are found. */
Matt Kraaidd19c692001-01-31 19:00:21 +0000965 error_msg("%s: no properly formatted MD5 checksum lines found",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000966 checkfile_name);
967 return FALSE;
968 } else {
969 if (!status_only) {
970 int n_computed_checkums = (n_properly_formated_lines
971 - n_open_or_read_failures);
972
973 if (n_open_or_read_failures > 0) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000974 error_msg("WARNING: %d of %d listed files could not be read",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000975 n_open_or_read_failures, n_properly_formated_lines);
976 return FALSE;
977 }
978
979 if (n_mismatched_checksums > 0) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000980 error_msg("WARNING: %d of %d computed checksums did NOT match",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000981 n_mismatched_checksums, n_computed_checkums);
982 return FALSE;
983 }
984 }
985 }
986
987 return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
988 && n_open_or_read_failures == 0) ? 0 : 1);
989}
990
991int md5sum_main(int argc,
992 char **argv)
993{
994 unsigned char md5buffer[16];
995 int do_check = 0;
996 int opt;
997 char **string = NULL;
998 size_t n_strings = 0;
999 size_t err = 0;
1000 int file_type_specified = 0;
1001 int binary = 0;
1002
1003 while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
1004 switch (opt) {
1005 case 'g': { /* read a string */
1006 if (string == NULL)
1007 string = (char **) xmalloc ((argc - 1) * sizeof (char *));
1008
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001009 string[n_strings++] = optarg;
1010 break;
1011 }
1012
1013 case 'b': /* read files in binary mode */
1014 file_type_specified = 1;
1015 binary = 1;
1016 break;
1017
1018 case 'c': /* check MD5 sums against given list */
1019 do_check = 1;
1020 break;
1021
1022 case 's': /* don't output anything, status code shows success */
1023 status_only = 1;
1024 warn = 0;
1025 break;
1026
1027 case 't': /* read files in text mode (default) */
1028 file_type_specified = 1;
1029 binary = 0;
1030 break;
1031
1032 case 'w': /* warn about improperly formated MD5 checksum lines */
1033 status_only = 0;
1034 warn = 1;
1035 break;
1036
1037 default:
Eric Andersen67991cf2001-02-14 21:23:06 +00001038 show_usage();
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001039 }
1040 }
1041
1042 if (file_type_specified && do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001043 error_msg_and_die("the -b and -t options are meaningless when verifying checksums");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001044 }
1045
1046 if (n_strings > 0 && do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001047 error_msg_and_die("the -g and -c options are mutually exclusive");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001048 }
1049
1050 if (status_only && !do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001051 error_msg_and_die("the -s option is meaningful only when verifying checksums");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001052 }
1053
1054 if (warn && !do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001055 error_msg_and_die("the -w option is meaningful only when verifying checksums");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001056 }
1057
1058 if (n_strings > 0) {
1059 size_t i;
1060
1061 if (optind < argc) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001062 error_msg_and_die("no files may be specified when using -g");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001063 }
1064 for (i = 0; i < n_strings; ++i) {
1065 size_t cnt;
1066 md5_buffer (string[i], strlen (string[i]), md5buffer);
1067
1068 for (cnt = 0; cnt < 16; ++cnt)
1069 printf ("%02x", md5buffer[cnt]);
1070
1071 printf (" \"%s\"\n", string[i]);
1072 }
1073 } else if (do_check) {
1074 if (optind + 1 < argc) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001075 error_msg("only one argument may be specified when using -c");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001076 }
1077
1078 err = md5_check ((optind == argc) ? "-" : argv[optind]);
1079 } else {
1080 if (optind == argc)
1081 argv[argc++] = "-";
1082
1083 for (; optind < argc; ++optind) {
1084 int fail;
1085 char *file = argv[optind];
1086
1087 fail = md5_file (file, binary, md5buffer);
1088 err |= fail;
Eric Andersen7aa1f5c2001-02-22 04:59:16 +00001089 if (!fail && STREQ(file, "-")) {
1090 size_t i;
1091 for (i = 0; i < 16; ++i)
1092 printf ("%02x", md5buffer[i]);
1093 putchar ('\n');
1094 } else if (!fail) {
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001095 size_t i;
1096 /* Output a leading backslash if the file name contains
1097 a newline or backslash. */
1098 if (strchr (file, '\n') || strchr (file, '\\'))
1099 putchar ('\\');
1100
1101 for (i = 0; i < 16; ++i)
1102 printf ("%02x", md5buffer[i]);
1103
1104 putchar (' ');
1105 if (binary)
1106 putchar ('*');
1107 else
1108 putchar (' ');
1109
1110 /* Translate each NEWLINE byte to the string, "\\n",
1111 and each backslash to "\\\\". */
1112 for (i = 0; i < strlen (file); ++i) {
1113 switch (file[i]) {
1114 case '\n':
1115 fputs ("\\n", stdout);
1116 break;
1117
1118 case '\\':
1119 fputs ("\\\\", stdout);
1120 break;
1121
1122 default:
1123 putchar (file[i]);
1124 break;
1125 }
1126 }
1127 putchar ('\n');
1128 }
1129 }
1130 }
1131
1132 if (fclose (stdout) == EOF) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001133 error_msg_and_die("write error");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001134 }
1135
1136 if (have_read_stdin && fclose (stdin) == EOF) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001137 error_msg_and_die("standard input");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001138 }
1139
Matt Kraai3e856ce2000-12-01 02:55:13 +00001140 if (err == 0)
1141 return EXIT_SUCCESS;
1142 else
1143 return EXIT_FAILURE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001144}