diff options
Diffstat (limited to 'utils/lib/path.c')
| -rw-r--r-- | utils/lib/path.c | 1248 |
1 files changed, 0 insertions, 1248 deletions
diff --git a/utils/lib/path.c b/utils/lib/path.c deleted file mode 100644 index 75fa853..0000000 --- a/utils/lib/path.c +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * Simple functions to access files. Paths can be globally prefixed to read - * data from an alternative source (e.g. a /proc dump for regression tests). - * - * The paths is possible to format by printf-like way for functions with "f" - * postfix in the name (e.g. readf, openf, ... ul_path_readf_u64()). - * - * The ul_path_read_* API is possible to use without path_cxt handler. In this - * case is not possible to use global prefix and printf-like formatting. - * - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> [February 2018] - */ -#include <stdarg.h> -#include <string.h> -#include <unistd.h> -#include <stdio.h> -#include <inttypes.h> -#include <errno.h> - -#include "c.h" -#include "fileutils.h" -#include "all-io.h" -#include "path.h" -#include "debug.h" -#include "strutils.h" - -/* - * Debug stuff (based on include/debug.h) - */ -static UL_DEBUG_DEFINE_MASK(ulpath); -UL_DEBUG_DEFINE_MASKNAMES(ulpath) = UL_DEBUG_EMPTY_MASKNAMES; - -#define ULPATH_DEBUG_INIT (1 << 1) -#define ULPATH_DEBUG_CXT (1 << 2) - -#define DBG(m, x) __UL_DBG(ulpath, ULPATH_DEBUG_, m, x) -#define ON_DBG(m, x) __UL_DBG_CALL(ulpath, ULPATH_DEBUG_, m, x) - -#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpath) -#include "debugobj.h" - -void ul_path_init_debug(void) -{ - if (ulpath_debug_mask) - return; - __UL_INIT_DEBUG_FROM_ENV(ulpath, ULPATH_DEBUG_, 0, ULPATH_DEBUG); -} - -struct path_cxt *ul_new_path(const char *dir, ...) -{ - struct path_cxt *pc = calloc(1, sizeof(*pc)); - - if (!pc) - return NULL; - - DBG(CXT, ul_debugobj(pc, "alloc")); - - pc->refcount = 1; - pc->dir_fd = -1; - - if (dir) { - int rc; - va_list ap; - - va_start(ap, dir); - rc = vasprintf(&pc->dir_path, dir, ap); - va_end(ap); - - if (rc < 0 || !pc->dir_path) - goto fail; - } - return pc; -fail: - ul_unref_path(pc); - return NULL; -} - -void ul_ref_path(struct path_cxt *pc) -{ - if (pc) - pc->refcount++; -} - -void ul_unref_path(struct path_cxt *pc) -{ - if (!pc) - return; - - pc->refcount--; - - if (pc->refcount <= 0) { - DBG(CXT, ul_debugobj(pc, "dealloc")); - if (pc->dialect) - pc->free_dialect(pc); - ul_path_close_dirfd(pc); - free(pc->dir_path); - free(pc->prefix); - free(pc); - } -} - -int ul_path_set_prefix(struct path_cxt *pc, const char *prefix) -{ - char *p = NULL; - - assert(pc->dir_fd < 0); - - if (prefix) { - p = strdup(prefix); - if (!p) - return -ENOMEM; - } - - free(pc->prefix); - pc->prefix = p; - DBG(CXT, ul_debugobj(pc, "new prefix: '%s'", p)); - return 0; -} - -const char *ul_path_get_prefix(struct path_cxt *pc) -{ - return pc ? pc->prefix : NULL; -} - -int ul_path_set_dir(struct path_cxt *pc, const char *dir) -{ - char *p = NULL; - - if (dir) { - p = strdup(dir); - if (!p) - return -ENOMEM; - } - - if (pc->dir_fd >= 0) { - close(pc->dir_fd); - pc->dir_fd = -1; - } - - free(pc->dir_path); - pc->dir_path = p; - DBG(CXT, ul_debugobj(pc, "new dir: '%s'", p)); - return 0; -} - -const char *ul_path_get_dir(struct path_cxt *pc) -{ - return pc ? pc->dir_path : NULL; -} - -int ul_path_set_dialect(struct path_cxt *pc, void *data, void free_data(struct path_cxt *)) -{ - pc->dialect = data; - pc->free_dialect = free_data; - DBG(CXT, ul_debugobj(pc, "(re)set dialect")); - return 0; -} - -void *ul_path_get_dialect(struct path_cxt *pc) -{ - return pc ? pc->dialect : NULL; -} - -int ul_path_set_enoent_redirect(struct path_cxt *pc, int (*func)(struct path_cxt *, const char *, int *)) -{ - pc->redirect_on_enoent = func; - return 0; -} - -static const char *get_absdir(struct path_cxt *pc) -{ - int rc; - const char *dirpath; - - if (!pc->prefix) - return pc->dir_path; - - dirpath = pc->dir_path; - if (!dirpath) - return pc->prefix; - if (*dirpath == '/') - dirpath++; - - rc = snprintf(pc->path_buffer, sizeof(pc->path_buffer), "%s/%s", pc->prefix, dirpath); - if (rc < 0) - return NULL; - if ((size_t)rc >= sizeof(pc->path_buffer)) { - errno = ENAMETOOLONG; - return NULL; - } - - return pc->path_buffer; -} - -int ul_path_is_accessible(struct path_cxt *pc) -{ - const char *path; - assert(pc); - - if (pc->dir_fd >= 0) - return 1; - - path = get_absdir(pc); - if (!path) - return 0; - return access(path, F_OK) == 0; -} - -int ul_path_get_dirfd(struct path_cxt *pc) -{ - assert(pc); - assert(pc->dir_path); - - if (pc->dir_fd < 0) { - const char *path = get_absdir(pc); - if (!path) - return -errno; - - DBG(CXT, ul_debugobj(pc, "opening dir: '%s'", path)); - pc->dir_fd = open(path, O_RDONLY|O_CLOEXEC); - } - - return pc->dir_fd; -} - -/* Note that next ul_path_get_dirfd() will reopen the directory */ -void ul_path_close_dirfd(struct path_cxt *pc) -{ - assert(pc); - - if (pc->dir_fd >= 0) { - DBG(CXT, ul_debugobj(pc, "closing dir")); - close(pc->dir_fd); - pc->dir_fd = -1; - } -} - -int ul_path_isopen_dirfd(struct path_cxt *pc) -{ - return pc && pc->dir_fd >= 0; -} - -static const char *ul_path_mkpath(struct path_cxt *pc, const char *path, va_list ap) -{ - int rc; - - errno = 0; - - rc = vsnprintf(pc->path_buffer, sizeof(pc->path_buffer), path, ap); - if (rc < 0) { - if (!errno) - errno = EINVAL; - return NULL; - } - - if ((size_t)rc >= sizeof(pc->path_buffer)) { - errno = ENAMETOOLONG; - return NULL; - } - - return pc->path_buffer; -} - -char *ul_path_get_abspath(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...) -{ - if (path) { - int rc; - va_list ap; - const char *tail = NULL, *dirpath = pc->dir_path; - - va_start(ap, path); - tail = ul_path_mkpath(pc, path, ap); - va_end(ap); - - if (dirpath && *dirpath == '/') - dirpath++; - if (tail && *tail == '/') - tail++; - - rc = snprintf(buf, bufsz, "%s/%s/%s", - pc->prefix ? pc->prefix : "", - dirpath ? dirpath : "", - tail ? tail : ""); - - if ((size_t)rc >= bufsz) { - errno = ENAMETOOLONG; - return NULL; - } - } else { - const char *tmp = get_absdir(pc); - - if (!tmp) - return NULL; - xstrncpy(buf, tmp, bufsz); - } - - return buf; -} - - -int ul_path_access(struct path_cxt *pc, int mode, const char *path) -{ - int rc; - - if (!pc) { - rc = access(path, mode); - DBG(CXT, ul_debug("access '%s' [no context, rc=%d]", path, rc)); - } else { - int dir = ul_path_get_dirfd(pc); - if (dir < 0) - return dir; - if (*path == '/') - path++; - - rc = faccessat(dir, path, mode, 0); - - if (rc && errno == ENOENT - && pc->redirect_on_enoent - && pc->redirect_on_enoent(pc, path, &dir) == 0) - rc = faccessat(dir, path, mode, 0); - - DBG(CXT, ul_debugobj(pc, "access: '%s' [rc=%d]", path, rc)); - } - return rc; -} - -int ul_path_accessf(struct path_cxt *pc, int mode, const char *path, ...) -{ - va_list ap; - const char *p; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_access(pc, mode, p); -} - -int ul_path_stat(struct path_cxt *pc, struct stat *sb, const char *path) -{ - int rc; - - if (!pc) { - rc = stat(path, sb); - DBG(CXT, ul_debug("stat '%s' [no context, rc=%d]", path, rc)); - } else { - int dir = ul_path_get_dirfd(pc); - if (dir < 0) - return dir; - if (*path == '/') - path++; - - rc = fstatat(dir, path, sb, 0); - - if (rc && errno == ENOENT - && pc->redirect_on_enoent - && pc->redirect_on_enoent(pc, path, &dir) == 0) - rc = fstatat(dir, path, sb, 0); - - DBG(CXT, ul_debugobj(pc, "stat '%s' [rc=%d]", path, rc)); - } - return rc; -} - -int ul_path_open(struct path_cxt *pc, int flags, const char *path) -{ - int fd; - - if (!pc) { - fd = open(path, flags); - DBG(CXT, ul_debug("opening '%s' [no context]", path)); - } else { - int fdx; - int dir = ul_path_get_dirfd(pc); - if (dir < 0) - return dir; - - if (*path == '/') - path++; - - fdx = fd = openat(dir, path, flags); - - if (fd < 0 && errno == ENOENT - && pc->redirect_on_enoent - && pc->redirect_on_enoent(pc, path, &dir) == 0) - fd = openat(dir, path, flags); - - DBG(CXT, ul_debugobj(pc, "opening '%s'%s", path, fdx != fd ? " [redirected]" : "")); - } - return fd; -} - -int ul_path_vopenf(struct path_cxt *pc, int flags, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? -errno : ul_path_open(pc, flags, p); -} - -int ul_path_openf(struct path_cxt *pc, int flags, const char *path, ...) -{ - va_list ap; - int rc; - - va_start(ap, path); - rc = ul_path_vopenf(pc, flags, path, ap); - va_end(ap); - - return rc; -} - -/* - * Maybe stupid, but good enough ;-) - */ -static int mode2flags(const char *mode) -{ - int flags = 0; - const char *p; - - for (p = mode; p && *p; p++) { - if (*p == 'r' && *(p + 1) == '+') - flags |= O_RDWR; - else if (*p == 'r') - flags |= O_RDONLY; - - else if (*p == 'w' && *(p + 1) == '+') - flags |= O_RDWR | O_TRUNC; - else if (*p == 'w') - flags |= O_WRONLY | O_TRUNC; - - else if (*p == 'a' && *(p + 1) == '+') - flags |= O_RDWR | O_APPEND; - else if (*p == 'a') - flags |= O_WRONLY | O_APPEND; -#ifdef O_CLOEXEC - else if (*p == *UL_CLOEXECSTR) - flags |= O_CLOEXEC; -#endif - } - - return flags; -} - -FILE *ul_path_fopen(struct path_cxt *pc, const char *mode, const char *path) -{ - int flags = mode2flags(mode); - int fd = ul_path_open(pc, flags, path); - - if (fd < 0) - return NULL; - - return fdopen(fd, mode); -} - - -FILE *ul_path_vfopenf(struct path_cxt *pc, const char *mode, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? NULL : ul_path_fopen(pc, mode, p); -} - -FILE *ul_path_fopenf(struct path_cxt *pc, const char *mode, const char *path, ...) -{ - FILE *f; - va_list ap; - - va_start(ap, path); - f = ul_path_vfopenf(pc, mode, path, ap); - va_end(ap); - - return f; -} - -/* - * Open directory @path in read-onl mode. If the path is NULL then duplicate FD - * to the directory addressed by @pc. - */ -DIR *ul_path_opendir(struct path_cxt *pc, const char *path) -{ - DIR *dir; - int fd = -1; - - if (path) - fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, path); - else if (pc->dir_path) { - int dirfd; - - DBG(CXT, ul_debugobj(pc, "duplicate dir path")); - dirfd = ul_path_get_dirfd(pc); - if (dirfd >= 0) - fd = dup_fd_cloexec(dirfd, STDERR_FILENO + 1); - } - - if (fd < 0) - return NULL; - - dir = fdopendir(fd); - if (!dir) { - close(fd); - return NULL; - } - if (!path) - rewinddir(dir); - return dir; -} - - -/* - * Open directory @path in read-onl mode. If the path is NULL then duplicate FD - * to the directory addressed by @pc. - */ -DIR *ul_path_vopendirf(struct path_cxt *pc, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? NULL : ul_path_opendir(pc, p); -} - -/* - * Open directory @path in read-onl mode. If the path is NULL then duplicate FD - * to the directory addressed by @pc. - */ -DIR *ul_path_opendirf(struct path_cxt *pc, const char *path, ...) -{ - va_list ap; - DIR *dir; - - va_start(ap, path); - dir = ul_path_vopendirf(pc, path, ap); - va_end(ap); - - return dir; -} - -/* - * If @path is NULL then readlink is called on @pc directory. - */ -ssize_t ul_path_readlink(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path) -{ - int dirfd; - - if (!path) { - const char *p = get_absdir(pc); - if (!p) - return -errno; - return readlink(p, buf, bufsiz); - } - - dirfd = ul_path_get_dirfd(pc); - if (dirfd < 0) - return dirfd; - - if (*path == '/') - path++; - - return readlinkat(dirfd, path, buf, bufsiz); -} - -/* - * If @path is NULL then readlink is called on @pc directory. - */ -ssize_t ul_path_readlinkf(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_readlink(pc, buf, bufsiz, p); -} - -int ul_path_read(struct path_cxt *pc, char *buf, size_t len, const char *path) -{ - int rc, errsv; - int fd; - - fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - DBG(CXT, ul_debug(" reading '%s'", path)); - rc = read_all(fd, buf, len); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_vreadf(struct path_cxt *pc, char *buf, size_t len, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? -errno : ul_path_read(pc, buf, len, p); -} - -int ul_path_readf(struct path_cxt *pc, char *buf, size_t len, const char *path, ...) -{ - va_list ap; - int rc; - - va_start(ap, path); - rc = ul_path_vreadf(pc, buf, len, path, ap); - va_end(ap); - - return rc; -} - - -/* - * Returns newly allocated buffer with data from file. Maximal size is BUFSIZ - * (send patch if you need something bigger;-) - * - * Returns size of the string! - */ -int ul_path_read_string(struct path_cxt *pc, char **str, const char *path) -{ - char buf[BUFSIZ]; - int rc; - - if (!str) - return -EINVAL; - - *str = NULL; - rc = ul_path_read(pc, buf, sizeof(buf) - 1, path); - if (rc < 0) - return rc; - - /* Remove tailing newline (usual in sysfs) */ - if (rc > 0 && *(buf + rc - 1) == '\n') - --rc; - - buf[rc] = '\0'; - *str = strdup(buf); - if (!*str) - rc = -ENOMEM; - - return rc; -} - -int ul_path_readf_string(struct path_cxt *pc, char **str, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_string(pc, str, p); -} - -int ul_path_read_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path) -{ - int rc = ul_path_read(pc, buf, bufsz - 1, path); - if (rc < 0) - return rc; - - /* Remove tailing newline (usual in sysfs) */ - if (rc > 0 && *(buf + rc - 1) == '\n') - buf[--rc] = '\0'; - else - buf[rc - 1] = '\0'; - - return rc; -} - -int ul_path_readf_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_buffer(pc, buf, bufsz, p); -} - -int ul_path_scanf(struct path_cxt *pc, const char *path, const char *fmt, ...) -{ - FILE *f; - va_list fmt_ap; - int rc; - - f = ul_path_fopen(pc, "r" UL_CLOEXECSTR, path); - if (!f) - return -EINVAL; - - DBG(CXT, ul_debug(" fscanf [%s] '%s'", fmt, path)); - - va_start(fmt_ap, fmt); - rc = vfscanf(f, fmt, fmt_ap); - va_end(fmt_ap); - - fclose(f); - return rc; -} - -int ul_path_scanff(struct path_cxt *pc, const char *path, va_list ap, const char *fmt, ...) -{ - FILE *f; - va_list fmt_ap; - int rc; - - f = ul_path_vfopenf(pc, "r" UL_CLOEXECSTR, path, ap); - if (!f) - return -EINVAL; - - va_start(fmt_ap, fmt); - rc = vfscanf(f, fmt, fmt_ap); - va_end(fmt_ap); - - fclose(f); - return rc; -} - - -int ul_path_read_s64(struct path_cxt *pc, int64_t *res, const char *path) -{ - int64_t x = 0; - int rc; - - rc = ul_path_scanf(pc, path, "%"SCNd64, &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_s64(struct path_cxt *pc, int64_t *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_s64(pc, res, p); -} - -int ul_path_read_u64(struct path_cxt *pc, uint64_t *res, const char *path) -{ - uint64_t x = 0; - int rc; - - rc = ul_path_scanf(pc, path, "%"SCNu64, &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_u64(struct path_cxt *pc, uint64_t *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_u64(pc, res, p); -} - -int ul_path_read_s32(struct path_cxt *pc, int *res, const char *path) -{ - int rc, x = 0; - - rc = ul_path_scanf(pc, path, "%d", &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_s32(struct path_cxt *pc, int *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_s32(pc, res, p); -} - -int ul_path_read_u32(struct path_cxt *pc, unsigned int *res, const char *path) -{ - int rc; - unsigned int x; - - rc = ul_path_scanf(pc, path, "%u", &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_u32(struct path_cxt *pc, unsigned int *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_u32(pc, res, p); -} - -int ul_path_read_majmin(struct path_cxt *pc, dev_t *res, const char *path) -{ - int rc, maj, min; - - rc = ul_path_scanf(pc, path, "%d:%d", &maj, &min); - if (rc != 2) - return -1; - if (res) - *res = makedev(maj, min); - return 0; -} - -int ul_path_readf_majmin(struct path_cxt *pc, dev_t *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_majmin(pc, res, p); -} - -int ul_path_write_string(struct path_cxt *pc, const char *str, const char *path) -{ - int rc, errsv; - int fd; - - fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - rc = write_all(fd, str, strlen(str)); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_writef_string(struct path_cxt *pc, const char *str, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_write_string(pc, str, p); -} - -int ul_path_write_s64(struct path_cxt *pc, int64_t num, const char *path) -{ - char buf[sizeof(stringify_value(LLONG_MAX))]; - int rc, errsv; - int fd, len; - - fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - len = snprintf(buf, sizeof(buf), "%" PRId64, num); - if (len < 0 || (size_t) len >= sizeof(buf)) - rc = len < 0 ? -errno : -E2BIG; - else - rc = write_all(fd, buf, len); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_write_u64(struct path_cxt *pc, uint64_t num, const char *path) -{ - char buf[sizeof(stringify_value(ULLONG_MAX))]; - int rc, errsv; - int fd, len; - - fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - len = snprintf(buf, sizeof(buf), "%" PRIu64, num); - if (len < 0 || (size_t) len >= sizeof(buf)) - rc = len < 0 ? -errno : -E2BIG; - else - rc = write_all(fd, buf, len); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_writef_u64(struct path_cxt *pc, uint64_t num, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_write_u64(pc, num, p); - -} - -int ul_path_count_dirents(struct path_cxt *pc, const char *path) -{ - DIR *dir; - int r = 0; - - dir = ul_path_opendir(pc, path); - if (!dir) - return 0; - - while (xreaddir(dir)) r++; - - closedir(dir); - return r; -} - -int ul_path_countf_dirents(struct path_cxt *pc, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_count_dirents(pc, p); -} - -/* - * Like fopen() but, @path is always prefixed by @prefix. This function is - * useful in case when ul_path_* API is overkill. - */ -FILE *ul_prefix_fopen(const char *prefix, const char *path, const char *mode) -{ - char buf[PATH_MAX]; - - if (!path) - return NULL; - if (!prefix) - return fopen(path, mode); - if (*path == '/') - path++; - - snprintf(buf, sizeof(buf), "%s/%s", prefix, path); - return fopen(buf, mode); -} - -#ifdef HAVE_CPU_SET_T -static int ul_path_cpuparse(struct path_cxt *pc, cpu_set_t **set, int maxcpus, int islist, const char *path, va_list ap) -{ - FILE *f; - size_t setsize, len = maxcpus * 7; - char buf[len]; - int rc; - - *set = NULL; - - f = ul_path_vfopenf(pc, "r" UL_CLOEXECSTR, path, ap); - if (!f) - return -errno; - - rc = fgets(buf, len, f) == NULL ? -errno : 0; - fclose(f); - - if (rc) - return rc; - - len = strlen(buf); - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - *set = cpuset_alloc(maxcpus, &setsize, NULL); - if (!*set) - return -ENOMEM; - - if (islist) { - if (cpulist_parse(buf, *set, setsize, 0)) { - cpuset_free(*set); - return -EINVAL; - } - } else { - if (cpumask_parse(buf, *set, setsize)) { - cpuset_free(*set); - return -EINVAL; - } - } - return 0; -} - -int ul_path_readf_cpuset(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...) -{ - va_list ap; - int rc = 0; - - va_start(ap, path); - rc = ul_path_cpuparse(pc, set, maxcpus, 0, path, ap); - va_end(ap); - - return rc; -} - -int ul_path_readf_cpulist(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...) -{ - va_list ap; - int rc = 0; - - va_start(ap, path); - rc = ul_path_cpuparse(pc, set, maxcpus, 1, path, ap); - va_end(ap); - - return rc; -} - -#endif /* HAVE_CPU_SET_T */ - - -#ifdef TEST_PROGRAM_PATH -#include <getopt.h> - -static void __attribute__((__noreturn__)) usage(void) -{ - fprintf(stdout, " %s [options] <dir> <command>\n\n", program_invocation_short_name); - fputs(" -p, --prefix <dir> redirect hardcoded paths to <dir>\n", stdout); - - fputs(" Commands:\n", stdout); - fputs(" read-u64 <file> read uint64_t from file\n", stdout); - fputs(" read-s64 <file> read int64_t from file\n", stdout); - fputs(" read-u32 <file> read uint32_t from file\n", stdout); - fputs(" read-s32 <file> read int32_t from file\n", stdout); - fputs(" read-string <file> read string from file\n", stdout); - fputs(" read-majmin <file> read devno from file\n", stdout); - fputs(" read-link <file> read symlink\n", stdout); - fputs(" write-string <file> <str> write string from file\n", stdout); - fputs(" write-u64 <file> <str> write uint64_t from file\n", stdout); - - exit(EXIT_SUCCESS); -} - -int main(int argc, char *argv[]) -{ - int c; - const char *prefix = NULL, *dir, *file, *command; - struct path_cxt *pc = NULL; - - static const struct option longopts[] = { - { "prefix", 1, NULL, 'p' }, - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - - while((c = getopt_long(argc, argv, "p:h", longopts, NULL)) != -1) { - switch(c) { - case 'p': - prefix = optarg; - break; - case 'h': - usage(); - break; - default: - err(EXIT_FAILURE, "try --help"); - } - } - - if (optind == argc) - errx(EXIT_FAILURE, "<dir> not defined"); - dir = argv[optind++]; - - ul_path_init_debug(); - - pc = ul_new_path(dir); - if (!pc) - err(EXIT_FAILURE, "failed to initialize path context"); - if (prefix) - ul_path_set_prefix(pc, prefix); - - if (optind == argc) - errx(EXIT_FAILURE, "<command> not defined"); - command = argv[optind++]; - - if (strcmp(command, "read-u32") == 0) { - uint32_t res; - - if (optind == argc) - errx(EXIT_FAILURE, "<file> not defined"); - file = argv[optind++]; - - if (ul_path_read_u32(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %u\n", file, res); - - if (ul_path_readf_u32(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %u\n", file, res); - - } else if (strcmp(command, "read-s32") == 0) { - int32_t res; - - if (optind == argc) - errx(EXIT_FAILURE, "<file> not defined"); - file = argv[optind++]; - - if (ul_path_read_s32(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %d\n", file, res); - - if (ul_path_readf_s32(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %d\n", file, res); - - } else if (strcmp(command, "read-u64") == 0) { - uint64_t res; - - if (optind == argc) - errx(EXIT_FAILURE, "<file> not defined"); - file = argv[optind++]; - - if (ul_path_read_u64(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %" PRIu64 "\n", file, res); - - if (ul_path_readf_u64(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %" PRIu64 "\n", file, res); - - } else if (strcmp(command, "read-s64") == 0) { - int64_t res; - - if (optind == argc) - errx(EXIT_FAILURE, "<file> not defined"); - file = argv[optind++]; - - if (ul_path_read_s64(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %" PRIu64 "\n", file, res); - - if (ul_path_readf_s64(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %" PRIu64 "\n", file, res); - - } else if (strcmp(command, "read-majmin") == 0) { - dev_t res; - - if (optind == argc) - errx(EXIT_FAILURE, "<file> not defined"); - file = argv[optind++]; - - if (ul_path_read_majmin(pc, &res, file) != 0) - err(EXIT_FAILURE, "read maj:min failed"); - printf("read: %s: %d\n", file, (int) res); - - if (ul_path_readf_majmin(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf maj:min failed"); - printf("readf: %s: %d\n", file, (int) res); - - } else if (strcmp(command, "read-string") == 0) { - char *res; - - if (optind == argc) - errx(EXIT_FAILURE, "<file> not defined"); - file = argv[optind++]; - - if (ul_path_read_string(pc, &res, file) < 0) - err(EXIT_FAILURE, "read string failed"); - printf("read: %s: %s\n", file, res); - - if (ul_path_readf_string(pc, &res, "%s", file) < 0) - err(EXIT_FAILURE, "readf string failed"); - printf("readf: %s: %s\n", file, res); - - } else if (strcmp(command, "read-link") == 0) { - char res[PATH_MAX]; - - if (optind == argc) - errx(EXIT_FAILURE, "<file> not defined"); - file = argv[optind++]; - - if (ul_path_readlink(pc, res, sizeof(res), file) < 0) - err(EXIT_FAILURE, "read symlink failed"); - printf("read: %s: %s\n", file, res); - - if (ul_path_readlinkf(pc, res, sizeof(res), "%s", file) < 0) - err(EXIT_FAILURE, "readf symlink failed"); - printf("readf: %s: %s\n", file, res); - - } else if (strcmp(command, "write-string") == 0) { - char *str; - - if (optind + 1 == argc) - errx(EXIT_FAILURE, "<file> <string> not defined"); - file = argv[optind++]; - str = argv[optind++]; - - if (ul_path_write_string(pc, str, file) != 0) - err(EXIT_FAILURE, "write string failed"); - if (ul_path_writef_string(pc, str, "%s", file) != 0) - err(EXIT_FAILURE, "writef string failed"); - - } else if (strcmp(command, "write-u64") == 0) { - uint64_t num; - - if (optind + 1 == argc) - errx(EXIT_FAILURE, "<file> <num> not defined"); - file = argv[optind++]; - num = strtoumax(argv[optind++], NULL, 0); - - if (ul_path_write_u64(pc, num, file) != 0) - err(EXIT_FAILURE, "write u64 failed"); - if (ul_path_writef_u64(pc, num, "%s", file) != 0) - err(EXIT_FAILURE, "writef u64 failed"); - } - - ul_unref_path(pc); - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM_PATH */ - |
