summaryrefslogtreecommitdiff
path: root/util/sbase/dd.c
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2025-10-04 09:14:33 +0100
committerLeah Rowe <leah@libreboot.org>2025-10-04 09:20:12 +0100
commite9a910b33c7837b4b868e3abda18eb4810df7f02 (patch)
tree749e1830cb0607952df1a1afc0ae09ec1db54140 /util/sbase/dd.c
parent2cfaba181b3c68761871fa47b32725c934423c14 (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.c237
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;
+}