/* * Copyright (C) 2003 Glenn L. McGrath * Copyright (C) 2003-2004 Erik Andersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include "busybox.h" #define FLAG_SILENT 1 #define FLAG_CHECK 2 #define FLAG_WARN 4 /* This might be useful elsewhere */ static unsigned char *hash_bin_to_hex(unsigned char *hash_value, unsigned char hash_length) { int x, len, max; unsigned char *hex_value; max = (hash_length * 2) + 2; hex_value = xmalloc(max); for (x = len = 0; x < hash_length; x++) { len += snprintf((char*)(hex_value + len), max - len, "%02x", hash_value[x]); } return (hex_value); } static uint8_t *hash_file(const char *filename, uint8_t hash_algo) { int src_fd = strcmp(filename, "-") == 0 ? STDIN_FILENO : open(filename, O_RDONLY); if (src_fd == -1) { bb_perror_msg("%s", filename); return NULL; } else { uint8_t *hash_value; RESERVE_CONFIG_UBUFFER(hash_value_bin, 20); hash_value = hash_fd(src_fd, -1, hash_algo, hash_value_bin) != -2 ? hash_bin_to_hex(hash_value_bin, hash_algo == HASH_MD5 ? 16 : 20) : NULL; RELEASE_CONFIG_BUFFER(hash_value_bin); close(src_fd); return hash_value; } } /* This could become a common function for md5 as well, by using md5_stream */ static int hash_files(int argc, char **argv, const uint8_t hash_algo) { int return_value = EXIT_SUCCESS; uint8_t *hash_value; #ifdef CONFIG_FEATURE_MD5_SHA1_SUM_CHECK unsigned int flags; flags = bb_getopt_ulflags(argc, argv, "scw"); #endif #ifdef CONFIG_FEATURE_MD5_SHA1_SUM_CHECK if (!(flags & FLAG_CHECK)) { if (flags & FLAG_SILENT) { bb_error_msg_and_die ("the -s option is meaningful only when verifying checksums"); } else if (flags & FLAG_WARN) { bb_error_msg_and_die ("the -w option is meaningful only when verifying checksums"); } } #endif if (argc == optind) { argv[argc++] = "-"; } #ifdef CONFIG_FEATURE_MD5_SHA1_SUM_CHECK if (flags & FLAG_CHECK) { FILE *pre_computed_stream; int count_total = 0; int count_failed = 0; char *file_ptr = argv[optind]; char *line; if (optind + 1 != argc) { bb_error_msg_and_die ("only one argument may be specified when using -c"); } if (strcmp(file_ptr, "-") == 0) { pre_computed_stream = stdin; } else { pre_computed_stream = bb_xfopen(file_ptr, "r"); } while ((line = bb_get_chomped_line_from_file(pre_computed_stream)) != NULL) { char *filename_ptr; count_total++; filename_ptr = strstr(line, " "); if (filename_ptr == NULL) { if (flags & FLAG_WARN) { bb_error_msg("Invalid format"); } free(line); continue; } *filename_ptr = '\0'; filename_ptr += 2; hash_value = hash_file(filename_ptr, hash_algo); if (hash_value && (strcmp((char*)hash_value, line) == 0)) { if (!(flags & FLAG_SILENT)) printf("%s: OK\n", filename_ptr); } else { if (!(flags & FLAG_SILENT)) printf("%s: FAILED\n", filename_ptr); count_failed++; return_value = EXIT_FAILURE; } /* possible free(NULL) */ free(hash_value); free(line); } if (count_failed && !(flags & FLAG_SILENT)) { bb_error_msg("WARNING: %d of %d computed checksums did NOT match", count_failed, count_total); } if (bb_fclose_nonstdin(pre_computed_stream) == EOF) { bb_perror_msg_and_die("Couldnt close file %s", file_ptr); } } else #endif { uint8_t hash_length; if (hash_algo == HASH_MD5) { hash_length = 16; } else { hash_length = 20; } hash_value = xmalloc(hash_length); while (optind < argc) { char *file_ptr = argv[optind++]; hash_value = hash_file(file_ptr, hash_algo); if (hash_value == NULL) { return_value = EXIT_FAILURE; } else { printf("%s %s\n", hash_value, file_ptr); free(hash_value); } } } return (return_value); } #ifdef CONFIG_MD5SUM extern int md5sum_main(int argc, char **argv) { return(hash_files(argc, argv, HASH_MD5)); } #endif #ifdef CONFIG_SHA1SUM extern int sha1sum_main(int argc, char **argv) { return(hash_files(argc, argv, HASH_SHA1)); } #endif