diff options
author | Leah Rowe <leah@libreboot.org> | 2025-10-04 09:14:33 +0100 |
---|---|---|
committer | Leah Rowe <leah@libreboot.org> | 2025-10-04 09:20:12 +0100 |
commit | e9a910b33c7837b4b868e3abda18eb4810df7f02 (patch) | |
tree | 749e1830cb0607952df1a1afc0ae09ec1db54140 /util/sbase/dd.c | |
parent | 2cfaba181b3c68761871fa47b32725c934423c14 (diff) |
config/git: import suckless sbase
i currently use the output of sha512sum in several
places of xbmk, which is a bit unreliable in case
output changes.
other cases where i use util outputs in variables
are probably reliable, because i'm using mostly
posix utilities in those.
to mitigate this, i now import suckless sbase, which
has a reasonable sha512sum implementation.
*every* binary it builds is being placed in build.list,
because i'll probably start using more of them.
for example, i may start modifying the "date"
implementation, adding the GNU-specific options that
i need as mentioned on init.sh
i'm importing it in util/ because the sha512sum
util is needed for verifying project sources, so
if sbase itself is a "project source", that means
we can into a chicken and egg bootstrapping problem.
this is sbase at revision:
055cc1ae1b3a13c3d8f25af0a4a3316590efcd48
Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util/sbase/dd.c')
-rw-r--r-- | util/sbase/dd.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/util/sbase/dd.c b/util/sbase/dd.c new file mode 100644 index 00000000..36eb4094 --- /dev/null +++ b/util/sbase/dd.c @@ -0,0 +1,237 @@ +/* See LICENSE file for copyright and license details. */ +#include <ctype.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#include "util.h" + +static off_t ifull, ofull, ipart, opart; + +static void +usage(void) +{ + eprintf("usage: %s [operand...]\n", argv0); +} + +static size_t +parsesize(char *expr) +{ + char *s = expr; + size_t n = 1; + + for (;;) { + n *= strtoumax(s, &s, 10); + switch (*s) { + case 'k': n <<= 10; s++; break; + case 'b': n <<= 9; s++; break; + } + if (*s != 'x' || !s[1]) + break; + s++; + } + if (*s || n == 0) + eprintf("invalid block size expression '%s'\n", expr); + + return n; +} + +static void +bswap(unsigned char *buf, size_t len) +{ + int c; + + for (len &= ~1; len > 0; buf += 2, len -= 2) { + c = buf[0]; + buf[0] = buf[1]; + buf[1] = c; + } +} + +static void +lcase(unsigned char *buf, size_t len) +{ + for (; len > 0; buf++, len--) + buf[0] = tolower(buf[0]); +} + +static void +ucase(unsigned char *buf, size_t len) +{ + for (; len > 0; buf++, len--) + buf[0] = toupper(buf[0]); +} + +static void +summary(void) +{ + fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records in\n", (intmax_t)ifull, (intmax_t)ipart); + fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records out\n", (intmax_t)ofull, (intmax_t)opart); +} + +int +main(int argc, char *argv[]) +{ + enum { + LCASE = 1 << 0, + UCASE = 1 << 1, + SWAB = 1 << 2, + NOERROR = 1 << 3, + NOTRUNC = 1 << 4, + SYNC = 1 << 5, + } conv = 0; + char *arg, *val, *end; + const char *iname = "-", *oname = "-"; + int ifd = 0, ofd = 1, eof = 0; + size_t len, bs = 0, ibs = 512, obs = 512, ipos = 0, opos = 0; + off_t skip = 0, seek = 0, count = -1; + ssize_t ret; + unsigned char *buf; + + argv0 = argc ? (argc--, *argv++) : "dd"; + for (; argc > 0; argc--, argv++) { + arg = *argv; + val = strchr(arg, '='); + if (!val) + usage(); + *val++ = '\0'; + if (strcmp(arg, "if") == 0) { + iname = val; + } else if (strcmp(arg, "of") == 0) { + oname = val; + } else if (strcmp(arg, "ibs") == 0) { + ibs = parsesize(val); + } else if (strcmp(arg, "obs") == 0) { + obs = parsesize(val); + } else if (strcmp(arg, "bs") == 0) { + bs = parsesize(val); + } else if (strcmp(arg, "skip") == 0) { + skip = estrtonum(val, 0, LLONG_MAX); + } else if (strcmp(arg, "seek") == 0) { + seek = estrtonum(val, 0, LLONG_MAX); + } else if (strcmp(arg, "count") == 0) { + count = estrtonum(val, 0, LLONG_MAX); + } else if (strcmp(arg, "conv") == 0) { + do { + end = strchr(val, ','); + if (end) + *end++ = '\0'; + if (strcmp(val, "lcase") == 0) + conv |= LCASE; + else if (strcmp(val, "ucase") == 0) + conv |= UCASE; + else if (strcmp(val, "swab") == 0) + conv |= SWAB; + else if (strcmp(val, "noerror") == 0) + conv |= NOERROR; + else if (strcmp(val, "notrunc") == 0) + conv |= NOTRUNC; + else if (strcmp(val, "sync") == 0) + conv |= SYNC; + else + eprintf("unknown conv flag '%s'\n", val); + val = end; + } while (val); + } else { + weprintf("unknown operand '%s'\n", arg); + usage(); + } + } + + if (bs) + ibs = obs = bs; + if (strcmp(iname, "-") != 0) { + ifd = open(iname, O_RDONLY); + if (ifd < 0) + eprintf("open %s:", iname); + } + if (strcmp(oname, "-") != 0) { + ofd = open(oname, O_WRONLY | O_CREAT | (conv & NOTRUNC || seek ? 0 : O_TRUNC), 0666); + if (ofd < 0) + eprintf("open %s:", oname); + } + + len = MAX(ibs, obs) + ibs; + buf = emalloc(len); + if (skip && lseek(ifd, skip * ibs, SEEK_SET) < 0) { + while (skip--) { + ret = read(ifd, buf, ibs); + if (ret < 0) + eprintf("read:"); + if (ret == 0) { + eof = 1; + break; + } + } + } + if (seek) { + if (!(conv & NOTRUNC) && ftruncate(ofd, seek * ibs) != 0) + eprintf("ftruncate:"); + if (lseek(ofd, seek * ibs, SEEK_SET) < 0) + eprintf("lseek:"); + /* XXX: handle non-seekable files */ + } + while (!eof) { + while (ipos - opos < obs) { + if (ifull + ipart == count) { + eof = 1; + break; + } + ret = read(ifd, buf + ipos, ibs); + if (ret == 0) { + eof = 1; + break; + } + if (ret < 0) { + weprintf("read:"); + if (!(conv & NOERROR)) + return 1; + summary(); + if (!(conv & SYNC)) + continue; + ret = 0; + } + if (ret < ibs) { + ipart++; + if (conv & SYNC) { + memset(buf + ipos + ret, 0, ibs - ret); + ret = ibs; + } + } else { + ifull++; + } + if (conv & SWAB) + bswap(buf + ipos, ret); + if (conv & LCASE) + lcase(buf + ipos, ret); + if (conv & UCASE) + ucase(buf + ipos, ret); + ipos += ret; + if (bs && !(conv & (SWAB | LCASE | UCASE))) + break; + } + if (ipos == opos) + break; + do { + ret = write(ofd, buf + opos, MIN(obs, ipos - opos)); + if (ret < 0) + eprintf("write:"); + if (ret == 0) + eprintf("write returned 0\n"); + if (ret < obs) + opart++; + else + ofull++; + opos += ret; + } while (ipos - opos >= (eof ? 1 : obs)); + if (opos < ipos) + memmove(buf, buf + opos, ipos - opos); + ipos -= opos; + opos = 0; + } + summary(); + + return 0; +} |