(OPENOPTS, TEXT1T01, TEXTCNVT): Remove.
[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 <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
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              && hex_digits (hex_digest)))
419         {
420           if (warn)
421             {
422               error (0, 0,
423                      _("%s: %" PRIuMAX
424                        ": improperly formatted %s checksum line"),
425                      checkfile_name, line_number,
426                      DIGEST_TYPE_STRING (algorithm));
427             }
428         }
429       else
430         {
431           static const char bin2hex[] = { '0', '1', '2', '3',
432                                           '4', '5', '6', '7',
433                                           '8', '9', 'a', 'b',
434                                           'c', 'd', 'e', 'f' };
435           bool ok;
436
437           ++n_properly_formatted_lines;
438
439           ok = digest_file (filename, binary, bin_buffer, digest_stream);
440
441           if (!ok)
442             {
443               ++n_open_or_read_failures;
444               if (!status_only)
445                 {
446                   printf (_("%s: FAILED open or read\n"), filename);
447                   fflush (stdout);
448                 }
449             }
450           else
451             {
452               size_t digest_bin_bytes = digest_hex_bytes / 2;
453               size_t cnt;
454               /* Compare generated binary number with text representation
455                  in check file.  Ignore case of hex digits.  */
456               for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
457                 {
458                   if (TOLOWER (hex_digest[2 * cnt])
459                       != bin2hex[bin_buffer[cnt] >> 4]
460                       || (TOLOWER (hex_digest[2 * cnt + 1])
461                           != (bin2hex[bin_buffer[cnt] & 0xf])))
462                     break;
463                 }
464               if (cnt != digest_bin_bytes)
465                 ++n_mismatched_checksums;
466
467               if (!status_only)
468                 {
469                   printf ("%s: %s\n", filename,
470                           (cnt != digest_bin_bytes ? _("FAILED") : _("OK")));
471                   fflush (stdout);
472                 }
473             }
474         }
475     }
476   while (!feof (checkfile_stream) && !ferror (checkfile_stream));
477
478   free (line);
479
480   if (ferror (checkfile_stream))
481     {
482       error (0, 0, _("%s: read error"), checkfile_name);
483       return false;
484     }
485
486   if (!is_stdin && fclose (checkfile_stream) != 0)
487     {
488       error (0, errno, "%s", checkfile_name);
489       return false;
490     }
491
492   if (n_properly_formatted_lines == 0)
493     {
494       /* Warn if no tests are found.  */
495       error (0, 0, _("%s: no properly formatted %s checksum lines found"),
496              checkfile_name, DIGEST_TYPE_STRING (algorithm));
497     }
498   else
499     {
500       if (!status_only)
501         {
502           if (n_open_or_read_failures != 0)
503             error (0, 0,
504                    ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
505                              " listed file could not be read",
506                              "WARNING: %" PRIuMAX " of %" PRIuMAX
507                              " listed files could not be read",
508                              n_properly_formatted_lines),
509                    n_open_or_read_failures, n_properly_formatted_lines);
510
511           if (n_mismatched_checksums != 0)
512             {
513               uintmax_t n_computed_checksums =
514                 (n_properly_formatted_lines - n_open_or_read_failures);
515               error (0, 0,
516                      ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
517                                " computed checksum did NOT match",
518                                "WARNING: %" PRIuMAX " of %" PRIuMAX
519                                " computed checksums did NOT match",
520                                n_computed_checksums),
521                      n_mismatched_checksums, n_computed_checksums);
522             }
523         }
524     }
525
526   return (n_properly_formatted_lines != 0
527           && n_mismatched_checksums == 0
528           && n_open_or_read_failures == 0);
529 }
530
531 int
532 main (int argc, char **argv)
533 {
534   unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
535   bool do_check = false;
536   int opt;
537   bool ok = true;
538   bool file_type_specified = false;
539
540 #if O_BINARY
541   /* Binary is default on MSDOS, so the actual file contents
542      are used in computation.  */
543   bool binary = true;
544 #else
545   /* Text is default of the Plumb/Lankester format.  */
546   bool binary = false;
547 #endif
548
549   /* Setting values of global variables.  */
550   initialize_main (&argc, &argv);
551   program_name = argv[0];
552   setlocale (LC_ALL, "");
553   bindtextdomain (PACKAGE, LOCALEDIR);
554   textdomain (PACKAGE);
555
556   atexit (close_stdout);
557
558   while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
559     switch (opt)
560       {
561       case 'b':
562         file_type_specified = true;
563         binary = true;
564         break;
565       case 'c':
566         do_check = true;
567         break;
568       case STATUS_OPTION:
569         status_only = true;
570         warn = false;
571         break;
572       case 't':
573         file_type_specified = true;
574         binary = false;
575         break;
576       case 'w':
577         status_only = false;
578         warn = true;
579         break;
580       case_GETOPT_HELP_CHAR;
581       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
582       default:
583         usage (EXIT_FAILURE);
584       }
585
586   min_digest_line_length = MIN_DIGEST_LINE_LENGTH (algorithm);
587   digest_hex_bytes = DIGEST_HEX_BYTES (algorithm);
588
589   if (file_type_specified & do_check)
590     {
591       error (0, 0, _("the --binary and --text options are meaningless when "
592                      "verifying checksums"));
593       usage (EXIT_FAILURE);
594     }
595
596   if (status_only & !do_check)
597     {
598       error (0, 0,
599        _("the --status option is meaningful only when verifying checksums"));
600       usage (EXIT_FAILURE);
601     }
602
603   if (warn & !do_check)
604     {
605       error (0, 0,
606        _("the --warn option is meaningful only when verifying checksums"));
607       usage (EXIT_FAILURE);
608     }
609
610   if (do_check)
611     {
612       if (optind + 1 < argc)
613         {
614           error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
615           fprintf (stderr, "%s\n",
616                    _("Only one operand may be specified when using --check."));
617           usage (EXIT_FAILURE);
618         }
619
620       ok = digest_check (optind == argc ? "-" : argv[optind],
621                          DIGEST_STREAM (algorithm));
622     }
623   else
624     {
625       if (optind == argc)
626         argv[argc++] = "-";
627
628       for (; optind < argc; ++optind)
629         {
630           char *file = argv[optind];
631
632           if (! digest_file (file, binary, bin_buffer,
633                              DIGEST_STREAM (algorithm)))
634             ok = false;
635           else
636             {
637               size_t i;
638
639               /* Output a leading backslash if the file name contains
640                  a newline or backslash.  */
641               if (strchr (file, '\n') || strchr (file, '\\'))
642                 putchar ('\\');
643
644               for (i = 0; i < (digest_hex_bytes / 2); ++i)
645                 printf ("%02x", bin_buffer[i]);
646
647               putchar (' ');
648               if (binary)
649                 putchar ('*');
650               else
651                 putchar (' ');
652
653               /* Translate each NEWLINE byte to the string, "\\n",
654                  and each backslash to "\\\\".  */
655               for (i = 0; i < strlen (file); ++i)
656                 {
657                   switch (file[i])
658                     {
659                     case '\n':
660                       fputs ("\\n", stdout);
661                       break;
662
663                     case '\\':
664                       fputs ("\\\\", stdout);
665                       break;
666
667                     default:
668                       putchar (file[i]);
669                       break;
670                     }
671                 }
672               putchar ('\n');
673             }
674         }
675     }
676
677   if (have_read_stdin && fclose (stdin) == EOF)
678     error (EXIT_FAILURE, errno, _("standard input"));
679
680   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
681 }