(STRING_OPTION): Remove.
[platform/upstream/coreutils.git] / src / md5sum.c
1 /* Compute MD5 or SHA1 checksum of files or strings
2    Copyright (C) 1995-2004 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>.  */
19
20 #include <config.h>
21
22 #include <getopt.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25
26 #include "system.h"
27
28 #include "md5.h"
29 #include "sha1.h"
30 #include "checksum.h"
31 #include "getline.h"
32 #include "error.h"
33 #include "quote.h"
34
35 /* The official name of this program (e.g., no `g' prefix).  */
36 #define PROGRAM_NAME (algorithm == ALG_MD5 ? "md5sum" : "sha1sum")
37
38 #define AUTHORS "Ulrich Drepper", "Scott Miller"
39
40 /* Most systems do not distinguish between external and internal
41    text representations.  */
42 /* FIXME: This begs for an autoconf test.  */
43 #if O_BINARY
44 # define OPENOPTS(BINARY) ((BINARY) ? TEXT1TO1 : TEXTCNVT)
45 # define TEXT1TO1 "rb"
46 # define TEXTCNVT "r"
47 #else
48 # if defined VMS
49 #  define OPENOPTS(BINARY) ((BINARY) ? TEXT1TO1 : TEXTCNVT)
50 #  define TEXT1TO1 "rb", "ctx=stm"
51 #  define TEXTCNVT "r", "ctx=stm"
52 # else
53 #  if UNIX || __UNIX__ || unix || __unix__ || _POSIX_VERSION
54 #   define OPENOPTS(BINARY) "r"
55 #  else
56     /* The following line is intended to evoke an error.
57        Using #error is not portable enough.  */
58     "Cannot determine system type."
59 #  endif
60 # endif
61 #endif
62
63
64 #define DIGEST_TYPE_STRING(Alg) ((Alg) == ALG_MD5 ? "MD5" : "SHA1")
65 #define DIGEST_STREAM(Alg) ((Alg) == ALG_MD5 ? md5_stream : sha1_stream)
66
67 #define DIGEST_BITS(Alg) ((Alg) == ALG_MD5 ? 128 : 160)
68 #define DIGEST_HEX_BYTES(Alg) (DIGEST_BITS (Alg) / 4)
69 #define DIGEST_BIN_BYTES(Alg) (DIGEST_BITS (Alg) / 8)
70
71 #define MAX_DIGEST_BIN_BYTES MAX (DIGEST_BIN_BYTES (ALG_MD5), \
72                                   DIGEST_BIN_BYTES (ALG_SHA1))
73
74 /* The minimum length of a valid digest line.  This length does
75    not include any newline character at the end of a line.  */
76 #define MIN_DIGEST_LINE_LENGTH(Alg) \
77   (DIGEST_HEX_BYTES (Alg) /* length of hexadecimal message digest */ \
78    + 2 /* blank and binary indicator */ \
79    + 1 /* minimum filename length */ )
80
81 /* True if any of the files read were the standard input. */
82 static bool have_read_stdin;
83
84 /* The minimum length of a valid checksum line for the selected algorithm.  */
85 static size_t min_digest_line_length;
86
87 /* Set to the length of a digest hex string for the selected algorithm.  */
88 static size_t digest_hex_bytes;
89
90 /* With --check, don't generate any output.
91    The exit code indicates success or failure.  */
92 static bool status_only = false;
93
94 /* With --check, print a message to standard error warning about each
95    improperly formatted checksum line.  */
96 static bool warn = false;
97
98 /* Declared and set via one of the wrapper .c files.  */
99 /* int algorithm = ALG_UNSPECIFIED; */
100
101 /* The name this program was run with.  */
102 char *program_name;
103
104 /* For long options that have no equivalent short option, use a
105    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
106 enum
107 {
108   STATUS_OPTION = CHAR_MAX + 1
109 };
110
111 static const struct option long_options[] =
112 {
113   { "binary", no_argument, 0, 'b' },
114   { "check", no_argument, 0, 'c' },
115   { "status", no_argument, 0, STATUS_OPTION },
116   { "text", no_argument, 0, 't' },
117   { "warn", no_argument, 0, 'w' },
118   { GETOPT_HELP_OPTION_DECL },
119   { GETOPT_VERSION_OPTION_DECL },
120   { NULL, 0, NULL, 0 }
121 };
122
123 void
124 usage (int status)
125 {
126   if (status != EXIT_SUCCESS)
127     fprintf (stderr, _("Try `%s --help' for more information.\n"),
128              program_name);
129   else
130     {
131       printf (_("\
132 Usage: %s [OPTION] [FILE]...\n\
133   or:  %s [OPTION] --check [FILE]\n\
134 Print or check %s (%d-bit) checksums.\n\
135 With no FILE, or when FILE is -, read standard input.\n\
136 "),
137               program_name, program_name,
138               DIGEST_TYPE_STRING (algorithm),
139               DIGEST_BITS (algorithm));
140       printf (_("\
141 \n\
142   -b, --binary            read files in binary mode (default on DOS/Windows)\n\
143   -c, --check             check %s sums against given list\n\
144   -t, --text              read files in text mode (default)\n\
145 \n\
146 "),
147               DIGEST_TYPE_STRING (algorithm));
148       fputs (_("\
149 The following two options are useful only when verifying checksums:\n\
150       --status            don't output anything, status code shows success\n\
151   -w, --warn              warn about improperly formated checksum lines\n\
152 \n\
153 "), stdout);
154       fputs (HELP_OPTION_DESCRIPTION, stdout);
155       fputs (VERSION_OPTION_DESCRIPTION, stdout);
156       printf (_("\
157 \n\
158 The sums are computed as described in %s.  When checking, the input\n\
159 should be a former output of this program.  The default mode is to print\n\
160 a line with checksum, a character indicating type (`*' for binary, ` ' for\n\
161 text), and name for each FILE.\n"),
162               (algorithm == ALG_MD5 ? "RFC 1321" : "FIPS-180-1"));
163       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
164     }
165
166   exit (status);
167 }
168
169 #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
170
171 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
172    'sha1' command into two parts: a hexadecimal digest, and the file
173    name.  S is modified.  Return true if successful.  */
174
175 static bool
176 bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest, char **file_name)
177 {
178   size_t i;
179
180   *file_name = s;
181
182   /* Find end of filename. The BSD 'md5' and 'sha1' commands do not escape
183      filenames, so search backwards for the last ')'. */
184   i = s_len - 1;
185   while (i && s[i] != ')')
186     i--;
187
188   if (s[i] != ')')
189     return false;
190
191   s[i++] = '\0';
192
193   while (ISWHITE (s[i]))
194     i++;
195
196   if (s[i] != '=')
197     return false;
198
199   i++;
200
201   while (ISWHITE (s[i]))
202     i++;
203
204   *hex_digest = (unsigned char *) &s[i];
205   return true;
206 }
207
208 /* Split the string S (of length S_LEN) into three parts:
209    a hexadecimal digest, binary flag, and the file name.
210    S is modified.  Return true if successful.  */
211
212 static bool
213 split_3 (char *s, size_t s_len,
214          unsigned char **hex_digest, bool *binary, char **file_name)
215 {
216   size_t i;
217   bool escaped_filename = false;
218   size_t algo_name_len;
219
220   i = 0;
221   while (ISWHITE (s[i]))
222     ++i;
223
224   /* Check for BSD-style checksum line. */
225   algo_name_len = strlen (DIGEST_TYPE_STRING (algorithm));
226   if (strncmp (s + i, DIGEST_TYPE_STRING (algorithm), algo_name_len) == 0)
227     {
228       if (strncmp (s + i + algo_name_len, " (", 2) == 0)
229         {
230           *binary = false;
231           return bsd_split_3 (s +      i + algo_name_len + 2,
232                               s_len - (i + algo_name_len + 2),
233                               hex_digest, file_name);
234         }
235     }
236
237   /* Ignore this line if it is too short.
238      Each line must have at least `min_digest_line_length - 1' (or one more, if
239      the first is a backslash) more characters to contain correct message digest
240      information.  */
241   if (s_len - i < min_digest_line_length + (s[i] == '\\'))
242     return false;
243
244   if (s[i] == '\\')
245     {
246       ++i;
247       escaped_filename = true;
248     }
249   *hex_digest = (unsigned char *) &s[i];
250
251   /* The first field has to be the n-character hexadecimal
252      representation of the message digest.  If it is not followed
253      immediately by a white space it's an error.  */
254   i += digest_hex_bytes;
255   if (!ISWHITE (s[i]))
256     return false;
257
258   s[i++] = '\0';
259
260   if (s[i] != ' ' && s[i] != '*')
261     return false;
262   *binary = (s[i++] == '*');
263
264   /* All characters between the type indicator and end of line are
265      significant -- that includes leading and trailing white space.  */
266   *file_name = &s[i];
267
268   if (escaped_filename)
269     {
270       /* Translate each `\n' string in the file name to a NEWLINE,
271          and each `\\' string to a backslash.  */
272
273       char *dst = &s[i];
274
275       while (i < s_len)
276         {
277           switch (s[i])
278             {
279             case '\\':
280               if (i == s_len - 1)
281                 {
282                   /* A valid line does not end with a backslash.  */
283                   return false;
284                 }
285               ++i;
286               switch (s[i++])
287                 {
288                 case 'n':
289                   *dst++ = '\n';
290                   break;
291                 case '\\':
292                   *dst++ = '\\';
293                   break;
294                 default:
295                   /* Only `\' or `n' may follow a backslash.  */
296                   return false;
297                 }
298               break;
299
300             case '\0':
301               /* The file name may not contain a NUL.  */
302               return false;
303               break;
304
305             default:
306               *dst++ = s[i++];
307               break;
308             }
309         }
310       *dst = '\0';
311     }
312   return true;
313 }
314
315 static bool
316 hex_digits (unsigned char const *s)
317 {
318   while (*s)
319     {
320       if (!ISXDIGIT (*s))
321         return false;
322       ++s;
323     }
324   return true;
325 }
326
327 /* An interface to the function, DIGEST_STREAM,
328    (either md5_stream or sha1_stream).
329    Operate on FILENAME (it may be "-") and put the result in *BIN_RESULT.
330    Return true if successful.  */
331
332 static bool
333 digest_file (const char *filename, bool binary, unsigned char *bin_result,
334              int (*digest_stream) (FILE *, void *))
335 {
336   FILE *fp;
337   int err;
338
339   if (STREQ (filename, "-"))
340     {
341       have_read_stdin = true;
342       fp = stdin;
343 #if O_BINARY
344       /* If we need binary reads from a pipe or redirected stdin, we need
345          to switch it to BINARY mode here, since stdin is already open.  */
346       if (binary)
347         SET_BINARY (fileno (stdin));
348 #endif
349     }
350   else
351     {
352       /* OPENOPTS is a macro.  It varies with the system.
353          Some systems distinguish between internal and
354          external text representations.  */
355
356       fp = fopen (filename, OPENOPTS (binary));
357       if (fp == NULL)
358         {
359           error (0, errno, "%s", filename);
360           return false;
361         }
362     }
363
364   err = (*digest_stream) (fp, bin_result);
365   if (err)
366     {
367       error (0, errno, "%s", filename);
368       if (fp != stdin)
369         fclose (fp);
370       return false;
371     }
372
373   if (fp != stdin && fclose (fp) == EOF)
374     {
375       error (0, errno, "%s", filename);
376       return false;
377     }
378
379   return true;
380 }
381
382 static bool
383 digest_check (const char *checkfile_name, int (*digest_stream) (FILE *, void *))
384 {
385   FILE *checkfile_stream;
386   uintmax_t n_properly_formatted_lines = 0;
387   uintmax_t n_mismatched_checksums = 0;
388   uintmax_t n_open_or_read_failures = 0;
389   unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
390   uintmax_t line_number;
391   char *line;
392   size_t line_chars_allocated;
393
394   if (STREQ (checkfile_name, "-"))
395     {
396       have_read_stdin = true;
397       checkfile_name = _("standard input");
398       checkfile_stream = stdin;
399     }
400   else
401     {
402       checkfile_stream = fopen (checkfile_name, "r");
403       if (checkfile_stream == NULL)
404         {
405           error (0, errno, "%s", checkfile_name);
406           return false;
407         }
408     }
409
410   SET_MODE (fileno (checkfile_stream), O_TEXT);
411   line_number = 0;
412   line = NULL;
413   line_chars_allocated = 0;
414   do
415     {
416       char *filename;
417       bool binary;
418       unsigned char *hex_digest;
419       ssize_t line_length;
420
421       ++line_number;
422       if (line_number == 0)
423         error (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
424                checkfile_name);
425
426       line_length = getline (&line, &line_chars_allocated, checkfile_stream);
427       if (line_length <= 0)
428         break;
429
430       /* Ignore comment lines, which begin with a '#' character.  */
431       if (line[0] == '#')
432         continue;
433
434       /* Remove any trailing newline.  */
435       if (line[line_length - 1] == '\n')
436         line[--line_length] = '\0';
437
438       if (! (split_3 (line, line_length, &hex_digest, &binary, &filename)
439              && hex_digits (hex_digest)))
440         {
441           if (warn)
442             {
443               error (0, 0,
444                      _("%s: %" PRIuMAX
445                        ": improperly formatted %s checksum line"),
446                      checkfile_name, line_number,
447                      DIGEST_TYPE_STRING (algorithm));
448             }
449         }
450       else
451         {
452           static const char bin2hex[] = { '0', '1', '2', '3',
453                                           '4', '5', '6', '7',
454                                           '8', '9', 'a', 'b',
455                                           'c', 'd', 'e', 'f' };
456           bool ok;
457
458           ++n_properly_formatted_lines;
459
460           ok = digest_file (filename, binary, bin_buffer, digest_stream);
461
462           if (!ok)
463             {
464               ++n_open_or_read_failures;
465               if (!status_only)
466                 {
467                   printf (_("%s: FAILED open or read\n"), filename);
468                   fflush (stdout);
469                 }
470             }
471           else
472             {
473               size_t digest_bin_bytes = digest_hex_bytes / 2;
474               size_t cnt;
475               /* Compare generated binary number with text representation
476                  in check file.  Ignore case of hex digits.  */
477               for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
478                 {
479                   if (TOLOWER (hex_digest[2 * cnt])
480                       != bin2hex[bin_buffer[cnt] >> 4]
481                       || (TOLOWER (hex_digest[2 * cnt + 1])
482                           != (bin2hex[bin_buffer[cnt] & 0xf])))
483                     break;
484                 }
485               if (cnt != digest_bin_bytes)
486                 ++n_mismatched_checksums;
487
488               if (!status_only)
489                 {
490                   printf ("%s: %s\n", filename,
491                           (cnt != digest_bin_bytes ? _("FAILED") : _("OK")));
492                   fflush (stdout);
493                 }
494             }
495         }
496     }
497   while (!feof (checkfile_stream) && !ferror (checkfile_stream));
498
499   if (line)
500     free (line);
501
502   if (ferror (checkfile_stream))
503     {
504       error (0, 0, _("%s: read error"), checkfile_name);
505       return false;
506     }
507
508   if (checkfile_stream != stdin && fclose (checkfile_stream) == EOF)
509     {
510       error (0, errno, "%s", checkfile_name);
511       return false;
512     }
513
514   if (n_properly_formatted_lines == 0)
515     {
516       /* Warn if no tests are found.  */
517       error (0, 0, _("%s: no properly formatted %s checksum lines found"),
518              checkfile_name, DIGEST_TYPE_STRING (algorithm));
519     }
520   else
521     {
522       if (!status_only)
523         {
524           if (n_open_or_read_failures != 0)
525             error (0, 0,
526                    ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
527                              " listed file could not be read",
528                              "WARNING: %" PRIuMAX " of %" PRIuMAX
529                              " listed files could not be read",
530                              n_properly_formatted_lines),
531                    n_open_or_read_failures, n_properly_formatted_lines);
532
533           if (n_mismatched_checksums != 0)
534             {
535               uintmax_t n_computed_checksums =
536                 (n_properly_formatted_lines - n_open_or_read_failures);
537               error (0, 0,
538                      ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
539                                " computed checksum did NOT match",
540                                "WARNING: %" PRIuMAX " of %" PRIuMAX
541                                " computed checksums did NOT match",
542                                n_computed_checksums),
543                      n_mismatched_checksums, n_computed_checksums);
544             }
545         }
546     }
547
548   return (n_properly_formatted_lines != 0
549           && n_mismatched_checksums == 0
550           && n_open_or_read_failures == 0);
551 }
552
553 int
554 main (int argc, char **argv)
555 {
556   unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
557   bool do_check = false;
558   int opt;
559   bool ok = true;
560   bool file_type_specified = false;
561
562 #if O_BINARY
563   /* Binary is default on MSDOS, so the actual file contents
564      are used in computation.  */
565   bool binary = true;
566 #else
567   /* Text is default of the Plumb/Lankester format.  */
568   bool binary = false;
569 #endif
570
571   /* Setting values of global variables.  */
572   initialize_main (&argc, &argv);
573   program_name = argv[0];
574   setlocale (LC_ALL, "");
575   bindtextdomain (PACKAGE, LOCALEDIR);
576   textdomain (PACKAGE);
577
578   atexit (close_stdout);
579
580   while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
581     switch (opt)
582       {
583       case 'b':
584         file_type_specified = true;
585         binary = true;
586         break;
587       case 'c':
588         do_check = true;
589         break;
590       case STATUS_OPTION:
591         status_only = true;
592         warn = false;
593         break;
594       case 't':
595         file_type_specified = true;
596         binary = false;
597         break;
598       case 'w':
599         status_only = false;
600         warn = true;
601         break;
602       case_GETOPT_HELP_CHAR;
603       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
604       default:
605         usage (EXIT_FAILURE);
606       }
607
608   min_digest_line_length = MIN_DIGEST_LINE_LENGTH (algorithm);
609   digest_hex_bytes = DIGEST_HEX_BYTES (algorithm);
610
611   if (file_type_specified & do_check)
612     {
613       error (0, 0, _("the --binary and --text options are meaningless when "
614                      "verifying checksums"));
615       usage (EXIT_FAILURE);
616     }
617
618   if (status_only & !do_check)
619     {
620       error (0, 0,
621        _("the --status option is meaningful only when verifying checksums"));
622       usage (EXIT_FAILURE);
623     }
624
625   if (warn & !do_check)
626     {
627       error (0, 0,
628        _("the --warn option is meaningful only when verifying checksums"));
629       usage (EXIT_FAILURE);
630     }
631
632   if (do_check)
633     {
634       if (optind + 1 < argc)
635         {
636           error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
637           fprintf (stderr, "%s\n",
638                    _("Only one operand may be specified when using --check."));
639           usage (EXIT_FAILURE);
640         }
641
642       ok = digest_check (optind == argc ? "-" : argv[optind],
643                          DIGEST_STREAM (algorithm));
644     }
645   else
646     {
647       if (optind == argc)
648         argv[argc++] = "-";
649
650       for (; optind < argc; ++optind)
651         {
652           char *file = argv[optind];
653
654           if (! digest_file (file, binary, bin_buffer,
655                              DIGEST_STREAM (algorithm)))
656             ok = false;
657           else
658             {
659               size_t i;
660
661               /* Output a leading backslash if the file name contains
662                  a newline or backslash.  */
663               if (strchr (file, '\n') || strchr (file, '\\'))
664                 putchar ('\\');
665
666               for (i = 0; i < (digest_hex_bytes / 2); ++i)
667                 printf ("%02x", bin_buffer[i]);
668
669               putchar (' ');
670               if (binary)
671                 putchar ('*');
672               else
673                 putchar (' ');
674
675               /* Translate each NEWLINE byte to the string, "\\n",
676                  and each backslash to "\\\\".  */
677               for (i = 0; i < strlen (file); ++i)
678                 {
679                   switch (file[i])
680                     {
681                     case '\n':
682                       fputs ("\\n", stdout);
683                       break;
684
685                     case '\\':
686                       fputs ("\\\\", stdout);
687                       break;
688
689                     default:
690                       putchar (file[i]);
691                       break;
692                     }
693                 }
694               putchar ('\n');
695             }
696         }
697     }
698
699   if (have_read_stdin && fclose (stdin) == EOF)
700     error (EXIT_FAILURE, errno, _("standard input"));
701
702   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
703 }