/* SPDX-License-Identifier: MIT * Copyright (c) 2026 Leah Rowe * * String functions */ #include #include #include #include #include #include #include #include #include #include "../include/common.h" /* scmp() - strict string comparison * * strict string comparison * similar to strncmp, but null and * unterminated inputs do not produce * a return value; on error, errno is * set and -1 is returned. * * the real return value is stored in * the 4th argument by pointer. * * the value at rval pointer is set, * only upon success. callers should * check the return value accordingly. */ int scmp(const char *a, const char *b, size_t maxlen, int *rval) { size_t ch; unsigned char ac; unsigned char bc; if (a == NULL || b == NULL || rval == NULL) { errno = EFAULT; return -1; } for (ch = 0; ch < maxlen; ch++) { ac = (unsigned char)a[ch]; bc = (unsigned char)b[ch]; if (ac != bc) { *rval = ac - bc; return 0; } if (ac == '\0') { *rval = 0; return 0; } } /* block unterminated strings */ errno = EFAULT; return -1; } /* slen() - strict strict length * * strict string length calculation * similar to strnlen, but null and * unterminated inputs do not produce * a return value; on error, errno is * set and -1 is returned. * * the real return value is stored in * the 3rd argument by pointer. * * the value at rval pointer is set, * only upon success. callers should * check the return value accordingly. */ int slen(const char *s, size_t maxlen, size_t *rval) { size_t ch; if (s == NULL || rval == NULL) { errno = EFAULT; return -1; } for (ch = 0; ch < maxlen && s[ch] != '\0'; ch++); if (ch == maxlen) { /* unterminated */ errno = EFAULT; return -1; } *rval = ch; return 0; } /* the one for nvmutil state is in state.c */ /* this one just exits */ void err_no_cleanup(int nvm_errval, const char *msg, ...) { va_list args; int saved_errno = errno; const char *p; #if defined(__OpenBSD__) && defined(OpenBSD) #if (OpenBSD) >= 509 if (pledge("stdio", NULL) == -1) fprintf(stderr, "pledge failure during exit"); #endif #endif if (!errno) saved_errno = errno = ECANCELED; if ((p = getnvmprogname()) != NULL) fprintf(stderr, "%s: ", p); va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, ": %s\n", strerror(errno)); exit(EXIT_FAILURE); } const char * getnvmprogname(void) { static char *rval = NULL; static char *p; static int setname = 0; if (!setname) { if ((rval = lbgetprogname(NULL)) == NULL) return NULL; p = strrchr(rval, '/'); if (p) rval = p + 1; setname = 1; } return rval; } /* singleton. if string not null, sets the string. after set, will not set anymore. either way, returns the string */ char * lbgetprogname(char *argv0) { static int setname = 0; static char *progname = NULL; size_t len; if (!setname) { if (if_err(argv0 == NULL || *argv0 == '\0', EFAULT) || slen(argv0, 4096, &len) < 0 || (progname = malloc(len + 1)) == NULL) return NULL; memcpy(progname, argv0, len + 1); setname = 1; } return progname; }