1 | /* vi: set sw=4 ts=4: */
|
---|
2 | /*
|
---|
3 | * sum -- checksum and count the blocks in a file
|
---|
4 | * Like BSD sum or SysV sum -r, except like SysV sum if -s option is given.
|
---|
5 | *
|
---|
6 | * Copyright (C) 86, 89, 91, 1995-2002, 2004 Free Software Foundation, Inc.
|
---|
7 | * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
|
---|
8 | * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
|
---|
9 | *
|
---|
10 | * Written by Kayvan Aghaiepour and David MacKenzie
|
---|
11 | * Taken from coreutils and turned into a busybox applet by Mike Frysinger
|
---|
12 | *
|
---|
13 | * Licensed under the GPL v2, see the file LICENSE in this tarball.
|
---|
14 | */
|
---|
15 |
|
---|
16 | #include <stdio.h>
|
---|
17 | #include <sys/types.h>
|
---|
18 | #include <sys/stat.h>
|
---|
19 | #include <fcntl.h>
|
---|
20 | #include <unistd.h>
|
---|
21 |
|
---|
22 | #include "busybox.h"
|
---|
23 |
|
---|
24 | /* 1 if any of the files read were the standard input */
|
---|
25 | static int have_read_stdin;
|
---|
26 |
|
---|
27 | /* make a little more readable and avoid using strcmp for just 2 bytes */
|
---|
28 | #define IS_STDIN(s) (s[0] == '-' && s[1] == '\0')
|
---|
29 |
|
---|
30 | /* Calculate and print the rotated checksum and the size in 1K blocks
|
---|
31 | of file FILE, or of the standard input if FILE is "-".
|
---|
32 | If PRINT_NAME is >1, print FILE next to the checksum and size.
|
---|
33 | The checksum varies depending on sizeof (int).
|
---|
34 | Return 1 if successful. */
|
---|
35 | static int bsd_sum_file(const char *file, int print_name)
|
---|
36 | {
|
---|
37 | FILE *fp;
|
---|
38 | int checksum = 0; /* The checksum mod 2^16. */
|
---|
39 | uintmax_t total_bytes = 0; /* The number of bytes. */
|
---|
40 | int ch; /* Each character read. */
|
---|
41 |
|
---|
42 | if (IS_STDIN(file)) {
|
---|
43 | fp = stdin;
|
---|
44 | have_read_stdin = 1;
|
---|
45 | } else {
|
---|
46 | fp = bb_wfopen(file, "r");
|
---|
47 | if (fp == NULL)
|
---|
48 | return 0;
|
---|
49 | }
|
---|
50 |
|
---|
51 | while ((ch = getc(fp)) != EOF) {
|
---|
52 | ++total_bytes;
|
---|
53 | checksum = (checksum >> 1) + ((checksum & 1) << 15);
|
---|
54 | checksum += ch;
|
---|
55 | checksum &= 0xffff; /* Keep it within bounds. */
|
---|
56 | }
|
---|
57 |
|
---|
58 | if (ferror(fp)) {
|
---|
59 | bb_perror_msg(file);
|
---|
60 | bb_fclose_nonstdin(fp);
|
---|
61 | return 0;
|
---|
62 | }
|
---|
63 |
|
---|
64 | if (bb_fclose_nonstdin(fp) == EOF) {
|
---|
65 | bb_perror_msg(file);
|
---|
66 | return 0;
|
---|
67 | }
|
---|
68 |
|
---|
69 | printf("%05d %5ju ", checksum, (total_bytes+1023)/1024);
|
---|
70 | if (print_name > 1)
|
---|
71 | puts(file);
|
---|
72 | else
|
---|
73 | printf("\n");
|
---|
74 |
|
---|
75 | return 1;
|
---|
76 | }
|
---|
77 |
|
---|
78 | /* Calculate and print the checksum and the size in 512-byte blocks
|
---|
79 | of file FILE, or of the standard input if FILE is "-".
|
---|
80 | If PRINT_NAME is >0, print FILE next to the checksum and size.
|
---|
81 | Return 1 if successful. */
|
---|
82 | #define MY_BUF_SIZE 8192
|
---|
83 | static int sysv_sum_file(const char *file, int print_name)
|
---|
84 | {
|
---|
85 | RESERVE_CONFIG_BUFFER(buf, MY_BUF_SIZE);
|
---|
86 | int fd;
|
---|
87 | uintmax_t total_bytes = 0;
|
---|
88 |
|
---|
89 | /* The sum of all the input bytes, modulo (UINT_MAX + 1). */
|
---|
90 | unsigned int s = 0;
|
---|
91 |
|
---|
92 | if (IS_STDIN(file)) {
|
---|
93 | fd = 0;
|
---|
94 | have_read_stdin = 1;
|
---|
95 | } else {
|
---|
96 | fd = open(file, O_RDONLY);
|
---|
97 | if (fd == -1)
|
---|
98 | goto release_and_ret;
|
---|
99 | }
|
---|
100 |
|
---|
101 | while (1) {
|
---|
102 | size_t bytes_read = safe_read(fd, buf, MY_BUF_SIZE);
|
---|
103 |
|
---|
104 | if (bytes_read == 0)
|
---|
105 | break;
|
---|
106 |
|
---|
107 | if (bytes_read == -1) {
|
---|
108 | release_and_ret:
|
---|
109 | bb_perror_msg(file);
|
---|
110 | RELEASE_CONFIG_BUFFER(buf);
|
---|
111 | if (!IS_STDIN(file))
|
---|
112 | close(fd);
|
---|
113 | return 0;
|
---|
114 | }
|
---|
115 |
|
---|
116 | total_bytes += bytes_read;
|
---|
117 | while (bytes_read--)
|
---|
118 | s += buf[bytes_read];
|
---|
119 | }
|
---|
120 |
|
---|
121 | if (!IS_STDIN(file) && close(fd) == -1)
|
---|
122 | goto release_and_ret;
|
---|
123 | else
|
---|
124 | RELEASE_CONFIG_BUFFER(buf);
|
---|
125 |
|
---|
126 | {
|
---|
127 | int r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
|
---|
128 | s = (r & 0xffff) + (r >> 16);
|
---|
129 |
|
---|
130 | printf("%d %ju ", s, (total_bytes+511)/512);
|
---|
131 | }
|
---|
132 | puts(print_name ? file : "");
|
---|
133 |
|
---|
134 | return 1;
|
---|
135 | }
|
---|
136 |
|
---|
137 | int sum_main(int argc, char **argv)
|
---|
138 | {
|
---|
139 | int flags;
|
---|
140 | int ok;
|
---|
141 | int (*sum_func)(const char *, int) = bsd_sum_file;
|
---|
142 |
|
---|
143 | /* give the bsd func priority over sysv func */
|
---|
144 | flags = bb_getopt_ulflags(argc, argv, "sr");
|
---|
145 | if (flags & 1)
|
---|
146 | sum_func = sysv_sum_file;
|
---|
147 | if (flags & 2)
|
---|
148 | sum_func = bsd_sum_file;
|
---|
149 |
|
---|
150 | have_read_stdin = 0;
|
---|
151 | if ((argc - optind) == 0)
|
---|
152 | ok = sum_func("-", 0);
|
---|
153 | else
|
---|
154 | for (ok = 1; optind < argc; optind++)
|
---|
155 | ok &= sum_func(argv[optind], 1);
|
---|
156 |
|
---|
157 | if (have_read_stdin && fclose(stdin) == EOF)
|
---|
158 | bb_perror_msg_and_die("-");
|
---|
159 |
|
---|
160 | exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
---|
161 | }
|
---|