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 or later, see the file LICENSE in this tarball. 14 */ 15 16#include "libbb.h" 17 18enum { SUM_BSD, PRINT_NAME, SUM_SYSV }; 19 20/* BSD: calculate and print the rotated checksum and the size in 1K blocks 21 The checksum varies depending on sizeof (int). */ 22/* SYSV: calculate and print the checksum and the size in 512-byte blocks */ 23/* Return 1 if successful. */ 24static unsigned sum_file(const char *file, const unsigned type) 25{ 26#define buf bb_common_bufsiz1 27 uintmax_t total_bytes = 0; 28 int fd = 0, r; 29 30 /* The sum of all the input bytes, modulo (UINT_MAX + 1). */ 31 unsigned s = 0; 32 33 if (NOT_LONE_DASH(file)) { 34 fd = open(file, O_RDONLY); 35 if (fd == -1) 36 goto ret_bad; 37 } 38 39 while (1) { 40 size_t bytes_read = safe_read(fd, buf, BUFSIZ); 41 42 if ((ssize_t)bytes_read <= 0) { 43 r = (fd && close(fd) != 0); 44 if (!bytes_read && !r) 45 /* no error */ 46 break; 47 ret_bad: 48 bb_perror_msg(file); 49 return 0; 50 } 51 52 total_bytes += bytes_read; 53 if (type >= SUM_SYSV) { 54 do s += buf[--bytes_read]; while (bytes_read); 55 } else { 56 r = 0; 57 do { 58 s = (s >> 1) + ((s & 1) << 15); 59 s += buf[r++]; 60 s &= 0xffff; /* Keep it within bounds. */ 61 } while (--bytes_read); 62 } 63 } 64 65 if (type < PRINT_NAME) 66 file = ""; 67 if (type >= SUM_SYSV) { 68 r = (s & 0xffff) + ((s & 0xffffffff) >> 16); 69 s = (r & 0xffff) + (r >> 16); 70 printf("%d %ju %s\n", s, (total_bytes+511)/512, file); 71 } else 72 printf("%05d %5ju %s\n", s, (total_bytes+1023)/1024, file); 73 return 1; 74#undef buf 75} 76 77int sum_main(int argc, char **argv); 78int sum_main(int argc, char **argv) 79{ 80 unsigned n; 81 unsigned type = SUM_BSD; 82 83 n = getopt32(argv, "sr"); 84 if (n & 1) type = SUM_SYSV; 85 /* give the bsd priority over sysv func */ 86 if (n & 2) type = SUM_BSD; 87 88 if (argc == optind) { 89 /* Do not print the name */ 90 n = sum_file("-", type); 91 } else { 92 /* Need to print the name if either 93 - more than one file given 94 - doing sysv */ 95 type += argc - 1 > optind || type == SUM_SYSV; 96 for (n = 1; optind < argc; optind++) 97 n &= sum_file(argv[optind], type); 98 } 99 return !n; 100} 101