(usage): Fix typo s/formated/formatted/ reported by Norbert Kiesel
[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 Print or check %s (%d-bit) checksums.\n\
111 With no FILE, or when FILE is -, read standard input.\n\
112 \n\
113 "),
114               program_name,
115               DIGEST_TYPE_STRING (algorithm),
116               DIGEST_BITS (algorithm));
117       if (O_BINARY)
118         fputs (_("\
119   -b, --binary            read in binary mode (default unless reading tty stdin)\n\
120 "), stdout);
121       else
122         fputs (_("\
123   -b, --binary            read in binary mode\n\
124 "), stdout);
125       printf (_("\
126   -c, --check             read %s sums from the FILEs and check them\n"),
127               DIGEST_TYPE_STRING (algorithm));
128       if (O_BINARY)
129         fputs (_("\
130   -t, --text              read in text mode (default if reading tty stdin)\n\
131 "), stdout);
132       else
133         fputs (_("\
134   -t, --text              read in text mode (default)\n\
135 "), stdout);
136       fputs (_("\
137 \n\
138 The following two options are useful only when verifying checksums:\n\
139       --status            don't output anything, status code shows success\n\
140   -w, --warn              warn about improperly formatted checksum lines\n\
141 \n\
142 "), stdout);
143       fputs (HELP_OPTION_DESCRIPTION, stdout);
144       fputs (VERSION_OPTION_DESCRIPTION, stdout);
145       printf (_("\
146 \n\
147 The sums are computed as described in %s.  When checking, the input\n\
148 should be a former output of this program.  The default mode is to print\n\
149 a line with checksum, a character indicating type (`*' for binary, ` ' for\n\
150 text), and name for each FILE.\n"),
151               (algorithm == ALG_MD5 ? "RFC 1321" : "FIPS-180-1"));
152       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
153     }
154
155   exit (status);
156 }
157
158 #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
159
160 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
161    'sha1' command into two parts: a hexadecimal digest, and the file
162    name.  S is modified.  Return true if successful.  */
163
164 static bool
165 bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest, char **file_name)
166 {
167   size_t i;
168
169   *file_name = s;
170
171   /* Find end of filename. The BSD 'md5' and 'sha1' commands do not escape
172      filenames, so search backwards for the last ')'. */
173   i = s_len - 1;
174   while (i && s[i] != ')')
175     i--;
176
177   if (s[i] != ')')
178     return false;
179
180   s[i++] = '\0';
181
182   while (ISWHITE (s[i]))
183     i++;
184
185   if (s[i] != '=')
186     return false;
187
188   i++;
189
190   while (ISWHITE (s[i]))
191     i++;
192
193   *hex_digest = (unsigned char *) &s[i];
194   return true;
195 }
196
197 /* Split the string S (of length S_LEN) into three parts:
198    a hexadecimal digest, binary flag, and the file name.
199    S is modified.  Return true if successful.  */
200
201 static bool
202 split_3 (char *s, size_t s_len,
203          unsigned char **hex_digest, int *binary, char **file_name)
204 {
205   size_t i;
206   bool escaped_filename = false;
207   size_t algo_name_len;
208
209   i = 0;
210   while (ISWHITE (s[i]))
211     ++i;
212
213   /* Check for BSD-style checksum line. */
214   algo_name_len = strlen (DIGEST_TYPE_STRING (algorithm));
215   if (strncmp (s + i, DIGEST_TYPE_STRING (algorithm), algo_name_len) == 0)
216     {
217       if (strncmp (s + i + algo_name_len, " (", 2) == 0)
218         {
219           *binary = 0;
220           return bsd_split_3 (s +      i + algo_name_len + 2,
221                               s_len - (i + algo_name_len + 2),
222                               hex_digest, file_name);
223         }
224     }
225
226   /* Ignore this line if it is too short.
227      Each line must have at least `min_digest_line_length - 1' (or one more, if
228      the first is a backslash) more characters to contain correct message digest
229      information.  */
230   if (s_len - i < min_digest_line_length + (s[i] == '\\'))
231     return false;
232
233   if (s[i] == '\\')
234     {
235       ++i;
236       escaped_filename = true;
237     }
238   *hex_digest = (unsigned char *) &s[i];
239
240   /* The first field has to be the n-character hexadecimal
241      representation of the message digest.  If it is not followed
242      immediately by a white space it's an error.  */
243   i += digest_hex_bytes;
244   if (!ISWHITE (s[i]))
245     return false;
246
247   s[i++] = '\0';
248
249   if (s[i] != ' ' && s[i] != '*')
250     return false;
251   *binary = (s[i++] == '*');
252
253   /* All characters between the type indicator and end of line are
254      significant -- that includes leading and trailing white space.  */
255   *file_name = &s[i];
256
257   if (escaped_filename)
258     {
259       /* Translate each `\n' string in the file name to a NEWLINE,
260          and each `\\' string to a backslash.  */
261
262       char *dst = &s[i];
263
264       while (i < s_len)
265         {
266           switch (s[i])
267             {
268             case '\\':
269               if (i == s_len - 1)
270                 {
271                   /* A valid line does not end with a backslash.  */
272                   return false;
273                 }
274               ++i;
275               switch (s[i++])
276                 {
277                 case 'n':
278                   *dst++ = '\n';
279                   break;
280                 case '\\':
281                   *dst++ = '\\';
282                   break;
283                 default:
284                   /* Only `\' or `n' may follow a backslash.  */
285                   return false;
286                 }
287               break;
288
289             case '\0':
290               /* The file name may not contain a NUL.  */
291               return false;
292               break;
293
294             default:
295               *dst++ = s[i++];
296               break;
297             }
298         }
299       *dst = '\0';
300     }
301   return true;
302 }
303
304 static bool
305 hex_digits (unsigned char const *s)
306 {
307   while (*s)
308     {
309       if (!ISXDIGIT (*s))
310         return false;
311       ++s;
312     }
313   return true;
314 }
315
316 /* An interface to the function, DIGEST_STREAM,
317    (either md5_stream or sha1_stream).
318    Operate on FILENAME (it may be "-").
319
320    *BINARY indicates whether the file is binary.  BINARY < 0 means it
321    depends on whether binary mode makes any difference and the file is
322    a terminal; in that case, clear *BINARY if the file was treated as
323    text because it was a terminal.
324
325    Put the checksum in *BIN_RESULT.
326    Return true if successful.  */
327
328 static bool
329 digest_file (const char *filename, int *binary, unsigned char *bin_result,
330              int (*digest_stream) (FILE *, void *))
331 {
332   FILE *fp;
333   int err;
334   bool is_stdin = STREQ (filename, "-");
335
336   if (is_stdin)
337     {
338       have_read_stdin = true;
339       fp = stdin;
340       if (O_BINARY && *binary)
341         {
342           if (*binary < 0)
343             *binary = ! isatty (STDIN_FILENO);
344           if (*binary)
345             freopen (NULL, "rb", stdin);
346         }
347     }
348   else
349     {
350       fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r"));
351       if (fp == NULL)
352         {
353           error (0, errno, "%s", filename);
354           return false;
355         }
356     }
357
358   err = (*digest_stream) (fp, bin_result);
359   if (err)
360     {
361       error (0, errno, "%s", filename);
362       if (fp != stdin)
363         fclose (fp);
364       return false;
365     }
366
367   if (!is_stdin && fclose (fp) != 0)
368     {
369       error (0, errno, "%s", filename);
370       return false;
371     }
372
373   return true;
374 }
375
376 static bool
377 digest_check (const char *checkfile_name, int (*digest_stream) (FILE *, void *))
378 {
379   FILE *checkfile_stream;
380   uintmax_t n_properly_formatted_lines = 0;
381   uintmax_t n_mismatched_checksums = 0;
382   uintmax_t n_open_or_read_failures = 0;
383   unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
384   uintmax_t line_number;
385   char *line;
386   size_t line_chars_allocated;
387   bool is_stdin = STREQ (checkfile_name, "-");
388
389   if (is_stdin)
390     {
391       have_read_stdin = true;
392       checkfile_name = _("standard input");
393       checkfile_stream = stdin;
394     }
395   else
396     {
397       checkfile_stream = fopen (checkfile_name, "r");
398       if (checkfile_stream == NULL)
399         {
400           error (0, errno, "%s", checkfile_name);
401           return false;
402         }
403     }
404
405   line_number = 0;
406   line = NULL;
407   line_chars_allocated = 0;
408   do
409     {
410       char *filename;
411       int binary;
412       unsigned char *hex_digest IF_LINT (= NULL);
413       ssize_t line_length;
414
415       ++line_number;
416       if (line_number == 0)
417         error (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
418                checkfile_name);
419
420       line_length = getline (&line, &line_chars_allocated, checkfile_stream);
421       if (line_length <= 0)
422         break;
423
424       /* Ignore comment lines, which begin with a '#' character.  */
425       if (line[0] == '#')
426         continue;
427
428       /* Remove any trailing newline.  */
429       if (line[line_length - 1] == '\n')
430         line[--line_length] = '\0';
431
432       if (! (split_3 (line, line_length, &hex_digest, &binary, &filename)
433              && ! (is_stdin && STREQ (filename, "-"))
434              && hex_digits (hex_digest)))
435         {
436           if (warn)
437             {
438               error (0, 0,
439                      _("%s: %" PRIuMAX
440                        ": improperly formatted %s checksum line"),
441                      checkfile_name, line_number,
442                      DIGEST_TYPE_STRING (algorithm));
443             }
444         }
445       else
446         {
447           static const char bin2hex[] = { '0', '1', '2', '3',
448                                           '4', '5', '6', '7',
449                                           '8', '9', 'a', 'b',
450                                           'c', 'd', 'e', 'f' };
451           bool ok;
452
453           ++n_properly_formatted_lines;
454
455           ok = digest_file (filename, &binary, bin_buffer, digest_stream);
456
457           if (!ok)
458             {
459               ++n_open_or_read_failures;
460               if (!status_only)
461                 {
462                   printf (_("%s: FAILED open or read\n"), filename);
463                   fflush (stdout);
464                 }
465             }
466           else
467             {
468               size_t digest_bin_bytes = digest_hex_bytes / 2;
469               size_t cnt;
470               /* Compare generated binary number with text representation
471                  in check file.  Ignore case of hex digits.  */
472               for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
473                 {
474                   if (TOLOWER (hex_digest[2 * cnt])
475                       != bin2hex[bin_buffer[cnt] >> 4]
476                       || (TOLOWER (hex_digest[2 * cnt + 1])
477                           != (bin2hex[bin_buffer[cnt] & 0xf])))
478                     break;
479                 }
480               if (cnt != digest_bin_bytes)
481                 ++n_mismatched_checksums;
482
483               if (!status_only)
484                 {
485                   printf ("%s: %s\n", filename,
486                           (cnt != digest_bin_bytes ? _("FAILED") : _("OK")));
487                   fflush (stdout);
488                 }
489             }
490         }
491     }
492   while (!feof (checkfile_stream) && !ferror (checkfile_stream));
493
494   free (line);
495
496   if (ferror (checkfile_stream))
497     {
498       error (0, 0, _("%s: read error"), checkfile_name);
499       return false;
500     }
501
502   if (!is_stdin && fclose (checkfile_stream) != 0)
503     {
504       error (0, errno, "%s", checkfile_name);
505       return false;
506     }
507
508   if (n_properly_formatted_lines == 0)
509     {
510       /* Warn if no tests are found.  */
511       error (0, 0, _("%s: no properly formatted %s checksum lines found"),
512              checkfile_name, DIGEST_TYPE_STRING (algorithm));
513     }
514   else
515     {
516       if (!status_only)
517         {
518           if (n_open_or_read_failures != 0)
519             error (0, 0,
520                    ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
521                              " listed file could not be read",
522                              "WARNING: %" PRIuMAX " of %" PRIuMAX
523                              " listed files could not be read",
524                              n_properly_formatted_lines),
525                    n_open_or_read_failures, n_properly_formatted_lines);
526
527           if (n_mismatched_checksums != 0)
528             {
529               uintmax_t n_computed_checksums =
530                 (n_properly_formatted_lines - n_open_or_read_failures);
531               error (0, 0,
532                      ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
533                                " computed checksum did NOT match",
534                                "WARNING: %" PRIuMAX " of %" PRIuMAX
535                                " computed checksums did NOT match",
536                                n_computed_checksums),
537                      n_mismatched_checksums, n_computed_checksums);
538             }
539         }
540     }
541
542   return (n_properly_formatted_lines != 0
543           && n_mismatched_checksums == 0
544           && n_open_or_read_failures == 0);
545 }
546
547 int
548 main (int argc, char **argv)
549 {
550   unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
551   bool do_check = false;
552   int opt;
553   bool ok = true;
554   int binary = -1;
555
556   /* Setting values of global variables.  */
557   initialize_main (&argc, &argv);
558   program_name = argv[0];
559   setlocale (LC_ALL, "");
560   bindtextdomain (PACKAGE, LOCALEDIR);
561   textdomain (PACKAGE);
562
563   atexit (close_stdout);
564
565   while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
566     switch (opt)
567       {
568       case 'b':
569         binary = 1;
570         break;
571       case 'c':
572         do_check = true;
573         break;
574       case STATUS_OPTION:
575         status_only = true;
576         warn = false;
577         break;
578       case 't':
579         binary = 0;
580         break;
581       case 'w':
582         status_only = false;
583         warn = true;
584         break;
585       case_GETOPT_HELP_CHAR;
586       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
587       default:
588         usage (EXIT_FAILURE);
589       }
590
591   min_digest_line_length = MIN_DIGEST_LINE_LENGTH (algorithm);
592   digest_hex_bytes = DIGEST_HEX_BYTES (algorithm);
593
594   if (0 <= binary && do_check)
595     {
596       error (0, 0, _("the --binary and --text options are meaningless when "
597                      "verifying checksums"));
598       usage (EXIT_FAILURE);
599     }
600
601   if (status_only & !do_check)
602     {
603       error (0, 0,
604        _("the --status option is meaningful only when verifying checksums"));
605       usage (EXIT_FAILURE);
606     }
607
608   if (warn & !do_check)
609     {
610       error (0, 0,
611        _("the --warn option is meaningful only when verifying checksums"));
612       usage (EXIT_FAILURE);
613     }
614
615   if (optind == argc)
616     argv[argc++] = "-";
617
618   for (; optind < argc; ++optind)
619     {
620       char *file = argv[optind];
621
622       if (do_check)
623         ok &= digest_check (file, DIGEST_STREAM (algorithm));
624       else
625         {
626           int file_is_binary = binary;
627
628           if (! digest_file (file, &file_is_binary, bin_buffer,
629                              DIGEST_STREAM (algorithm)))
630             ok = false;
631           else
632             {
633               size_t i;
634
635               /* Output a leading backslash if the file name contains
636                  a newline or backslash.  */
637               if (strchr (file, '\n') || strchr (file, '\\'))
638                 putchar ('\\');
639
640               for (i = 0; i < (digest_hex_bytes / 2); ++i)
641                 printf ("%02x", bin_buffer[i]);
642
643               putchar (' ');
644               if (file_is_binary)
645                 putchar ('*');
646               else
647                 putchar (' ');
648
649               /* Translate each NEWLINE byte to the string, "\\n",
650                  and each backslash to "\\\\".  */
651               for (i = 0; i < strlen (file); ++i)
652                 {
653                   switch (file[i])
654                     {
655                     case '\n':
656                       fputs ("\\n", stdout);
657                       break;
658
659                     case '\\':
660                       fputs ("\\\\", stdout);
661                       break;
662
663                     default:
664                       putchar (file[i]);
665                       break;
666                     }
667                 }
668               putchar ('\n');
669             }
670         }
671     }
672
673   if (have_read_stdin && fclose (stdin) == EOF)
674     error (EXIT_FAILURE, errno, _("standard input"));
675
676   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
677 }