(cksum): Avoid setmode; use POSIX-specified routines instead.
[platform/upstream/coreutils.git] / src / cksum.c
1 /* cksum -- calculate and print POSIX checksums and sizes of files
2    Copyright (C) 92, 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 \f
18 /* Written by Q. Frank Xia, qx@math.columbia.edu.
19    Cosmetic changes and reorganization by David MacKenzie, djm@gnu.ai.mit.edu.
20
21   Usage: cksum [file...]
22
23   The code segment between "#ifdef CRCTAB" and "#else" is the code
24   which calculates the "crctab". It is included for those who want
25   verify the correctness of the "crctab". To recreate the "crctab",
26   do something like the following:
27
28       cc -DCRCTAB -o crctab cksum.c
29       crctab > crctab.h
30
31   This software is compatible with neither the System V nor the BSD
32   `sum' program.  It is supposed to conform to POSIX, except perhaps
33   for foreign language support.  Any inconsistency with the standard
34   (other than foreign language support) is a bug.  */
35
36 #include <config.h>
37
38 /* The official name of this program (e.g., no `g' prefix).  */
39 #define PROGRAM_NAME "cksum"
40
41 #define AUTHORS "Q. Frank Xia"
42
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include "system.h"
46
47 #if !defined UINT_FAST32_MAX && !defined uint_fast32_t
48 # define uint_fast32_t unsigned int
49 #endif
50
51 #ifdef CRCTAB
52
53 # define BIT(x) ((uint_fast32_t) 1 << (x))
54 # define SBIT   BIT (31)
55
56 /* The generating polynomial is
57
58           32   26   23   22   16   12   11   10   8   7   5   4   2   1
59     G(X)=X  + X  + X  + X  + X  + X  + X  + X  + X + X + X + X + X + X + 1
60
61   The i bit in GEN is set if X^i is a summand of G(X) except X^32.  */
62
63 # define GEN    (BIT (26) | BIT (23) | BIT (22) | BIT (16) | BIT (12) \
64                  | BIT (11) | BIT (10) | BIT (8) | BIT (7) | BIT (5) \
65                  | BIT (4) | BIT (2) | BIT (1) | BIT (0))
66
67 static uint_fast32_t r[8];
68
69 static void
70 fill_r (void)
71 {
72   int i;
73
74   r[0] = GEN;
75   for (i = 1; i < 8; i++)
76     r[i] = (r[i - 1] << 1) ^ ((r[i - 1] & SBIT) ? GEN : 0);
77 }
78
79 static uint_fast32_t
80 crc_remainder (int m)
81 {
82   uint_fast32_t rem = 0;
83   int i;
84
85   for (i = 0; i < 8; i++)
86     if (BIT (i) & m)
87       rem ^= r[i];
88
89   return rem & 0xFFFFFFFF;      /* Make it run on 64-bit machine.  */
90 }
91
92 int
93 main (void)
94 {
95   int i;
96
97   fill_r ();
98   printf ("static uint_fast32_t const crctab[256] =\n{\n  0x00000000");
99   for (i = 0; i < 51; i++)
100     {
101       printf (",\n  0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
102               crc_remainder (i * 5 + 1), crc_remainder (i * 5 + 2),
103               crc_remainder (i * 5 + 3), crc_remainder (i * 5 + 4),
104               crc_remainder (i * 5 + 5));
105     }
106   printf ("\n};\n");
107   exit (EXIT_SUCCESS);
108 }
109
110 #else /* !CRCTAB */
111
112 # include <getopt.h>
113 # include "long-options.h"
114 # include "error.h"
115 # include "inttostr.h"
116
117 /* Number of bytes to read at once.  */
118 # define BUFLEN (1 << 16)
119
120 /* The name this program was run with.  */
121 char *program_name;
122
123 static uint_fast32_t const crctab[256] =
124 {
125   0x00000000,
126   0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
127   0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
128   0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
129   0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
130   0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
131   0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
132   0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
133   0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
134   0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
135   0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
136   0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
137   0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
138   0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
139   0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
140   0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
141   0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
142   0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
143   0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
144   0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
145   0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
146   0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
147   0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
148   0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
149   0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
150   0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
151   0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
152   0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
153   0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
154   0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
155   0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
156   0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
157   0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
158   0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
159   0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
160   0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
161   0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
162   0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
163   0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
164   0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
165   0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
166   0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
167   0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
168   0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
169   0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
170   0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
171   0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
172   0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
173   0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
174   0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
175   0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
176   0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
177 };
178
179 /* Nonzero if any of the files read were the standard input. */
180 static bool have_read_stdin;
181
182 /* Calculate and print the checksum and length in bytes
183    of file FILE, or of the standard input if FILE is "-".
184    If PRINT_NAME is true, print FILE next to the checksum and size.
185    Return true if successful.  */
186
187 static bool
188 cksum (const char *file, bool print_name)
189 {
190   unsigned char buf[BUFLEN];
191   uint_fast32_t crc = 0;
192   uintmax_t length = 0;
193   size_t bytes_read;
194   FILE *fp;
195   char length_buf[INT_BUFSIZE_BOUND (uintmax_t)];
196   char const *hp;
197
198   if (STREQ (file, "-"))
199     {
200       fp = stdin;
201       have_read_stdin = true;
202       if (O_BINARY && ! isatty (STDIN_FILENO))
203         freopen (NULL, "rb", stdin);
204     }
205   else
206     {
207       fp = fopen (file, (O_BINARY ? "rb" : "r"));
208       if (fp == NULL)
209         {
210           error (0, errno, "%s", file);
211           return false;
212         }
213     }
214
215   while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0)
216     {
217       unsigned char *cp = buf;
218
219       if (length + bytes_read < length)
220         error (EXIT_FAILURE, 0, _("%s: file too long"), file);
221       length += bytes_read;
222       while (bytes_read--)
223         crc = (crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
224       if (feof (fp))
225         break;
226     }
227
228   if (ferror (fp))
229     {
230       error (0, errno, "%s", file);
231       if (!STREQ (file, "-"))
232         fclose (fp);
233       return false;
234     }
235
236   if (!STREQ (file, "-") && fclose (fp) == EOF)
237     {
238       error (0, errno, "%s", file);
239       return false;
240     }
241
242   hp = umaxtostr (length, length_buf);
243
244   for (; length; length >>= 8)
245     crc = (crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
246
247   crc = ~crc & 0xFFFFFFFF;
248
249   if (print_name)
250     printf ("%u %s %s\n", (unsigned int) crc, hp, file);
251   else
252     printf ("%u %s\n", (unsigned int) crc, hp);
253
254   if (ferror (stdout))
255     error (EXIT_FAILURE, errno, "-: %s", _("write error"));
256
257   return true;
258 }
259
260 void
261 usage (int status)
262 {
263   if (status != EXIT_SUCCESS)
264     fprintf (stderr, _("Try `%s --help' for more information.\n"),
265              program_name);
266   else
267     {
268       printf (_("\
269 Usage: %s [FILE]...\n\
270   or:  %s [OPTION]\n\
271 "),
272               program_name, program_name);
273       fputs (_("\
274 Print CRC checksum and byte counts of each FILE.\n\
275 \n\
276 "), stdout);
277       fputs (HELP_OPTION_DESCRIPTION, stdout);
278       fputs (VERSION_OPTION_DESCRIPTION, stdout);
279       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
280     }
281   exit (status);
282 }
283
284 int
285 main (int argc, char **argv)
286 {
287   int i;
288   bool ok;
289
290   initialize_main (&argc, &argv);
291   program_name = argv[0];
292   setlocale (LC_ALL, "");
293   bindtextdomain (PACKAGE, LOCALEDIR);
294   textdomain (PACKAGE);
295
296   atexit (close_stdout);
297
298   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION,
299                       usage, AUTHORS, (char const *) NULL);
300   if (getopt_long (argc, argv, "", NULL, NULL) != -1)
301     usage (EXIT_FAILURE);
302
303   have_read_stdin = false;
304
305   if (optind == argc)
306     ok = cksum ("-", false);
307   else
308     {
309       ok = true;
310       for (i = optind; i < argc; i++)
311         ok &= cksum (argv[i], true);
312     }
313
314   if (have_read_stdin && fclose (stdin) == EOF)
315     error (EXIT_FAILURE, errno, "-");
316   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
317 }
318
319 #endif /* !CRCTAB */