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