diff options
| -rw-r--r-- | util/nvmutil/Makefile | 12 | ||||
| -rw-r--r-- | util/nvmutil/nvmutil.c | 391 | ||||
| -rw-r--r-- | util/spkmodem_recv/spkmodem-recv.c | 123 |
3 files changed, 361 insertions, 165 deletions
diff --git a/util/nvmutil/Makefile b/util/nvmutil/Makefile index bef6f28c..719e1c1e 100644 --- a/util/nvmutil/Makefile +++ b/util/nvmutil/Makefile @@ -1,9 +1,10 @@ # SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2022,2026 Leah Rowe <leah@libreboot.org> -# SPDX-FileCopyrightText: 2023 Riku Viitanen <riku.viitanen@protonmail.com> +# Copyright (c) 2022,2026 Leah Rowe <leah@libreboot.org> +# Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com> CC?=cc CFLAGS?=-Os -Wall -Wextra -Werror -pedantic -std=c90 +LDFLAGS?= DESTDIR?= PREFIX?=/usr/local INSTALL?=install @@ -13,11 +14,12 @@ PROG=nvmutil all: $(PROG) $(PROG): nvmutil.c - $(CC) $(CFLAGS) nvmutil.c -o $(PROG) + $(CC) $(CFLAGS) $(LDFLAGS) nvmutil.c -o $(PROG) install: $(PROG) - mkdir -p $(DESTDIR)$(PREFIX)/bin/ - install $(PROG) $(DESTDIR)$(PREFIX)/bin/ + $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin + $(INSTALL) $(PROG) $(DESTDIR)$(PREFIX)/bin/$(PROG) + chmod 755 $(DESTDIR)$(PREFIX)/bin/$(PROG) uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/$(PROG) diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index 68e041a3..b718ac6e 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -12,9 +12,138 @@ * * Recommended CFLAGS for Clang/GCC: * - * -Os -Wall -Wextra -Werror -pedantic -std=c99 + * -Os -Wall -Wextra -Werror -pedantic -std=c90 */ +/* + * Major TODO: split this into multiple files. + * This program has become quite large now, mostly + * due to all the extra sanity checks / portability. + * Make most of nvmutil a *library* for re-use + * + * TODO: gettimeofday not posible - use portable functions. + * TODO: uint32_t fallback: modify the program instead + * to run on 16-bit systems: smaller buffers, and do + * operations byte-based instead of word-based. + * + * TODO: _XOPEN_SOURCE 500 probably not needed anymore. + * the portable fallbacks alone are likely enough. + * e.g. i don't need stdint, and i don't use pwrite/pread + * anymore. + * + * TODO: version detection of various BSDs to detect + * arc4random, use that if available. but also work on + * older versions of those BSDs (also MacOS) that lack it. + * + * TODO: portability/testing on non-Unix systems: + * old DOS. all windows versions (probably irrelevant + * because you can use cygwin/wsl, whatever), classic MacOS, + * also test really old unix e.g. sunos and irix. Be/Haiku too! + * + * TODO: reliance on global variables for status. make + * functions use structs passed as args instead, make + * functions re-useable (including libraries), etc. + * + * TODO: bound checks for files per-command, e.g. only + * first 6 bytes for CMD_SETMAC + * + * TODO: clean up the do_rw function: make PSCHREIB and + * so on clearer, probably just define them inline and + * validate them inline (no define). + * TODO: in command sanitizer: verify that each given + * entry corresponds to the correct function, in the + * pointer (this check is currently missing) + * + * TODO: general modularisierung of the entire codebase. + * TODO: better explain copy/swap read inversion trick + * by improving existing comments + * TODO: lots of overwritten comments in code. tidy it up. + * + * TODO: use getopt for nvmutil args, so that multiple + * operations can be performed, and also on many + * files at once (noting limitations with cat) + * BONUS: implement own getopt(), for portability + * + * TODO: document fuzzing / static analysis methods + * for the code, and: + * TODO: implement rigorous unit tests (separate util) + * NOTE: this would *include* known good test files + * in various configurations, also invalid files. + * the tests would likely be portable posix shell + * scripts rather than a new C program, but a modularisiert + * codebase would allow me to write a separate C + * program to test some finer intricacies + * TODO: the unit tests would basically test regressions + * TODO: after writing back a gbe to file, close() and + * open() it again, read it again, and check that + * the contents were written correctly, providing + * a warning if they were. do this in the main + * program. + * TODO: the unit tests would include an aggressive set + * of fuzz tests, under controlled conditions + * + * TODO: also document the layout of Intel GbE files, so + * that wily individuals can easily expand the + * featureset of nvmutil. + * TODO: remove some clever code, e.g.: + * rw_type == PLESEN << 2 + * make stuff like that clearer. + * ditto the invert copy/swap trick + * TODO: write a manpage + * TODO: simplify the command sanitization, implement more + * of it as build time checks, e.g. static asserts. + * generally remove cleverness from the code, instead + * prefyerring readibility + * TODO: also document nvmutil's coding style, which is + * its own style at this point! + * TODO: when all the above (and possibly more) is done, + * submit this tool to coreboot with a further change + * to their build system that lets users modify + * GbE images, especially set MAC addresses, when + * including GbE files in coreboot configs. + */ +/* + BONUS TODO: + CI/CD. woodpecker is good enough, sourcehut also has one. + tie this in with other things mentioned here, + e.g. fuzzer / unit tests +*/ + +/* Major TODO: reproducible builds +Test with and without these: + +CFLAGS += -fno-record-gcc-switches +CFLAGS += -ffile-prefix-map=$(PWD)=. +CFLAGS += -fdebug-prefix-map=$(PWD)=. + +I already avoid unique timestamps per-build, +by not using them, e.g. not reporting build +time in the program. + +When splitting the nvmutil.c file later, do e.g.: + +SRC = main.c io.c nvm.c cmd.c +OBJ = $(SRC:.c=.o) + +^ explicitly declare the order in which to build +*/ + +/* +TODO: +further note when fuzzing is implemented: +use deterministic randomisation, with a +guaranteed seed - so e.g. don't use /dev/urandom +in test builds. e.g. just use normal rand() +but with a static seed e.g. 1234 +*/ +/* +TODO: stricter build flags, e.g. +CFLAGS += -fstack-protector-strong +CFLAGS += -fno-common +CFLAGS += -D_FORTIFY_SOURCE=2 +CFLAGS += -fPIE +*/ + #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif @@ -27,6 +156,7 @@ #include <sys/param.h> #endif #include <sys/types.h> +#include <sys/time.h> #include <sys/stat.h> #include <errno.h> @@ -51,6 +181,7 @@ typedef unsigned int uint32_t; #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> typedef char static_assert_char_is_8_bits[(CHAR_BIT == 8) ? 1 : -1]; @@ -161,6 +292,8 @@ static void set_mac_nib(size_t mac_str_pos, size_t mac_byte_pos, size_t mac_nib_pos); static uint16_t hextonum(char ch_s); static uint16_t rhex(void); +static uint16_t fallback_rand(void); +static unsigned long entropy_jitter(void); static void write_mac_part(size_t partnum); /* @@ -211,6 +344,8 @@ static off_t gbe_x_offset(size_t part, const char *f_op, const char *d_type, off_t nsize, off_t ncmp); static ssize_t rw_file_exact(int fd, uint8_t *mem, size_t len, off_t off, int rw_type); +static ssize_t rw_file_once(int fd, uint8_t *mem, size_t len, + off_t off, int rw_type, size_t rc); static ssize_t do_rw(int fd, uint8_t *mem, size_t len, off_t off, int rw_type); static ssize_t prw(int fd, void *mem, size_t nrw, @@ -223,7 +358,6 @@ static off_t lseek_eintr(int fd, off_t off, int whence); static void err(int nvm_errval, const char *msg, ...); static void close_files(void); static const char *getnvmprogname(void); -static void set_err_if_unset(int errval); static void usage(uint8_t usage_exit); /* @@ -261,7 +395,6 @@ static void usage(uint8_t usage_exit); #define items(x) (sizeof((x)) / sizeof((x)[0])) static const char newrandom[] = "/dev/urandom"; -static const char oldrandom[] = "/dev/random"; /* fallback on OLD unix */ static const char *rname = NULL; /* @@ -435,6 +568,8 @@ static size_t cmd_index = CMD_NULL; typedef char assert_argc3[(ARGC_3==3)?1:-1]; typedef char assert_argc4[(ARGC_4==4)?1:-1]; +static int use_prng = 0; + int main(int argc, char *argv[]) { @@ -448,8 +583,8 @@ main(int argc, char *argv[]) #ifdef NVMUTIL_UNVEIL if (pledge("stdio rpath wpath unveil", NULL) == -1) err(errno, "pledge"); - if (unveil("/dev/null", "r") == -1) - err(errno, "unveil '/dev/null'"); + if (unveil("/dev/urandom", "r") == -1) + err(errno, "unveil /dev/urandom"); #else if (pledge("stdio rpath wpath", NULL) == -1) err(errno, "pledge"); @@ -503,20 +638,13 @@ main(int argc, char *argv[]) read_gbe_file(); read_checksums(); - errno = 0; run_cmd(cmd_index); - if (errno && (!(part_valid[0] || part_valid[1]))) - err(errno, "%s: Unhandled error (WRITE SKIPPED)", fname); - if (command[cmd_index].flags == O_RDWR) write_gbe_file(); close_files(); - if (errno) - err(errno, "Unhandled error on exit"); - return EXIT_SUCCESS; } @@ -714,7 +842,7 @@ xstrxcmp(const char *a, const char *b, size_t maxlen) /* * Should never reach here. This keeps compilers happy. */ - set_err_if_unset(EINVAL); + errno = EINVAL; return -1; } @@ -722,26 +850,13 @@ static void open_dev_urandom(void) { rname = newrandom; - urandom_fd = open(rname, O_RDONLY | O_BINARY | O_NONBLOCK); + urandom_fd = open(rname, O_RDONLY); if (urandom_fd != -1) return; - /* - * Fall back to /dev/random on very old Unix. - * - * We must reset errno, to remove stale state - * set by reading /dev/urandom - */ - - fprintf(stderr, "Can't open %s (will use %s instead)\n", - newrandom, oldrandom); - - errno = 0; - - rname = oldrandom; - urandom_fd = open(rname, O_RDONLY | O_BINARY | O_NONBLOCK); - if (urandom_fd == -1) - err(errno, "%s: could not open", rname); + /* fallback on VERY VERY VERY old unix */ + use_prng = 1; + srand((unsigned)(time(NULL) ^ getpid())); } static void @@ -837,14 +952,11 @@ read_checksums(void) ++num_invalid; } - if (num_invalid < max_invalid) - errno = 0; - if (num_invalid >= max_invalid) { if (max_invalid == 1) - err(EINVAL, "%s: part %lu has a bad checksum", + err(ECANCELED, "%s: part %lu has a bad checksum", fname, (unsigned long)part); - err(EINVAL, "%s: No valid checksum found in file", + err(ECANCELED, "%s: No valid checksum found in file", fname); } } @@ -858,7 +970,6 @@ good_checksum(size_t partnum) if (current_checksum == expected_checksum) return 1; - set_err_if_unset(EINVAL); return 0; } @@ -874,7 +985,7 @@ static void check_command_num(size_t c) { if (!valid_command(c)) - err(errno, "Invalid run_cmd arg: %lu", + err(EINVAL, "Invalid run_cmd arg: %lu", (unsigned long)c); } @@ -1022,16 +1133,72 @@ rhex(void) static size_t n = 0; static uint8_t rnum[12]; + if (use_prng) { + /* + * On very old Unix systems that + * lack /dev/random and /dev/urandom + */ + return fallback_rand(); + } + + if (urandom_fd < 0) + err(ECANCELED, "Your operating system has no /dev/[u]random"); + if (!n) { n = sizeof(rnum); if (rw_file_exact(urandom_fd, rnum, n, 0, LESEN) == -1) err(errno, "Randomisation failed"); - errno = 0; } return (uint16_t)(rnum[--n] & 0xf); } +static uint16_t +fallback_rand(void) +{ + struct timeval tv; + unsigned long mix; + static unsigned long counter = 0; + + gettimeofday(&tv, NULL); + + mix = (unsigned long)tv.tv_sec + ^ (unsigned long)tv.tv_usec + ^ (unsigned long)getpid() + ^ (unsigned long)&mix + ^ counter++ + ^ entropy_jitter(); + + /* + * Stack addresses can vary between + * calls, thus increasing entropy. + */ + mix ^= (unsigned long)&mix; + mix ^= (unsigned long)&tv; + mix ^= (unsigned long)&counter; + + return (uint16_t)(mix & 0xf); +} + +static unsigned long +entropy_jitter(void) +{ + struct timeval a, b; + unsigned long mix = 0; + int i; + + for (i = 0; i < 8; i++) { + gettimeofday(&a, NULL); + getpid(); + gettimeofday(&b, NULL); + + mix ^= (unsigned long)(b.tv_usec - a.tv_usec); + mix ^= (unsigned long)&mix; + } + + return mix; +} + static void write_mac_part(size_t partnum) { @@ -1057,9 +1224,6 @@ cmd_helper_dump(void) part_valid[0] = good_checksum(0); part_valid[1] = good_checksum(1); - if (part_valid[0] || part_valid[1]) - errno = 0; - for (partnum = 0; partnum < 2; partnum++) { if (!part_valid[partnum]) fprintf(stderr, @@ -1079,9 +1243,10 @@ static void print_mac_from_nvm(size_t partnum) { size_t c; + uint16_t val16; for (c = 0; c < 3; c++) { - uint16_t val16 = nvm_word(c, partnum); + val16 = nvm_word(c, partnum); printf("%02x:%02x", val16 & 0xff, val16 >> 8); if (c == 2) printf("\n"); @@ -1155,19 +1320,7 @@ gbe_cat_buf(uint8_t *b) if (errno != EAGAIN) err(errno, "stdout: cat"); - - /* - * We assume that no data - * was written to stdout. - */ - errno = 0; } - - /* - * No errors here. - * Avoid the warning in main() - */ - errno = 0; } static void @@ -1331,8 +1484,6 @@ rw_gbe_file_part(size_t p, int rw_type, rw_type) == -1) err(errno, "%s: %s: part %lu", fname, rw_type_str, (unsigned long)p); - - errno = 0; } /* @@ -1402,41 +1553,89 @@ gbe_x_offset(size_t p, const char *f_op, const char *d_type, * be used on sockets or pipes, because 0-byte * reads are treated like fatal errors. This * means that EOF is also considered fatal. + * + * WARNING: Do not use O_APPEND on open() when + * using this function. If you do, POSIX allows + * write() to ignore the current file offset and + * write at EOF, which means that our use of + * lseek in prw() does not guarantee writing at + * a specified offset. So if using PSCHREIB or + * PLESEN, make sure not to pass a file descriptor + * with the O_APPEND flag. Alternatively, modify + * do_rw() to directly use pwrite() and pread() + * instead of prw(). */ static ssize_t rw_file_exact(int fd, uint8_t *mem, size_t len, off_t off, int rw_type) { - ssize_t rval = 0; - size_t rc = 0; + ssize_t rv; + size_t rc; if (fd < 0 || !len || len > (size_t)SSIZE_MAX) { - set_err_if_unset(EIO); + errno = EIO; return -1; } - while (rc < len) { - rval = do_rw(fd, mem + rc, len - rc, off + rc, rw_type); - - if (rval < 0 && errno == EINTR) { - continue; - } else if (rval < 0) { - set_err_if_unset(EIO); - return -1; - } - if ((size_t)rval > (len - rc) /* Prevent overflow */ - || rval == 0) { /* Prevent infinite 0-byte loop */ - set_err_if_unset(EIO); + for (rc = 0, rv = 0; rc < len; rc += (size_t)rv) { + if ((rv = rw_file_once(fd, mem, len, off, rw_type, rc)) == -1) return -1; - } - - rc += (size_t)rval; } return rc; } static ssize_t +rw_file_once(int fd, uint8_t *mem, size_t len, + off_t off, int rw_type, size_t rc) +{ + ssize_t rv; + size_t retries_on_zero = 0; + size_t max_retries = 10; + +read_again: + rv = do_rw(fd, mem + rc, len - rc, off + rc, rw_type); + + if (rv < 0 && errno == EINTR) { + goto read_again; + } else if (rv < 0) { + errno = EIO; + return -1; + } + + /* + * Theoretical bug: if a buggy libc returned + * a size larger than SSIZE_MAX, the cast may + * cause an overflow. Specifications guarantee + * this won't happen, but spec != implementation + */ + if ((size_t)rv > SSIZE_MAX) { + errno = EIO; + return -1; + /* we will not tolerate your buggy libc */ + } + + if ((size_t)rv > (len - rc) /* Prevent overflow */ + || rv == 0) { /* Prevent infinite 0-byte loop */ + if (rv == 0) { + /* + * Fault tolerance against infinite + * zero-byte loop: re-try a finite + * number of times. This mitigates + * otherwise OK but slow filesystems + * e.g. NFS or slow media. + */ + if (retries_on_zero++ < max_retries) + goto read_again; + } + errno = EIO; + return -1; + } + + return rv; +} + +static ssize_t do_rw(int fd, uint8_t *mem, size_t len, off_t off, int rw_type) { @@ -1449,7 +1648,7 @@ do_rw(int fd, uint8_t *mem, if (rw_type == PLESEN || rw_type == PSCHREIB) return prw(fd, mem, len, off, rw_type); - set_err_if_unset(EINVAL); + errno = EINVAL; return -1; } @@ -1507,23 +1706,12 @@ err(int nvm_errval, const char *msg, ...) { va_list args; - /* - * We need to ensure that files are closed - * on exit, including error exits. This - * would otherwise recurse, because the - * close_files() function also calls err(), - * but with -1 on nvm_errval. It's the only - * one that does this. - * - * Since the errval is for setting errno, -1 - * would be incorrect. Therefore, set_err_if_unset() - * avoids overriding errno if the given value - * is negative. - * - * Be careful modifying err() and close_files(). - */ - if (nvm_errval != -1) + if (nvm_errval >= 0) { close_files(); + errno = nvm_errval; + } + if (errno <= 0) + errno = ECANCELED; fprintf(stderr, "%s: ", getnvmprogname()); @@ -1531,7 +1719,6 @@ err(int nvm_errval, const char *msg, ...) vfprintf(stderr, msg, args); va_end(args); - set_err_if_unset(nvm_errval); fprintf(stderr, ": %s", strerror(errno)); fprintf(stderr, "\n"); @@ -1570,26 +1757,6 @@ getnvmprogname(void) return argv0; } -/* - * Set errno only if it hasn't already been set. - * This prevents overriding real libc errors. - * - * We use errno for regular program state, while - * being careful not to clobber what was set by - * real libc function, or a minority of our stub - * functions such as prw() - */ -static void -set_err_if_unset(int x) -{ - if (errno) - return; - if (x > 0) - errno = x; - else - errno = ECANCELED; -} - static void usage(uint8_t usage_exit) { diff --git a/util/spkmodem_recv/spkmodem-recv.c b/util/spkmodem_recv/spkmodem-recv.c index d448c84b..48b06527 100644 --- a/util/spkmodem_recv/spkmodem-recv.c +++ b/util/spkmodem_recv/spkmodem-recv.c @@ -1,11 +1,24 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* SPDX-FileCopyrightText: 2013 Free Software Foundation, Inc. */ -/* Usage: parec --channels=1 --rate=48000 --format=s16le | ./spkmodem-recv */ - -/* Forked from coreboot's version, at util/spkmodem_recv/ in coreboot.git, - * revision 5c2b5fcf2f9c9259938fd03cfa3ea06b36a007f0 as of 3 January 2022. - * This version is heavily modified, re-written based on OpenBSD Kernel Source - * File Style Guide (KNF); this change is Copyright 2023,2026 Leah Rowe. */ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2013 Free Software Foundation, Inc. + * Copyright (c) 2023, 2026 Leah Rowe <leah@libreboot.org> + * + * This program receives text encoded as pulses on the PC speaker, + * and decodes them. This is a special type of interface provided + * by coreboot and GRUB, for computers that lack serial ports. + * + * Usage example (NOTE: little endian!): + * parec --channels=1 --rate=48000 --format=s16le | ./spkmodem-recv + * + * Originally provided by GNU GRUB, this version is a heavily + * modified fork that complies with the OpenBSD Kernel Source + * File Style Guide (KNF) instead of GNU coding standards; it + * emphasises strict error handling, portability and code + * quality, as characterised by OpenBSD projects. + * + * This fork of spkmodem-recv is provided with Libreboot releases: + * https://libreboot.org/ + */ #define _POSIX_SOURCE @@ -61,10 +74,12 @@ struct decoder_state { unsigned char ascii; int debug; + int swap_bytes; }; static const char *argv0; +static int host_is_big_endian(void); static void handle_audio(struct decoder_state *st); static int valid_signal(struct decoder_state *st); static void decode_pulse(struct decoder_state *st); @@ -84,10 +99,6 @@ extern int optind; extern int opterr; extern int optopt; -#ifndef errno -extern int errno; -#endif - int main(int argc, char **argv) { @@ -110,15 +121,15 @@ main(int argc, char **argv) argv0 = argv[0]; while ((c = getopt(argc, argv, "d")) != -1) { - switch (c) { - case 'd': - st.debug = 1; - break; - default: + if (c != 'd') usage(); - } + st.debug = 1; + break; } + if (host_is_big_endian()) + st.swap_bytes = 1; + setvbuf(stdout, NULL, _IONBF, 0); for (;;) @@ -127,6 +138,13 @@ main(int argc, char **argv) return EXIT_SUCCESS; } +static int +host_is_big_endian(void) +{ + unsigned int x = 1; + return (*(unsigned char *)&x == 0); +} + static void handle_audio(struct decoder_state *st) { @@ -134,20 +152,17 @@ handle_audio(struct decoder_state *st) if (st->sample_count > (3 * SAMPLES_PER_FRAME)) reset_char(st); + if (!valid_signal(st)) { + decode_pulse(st); + return; + } - if (valid_signal(st)) { - - if (set_ascii_bit(st) < 0) - print_char(st); - - st->sample_count = 0; - - for (sample = 0; sample < SAMPLES_PER_FRAME; sample++) - decode_pulse(st); + if (set_ascii_bit(st) < 0) + print_char(st); - } else { + st->sample_count = 0; + for (sample = 0; sample < SAMPLES_PER_FRAME; sample++) decode_pulse(st); - } } static int @@ -164,28 +179,35 @@ decode_pulse(struct decoder_state *st) { unsigned char old_ring, old_sep; unsigned char new_pulse; + int ringpos; + signed short sample; - old_ring = st->pulse[st->ringpos]; + ringpos = st->ringpos; + + old_ring = st->pulse[ringpos]; old_sep = st->pulse[st->sep_pos]; st->freq_data -= old_ring; st->freq_data += old_sep; st->freq_separator -= old_sep; - st->frame[st->ringpos] = read_sample(st); + sample = read_sample(st); + st->frame[ringpos] = sample; - if (st->frame[st->ringpos] > THRESHOLD || - st->frame[st->ringpos] < -THRESHOLD) + if ((unsigned)(sample + THRESHOLD) + > (unsigned)(2 * THRESHOLD)) new_pulse = 1; else new_pulse = 0; - st->pulse[st->ringpos] = new_pulse; + st->pulse[ringpos] = new_pulse; st->freq_separator += new_pulse; - st->ringpos++; - if (st->ringpos >= MAX_SAMPLES) - st->ringpos = 0; + ringpos++; + if (ringpos >= MAX_SAMPLES) + ringpos = 0; + + st->ringpos = ringpos; st->sep_pos++; if (st->sep_pos >= MAX_SAMPLES) @@ -198,6 +220,8 @@ static signed short read_sample(struct decoder_state *st) { size_t n; + signed short sample; + unsigned short u; while (st->inpos >= st->inlen) { @@ -205,16 +229,26 @@ read_sample(struct decoder_state *st) READ_BUF, stdin); if (n == 0) { + if (ferror(stdin)) + err(errno, "stdin read"); if (feof(stdin)) exit(EXIT_SUCCESS); - err(errno, "stdin read"); } st->inpos = 0; st->inlen = n; } - return st->inbuf[st->inpos++]; + sample = st->inbuf[st->inpos++]; + + if (st->swap_bytes) { + u = (unsigned short)sample; + u = (u >> 8) | (u << 8); + + sample = (signed short)u; + } + + return sample; } static int @@ -222,12 +256,10 @@ set_ascii_bit(struct decoder_state *st) { if (st->debug) print_stats(st); - if (st->freq_data < FREQ_DATA_THRESHOLD) st->ascii |= (1 << st->ascii_bit); st->ascii_bit--; - return st->ascii_bit; } @@ -247,9 +279,7 @@ print_stats(struct decoder_state *st) { long pos; - pos = ftell(stdin); - - if (pos == -1) { + if ((pos = ftell(stdin)) == -1) { printf("%d %d %d\n", st->freq_data, st->freq_separator, @@ -282,10 +312,7 @@ err(int errval, const char *msg, ...) vfprintf(stderr, msg, ap); va_end(ap); - if (!errno) - errno = errval; - - fprintf(stderr, ": %s\n", strerror(errno)); + fprintf(stderr, ": %s\n", strerror(errval)); exit(EXIT_FAILURE); } |
