diff options
Diffstat (limited to 'util/libreboot-utils/lib/string.c')
| -rw-r--r-- | util/libreboot-utils/lib/string.c | 643 |
1 files changed, 0 insertions, 643 deletions
diff --git a/util/libreboot-utils/lib/string.c b/util/libreboot-utils/lib/string.c deleted file mode 100644 index 7388cf35..00000000 --- a/util/libreboot-utils/lib/string.c +++ /dev/null @@ -1,643 +0,0 @@ -/* SPDX-License-Identifier: MIT - * Copyright (c) 2026 Leah Rowe <leah@libreboot.org> - * - * String functions - */ - -#include <sys/types.h> -#include <sys/stat.h> - -#include <errno.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <limits.h> -#include <stdint.h> - -#include "../include/common.h" - -/* for null detection inside - * word-optimised string functions - */ -#define ff ((size_t)-1 / 0xFF) -#define high ((ff) * 0x80) -/* NOTE: - * do not assume that a match means - * both words have null at the same - * location. see how this is handled - * e.g. in scmp. - */ -#define zeroes(x) (((x) - (ff)) & ~(x) & (high)) - -size_t -page_remain(const void *p) -{ - /* calling sysconf repeatedly - * is folly. cache it (static) - */ - static size_t pagesz = 0; - if (!pagesz) - pagesz = (size_t)pagesize(); - - return pagesz - ((uintptr_t)p & (pagesz - 1)); -} - -long -pagesize(void) -{ - static long rval = 0; - static int set = 0; - int saved_errno = 0; - - if (!set) { - if ((rval = sysconf(_SC_PAGESIZE)) < 0) - exitf("could not determine page size"); - set = 1; - } - - reset_caller_errno(0); - return rval; -} - -void -free_and_set_null(char **buf) -{ - if (buf == NULL) - exitf( - "null ptr (to ptr for freeing) in free_and_set_null"); - - if (*buf == NULL) - return; - - free(*buf); - *buf = NULL; -} - -/* safe(ish) malloc. - - use this and free_and_set_null() - in your program, to reduce the - chance of use after frees! - - if you use these functions in the - intended way, you will greatly reduce - the number of bugs in your code - */ -char * -smalloc(char **buf, size_t size) -{ - return (char *)vmalloc((void **)buf, size); -} -void * -vmalloc(void **buf, size_t size) -{ - int saved_errno = errno; - void *rval = NULL; - errno = 0; - - if (size >= SIZE_MAX - 1) - exitf("integer overflow in vmalloc"); - if (buf == NULL) - exitf("Bad pointer passed to vmalloc"); - - /* lots of programs will - * re-initialise a buffer - * that was allocated, without - * freeing or NULLing it. this - * is here intentionally, to - * force the programmer to behave - */ - if (*buf != NULL) - exitf("Non-null pointer given to vmalloc"); - - if (!size) - exitf( - "Tried to vmalloc(0) and that is very bad. Fix it now"); - - if ((rval = malloc(size)) == NULL) - exitf("malloc fail in vmalloc"); - - reset_caller_errno(0); - return *buf = rval; -} - -/* strict word-based strcmp */ -int -scmp(const char *a, - const char *b, - size_t maxlen, - int *rval) -{ - size_t i = 0; - size_t j; - size_t wa; - size_t wb; - int saved_errno = errno; - errno = 0; - - if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT)) - goto err; - - for ( ; ((uintptr_t)(a + i) % sizeof(size_t)) != 0; i++) { - - if (if_err(i >= maxlen, EOVERFLOW)) - goto err; - else if (!ccmp(a, b, i, rval)) - goto out; - } - - for ( ; i + sizeof(size_t) <= maxlen; - i += sizeof(size_t)) { - - /* prevent crossing page boundary on word check */ - if (page_remain(a + i) < sizeof(size_t) || - page_remain(b + i) < sizeof(size_t)) - break; - - memcpy(&wa, a + i, sizeof(size_t)); - memcpy(&wb, b + i, sizeof(size_t)); - - if (wa != wb) - for (j = 0; j < sizeof(size_t); j++) - if (!ccmp(a, b, i + j, rval)) - goto out; - - if (!zeroes(wa)) - continue; - - *rval = 0; - goto out; - } - - for ( ; i < maxlen; i++) - if (!ccmp(a, b, i, rval)) - goto out; - -err: - (void) with_fallback_errno(EFAULT); - if (rval != NULL) - *rval = -1; - - exitf("scmp"); - return -1; -out: - reset_caller_errno(0); - return *rval; -} - -int ccmp(const char *a, const char *b, - size_t i, int *rval) -{ - unsigned char ac; - unsigned char bc; - - if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT)) - exitf("ccmp"); - - ac = (unsigned char)a[i]; - bc = (unsigned char)b[i]; - - if (ac != bc) { - *rval = ac - bc; - return 0; - } else if (ac == '\0') { - *rval = 0; - return 0; - } - - return 1; -} - -/* strict word-based strlen */ -size_t -slen(const char *s, - size_t maxlen, - size_t *rval) -{ - int saved_errno = errno; - size_t i = 0; - size_t w; - size_t j; - errno = 0; - - if (if_err(s == NULL || rval == NULL, EFAULT)) - goto err; - - for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) { - - if (if_err(i >= maxlen, EOVERFLOW)) - goto err; - if (s[i] == '\0') { - *rval = i; - goto out; - } - } - - for ( ; i + sizeof(size_t) <= maxlen; - i += sizeof(size_t)) { - - memcpy(&w, s + i, sizeof(size_t)); - if (!zeroes(w)) - continue; - - for (j = 0; j < sizeof(size_t); j++) { - if (s[i + j] == '\0') { - *rval = i + j; - goto out; - } - } - } - - for ( ; i < maxlen; i++) { - if (s[i] == '\0') { - *rval = i; - goto out; - } - } - -err: - (void) with_fallback_errno(EFAULT); - if (rval != NULL) - *rval = 0; - - exitf("slen"); /* abort */ - return 0; /* gcc15 is happy */ -out: - reset_caller_errno(0); - return *rval; -} - -int -dup_pair(char **dir, const char *d, - char **base, const char *b) -{ - char *dtmp = NULL; - char *btmp = NULL; - - if (d && sdup(d, PATH_MAX, &dtmp) == NULL) - return -1; - - if (b && sdup(b, PATH_MAX, &btmp) == NULL) { - free(dtmp); - return -1; - } - - *dir = dtmp; - *base = btmp; - - return 0; -} - -/* strict word-based strdup */ -char * -sdup(const char *s, - size_t max, char **dest) -{ - size_t j; - size_t w; - size_t i = 0; - char *out = NULL; - int saved_errno = errno; - errno = 0; - - if (if_err(dest == NULL || *dest != NULL || s == NULL, EFAULT)) - goto err; - - out = smalloc(dest, max); - - for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) { - - if (if_err(i >= max, EOVERFLOW)) - goto err; - - out[i] = s[i]; - if (s[i] == '\0') { - *dest = out; - goto out; - } - } - - for ( ; i + sizeof(size_t) <= max; i += sizeof(size_t)) { - - if (page_remain(s + i) < sizeof(size_t)) - break; - - memcpy(&w, s + i, sizeof(size_t)); - if (!zeroes(w)) { - memcpy(out + i, &w, sizeof(size_t)); - continue; - } - - for (j = 0; j < sizeof(size_t); j++) { - - out[i + j] = s[i + j]; - if (s[i + j] == '\0') { - *dest = out; - goto out; - } - } - } - - for ( ; i < max; i++) { - - out[i] = s[i]; - if (s[i] == '\0') { - *dest = out; - goto out; - } - } - -err: - free_and_set_null(&out); - if (dest != NULL) - *dest = NULL; - - (void) with_fallback_errno(EFAULT); - exitf("sdup"); - - return NULL; -out: - reset_caller_errno(0); - return *dest; -} - -/* concatenate N number of strings */ -char * -scatn(ssize_t sc, const char **sv, - size_t max, char **rval) -{ - int saved_errno = errno; - char *final = NULL; - char *rcur = NULL; - char *rtmp = NULL; - ssize_t i; - errno = 0; - - if (if_err(sc < 2, EINVAL) || - if_err(sv == NULL, EFAULT) || - if_err(rval == NULL || *rval != NULL, EFAULT)) - goto err; - - for (i = 0; i < sc; i++) { - - if (if_err(sv[i] == NULL, EFAULT)) - goto err; - else if (i == 0) { - (void) sdup(sv[0], max, &final); - continue; - } - - rtmp = NULL; - scat(final, sv[i], max, &rtmp); - - free_and_set_null(&final); - final = rtmp; - rtmp = NULL; - } - - reset_caller_errno(0); - *rval = final; - return *rval; -err: - free_and_set_null(&rcur); - free_and_set_null(&rtmp); - free_and_set_null(&final); - - (void) with_fallback_errno(EFAULT); - - exitf("scatn"); - return NULL; -} - -/* strict strcat */ -char * -scat(const char *s1, const char *s2, - size_t n, char **dest) -{ - size_t size1; - size_t size2; - char *rval = NULL; - int saved_errno = errno; - errno = 0; - - if (if_err(dest == NULL || *dest != NULL, EFAULT)) - goto err; - - slen(s1, n, &size1); - slen(s2, n, &size2); - - if (if_err(size1 - > SIZE_MAX - size2 - 1, EOVERFLOW)) - goto err; - - smalloc(&rval, size1 + size2 + 1); - - memcpy(rval, s1, size1); - memcpy(rval + size1, s2, size2); - *(rval + size1 + size2) = '\0'; - - reset_caller_errno(0); - *dest = rval; - return *dest; -err: - (void) with_fallback_errno(EINVAL); - if (dest != NULL) - *dest = NULL; - exitf("scat"); - - return NULL; -} - -/* strict split/de-cat - off is where - 2nd buffer will start from */ -void -dcat(const char *s, size_t n, - size_t off, char **dest1, - char **dest2) -{ - size_t size; - char *rval1 = NULL; - char *rval2 = NULL; - int saved_errno = errno; - errno = 0; - - if (if_err(dest1 == NULL || dest2 == NULL, EFAULT)) - goto err; - - if (if_err(slen(s, n, &size) >= SIZE_MAX - 1, EOVERFLOW) || - if_err(off >= size, EOVERFLOW)) - goto err; - - memcpy(smalloc(&rval1, off + 1), - s, off); - *(rval1 + off) = '\0'; - - memcpy(smalloc(&rval2, size - off +1), - s + off, size - off); - *(rval2 + size - off) = '\0'; - - *dest1 = rval1; - *dest2 = rval2; - - reset_caller_errno(0); - return; - -err: - *dest1 = *dest2 = NULL; - - free_and_set_null(&rval1); - free_and_set_null(&rval2); - - (void) with_fallback_errno(EINVAL); - exitf("dcat"); -} - -/* because no libc reimagination is complete - * without a reimplementation of memcmp. and - * no safe one is complete without null checks. - */ -int -vcmp(const void *s1, const void *s2, size_t n) -{ - int saved_errno = errno; - size_t i = 0; - size_t a; - size_t b; - - const unsigned char *x; - const unsigned char *y; - errno = 0; - - if (if_err(s1 == NULL || s2 == NULL, EFAULT)) - exitf("vcmp: null input"); - - x = s1; - y = s2; - - for ( ; i + sizeof(size_t) <= n; i += sizeof(size_t)) { - - memcpy(&a, x + i, sizeof(size_t)); - memcpy(&b, y + i, sizeof(size_t)); - - if (a != b) - break; - } - - for ( ; i < n; i++) - if (x[i] != y[i]) - return (int)x[i] - (int)y[i]; - - reset_caller_errno(0); - return 0; -} - -/* on functions that return with errno, - * i sometimes have a default fallback, - * which is set if errno wasn't changed, - * under error condition. - */ -int -with_fallback_errno(int fallback) -{ - if (!errno) - errno = fallback; - return -1; -} - -/* the one for nvmutil state is in state.c */ -/* this one just exits */ -void -exitf(const char *msg, ...) -{ - va_list args; - int saved_errno = errno; - - func_t err_cleanup = errhook(NULL); - err_cleanup(); - reset_caller_errno(0); - saved_errno = errno; - - if (!errno) - saved_errno = errno = ECANCELED; - - fprintf(stderr, "%s: ", lbgetprogname()); - - va_start(args, msg); - vfprintf(stderr, msg, args); - va_end(args); - - errno = saved_errno; - fprintf(stderr, ": %s\n", strerror(errno)); - - exit(EXIT_FAILURE); -} - -/* the err function will - * call this upon exit, and - * cleanup will be performed - * e.g. you might want to - * close some files, depending - * on your program. - * see: exitf() - */ -func_t errhook(func_t ptr) -{ - static int set = 0; - static func_t hook = NULL; - - if (!set) { - set = 1; - - if (ptr == NULL) - hook = no_op; - else - hook = ptr; - } - - return hook; -} - -void -no_op(void) -{ - return; -} - -const char * -lbgetprogname(void) -{ - char *name = lbsetprogname(NULL); - char *p = NULL; - if (name) - p = strrchr(name, '/'); - if (p) - return p + 1; - else if (name) - return name; - else - return "libreboot-utils"; -} - -/* singleton. if string not null, - sets the string. after set, - will not set anymore. either - way, returns the string - */ -char * -lbsetprogname(char *argv0) -{ - static char *progname = NULL; - static int set = 0; - - if (!set) { - if (argv0 == NULL) - return "libreboot-utils"; - (void) sdup(argv0, PATH_MAX, &progname); - set = 1; - } - - return progname; -} |
