LCOV - code coverage report
Current view: top level - src - md5sum.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 175 253 69.2 %
Date: 2018-01-30 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.10