summaryrefslogtreecommitdiff
path: root/util/sbase/libutil
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/libutil
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/libutil')
-rw-r--r--util/sbase/libutil/concat.c23
-rw-r--r--util/sbase/libutil/confirm.c22
-rw-r--r--util/sbase/libutil/cp.c176
-rw-r--r--util/sbase/libutil/crypt.c184
-rw-r--r--util/sbase/libutil/ealloc.c88
-rw-r--r--util/sbase/libutil/enmasse.c38
-rw-r--r--util/sbase/libutil/eprintf.c57
-rw-r--r--util/sbase/libutil/eregcomp.c27
-rw-r--r--util/sbase/libutil/estrtod.c18
-rw-r--r--util/sbase/libutil/fnck.c22
-rw-r--r--util/sbase/libutil/fshut.c43
-rw-r--r--util/sbase/libutil/getlines.c32
-rw-r--r--util/sbase/libutil/human.c25
-rw-r--r--util/sbase/libutil/linecmp.c17
-rw-r--r--util/sbase/libutil/md5.c148
-rw-r--r--util/sbase/libutil/memmem.c66
-rw-r--r--util/sbase/libutil/mkdirp.c39
-rw-r--r--util/sbase/libutil/mode.c152
-rw-r--r--util/sbase/libutil/parseoffset.c61
-rw-r--r--util/sbase/libutil/putword.c16
-rw-r--r--util/sbase/libutil/reallocarray.c56
-rw-r--r--util/sbase/libutil/recurse.c108
-rw-r--r--util/sbase/libutil/rm.c49
-rw-r--r--util/sbase/libutil/sha1.c144
-rw-r--r--util/sbase/libutil/sha224.c26
-rw-r--r--util/sbase/libutil/sha256.c154
-rw-r--r--util/sbase/libutil/sha384.c26
-rw-r--r--util/sbase/libutil/sha512-224.c26
-rw-r--r--util/sbase/libutil/sha512-256.c26
-rw-r--r--util/sbase/libutil/sha512.c175
-rw-r--r--util/sbase/libutil/strcasestr.c38
-rw-r--r--util/sbase/libutil/strlcat.c63
-rw-r--r--util/sbase/libutil/strlcpy.c59
-rw-r--r--util/sbase/libutil/strnsubst.c61
-rw-r--r--util/sbase/libutil/strsep.c37
-rw-r--r--util/sbase/libutil/strtonum.c85
-rw-r--r--util/sbase/libutil/unescape.c58
-rw-r--r--util/sbase/libutil/writeall.c21
38 files changed, 2466 insertions, 0 deletions
diff --git a/util/sbase/libutil/concat.c b/util/sbase/libutil/concat.c
new file mode 100644
index 00000000..2e9aa521
--- /dev/null
+++ b/util/sbase/libutil/concat.c
@@ -0,0 +1,23 @@
+/* See LICENSE file for copyright and license details. */
+#include <unistd.h>
+
+#include "../util.h"
+
+int
+concat(int f1, const char *s1, int f2, const char *s2)
+{
+ char buf[BUFSIZ];
+ ssize_t n;
+
+ while ((n = read(f1, buf, sizeof(buf))) > 0) {
+ if (writeall(f2, buf, n) < 0) {
+ weprintf("write %s:", s2);
+ return -2;
+ }
+ }
+ if (n < 0) {
+ weprintf("read %s:", s1);
+ return -1;
+ }
+ return 0;
+}
diff --git a/util/sbase/libutil/confirm.c b/util/sbase/libutil/confirm.c
new file mode 100644
index 00000000..44396af9
--- /dev/null
+++ b/util/sbase/libutil/confirm.c
@@ -0,0 +1,22 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "../util.h"
+
+int
+confirm(const char *fmt, ...)
+{
+ int c, ans;
+ va_list ap;
+
+ va_start(ap, fmt);
+ xvprintf(fmt, ap);
+ va_end(ap);
+
+ c = getchar();
+ ans = (c == 'y' || c == 'Y');
+ while (c != '\n' && c != EOF)
+ c = getchar();
+ return ans;
+}
diff --git a/util/sbase/libutil/cp.c b/util/sbase/libutil/cp.c
new file mode 100644
index 00000000..2ab32a03
--- /dev/null
+++ b/util/sbase/libutil/cp.c
@@ -0,0 +1,176 @@
+/* See LICENSE file for copyright and license details. */
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include "../fs.h"
+#include "../util.h"
+
+int cp_aflag = 0;
+int cp_fflag = 0;
+int cp_iflag = 0;
+int cp_pflag = 0;
+int cp_rflag = 0;
+int cp_vflag = 0;
+int cp_status = 0;
+int cp_follow;
+
+int
+cp(const char *s1, const char *s2, int depth)
+{
+ DIR *dp;
+ int f1, f2, flags = 0;
+ struct dirent *d;
+ struct stat st;
+ struct timespec times[2];
+ ssize_t r;
+ char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX];
+
+ if (cp_follow == 'P' || (cp_follow == 'H' && depth))
+ flags |= AT_SYMLINK_NOFOLLOW;
+
+ if (fstatat(AT_FDCWD, s1, &st, flags) < 0) {
+ weprintf("stat %s:", s1);
+ cp_status = 1;
+ return 0;
+ }
+
+ if (cp_iflag && access(s2, F_OK) == 0) {
+ if (!confirm("overwrite '%s'? ", s2))
+ return 0;
+ }
+
+ if (cp_vflag)
+ printf("%s -> %s\n", s1, s2);
+
+ if (S_ISLNK(st.st_mode)) {
+ if ((r = readlink(s1, target, sizeof(target) - 1)) >= 0) {
+ target[r] = '\0';
+ if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
+ weprintf("unlink %s:", s2);
+ cp_status = 1;
+ return 0;
+ } else if (symlink(target, s2) < 0) {
+ weprintf("symlink %s -> %s:", s2, target);
+ cp_status = 1;
+ return 0;
+ }
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ if (!cp_rflag) {
+ weprintf("%s is a directory\n", s1);
+ cp_status = 1;
+ return 0;
+ }
+ if (!(dp = opendir(s1))) {
+ weprintf("opendir %s:", s1);
+ cp_status = 1;
+ return 0;
+ }
+ if (mkdir(s2, st.st_mode) < 0 && errno != EEXIST) {
+ weprintf("mkdir %s:", s2);
+ cp_status = 1;
+ closedir(dp);
+ return 0;
+ }
+
+ while ((d = readdir(dp))) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ estrlcpy(ns1, s1, sizeof(ns1));
+ if (s1[strlen(s1) - 1] != '/')
+ estrlcat(ns1, "/", sizeof(ns1));
+ estrlcat(ns1, d->d_name, sizeof(ns1));
+
+ estrlcpy(ns2, s2, sizeof(ns2));
+ if (s2[strlen(s2) - 1] != '/')
+ estrlcat(ns2, "/", sizeof(ns2));
+ estrlcat(ns2, d->d_name, sizeof(ns2));
+
+ fnck(ns1, ns2, cp, depth + 1);
+ }
+
+ closedir(dp);
+ } else if (cp_aflag && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) ||
+ S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode))) {
+ if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
+ weprintf("unlink %s:", s2);
+ cp_status = 1;
+ return 0;
+ } else if (mknod(s2, st.st_mode, st.st_rdev) < 0) {
+ weprintf("mknod %s:", s2);
+ cp_status = 1;
+ return 0;
+ }
+ } else {
+ if ((f1 = open(s1, O_RDONLY)) < 0) {
+ weprintf("open %s:", s1);
+ cp_status = 1;
+ return 0;
+ }
+ if ((f2 = creat(s2, st.st_mode)) < 0 && cp_fflag) {
+ if (unlink(s2) < 0 && errno != ENOENT) {
+ weprintf("unlink %s:", s2);
+ cp_status = 1;
+ close(f1);
+ return 0;
+ }
+ f2 = creat(s2, st.st_mode);
+ }
+ if (f2 < 0) {
+ weprintf("creat %s:", s2);
+ cp_status = 1;
+ close(f1);
+ return 0;
+ }
+ if (concat(f1, s1, f2, s2) < 0) {
+ cp_status = 1;
+ close(f1);
+ close(f2);
+ return 0;
+ }
+
+ close(f1);
+ close(f2);
+ }
+
+ if (cp_aflag || cp_pflag) {
+ /* atime and mtime */
+ times[0] = st.st_atim;
+ times[1] = st.st_mtim;
+ if (utimensat(AT_FDCWD, s2, times, AT_SYMLINK_NOFOLLOW) < 0) {
+ weprintf("utimensat %s:", s2);
+ cp_status = 1;
+ }
+
+ /* owner and mode */
+ if (!S_ISLNK(st.st_mode)) {
+ if (chown(s2, st.st_uid, st.st_gid) < 0) {
+ weprintf("chown %s:", s2);
+ cp_status = 1;
+ st.st_mode &= ~(S_ISUID | S_ISGID);
+ }
+ if (chmod(s2, st.st_mode) < 0) {
+ weprintf("chmod %s:", s2);
+ cp_status = 1;
+ }
+ } else {
+ if (lchown(s2, st.st_uid, st.st_gid) < 0) {
+ weprintf("lchown %s:", s2);
+ cp_status = 1;
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/util/sbase/libutil/crypt.c b/util/sbase/libutil/crypt.c
new file mode 100644
index 00000000..e285614b
--- /dev/null
+++ b/util/sbase/libutil/crypt.c
@@ -0,0 +1,184 @@
+/* See LICENSE file for copyright and license details. */
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../crypt.h"
+#include "../text.h"
+#include "../util.h"
+
+static int
+hexdec(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1; /* unknown character */
+}
+
+static int
+mdcheckline(const char *s, uint8_t *md, size_t sz)
+{
+ size_t i;
+ int b1, b2;
+
+ for (i = 0; i < sz; i++) {
+ if (!*s || (b1 = hexdec(*s++)) < 0)
+ return -1; /* invalid format */
+ if (!*s || (b2 = hexdec(*s++)) < 0)
+ return -1; /* invalid format */
+ if ((uint8_t)((b1 << 4) | b2) != md[i])
+ return 0; /* value mismatch */
+ }
+ return (i == sz) ? 1 : 0;
+}
+
+static void
+mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t *md, size_t sz,
+ int *formatsucks, int *noread, int *nonmatch)
+{
+ int fd;
+ size_t bufsiz = 0;
+ int r;
+ char *line = NULL, *file, *p;
+
+ while (getline(&line, &bufsiz, listfp) > 0) {
+ if (!(file = strstr(line, " "))) {
+ (*formatsucks)++;
+ continue;
+ }
+ if ((file - line) / 2 != sz) {
+ (*formatsucks)++; /* checksum length mismatch */
+ continue;
+ }
+ *file = '\0';
+ file += 2;
+ for (p = file; *p && *p != '\n' && *p != '\r'; p++); /* strip newline */
+ *p = '\0';
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ weprintf("open %s:", file);
+ (*noread)++;
+ continue;
+ }
+ if (cryptsum(ops, fd, file, md)) {
+ (*noread)++;
+ continue;
+ }
+ r = mdcheckline(line, md, sz);
+ if (r == 1) {
+ printf("%s: OK\n", file);
+ } else if (r == 0) {
+ printf("%s: FAILED\n", file);
+ (*nonmatch)++;
+ } else {
+ (*formatsucks)++;
+ }
+ close(fd);
+ }
+ free(line);
+}
+
+int
+cryptcheck(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
+{
+ FILE *fp;
+ int formatsucks = 0, noread = 0, nonmatch = 0, ret = 0;
+
+ if (argc == 0) {
+ mdchecklist(stdin, ops, md, sz, &formatsucks, &noread, &nonmatch);
+ } else {
+ for (; *argv; argc--, argv++) {
+ if ((*argv)[0] == '-' && !(*argv)[1]) {
+ fp = stdin;
+ } else if (!(fp = fopen(*argv, "r"))) {
+ weprintf("fopen %s:", *argv);
+ ret = 1;
+ continue;
+ }
+ mdchecklist(fp, ops, md, sz, &formatsucks, &noread, &nonmatch);
+ if (fp != stdin)
+ fclose(fp);
+ }
+ }
+
+ if (formatsucks) {
+ weprintf("%d lines are improperly formatted\n", formatsucks);
+ ret = 1;
+ }
+ if (noread) {
+ weprintf("%d listed file could not be read\n", noread);
+ ret = 1;
+ }
+ if (nonmatch) {
+ weprintf("%d computed checksums did NOT match\n", nonmatch);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+int
+cryptmain(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
+{
+ int fd;
+ int ret = 0;
+
+ if (argc == 0) {
+ if (cryptsum(ops, 0, "<stdin>", md))
+ ret = 1;
+ else
+ mdprint(md, "<stdin>", sz);
+ } else {
+ for (; *argv; argc--, argv++) {
+ if ((*argv)[0] == '-' && !(*argv)[1]) {
+ *argv = "<stdin>";
+ fd = 0;
+ } else if ((fd = open(*argv, O_RDONLY)) < 0) {
+ weprintf("open %s:", *argv);
+ ret = 1;
+ continue;
+ }
+ if (cryptsum(ops, fd, *argv, md))
+ ret = 1;
+ else
+ mdprint(md, *argv, sz);
+ if (fd != 0)
+ close(fd);
+ }
+ }
+
+ return ret;
+}
+
+int
+cryptsum(struct crypt_ops *ops, int fd, const char *f, uint8_t *md)
+{
+ uint8_t buf[BUFSIZ];
+ ssize_t n;
+
+ ops->init(ops->s);
+ while ((n = read(fd, buf, sizeof(buf))) > 0)
+ ops->update(ops->s, buf, n);
+ if (n < 0) {
+ weprintf("%s: read error:", f);
+ return 1;
+ }
+ ops->sum(ops->s, md);
+ return 0;
+}
+
+void
+mdprint(const uint8_t *md, const char *f, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ printf("%02x", md[i]);
+ printf(" %s\n", f);
+}
diff --git a/util/sbase/libutil/ealloc.c b/util/sbase/libutil/ealloc.c
new file mode 100644
index 00000000..320865da
--- /dev/null
+++ b/util/sbase/libutil/ealloc.c
@@ -0,0 +1,88 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdlib.h>
+#include <string.h>
+
+#include "../util.h"
+
+void *
+ecalloc(size_t nmemb, size_t size)
+{
+ return encalloc(1, nmemb, size);
+}
+
+void *
+emalloc(size_t size)
+{
+ return enmalloc(1, size);
+}
+
+void *
+erealloc(void *p, size_t size)
+{
+ return enrealloc(1, p, size);
+}
+
+char *
+estrdup(const char *s)
+{
+ return enstrdup(1, s);
+}
+
+char *
+estrndup(const char *s, size_t n)
+{
+ return enstrndup(1, s, n);
+}
+
+void *
+encalloc(int status, size_t nmemb, size_t size)
+{
+ void *p;
+
+ p = calloc(nmemb, size);
+ if (!p)
+ enprintf(status, "calloc: out of memory\n");
+ return p;
+}
+
+void *
+enmalloc(int status, size_t size)
+{
+ void *p;
+
+ p = malloc(size);
+ if (!p)
+ enprintf(status, "malloc: out of memory\n");
+ return p;
+}
+
+void *
+enrealloc(int status, void *p, size_t size)
+{
+ p = realloc(p, size);
+ if (!p)
+ enprintf(status, "realloc: out of memory\n");
+ return p;
+}
+
+char *
+enstrdup(int status, const char *s)
+{
+ char *p;
+
+ p = strdup(s);
+ if (!p)
+ enprintf(status, "strdup: out of memory\n");
+ return p;
+}
+
+char *
+enstrndup(int status, const char *s, size_t n)
+{
+ char *p;
+
+ p = strndup(s, n);
+ if (!p)
+ enprintf(status, "strndup: out of memory\n");
+ return p;
+}
diff --git a/util/sbase/libutil/enmasse.c b/util/sbase/libutil/enmasse.c
new file mode 100644
index 00000000..a2e225ab
--- /dev/null
+++ b/util/sbase/libutil/enmasse.c
@@ -0,0 +1,38 @@
+/* See LICENSE file for copyright and license details. */
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "../util.h"
+
+void
+enmasse(int argc, char *argv[], int (*fn)(const char *, const char *, int))
+{
+ struct stat st;
+ char buf[PATH_MAX], *dir;
+ int i, len;
+ size_t dlen;
+
+ if (argc == 2 && !(stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode))) {
+ fnck(argv[0], argv[1], fn, 0);
+ return;
+ } else {
+ dir = (argc == 1) ? "." : argv[--argc];
+ }
+
+ for (i = 0; i < argc; i++) {
+ dlen = strlen(dir);
+ if (dlen > 0 && dir[dlen - 1] == '/')
+ len = snprintf(buf, sizeof(buf), "%s%s", dir, basename(argv[i]));
+ else
+ len = snprintf(buf, sizeof(buf), "%s/%s", dir, basename(argv[i]));
+ if (len < 0 || len >= sizeof(buf)) {
+ eprintf("%s/%s: filename too long\n", dir,
+ basename(argv[i]));
+ }
+ fnck(argv[i], buf, fn, 0);
+ }
+}
diff --git a/util/sbase/libutil/eprintf.c b/util/sbase/libutil/eprintf.c
new file mode 100644
index 00000000..7197fbb9
--- /dev/null
+++ b/util/sbase/libutil/eprintf.c
@@ -0,0 +1,57 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../util.h"
+
+char *argv0;
+
+void
+eprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xvprintf(fmt, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
+void
+enprintf(int status, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xvprintf(fmt, ap);
+ va_end(ap);
+
+ exit(status);
+}
+
+void
+weprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xvprintf(fmt, ap);
+ va_end(ap);
+}
+
+void
+xvprintf(const char *fmt, va_list ap)
+{
+ if (argv0 && strncmp(fmt, "usage", strlen("usage")))
+ fprintf(stderr, "%s: ", argv0);
+
+ vfprintf(stderr, fmt, ap);
+
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ }
+}
diff --git a/util/sbase/libutil/eregcomp.c b/util/sbase/libutil/eregcomp.c
new file mode 100644
index 00000000..02c8698c
--- /dev/null
+++ b/util/sbase/libutil/eregcomp.c
@@ -0,0 +1,27 @@
+#include <sys/types.h>
+
+#include <regex.h>
+#include <stdio.h>
+
+#include "../util.h"
+
+int
+enregcomp(int status, regex_t *preg, const char *regex, int cflags)
+{
+ char errbuf[BUFSIZ] = "";
+ int r;
+
+ if ((r = regcomp(preg, regex, cflags)) == 0)
+ return r;
+
+ regerror(r, preg, errbuf, sizeof(errbuf));
+ enprintf(status, "invalid regex: %s\n", errbuf);
+
+ return r;
+}
+
+int
+eregcomp(regex_t *preg, const char *regex, int cflags)
+{
+ return enregcomp(1, preg, regex, cflags);
+}
diff --git a/util/sbase/libutil/estrtod.c b/util/sbase/libutil/estrtod.c
new file mode 100644
index 00000000..24e4fdce
--- /dev/null
+++ b/util/sbase/libutil/estrtod.c
@@ -0,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../util.h"
+
+double
+estrtod(const char *s)
+{
+ char *end;
+ double d;
+
+ d = strtod(s, &end);
+ if (end == s || *end != '\0')
+ eprintf("%s: not a real number\n", s);
+ return d;
+}
diff --git a/util/sbase/libutil/fnck.c b/util/sbase/libutil/fnck.c
new file mode 100644
index 00000000..4f8875ba
--- /dev/null
+++ b/util/sbase/libutil/fnck.c
@@ -0,0 +1,22 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/stat.h>
+
+#include "../util.h"
+
+void
+fnck(const char *a, const char *b,
+ int (*fn)(const char *, const char *, int), int depth)
+{
+ struct stat sta, stb;
+
+ if (!stat(a, &sta)
+ && !stat(b, &stb)
+ && sta.st_dev == stb.st_dev
+ && sta.st_ino == stb.st_ino) {
+ weprintf("%s -> %s: same file\n", a, b);
+ return;
+ }
+
+ if (fn(a, b, depth) < 0)
+ eprintf("%s -> %s:", a, b);
+}
diff --git a/util/sbase/libutil/fshut.c b/util/sbase/libutil/fshut.c
new file mode 100644
index 00000000..e596f074
--- /dev/null
+++ b/util/sbase/libutil/fshut.c
@@ -0,0 +1,43 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../util.h"
+
+int
+fshut(FILE *fp, const char *fname)
+{
+ int ret = 0;
+
+ /* fflush() is undefined for input streams by ISO C,
+ * but not POSIX 2008 if you ignore ISO C overrides.
+ * Leave it unchecked and rely on the following
+ * functions to detect errors.
+ */
+ fflush(fp);
+
+ if (ferror(fp) && !ret) {
+ weprintf("ferror %s:", fname);
+ ret = 1;
+ }
+
+ if (fclose(fp) && !ret) {
+ weprintf("fclose %s:", fname);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+void
+enfshut(int status, FILE *fp, const char *fname)
+{
+ if (fshut(fp, fname))
+ exit(status);
+}
+
+void
+efshut(FILE *fp, const char *fname)
+{
+ enfshut(1, fp, fname);
+}
diff --git a/util/sbase/libutil/getlines.c b/util/sbase/libutil/getlines.c
new file mode 100644
index 00000000..cef9a612
--- /dev/null
+++ b/util/sbase/libutil/getlines.c
@@ -0,0 +1,32 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../text.h"
+#include "../util.h"
+
+void
+getlines(FILE *fp, struct linebuf *b)
+{
+ char *line = NULL;
+ size_t size = 0, linelen = 0;
+ ssize_t len;
+
+ while ((len = getline(&line, &size, fp)) > 0) {
+ if (++b->nlines > b->capacity) {
+ b->capacity += 512;
+ b->lines = ereallocarray(b->lines, b->capacity, sizeof(*b->lines));
+ }
+ linelen = len;
+ b->lines[b->nlines - 1].data = memcpy(emalloc(linelen + 1), line, linelen + 1);
+ b->lines[b->nlines - 1].len = linelen;
+ }
+ free(line);
+ if (b->lines && b->nlines && linelen && b->lines[b->nlines - 1].data[linelen - 1] != '\n') {
+ b->lines[b->nlines - 1].data = erealloc(b->lines[b->nlines - 1].data, linelen + 2);
+ b->lines[b->nlines - 1].data[linelen] = '\n';
+ b->lines[b->nlines - 1].data[linelen + 1] = '\0';
+ b->lines[b->nlines - 1].len++;
+ }
+}
diff --git a/util/sbase/libutil/human.c b/util/sbase/libutil/human.c
new file mode 100644
index 00000000..7e39ba5f
--- /dev/null
+++ b/util/sbase/libutil/human.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "../util.h"
+
+char *
+humansize(off_t n)
+{
+ static char buf[16];
+ const char postfixes[] = "BKMGTPE";
+ double size;
+ int i;
+
+ for (size = n, i = 0; size >= 1024 && i < strlen(postfixes); i++)
+ size /= 1024;
+
+ if (!i)
+ snprintf(buf, sizeof(buf), "%ju", (uintmax_t)n);
+ else
+ snprintf(buf, sizeof(buf), "%.1f%c", size, postfixes[i]);
+
+ return buf;
+}
diff --git a/util/sbase/libutil/linecmp.c b/util/sbase/libutil/linecmp.c
new file mode 100644
index 00000000..08fc0e3a
--- /dev/null
+++ b/util/sbase/libutil/linecmp.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <string.h>
+
+#include "../text.h"
+#include "../util.h"
+
+int
+linecmp(struct line *a, struct line *b)
+{
+ int res = 0;
+
+ if (!(res = memcmp(a->data, b->data, MIN(a->len, b->len))))
+ res = a->len - b->len;
+
+ return res;
+}
diff --git a/util/sbase/libutil/md5.c b/util/sbase/libutil/md5.c
new file mode 100644
index 00000000..c7483ac6
--- /dev/null
+++ b/util/sbase/libutil/md5.c
@@ -0,0 +1,148 @@
+/* public domain md5 implementation based on rfc1321 and libtomcrypt */
+#include <stdint.h>
+#include <string.h>
+
+#include "../md5.h"
+
+static uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define G(x,y,z) (y ^ (z & (y ^ x)))
+#define H(x,y,z) (x ^ y ^ z)
+#define I(x,y,z) (y ^ (x | ~z))
+#define FF(a,b,c,d,w,s,t) a += F(b,c,d) + w + t; a = rol(a,s) + b
+#define GG(a,b,c,d,w,s,t) a += G(b,c,d) + w + t; a = rol(a,s) + b
+#define HH(a,b,c,d,w,s,t) a += H(b,c,d) + w + t; a = rol(a,s) + b
+#define II(a,b,c,d,w,s,t) a += I(b,c,d) + w + t; a = rol(a,s) + b
+
+static const uint32_t tab[64] = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+static void
+processblock(struct md5 *s, const uint8_t *buf)
+{
+ uint32_t i, W[16], a, b, c, d;
+
+ for (i = 0; i < 16; i++) {
+ W[i] = buf[4*i];
+ W[i] |= (uint32_t)buf[4*i+1]<<8;
+ W[i] |= (uint32_t)buf[4*i+2]<<16;
+ W[i] |= (uint32_t)buf[4*i+3]<<24;
+ }
+
+ a = s->h[0];
+ b = s->h[1];
+ c = s->h[2];
+ d = s->h[3];
+
+ i = 0;
+ while (i < 16) {
+ FF(a,b,c,d, W[i], 7, tab[i]); i++;
+ FF(d,a,b,c, W[i], 12, tab[i]); i++;
+ FF(c,d,a,b, W[i], 17, tab[i]); i++;
+ FF(b,c,d,a, W[i], 22, tab[i]); i++;
+ }
+ while (i < 32) {
+ GG(a,b,c,d, W[(5*i+1)%16], 5, tab[i]); i++;
+ GG(d,a,b,c, W[(5*i+1)%16], 9, tab[i]); i++;
+ GG(c,d,a,b, W[(5*i+1)%16], 14, tab[i]); i++;
+ GG(b,c,d,a, W[(5*i+1)%16], 20, tab[i]); i++;
+ }
+ while (i < 48) {
+ HH(a,b,c,d, W[(3*i+5)%16], 4, tab[i]); i++;
+ HH(d,a,b,c, W[(3*i+5)%16], 11, tab[i]); i++;
+ HH(c,d,a,b, W[(3*i+5)%16], 16, tab[i]); i++;
+ HH(b,c,d,a, W[(3*i+5)%16], 23, tab[i]); i++;
+ }
+ while (i < 64) {
+ II(a,b,c,d, W[7*i%16], 6, tab[i]); i++;
+ II(d,a,b,c, W[7*i%16], 10, tab[i]); i++;
+ II(c,d,a,b, W[7*i%16], 15, tab[i]); i++;
+ II(b,c,d,a, W[7*i%16], 21, tab[i]); i++;
+ }
+
+ s->h[0] += a;
+ s->h[1] += b;
+ s->h[2] += c;
+ s->h[3] += d;
+}
+
+static void
+pad(struct md5 *s)
+{
+ unsigned r = s->len % 64;
+
+ s->buf[r++] = 0x80;
+ if (r > 56) {
+ memset(s->buf + r, 0, 64 - r);
+ r = 0;
+ processblock(s, s->buf);
+ }
+ memset(s->buf + r, 0, 56 - r);
+ s->len *= 8;
+ s->buf[56] = s->len;
+ s->buf[57] = s->len >> 8;
+ s->buf[58] = s->len >> 16;
+ s->buf[59] = s->len >> 24;
+ s->buf[60] = s->len >> 32;
+ s->buf[61] = s->len >> 40;
+ s->buf[62] = s->len >> 48;
+ s->buf[63] = s->len >> 56;
+ processblock(s, s->buf);
+}
+
+void
+md5_init(void *ctx)
+{
+ struct md5 *s = ctx;
+ s->len = 0;
+ s->h[0] = 0x67452301;
+ s->h[1] = 0xefcdab89;
+ s->h[2] = 0x98badcfe;
+ s->h[3] = 0x10325476;
+}
+
+void
+md5_sum(void *ctx, uint8_t md[MD5_DIGEST_LENGTH])
+{
+ struct md5 *s = ctx;
+ int i;
+
+ pad(s);
+ for (i = 0; i < 4; i++) {
+ md[4*i] = s->h[i];
+ md[4*i+1] = s->h[i] >> 8;
+ md[4*i+2] = s->h[i] >> 16;
+ md[4*i+3] = s->h[i] >> 24;
+ }
+}
+
+void
+md5_update(void *ctx, const void *m, unsigned long len)
+{
+ struct md5 *s = ctx;
+ const uint8_t *p = m;
+ unsigned r = s->len % 64;
+
+ s->len += len;
+ if (r) {
+ if (len < 64 - r) {
+ memcpy(s->buf + r, p, len);
+ return;
+ }
+ memcpy(s->buf + r, p, 64 - r);
+ len -= 64 - r;
+ p += 64 - r;
+ processblock(s, s->buf);
+ }
+ for (; len >= 64; len -= 64, p += 64)
+ processblock(s, p);
+ memcpy(s->buf, p, len);
+}
diff --git a/util/sbase/libutil/memmem.c b/util/sbase/libutil/memmem.c
new file mode 100644
index 00000000..7dfef34b
--- /dev/null
+++ b/util/sbase/libutil/memmem.c
@@ -0,0 +1,66 @@
+/* $OpenBSD: memmem.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
+
+/*
+ * Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "../util.h"
+
+/*
+ * Find the first occurrence of the byte string s in byte string l.
+ */
+
+void *
+memmem(const void *l, size_t l_len, const void *s, size_t s_len)
+{
+ const char *cur, *last;
+ const char *cl = l;
+ const char *cs = s;
+
+ /* a zero length needle should just return the haystack */
+ if (s_len == 0)
+ return (void *)cl;
+
+ /* "s" must be smaller or equal to "l" */
+ if (l_len < s_len)
+ return NULL;
+
+ /* special case where s_len == 1 */
+ if (s_len == 1)
+ return memchr(l, *cs, l_len);
+
+ /* the last position where its possible to find "s" in "l" */
+ last = cl + l_len - s_len;
+
+ for (cur = cl; cur <= last; cur++)
+ if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
+ return (void *)cur;
+
+ return NULL;
+}
diff --git a/util/sbase/libutil/mkdirp.c b/util/sbase/libutil/mkdirp.c
new file mode 100644
index 00000000..c3c678c0
--- /dev/null
+++ b/util/sbase/libutil/mkdirp.c
@@ -0,0 +1,39 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <limits.h>
+
+#include "../util.h"
+
+int
+mkdirp(const char *path, mode_t mode, mode_t pmode)
+{
+ char tmp[PATH_MAX], *p;
+ struct stat st;
+
+ if (stat(path, &st) == 0) {
+ if (S_ISDIR(st.st_mode))
+ return 0;
+ errno = ENOTDIR;
+ weprintf("%s:", path);
+ return -1;
+ }
+
+ estrlcpy(tmp, path, sizeof(tmp));
+ for (p = tmp + (tmp[0] == '/'); *p; p++) {
+ if (*p != '/')
+ continue;
+ *p = '\0';
+ if (mkdir(tmp, pmode) < 0 && errno != EEXIST) {
+ weprintf("mkdir %s:", tmp);
+ return -1;
+ }
+ *p = '/';
+ }
+ if (mkdir(tmp, mode) < 0 && errno != EEXIST) {
+ weprintf("mkdir %s:", tmp);
+ return -1;
+ }
+ return 0;
+}
diff --git a/util/sbase/libutil/mode.c b/util/sbase/libutil/mode.c
new file mode 100644
index 00000000..2754be79
--- /dev/null
+++ b/util/sbase/libutil/mode.c
@@ -0,0 +1,152 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "../util.h"
+
+mode_t
+getumask(void)
+{
+ mode_t mask = umask(0);
+ umask(mask);
+ return mask;
+}
+
+mode_t
+parsemode(const char *str, mode_t mode, mode_t mask)
+{
+ char *end;
+ const char *p = str;
+ int octal, op;
+ mode_t who, perm, clear;
+
+ octal = strtol(str, &end, 8);
+ if (*end == '\0') {
+ if (octal < 0 || octal > 07777)
+ eprintf("%s: invalid mode\n", str);
+ return octal;
+ }
+next:
+ /* first, determine which bits we will be modifying */
+ for (who = 0; *p; p++) {
+ switch (*p) {
+ /* masks */
+ case 'u':
+ who |= S_IRWXU|S_ISUID;
+ continue;
+ case 'g':
+ who |= S_IRWXG|S_ISGID;
+ continue;
+ case 'o':
+ who |= S_IRWXO|S_ISVTX;
+ continue;
+ case 'a':
+ who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO|S_ISVTX;
+ continue;
+ }
+ break;
+ }
+ if (who) {
+ clear = who;
+ } else {
+ clear = S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
+ who = ~mask;
+ }
+ while (*p) {
+ switch (*p) {
+ /* opers */
+ case '=':
+ case '+':
+ case '-':
+ op = (int)*p;
+ break;
+ default:
+ eprintf("%s: invalid mode\n", str);
+ }
+
+ perm = 0;
+ switch (*++p) {
+ /* copy */
+ case 'u':
+ if (mode & S_IRUSR)
+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
+ if (mode & S_IWUSR)
+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+ if (mode & S_IXUSR)
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ if (mode & S_ISUID)
+ perm |= S_ISUID|S_ISGID;
+ p++;
+ break;
+ case 'g':
+ if (mode & S_IRGRP)
+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
+ if (mode & S_IWGRP)
+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+ if (mode & S_IXGRP)
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ if (mode & S_ISGID)
+ perm |= S_ISUID|S_ISGID;
+ p++;
+ break;
+ case 'o':
+ if (mode & S_IROTH)
+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
+ if (mode & S_IWOTH)
+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+ if (mode & S_IXOTH)
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ p++;
+ break;
+ default:
+ for (; *p; p++) {
+ switch (*p) {
+ /* modes */
+ case 'r':
+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
+ break;
+ case 'w':
+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+ break;
+ case 'x':
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ break;
+ case 'X':
+ if (S_ISDIR(mode) || mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ break;
+ case 's':
+ perm |= S_ISUID|S_ISGID;
+ break;
+ case 't':
+ perm |= S_ISVTX;
+ break;
+ default:
+ goto apply;
+ }
+ }
+ }
+
+apply:
+ /* apply */
+ switch (op) {
+ case '=':
+ mode &= ~clear;
+ /* fallthrough */
+ case '+':
+ mode |= perm & who;
+ break;
+ case '-':
+ mode &= ~(perm & who);
+ break;
+ }
+ /* if we hit a comma, move on to the next clause */
+ if (*p == ',') {
+ p++;
+ goto next;
+ }
+ }
+ return mode & ~S_IFMT;
+}
diff --git a/util/sbase/libutil/parseoffset.c b/util/sbase/libutil/parseoffset.c
new file mode 100644
index 00000000..362a7829
--- /dev/null
+++ b/util/sbase/libutil/parseoffset.c
@@ -0,0 +1,61 @@
+/* See LICENSE file for copyright and license details. */
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../util.h"
+
+off_t
+parseoffset(const char *str)
+{
+ off_t res, scale = 1;
+ char *end;
+
+ /* strictly check what strtol() usually would let pass */
+ if (!str || !*str || isspace(*str) || *str == '+' || *str == '-') {
+ weprintf("parseoffset %s: invalid value\n", str);
+ return -1;
+ }
+
+ errno = 0;
+ res = strtol(str, &end, 0);
+ if (errno) {
+ weprintf("parseoffset %s: invalid value\n", str);
+ return -1;
+ }
+ if (res < 0) {
+ weprintf("parseoffset %s: negative value\n", str);
+ return -1;
+ }
+
+ /* suffix */
+ if (*end) {
+ switch (toupper((int)*end)) {
+ case 'B':
+ scale = 512L;
+ break;
+ case 'K':
+ scale = 1024L;
+ break;
+ case 'M':
+ scale = 1024L * 1024L;
+ break;
+ case 'G':
+ scale = 1024L * 1024L * 1024L;
+ break;
+ default:
+ weprintf("parseoffset %s: invalid suffix '%s'\n", str, end);
+ return -1;
+ }
+ }
+
+ /* prevent overflow */
+ if (res > (SSIZE_MAX / scale)) {
+ weprintf("parseoffset %s: out of range\n", str);
+ return -1;
+ }
+
+ return res * scale;
+}
diff --git a/util/sbase/libutil/putword.c b/util/sbase/libutil/putword.c
new file mode 100644
index 00000000..80a9860a
--- /dev/null
+++ b/util/sbase/libutil/putword.c
@@ -0,0 +1,16 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+
+#include "../util.h"
+
+void
+putword(FILE *fp, const char *s)
+{
+ static int first = 1;
+
+ if (!first)
+ fputc(' ', fp);
+
+ fputs(s, fp);
+ first = 0;
+}
diff --git a/util/sbase/libutil/reallocarray.c b/util/sbase/libutil/reallocarray.c
new file mode 100644
index 00000000..31ff6c31
--- /dev/null
+++ b/util/sbase/libutil/reallocarray.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "../util.h"
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(optr, size * nmemb);
+}
+
+void *
+ereallocarray(void *optr, size_t nmemb, size_t size)
+{
+ return enreallocarray(1, optr, nmemb, size);
+}
+
+void *
+enreallocarray(int status, void *optr, size_t nmemb, size_t size)
+{
+ void *p;
+
+ if (!(p = reallocarray(optr, nmemb, size)))
+ enprintf(status, "reallocarray: out of memory\n");
+
+ return p;
+}
diff --git a/util/sbase/libutil/recurse.c b/util/sbase/libutil/recurse.c
new file mode 100644
index 00000000..e66efaf5
--- /dev/null
+++ b/util/sbase/libutil/recurse.c
@@ -0,0 +1,108 @@
+/* See LICENSE file for copyright and license details. */
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "../fs.h"
+#include "../util.h"
+
+int recurse_status = 0;
+
+void
+recurse(int dirfd, const char *name, void *data, struct recursor *r)
+{
+ struct dirent *d;
+ struct history *new, *h;
+ struct stat st, dst;
+ DIR *dp;
+ int flags = 0, fd;
+ size_t pathlen = r->pathlen;
+
+ if (dirfd == AT_FDCWD)
+ pathlen = estrlcpy(r->path, name, sizeof(r->path));
+
+ if (r->follow == 'P' || (r->follow == 'H' && r->depth))
+ flags |= AT_SYMLINK_NOFOLLOW;
+
+ if (fstatat(dirfd, name, &st, flags) < 0) {
+ if (!(r->flags & SILENT)) {
+ weprintf("stat %s:", r->path);
+ recurse_status = 1;
+ }
+ return;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ r->fn(dirfd, name, &st, data, r);
+ return;
+ }
+
+ new = emalloc(sizeof(struct history));
+ new->prev = r->hist;
+ r->hist = new;
+ new->dev = st.st_dev;
+ new->ino = st.st_ino;
+
+ for (h = new->prev; h; h = h->prev)
+ if (h->ino == st.st_ino && h->dev == st.st_dev)
+ return;
+
+ if (!r->depth && (r->flags & DIRFIRST))
+ r->fn(dirfd, name, &st, data, r);
+
+ if (!r->maxdepth || r->depth + 1 < r->maxdepth) {
+ fd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
+ if (fd < 0) {
+ weprintf("open %s:", r->path);
+ recurse_status = 1;
+ }
+ if (!(dp = fdopendir(fd))) {
+ if (!(r->flags & SILENT)) {
+ weprintf("fdopendir:");
+ recurse_status = 1;
+ }
+ return;
+ }
+ if (r->path[pathlen - 1] != '/')
+ r->path[pathlen++] = '/';
+ if (r->follow == 'H')
+ flags |= AT_SYMLINK_NOFOLLOW;
+ while ((d = readdir(dp))) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+ r->pathlen = pathlen + estrlcpy(r->path + pathlen, d->d_name, sizeof(r->path) - pathlen);
+ if (fstatat(fd, d->d_name, &dst, flags) < 0) {
+ if (!(r->flags & SILENT)) {
+ weprintf("stat %s:", r->path);
+ recurse_status = 1;
+ }
+ } else if ((r->flags & SAMEDEV) && dst.st_dev != st.st_dev) {
+ continue;
+ } else {
+ r->depth++;
+ r->fn(fd, d->d_name, &dst, data, r);
+ r->depth--;
+ }
+ }
+ r->path[pathlen - 1] = '\0';
+ r->pathlen = pathlen - 1;
+ closedir(dp);
+ }
+
+ if (!r->depth) {
+ if (!(r->flags & DIRFIRST))
+ r->fn(dirfd, name, &st, data, r);
+
+ while (r->hist) {
+ h = r->hist;
+ r->hist = r->hist->prev;
+ free(h);
+ }
+ }
+}
diff --git a/util/sbase/libutil/rm.c b/util/sbase/libutil/rm.c
new file mode 100644
index 00000000..fb99840d
--- /dev/null
+++ b/util/sbase/libutil/rm.c
@@ -0,0 +1,49 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "../fs.h"
+#include "../util.h"
+
+int rm_status = 0;
+
+void
+rm(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
+{
+ int quiet, ask, write, flags, ignore;
+
+ ignore = r->flags & IGNORE;
+ quiet = r->flags & SILENT;
+ ask = r->flags & CONFIRM;
+ write = faccessat(dirfd, name, W_OK, 0) == 0;
+ flags = 0;
+
+ if (S_ISDIR(st->st_mode) && r->maxdepth) {
+ errno = EISDIR;
+ goto err;
+ }
+
+ if (!quiet && (!write && isatty(0) || ask)) {
+ if (!confirm("remove file '%s'", r->path));
+ return;
+ }
+
+ if (S_ISDIR(st->st_mode)) {
+ flags = AT_REMOVEDIR;
+ recurse(dirfd, name, NULL, r);
+ }
+
+ if (unlinkat(dirfd, name, flags) < 0)
+ goto err;
+ return;
+
+err:
+ if (!ignore) {
+ weprintf("cannot remove '%s':", r->path);
+ rm_status = 1;
+ }
+}
diff --git a/util/sbase/libutil/sha1.c b/util/sbase/libutil/sha1.c
new file mode 100644
index 00000000..3d76a1be
--- /dev/null
+++ b/util/sbase/libutil/sha1.c
@@ -0,0 +1,144 @@
+/* public domain sha1 implementation based on rfc3174 and libtomcrypt */
+#include <stdint.h>
+#include <string.h>
+
+#include "../sha1.h"
+
+static uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
+#define F0(b,c,d) (d ^ (b & (c ^ d)))
+#define F1(b,c,d) (b ^ c ^ d)
+#define F2(b,c,d) ((b & c) | (d & (b | c)))
+#define F3(b,c,d) (b ^ c ^ d)
+#define G0(a,b,c,d,e,i) e += rol(a,5)+F0(b,c,d)+W[i]+0x5A827999; b = rol(b,30)
+#define G1(a,b,c,d,e,i) e += rol(a,5)+F1(b,c,d)+W[i]+0x6ED9EBA1; b = rol(b,30)
+#define G2(a,b,c,d,e,i) e += rol(a,5)+F2(b,c,d)+W[i]+0x8F1BBCDC; b = rol(b,30)
+#define G3(a,b,c,d,e,i) e += rol(a,5)+F3(b,c,d)+W[i]+0xCA62C1D6; b = rol(b,30)
+
+static void
+processblock(struct sha1 *s, const uint8_t *buf)
+{
+ uint32_t W[80], a, b, c, d, e;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ W[i] = (uint32_t)buf[4*i]<<24;
+ W[i] |= (uint32_t)buf[4*i+1]<<16;
+ W[i] |= (uint32_t)buf[4*i+2]<<8;
+ W[i] |= buf[4*i+3];
+ }
+ for (; i < 80; i++)
+ W[i] = rol(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+ a = s->h[0];
+ b = s->h[1];
+ c = s->h[2];
+ d = s->h[3];
+ e = s->h[4];
+ for (i = 0; i < 20; ) {
+ G0(a,b,c,d,e,i++);
+ G0(e,a,b,c,d,i++);
+ G0(d,e,a,b,c,i++);
+ G0(c,d,e,a,b,i++);
+ G0(b,c,d,e,a,i++);
+ }
+ while (i < 40) {
+ G1(a,b,c,d,e,i++);
+ G1(e,a,b,c,d,i++);
+ G1(d,e,a,b,c,i++);
+ G1(c,d,e,a,b,i++);
+ G1(b,c,d,e,a,i++);
+ }
+ while (i < 60) {
+ G2(a,b,c,d,e,i++);
+ G2(e,a,b,c,d,i++);
+ G2(d,e,a,b,c,i++);
+ G2(c,d,e,a,b,i++);
+ G2(b,c,d,e,a,i++);
+ }
+ while (i < 80) {
+ G3(a,b,c,d,e,i++);
+ G3(e,a,b,c,d,i++);
+ G3(d,e,a,b,c,i++);
+ G3(c,d,e,a,b,i++);
+ G3(b,c,d,e,a,i++);
+ }
+ s->h[0] += a;
+ s->h[1] += b;
+ s->h[2] += c;
+ s->h[3] += d;
+ s->h[4] += e;
+}
+
+static void
+pad(struct sha1 *s)
+{
+ unsigned r = s->len % 64;
+
+ s->buf[r++] = 0x80;
+ if (r > 56) {
+ memset(s->buf + r, 0, 64 - r);
+ r = 0;
+ processblock(s, s->buf);
+ }
+ memset(s->buf + r, 0, 56 - r);
+ s->len *= 8;
+ s->buf[56] = s->len >> 56;
+ s->buf[57] = s->len >> 48;
+ s->buf[58] = s->len >> 40;
+ s->buf[59] = s->len >> 32;
+ s->buf[60] = s->len >> 24;
+ s->buf[61] = s->len >> 16;
+ s->buf[62] = s->len >> 8;
+ s->buf[63] = s->len;
+ processblock(s, s->buf);
+}
+
+void
+sha1_init(void *ctx)
+{
+ struct sha1 *s = ctx;
+
+ s->len = 0;
+ s->h[0] = 0x67452301;
+ s->h[1] = 0xEFCDAB89;
+ s->h[2] = 0x98BADCFE;
+ s->h[3] = 0x10325476;
+ s->h[4] = 0xC3D2E1F0;
+}
+
+void
+sha1_sum(void *ctx, uint8_t md[SHA1_DIGEST_LENGTH])
+{
+ struct sha1 *s = ctx;
+ int i;
+
+ pad(s);
+ for (i = 0; i < 5; i++) {
+ md[4*i] = s->h[i] >> 24;
+ md[4*i+1] = s->h[i] >> 16;
+ md[4*i+2] = s->h[i] >> 8;
+ md[4*i+3] = s->h[i];
+ }
+}
+
+void
+sha1_update(void *ctx, const void *m, unsigned long len)
+{
+ struct sha1 *s = ctx;
+ const uint8_t *p = m;
+ unsigned r = s->len % 64;
+
+ s->len += len;
+ if (r) {
+ if (len < 64 - r) {
+ memcpy(s->buf + r, p, len);
+ return;
+ }
+ memcpy(s->buf + r, p, 64 - r);
+ len -= 64 - r;
+ p += 64 - r;
+ processblock(s, s->buf);
+ }
+ for (; len >= 64; len -= 64, p += 64)
+ processblock(s, p);
+ memcpy(s->buf, p, len);
+}
diff --git a/util/sbase/libutil/sha224.c b/util/sbase/libutil/sha224.c
new file mode 100644
index 00000000..fce520f5
--- /dev/null
+++ b/util/sbase/libutil/sha224.c
@@ -0,0 +1,26 @@
+/* public domain sha224 implementation based on fips180-3 */
+#include <stdint.h>
+#include "../sha224.h"
+
+extern void sha256_sum_n(void *, uint8_t *, int n);
+
+void
+sha224_init(void *ctx)
+{
+ struct sha224 *s = ctx;
+ s->len = 0;
+ s->h[0] = 0xc1059ed8;
+ s->h[1] = 0x367cd507;
+ s->h[2] = 0x3070dd17;
+ s->h[3] = 0xf70e5939;
+ s->h[4] = 0xffc00b31;
+ s->h[5] = 0x68581511;
+ s->h[6] = 0x64f98fa7;
+ s->h[7] = 0xbefa4fa4;
+}
+
+void
+sha224_sum(void *ctx, uint8_t md[SHA224_DIGEST_LENGTH])
+{
+ sha256_sum_n(ctx, md, 8);
+}
diff --git a/util/sbase/libutil/sha256.c b/util/sbase/libutil/sha256.c
new file mode 100644
index 00000000..266cfecb
--- /dev/null
+++ b/util/sbase/libutil/sha256.c
@@ -0,0 +1,154 @@
+/* public domain sha256 implementation based on fips180-3 */
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../sha256.h"
+
+static uint32_t ror(uint32_t n, int k) { return (n >> k) | (n << (32-k)); }
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
+#define S0(x) (ror(x,2) ^ ror(x,13) ^ ror(x,22))
+#define S1(x) (ror(x,6) ^ ror(x,11) ^ ror(x,25))
+#define R0(x) (ror(x,7) ^ ror(x,18) ^ (x>>3))
+#define R1(x) (ror(x,17) ^ ror(x,19) ^ (x>>10))
+
+static const uint32_t K[64] = {
+0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static void
+processblock(struct sha256 *s, const uint8_t *buf)
+{
+ uint32_t W[64], t1, t2, a, b, c, d, e, f, g, h;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ W[i] = (uint32_t)buf[4*i]<<24;
+ W[i] |= (uint32_t)buf[4*i+1]<<16;
+ W[i] |= (uint32_t)buf[4*i+2]<<8;
+ W[i] |= buf[4*i+3];
+ }
+ for (; i < 64; i++)
+ W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
+ a = s->h[0];
+ b = s->h[1];
+ c = s->h[2];
+ d = s->h[3];
+ e = s->h[4];
+ f = s->h[5];
+ g = s->h[6];
+ h = s->h[7];
+ for (i = 0; i < 64; i++) {
+ t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
+ t2 = S0(a) + Maj(a,b,c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+ s->h[0] += a;
+ s->h[1] += b;
+ s->h[2] += c;
+ s->h[3] += d;
+ s->h[4] += e;
+ s->h[5] += f;
+ s->h[6] += g;
+ s->h[7] += h;
+}
+
+static void
+pad(struct sha256 *s)
+{
+ unsigned r = s->len % 64;
+
+ s->buf[r++] = 0x80;
+ if (r > 56) {
+ memset(s->buf + r, 0, 64 - r);
+ r = 0;
+ processblock(s, s->buf);
+ }
+ memset(s->buf + r, 0, 56 - r);
+ s->len *= 8;
+ s->buf[56] = s->len >> 56;
+ s->buf[57] = s->len >> 48;
+ s->buf[58] = s->len >> 40;
+ s->buf[59] = s->len >> 32;
+ s->buf[60] = s->len >> 24;
+ s->buf[61] = s->len >> 16;
+ s->buf[62] = s->len >> 8;
+ s->buf[63] = s->len;
+ processblock(s, s->buf);
+}
+
+void
+sha256_init(void *ctx)
+{
+ struct sha256 *s = ctx;
+ s->len = 0;
+ s->h[0] = 0x6a09e667;
+ s->h[1] = 0xbb67ae85;
+ s->h[2] = 0x3c6ef372;
+ s->h[3] = 0xa54ff53a;
+ s->h[4] = 0x510e527f;
+ s->h[5] = 0x9b05688c;
+ s->h[6] = 0x1f83d9ab;
+ s->h[7] = 0x5be0cd19;
+}
+
+void
+sha256_sum_n(void *ctx, uint8_t *md, int n)
+{
+ struct sha256 *s = ctx;
+ int i;
+
+ pad(s);
+ for (i = 0; i < n; i++) {
+ md[4*i] = s->h[i] >> 24;
+ md[4*i+1] = s->h[i] >> 16;
+ md[4*i+2] = s->h[i] >> 8;
+ md[4*i+3] = s->h[i];
+ }
+}
+
+void
+sha256_sum(void *ctx, uint8_t md[SHA256_DIGEST_LENGTH])
+{
+ sha256_sum_n(ctx, md, 8);
+}
+
+void
+sha256_update(void *ctx, const void *m, unsigned long len)
+{
+ struct sha256 *s = ctx;
+ const uint8_t *p = m;
+ unsigned r = s->len % 64;
+
+ s->len += len;
+ if (r) {
+ if (len < 64 - r) {
+ memcpy(s->buf + r, p, len);
+ return;
+ }
+ memcpy(s->buf + r, p, 64 - r);
+ len -= 64 - r;
+ p += 64 - r;
+ processblock(s, s->buf);
+ }
+ for (; len >= 64; len -= 64, p += 64)
+ processblock(s, p);
+ memcpy(s->buf, p, len);
+}
diff --git a/util/sbase/libutil/sha384.c b/util/sbase/libutil/sha384.c
new file mode 100644
index 00000000..0a0e7777
--- /dev/null
+++ b/util/sbase/libutil/sha384.c
@@ -0,0 +1,26 @@
+/* public domain sha384 implementation based on fips180-3 */
+#include <stdint.h>
+#include "../sha384.h"
+
+extern void sha512_sum_n(void *, uint8_t *, int n);
+
+void
+sha384_init(void *ctx)
+{
+ struct sha384 *s = ctx;
+ s->len = 0;
+ s->h[0] = 0xcbbb9d5dc1059ed8ULL;
+ s->h[1] = 0x629a292a367cd507ULL;
+ s->h[2] = 0x9159015a3070dd17ULL;
+ s->h[3] = 0x152fecd8f70e5939ULL;
+ s->h[4] = 0x67332667ffc00b31ULL;
+ s->h[5] = 0x8eb44a8768581511ULL;
+ s->h[6] = 0xdb0c2e0d64f98fa7ULL;
+ s->h[7] = 0x47b5481dbefa4fa4ULL;
+}
+
+void
+sha384_sum(void *ctx, uint8_t md[SHA384_DIGEST_LENGTH])
+{
+ sha512_sum_n(ctx, md, 6);
+}
diff --git a/util/sbase/libutil/sha512-224.c b/util/sbase/libutil/sha512-224.c
new file mode 100644
index 00000000..a5636c13
--- /dev/null
+++ b/util/sbase/libutil/sha512-224.c
@@ -0,0 +1,26 @@
+/* public domain sha512/224 implementation based on fips180-3 */
+#include <stdint.h>
+#include "../sha512-224.h"
+
+extern void sha512_sum_n(void *, uint8_t *, int n);
+
+void
+sha512_224_init(void *ctx)
+{
+ struct sha512_224 *s = ctx;
+ s->len = 0;
+ s->h[0] = 0x8c3d37c819544da2ULL;
+ s->h[1] = 0x73e1996689dcd4d6ULL;
+ s->h[2] = 0x1dfab7ae32ff9c82ULL;
+ s->h[3] = 0x679dd514582f9fcfULL;
+ s->h[4] = 0x0f6d2b697bd44da8ULL;
+ s->h[5] = 0x77e36f7304c48942ULL;
+ s->h[6] = 0x3f9d85a86a1d36c8ULL;
+ s->h[7] = 0x1112e6ad91d692a1ULL;
+}
+
+void
+sha512_224_sum(void *ctx, uint8_t md[SHA512_224_DIGEST_LENGTH])
+{
+ sha512_sum_n(ctx, md, 4);
+}
diff --git a/util/sbase/libutil/sha512-256.c b/util/sbase/libutil/sha512-256.c
new file mode 100644
index 00000000..d4b84495
--- /dev/null
+++ b/util/sbase/libutil/sha512-256.c
@@ -0,0 +1,26 @@
+/* public domain sha512/256 implementation based on fips180-3 */
+#include <stdint.h>
+#include "../sha512-256.h"
+
+extern void sha512_sum_n(void *, uint8_t *, int n);
+
+void
+sha512_256_init(void *ctx)
+{
+ struct sha512_256 *s = ctx;
+ s->len = 0;
+ s->h[0] = 0x22312194fc2bf72cULL;
+ s->h[1] = 0x9f555fa3c84c64c2ULL;
+ s->h[2] = 0x2393b86b6f53b151ULL;
+ s->h[3] = 0x963877195940eabdULL;
+ s->h[4] = 0x96283ee2a88effe3ULL;
+ s->h[5] = 0xbe5e1e2553863992ULL;
+ s->h[6] = 0x2b0199fc2c85b8aaULL;
+ s->h[7] = 0x0eb72ddc81c52ca2ULL;
+}
+
+void
+sha512_256_sum(void *ctx, uint8_t md[SHA512_256_DIGEST_LENGTH])
+{
+ sha512_sum_n(ctx, md, 4);
+}
diff --git a/util/sbase/libutil/sha512.c b/util/sbase/libutil/sha512.c
new file mode 100644
index 00000000..25264c78
--- /dev/null
+++ b/util/sbase/libutil/sha512.c
@@ -0,0 +1,175 @@
+/* public domain sha256 implementation based on fips180-3 */
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../sha512.h"
+
+static uint64_t ror(uint64_t n, int k) { return (n >> k) | (n << (64-k)); }
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
+#define S0(x) (ror(x,28) ^ ror(x,34) ^ ror(x,39))
+#define S1(x) (ror(x,14) ^ ror(x,18) ^ ror(x,41))
+#define R0(x) (ror(x,1) ^ ror(x,8) ^ (x>>7))
+#define R1(x) (ror(x,19) ^ ror(x,61) ^ (x>>6))
+
+static const uint64_t K[80] = {
+0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+static void
+processblock(struct sha512 *s, const uint8_t *buf)
+{
+ uint64_t W[80], t1, t2, a, b, c, d, e, f, g, h;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ W[i] = (uint64_t)buf[8*i]<<56;
+ W[i] |= (uint64_t)buf[8*i+1]<<48;
+ W[i] |= (uint64_t)buf[8*i+2]<<40;
+ W[i] |= (uint64_t)buf[8*i+3]<<32;
+ W[i] |= (uint64_t)buf[8*i+4]<<24;
+ W[i] |= (uint64_t)buf[8*i+5]<<16;
+ W[i] |= (uint64_t)buf[8*i+6]<<8;
+ W[i] |= buf[8*i+7];
+ }
+ for (; i < 80; i++)
+ W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
+ a = s->h[0];
+ b = s->h[1];
+ c = s->h[2];
+ d = s->h[3];
+ e = s->h[4];
+ f = s->h[5];
+ g = s->h[6];
+ h = s->h[7];
+ for (i = 0; i < 80; i++) {
+ t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
+ t2 = S0(a) + Maj(a,b,c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+ s->h[0] += a;
+ s->h[1] += b;
+ s->h[2] += c;
+ s->h[3] += d;
+ s->h[4] += e;
+ s->h[5] += f;
+ s->h[6] += g;
+ s->h[7] += h;
+}
+
+static void
+pad(struct sha512 *s)
+{
+ unsigned r = s->len % 128;
+
+ s->buf[r++] = 0x80;
+ if (r > 112) {
+ memset(s->buf + r, 0, 128 - r);
+ r = 0;
+ processblock(s, s->buf);
+ }
+ memset(s->buf + r, 0, 120 - r);
+ s->len *= 8;
+ s->buf[120] = s->len >> 56;
+ s->buf[121] = s->len >> 48;
+ s->buf[122] = s->len >> 40;
+ s->buf[123] = s->len >> 32;
+ s->buf[124] = s->len >> 24;
+ s->buf[125] = s->len >> 16;
+ s->buf[126] = s->len >> 8;
+ s->buf[127] = s->len;
+ processblock(s, s->buf);
+}
+
+void
+sha512_init(void *ctx)
+{
+ struct sha512 *s = ctx;
+ s->len = 0;
+ s->h[0] = 0x6a09e667f3bcc908ULL;
+ s->h[1] = 0xbb67ae8584caa73bULL;
+ s->h[2] = 0x3c6ef372fe94f82bULL;
+ s->h[3] = 0xa54ff53a5f1d36f1ULL;
+ s->h[4] = 0x510e527fade682d1ULL;
+ s->h[5] = 0x9b05688c2b3e6c1fULL;
+ s->h[6] = 0x1f83d9abfb41bd6bULL;
+ s->h[7] = 0x5be0cd19137e2179ULL;
+}
+
+void
+sha512_sum_n(void *ctx, uint8_t *md, int n)
+{
+ struct sha512 *s = ctx;
+ int i;
+
+ pad(s);
+ for (i = 0; i < n; i++) {
+ md[8*i] = s->h[i] >> 56;
+ md[8*i+1] = s->h[i] >> 48;
+ md[8*i+2] = s->h[i] >> 40;
+ md[8*i+3] = s->h[i] >> 32;
+ md[8*i+4] = s->h[i] >> 24;
+ md[8*i+5] = s->h[i] >> 16;
+ md[8*i+6] = s->h[i] >> 8;
+ md[8*i+7] = s->h[i];
+ }
+}
+
+void
+sha512_sum(void *ctx, uint8_t md[SHA512_DIGEST_LENGTH])
+{
+ sha512_sum_n(ctx, md, 8);
+}
+
+void
+sha512_update(void *ctx, const void *m, unsigned long len)
+{
+ struct sha512 *s = ctx;
+ const uint8_t *p = m;
+ unsigned r = s->len % 128;
+
+ s->len += len;
+ if (r) {
+ if (len < 128 - r) {
+ memcpy(s->buf + r, p, len);
+ return;
+ }
+ memcpy(s->buf + r, p, 128 - r);
+ len -= 128 - r;
+ p += 128 - r;
+ processblock(s, s->buf);
+ }
+ for (; len >= 128; len -= 128, p += 128)
+ processblock(s, p);
+ memcpy(s->buf, p, len);
+}
diff --git a/util/sbase/libutil/strcasestr.c b/util/sbase/libutil/strcasestr.c
new file mode 100644
index 00000000..26eb6bbd
--- /dev/null
+++ b/util/sbase/libutil/strcasestr.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2005-2014 Rich Felker, et al.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#include <string.h>
+#include <strings.h>
+
+#include "../util.h"
+
+char *
+strcasestr(const char *h, const char *n)
+{
+ size_t l = strlen(n);
+
+ for (; *h; h++)
+ if (!strncasecmp(h, n, l))
+ return (char *)h;
+
+ return 0;
+}
diff --git a/util/sbase/libutil/strlcat.c b/util/sbase/libutil/strlcat.c
new file mode 100644
index 00000000..bf263b87
--- /dev/null
+++ b/util/sbase/libutil/strlcat.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+#include "../util.h"
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+size_t
+estrlcat(char *dst, const char *src, size_t siz)
+{
+ size_t ret;
+
+ if ((ret = strlcat(dst, src, siz)) >= siz)
+ eprintf("strlcat: input string too long\n");
+
+ return ret;
+}
diff --git a/util/sbase/libutil/strlcpy.c b/util/sbase/libutil/strlcpy.c
new file mode 100644
index 00000000..44b618a0
--- /dev/null
+++ b/util/sbase/libutil/strlcpy.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+#include "../util.h"
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0')
+ break;
+ }
+ }
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+ return(s - src - 1); /* count does not include NUL */
+}
+
+size_t
+estrlcpy(char *dst, const char *src, size_t siz)
+{
+ size_t ret;
+
+ if ((ret = strlcpy(dst, src, siz)) >= siz)
+ eprintf("strlcpy: input string too long\n");
+
+ return ret;
+}
diff --git a/util/sbase/libutil/strnsubst.c b/util/sbase/libutil/strnsubst.c
new file mode 100644
index 00000000..2da54aba
--- /dev/null
+++ b/util/sbase/libutil/strnsubst.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2002 J. Mallett. All rights reserved.
+ * You may do whatever you want with this file as long as
+ * the above copyright and this notice remain intact, along
+ * with the following statement:
+ * For the man who taught me vi, and who got too old, too young.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../util.h"
+
+/*
+ * Replaces str with a string consisting of str with match replaced with
+ * replstr as many times as can be done before the constructed string is
+ * maxsize bytes large. It does not free the string pointed to by str, it
+ * is up to the calling program to be sure that the original contents of
+ * str as well as the new contents are handled in an appropriate manner.
+ * If replstr is NULL, then that internally is changed to a nil-string, so
+ * that we can still pretend to do somewhat meaningful substitution.
+ * No value is returned.
+ */
+void
+strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
+{
+ char *s1, *s2, *this;
+ size_t matchlen, s2len;
+ int n;
+
+ if ((s1 = *str) == NULL)
+ return;
+ s2 = emalloc(maxsize);
+
+ if (replstr == NULL)
+ replstr = "";
+
+ if (match == NULL || *match == '\0' || strlen(s1) >= maxsize) {
+ strlcpy(s2, s1, maxsize);
+ goto done;
+ }
+
+ *s2 = '\0';
+ s2len = 0;
+ matchlen = strlen(match);
+ for (;;) {
+ if ((this = strstr(s1, match)) == NULL)
+ break;
+ n = snprintf(s2 + s2len, maxsize - s2len, "%.*s%s",
+ (int)(this - s1), s1, replstr);
+ if (n == -1 || n + s2len + strlen(this + matchlen) >= maxsize)
+ break; /* out of room */
+ s2len += n;
+ s1 = this + matchlen;
+ }
+ strlcpy(s2 + s2len, s1, maxsize - s2len);
+done:
+ *str = s2;
+ return;
+}
diff --git a/util/sbase/libutil/strsep.c b/util/sbase/libutil/strsep.c
new file mode 100644
index 00000000..d9f06444
--- /dev/null
+++ b/util/sbase/libutil/strsep.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2005-2014 Rich Felker, et al.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#include <string.h>
+
+#include "../util.h"
+
+char *
+strsep(char **str, const char *sep)
+{
+ char *s = *str, *end;
+ if (!s) return NULL;
+ end = s + strcspn(s, sep);
+ if (*end) *end++ = 0;
+ else end = 0;
+ *str = end;
+ return s;
+}
diff --git a/util/sbase/libutil/strtonum.c b/util/sbase/libutil/strtonum.c
new file mode 100644
index 00000000..c0ac401f
--- /dev/null
+++ b/util/sbase/libutil/strtonum.c
@@ -0,0 +1,85 @@
+/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "../util.h"
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ int error = 0;
+ char *ep;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval) {
+ error = INVALID;
+ } else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
+
+long long
+enstrtonum(int status, const char *numstr, long long minval, long long maxval)
+{
+ const char *errstr;
+ long long ll;
+
+ ll = strtonum(numstr, minval, maxval, &errstr);
+ if (errstr)
+ enprintf(status, "strtonum %s: %s\n", numstr, errstr);
+ return ll;
+}
+
+long long
+estrtonum(const char *numstr, long long minval, long long maxval)
+{
+ return enstrtonum(1, numstr, minval, maxval);
+}
diff --git a/util/sbase/libutil/unescape.c b/util/sbase/libutil/unescape.c
new file mode 100644
index 00000000..b8f75ca9
--- /dev/null
+++ b/util/sbase/libutil/unescape.c
@@ -0,0 +1,58 @@
+/* See LICENSE file for copyright and license details. */
+#include <ctype.h>
+#include <string.h>
+
+#include "../util.h"
+
+#define is_odigit(c) ('0' <= c && c <= '7')
+
+size_t
+unescape(char *s)
+{
+ static const char escapes[256] = {
+ ['"'] = '"',
+ ['\''] = '\'',
+ ['\\'] = '\\',
+ ['a'] = '\a',
+ ['b'] = '\b',
+ ['E'] = 033,
+ ['e'] = 033,
+ ['f'] = '\f',
+ ['n'] = '\n',
+ ['r'] = '\r',
+ ['t'] = '\t',
+ ['v'] = '\v'
+ };
+ size_t m, q;
+ char *r, *w;
+
+ for (r = w = s; *r;) {
+ if (*r != '\\') {
+ *w++ = *r++;
+ continue;
+ }
+ r++;
+ if (!*r) {
+ eprintf("null escape sequence\n");
+ } else if (escapes[(unsigned char)*r]) {
+ *w++ = escapes[(unsigned char)*r++];
+ } else if (is_odigit(*r)) {
+ for (q = 0, m = 3; m && is_odigit(*r); m--, r++)
+ q = q * 8 + (*r - '0');
+ *w++ = MIN(q, 255);
+ } else if (*r == 'x' && isxdigit(r[1])) {
+ r++;
+ for (q = 0, m = 2; m && isxdigit(*r); m--, r++)
+ if (isdigit(*r))
+ q = q * 16 + (*r - '0');
+ else
+ q = q * 16 + (tolower(*r) - 'a' + 10);
+ *w++ = q;
+ } else {
+ eprintf("invalid escape sequence '\\%c'\n", *r);
+ }
+ }
+ *w = '\0';
+
+ return w - s;
+}
diff --git a/util/sbase/libutil/writeall.c b/util/sbase/libutil/writeall.c
new file mode 100644
index 00000000..4725ced8
--- /dev/null
+++ b/util/sbase/libutil/writeall.c
@@ -0,0 +1,21 @@
+/* See LICENSE file for copyright and license details. */
+#include <unistd.h>
+
+#include "../util.h"
+
+ssize_t
+writeall(int fd, const void *buf, size_t len)
+{
+ const char *p = buf;
+ ssize_t n;
+
+ while (len) {
+ n = write(fd, p, len);
+ if (n <= 0)
+ return n;
+ p += n;
+ len -= n;
+ }
+
+ return p - (const char *)buf;
+}