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