diff -uNr a/keksum/io.c b/keksum/io.c --- a/keksum/io.c dca3567c27d22156d45bdbb018961469ec4ca2af26ed7efa3d060cc237088f1b3fb8bb2df50b627b8f0f24c1d1d7cd56f497d0f9f5a1330b8549c15d5ac76910 +++ b/keksum/io.c 86ff171be9d92e83b6de31f07902fad1d524ced59b796e6e3de2cbd230897e81a90fdc71a69ab667677f10b7d613b190688c223b7559c90505681b6fa3257350 @@ -8,6 +8,7 @@ #include #include "io.h" +/* Write exactly len bytes from buf to fd, or die trying. */ void write_all(int fd, char const *buf, size_t len) { while (len) { ssize_t n = write(fd,buf,len); @@ -22,15 +23,16 @@ } } -size_t read_all(int fd, unsigned char *buf, size_t len) { +/* Read exactly len bytes from fd into buf, returning a short count only on EOF. + * On error, returns -1 and sets errno. */ +ssize_t read_all(int fd, unsigned char *buf, size_t len) { size_t olen = len; while (len) { ssize_t n = read(fd,buf,len); if (n <= 0) { if (n) { if (errno == EINTR) continue; - perr("read_all"); - _exit(errno); + return -1; } break; } diff -uNr a/keksum/io.h b/keksum/io.h --- a/keksum/io.h 64b3c8a8989834995dc2aa33bb1075a1dd53e8cb4f0e97847aaf8a8e2798f7b538d65af16bf656bf46de11126282b8c225f484df1e023123cb2b2437e5c7d676 +++ b/keksum/io.h 52f1007d12f5b605eb41509a12c799078020faf8b98202120321a1eec55c33b343670efc646c03baf0891b6f51aeb0ee4d76b11b9d08a496a60f963601ac665e @@ -1,7 +1,7 @@ -#include +#include void write_all(int fd, char const *buf, size_t len); -size_t read_all(int fd, unsigned char *buf, size_t len); +ssize_t read_all(int fd, unsigned char *buf, size_t len); void write_str(int fd, char const *s); void newline(int fd); void write_line(int fd, char const *s); diff -uNr a/keksum/keccak.c b/keksum/keccak.c --- a/keksum/keccak.c 2d36c51a50632358041e360e0be17f698bc87dd8ca2bdfed48731991905444b0b687f11930d612a9debb3bdfc49439292e6695f2db05c04b92299ba6791b0c7f +++ b/keksum/keccak.c 95fa68388a2b12bf22bbea2f42b65b9e95bbd70388b26d2dc75c051f07ffe3ef9dbb09255bc8ffca114352889a5a8ad88b940ff2e782712a1b4d46dc7382831a @@ -253,8 +253,10 @@ write_all(1,buf,2*len); } -/* Stream octets from stdin until EOF, then write hex to stdout. */ -void sponge(unsigned capacity, size_t out_bits) { +/* Stream octets from stdin until EOF, then write hex to stdout. + * On success, returns 0. + * On read error, returns -1 and sets errno. */ +int sponge(unsigned capacity, size_t out_bits) { static uint8_t buf[B/8]; unsigned rate = B - capacity, len = rate/8, @@ -267,7 +269,14 @@ /* absorb */ reset(); - while ((n = read_all(0,buf,len)) == len) { + for (;;) { + ssize_t nread = read_all(0,buf,len); + if (nread != len) { + if (nread < 0) return -1; /* read error */ + /* else, end of file */ + n = nread; + break; + } load(buf,len); keccakf(); } @@ -292,6 +301,7 @@ keccakf(); } extract(out_len); + return 0; } #ifdef TEST diff -uNr a/keksum/main.c b/keksum/main.c --- a/keksum/main.c d96e2cc71f3cad83002590418a194953719eab457b4084c05ccd4cd5b9051e6a2eef08581054451dd17f5558257473881434fdb90678e840fdfb63df03352f0a +++ b/keksum/main.c 294be705c083b166c4aa10f3ea8a6333633af013374c5886d8e26db6ff45fba04e4b47c3a08857589130cd2c2c8ddb5415059ffb42f302c660614c701fa4db01 @@ -7,12 +7,12 @@ #include #include "io.h" -void sponge(unsigned capacity, size_t out_bits); +int sponge(unsigned capacity, size_t out_bits); #pragma GCC diagnostic ignored "-Woverlength-strings" /* wat. */ static char const usage[] = -"Usage: keksum [-c] [-sCAPACITY] [-nLENGTH] [-h] [--] [FILE]...\n" +"Usage: keksum [-sCAPACITY] [-lLENGTH] [-h] [--] [FILE]...\n" "Compute KECCAK checksums.\n" "\n" "With no FILE, act as a filter, reading from standard input then printing\n" @@ -20,7 +20,6 @@ "name for each FILE.\n" "\n" "Options:\n" -" -c read sums from FILEs and check them (TODO)\n" " -l set output length in bits (default 512)\n" " -s set sponge capacity in bits (default 256)\n" " -h print this help and exit\n" @@ -99,21 +98,36 @@ usage_err("Capacity out of range"); if (argc) { + int status = 0; + /* Listing is similar to the GNU (?) format but with no input * mode character (you may know this as the mysterious extra * space): it's always binary. */ for (; argc; SHIFT) { - int fd = chkp(*argv, open(*argv, O_RDONLY)); + int fd = open(*argv, O_RDONLY); + if (fd == -1) { + perr(*argv); + status = 1; + continue; + } chkp("dup2", dup2(fd,0)); chkp("close", close(fd)); - sponge(capacity,out_len); + if (sponge(capacity,out_len) == -1) { + perr(*argv); + status = 1; + continue; + } write_str(1," "); write_line(1,*argv); } + return status; } else { - sponge(capacity,out_len); + if (sponge(capacity,out_len) == -1) { + perr("read"); + return 1; + } newline(1); + return 0; } - return 0; } diff -uNr a/keksum/manifest b/keksum/manifest --- a/keksum/manifest bd1aec53bfa5828bce3f2058d8c3eefb87e29f2e269180a81a11beb2b83feb1e2f668116470390f10a41c393ba9b487fbd38a175633251ce27a7223f99824b70 +++ b/keksum/manifest 61ecfe7760cfb2333d926e8915f90dee52b2f1222016d6af8dfd2c73af3d9eeca6b3dfec3c677e5a5baa6d11928f7731b9d451110e8d9ca8953e93aa8ce4296c @@ -1 +1,2 @@ 640981 keksum_subdir_genesis jfw Initial release (redone from keksum_genesis_3 to follow project subdir and manifest naming conventions) (redone from keksum_genesis for default capacity and test) +832286 keksum_error_recovery_and_usage jfw Continue to next file rather than aborting on open or read errors. Fix glaring typo for the length option in the usage synopsis, and remove the tease about a -c option to check against a reference hash listing, which isn't planned to be done any time soon.