aboutsummaryrefslogtreecommitdiff
path: root/coreutils/md5_sha1_sum.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/md5_sha1_sum.c')
-rw-r--r--coreutils/md5_sha1_sum.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
new file mode 100644
index 000000000..e8d3a1509
--- /dev/null
+++ b/coreutils/md5_sha1_sum.c
@@ -0,0 +1,186 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2003 Glenn L. McGrath
4 * Copyright (C) 2003-2004 Erik Andersen
5 *
6 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
7 */
8
9#include "busybox.h"
10
11typedef enum { HASH_SHA1, HASH_MD5 } hash_algo_t;
12
13#define FLAG_SILENT 1
14#define FLAG_CHECK 2
15#define FLAG_WARN 4
16
17/* This might be useful elsewhere */
18static unsigned char *hash_bin_to_hex(unsigned char *hash_value,
19 unsigned hash_length)
20{
21 int len = 0;
22 char *hex_value = xmalloc((hash_length * 2) + 2);
23 while (hash_length--) {
24 len += sprintf(hex_value + len, "%02x", *hash_value++);
25 }
26 return hex_value;
27}
28
29static uint8_t *hash_file(const char *filename, hash_algo_t hash_algo)
30{
31 int src_fd, hash_len, count;
32 union _ctx_ {
33 sha1_ctx_t sha1;
34 md5_ctx_t md5;
35 } context;
36 uint8_t *hash_value = NULL;
37 RESERVE_CONFIG_UBUFFER(in_buf, 4096);
38 void (*update)(const void*, size_t, void*);
39 void (*final)(void*, void*);
40
41 src_fd = STDIN_FILENO;
42 if (filename[0] != '-' || filename[1]) { /* not "-" */
43 src_fd = open(filename, O_RDONLY);
44 if (src_fd < 0) {
45 bb_perror_msg("%s", filename);
46 return NULL;
47 }
48 }
49
50 /* figure specific hash algorithims */
51 if (ENABLE_MD5SUM && hash_algo==HASH_MD5) {
52 md5_begin(&context.md5);
53 update = (void (*)(const void*, size_t, void*))md5_hash;
54 final = (void (*)(void*, void*))md5_end;
55 hash_len = 16;
56 } else if (ENABLE_SHA1SUM && hash_algo==HASH_SHA1) {
57 sha1_begin(&context.sha1);
58 update = (void (*)(const void*, size_t, void*))sha1_hash;
59 final = (void (*)(void*, void*))sha1_end;
60 hash_len = 20;
61 } else {
62 bb_error_msg_and_die("algorithm not supported");
63 }
64
65 while (0 < (count = safe_read(src_fd, in_buf, 4096))) {
66 update(in_buf, count, &context);
67 }
68
69 if (count == 0) {
70 final(in_buf, &context);
71 hash_value = hash_bin_to_hex(in_buf, hash_len);
72 }
73
74 RELEASE_CONFIG_BUFFER(in_buf);
75
76 if (src_fd != STDIN_FILENO) {
77 close(src_fd);
78 }
79
80 return hash_value;
81}
82
83int md5_sha1_sum_main(int argc, char **argv)
84{
85 int return_value = EXIT_SUCCESS;
86 uint8_t *hash_value;
87 unsigned flags;
88 hash_algo_t hash_algo = ENABLE_MD5SUM
89 ? (ENABLE_SHA1SUM ? (**argv=='m' ? HASH_MD5 : HASH_SHA1) : HASH_MD5)
90 : HASH_SHA1;
91
92 if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK)
93 flags = getopt32(argc, argv, "scw");
94 else optind = 1;
95
96 if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) {
97 if (flags & FLAG_SILENT) {
98 bb_error_msg_and_die
99 ("-%c is meaningful only when verifying checksums", 's');
100 } else if (flags & FLAG_WARN) {
101 bb_error_msg_and_die
102 ("-%c is meaningful only when verifying checksums", 'w');
103 }
104 }
105
106 if (argc == optind) {
107 argv[argc++] = "-";
108 }
109
110 if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) {
111 FILE *pre_computed_stream;
112 int count_total = 0;
113 int count_failed = 0;
114 char *file_ptr = argv[optind];
115 char *line;
116
117 if (optind + 1 != argc) {
118 bb_error_msg_and_die
119 ("only one argument may be specified when using -c");
120 }
121
122 pre_computed_stream = stdin;
123 if (file_ptr[0] != '-' || file_ptr[1]) { /* not "-" */
124 pre_computed_stream = xfopen(file_ptr, "r");
125 }
126
127 while ((line = xmalloc_getline(pre_computed_stream)) != NULL) {
128 char *filename_ptr;
129
130 count_total++;
131 filename_ptr = strstr(line, " ");
132 /* handle format for binary checksums */
133 if (filename_ptr == NULL) {
134 filename_ptr = strstr(line, " *");
135 }
136 if (filename_ptr == NULL) {
137 if (flags & FLAG_WARN) {
138 bb_error_msg("invalid format");
139 }
140 count_failed++;
141 return_value = EXIT_FAILURE;
142 free(line);
143 continue;
144 }
145 *filename_ptr = '\0';
146 filename_ptr += 2;
147
148 hash_value = hash_file(filename_ptr, hash_algo);
149
150 if (hash_value && (strcmp((char*)hash_value, line) == 0)) {
151 if (!(flags & FLAG_SILENT))
152 printf("%s: OK\n", filename_ptr);
153 } else {
154 if (!(flags & FLAG_SILENT))
155 printf("%s: FAILED\n", filename_ptr);
156 count_failed++;
157 return_value = EXIT_FAILURE;
158 }
159 /* possible free(NULL) */
160 free(hash_value);
161 free(line);
162 }
163 if (count_failed && !(flags & FLAG_SILENT)) {
164 bb_error_msg("WARNING: %d of %d computed checksums did NOT match",
165 count_failed, count_total);
166 }
167 /*
168 if (fclose_if_not_stdin(pre_computed_stream) == EOF) {
169 bb_perror_msg_and_die("cannot close file %s", file_ptr);
170 }
171 */
172 } else {
173 while (optind < argc) {
174 char *file_ptr = argv[optind++];
175
176 hash_value = hash_file(file_ptr, hash_algo);
177 if (hash_value == NULL) {
178 return_value = EXIT_FAILURE;
179 } else {
180 printf("%s %s\n", hash_value, file_ptr);
181 free(hash_value);
182 }
183 }
184 }
185 return return_value;
186}