#include "all-io.h"
#include "path.h"
#include "debug.h"
+#include "strutils.h"
/*
* Debug stuff (based on include/debug.h)
__UL_INIT_DEBUG_FROM_ENV(ulpath, ULPATH_DEBUG_, 0, ULPATH_DEBUG);
}
-struct path_cxt *ul_new_path(const char *dir)
+struct path_cxt *ul_new_path(const char *dir, ...)
{
struct path_cxt *pc = calloc(1, sizeof(*pc));
pc->dir_fd = -1;
if (dir) {
- pc->dir_path = strdup(dir);
- if (!pc->dir_path)
+ 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;
DBG(CXT, ul_debugobj(pc, "dealloc"));
if (pc->dialect)
pc->free_dialect(pc);
- if (pc->dir_fd >= 0)
- close(pc->dir_fd);
+ ul_path_close_dirfd(pc);
free(pc->dir_path);
free(pc->prefix);
free(pc);
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 = vsnprintf(pc->path_buffer, sizeof(pc->path_buffer), path, ap);
+ int rc;
- if (rc < 0)
+ 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;
if (!tmp)
return NULL;
- strncpy(buf, tmp, bufsz);
- buf[bufsz - 1] = '\0';
+ xstrncpy(buf, tmp, bufsz);
}
return buf;
int ul_path_access(struct path_cxt *pc, int mode, const char *path)
{
- int dir, rc;
-
- dir = ul_path_get_dirfd(pc);
- if (dir < 0)
- return dir;
+ int rc;
- DBG(CXT, ul_debugobj(pc, "access: '%s'", path));
- rc = faccessat(dir, path, mode, 0);
+ 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++;
- if (rc && errno == ENOENT
- && pc->redirect_on_enoent
- && pc->redirect_on_enoent(pc, path, &dir) == 0)
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;
}
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- return ul_path_access(pc, mode, p);
+ 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)
if (!pc) {
fd = open(path, flags);
- DBG(CXT, ul_debug("opening [%d] '%s'", flags, path));
+ DBG(CXT, ul_debug("opening '%s' [no context]", path));
} else {
+ int fdx;
int dir = ul_path_get_dirfd(pc);
if (dir < 0)
return dir;
- fd = openat(dir, path, flags);
+ 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 [%d] '%s'", flags, path));
+ 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;
-
- p = ul_path_mkpath(pc, path, ap);
- if (!p)
- return -errno;
+ const char *p = ul_path_mkpath(pc, path, ap);
- return ul_path_open(pc, flags, p);
+ return !p ? -errno : ul_path_open(pc, flags, p);
}
int ul_path_openf(struct path_cxt *pc, int flags, const char *path, ...)
FILE *ul_path_vfopenf(struct path_cxt *pc, const char *mode, const char *path, va_list ap)
{
- const char *p;
+ const char *p = ul_path_mkpath(pc, path, ap);
- p = ul_path_mkpath(pc, path, ap);
- if (!p)
- return NULL;
-
- return ul_path_fopen(pc, mode, p);
+ return !p ? NULL : ul_path_fopen(pc, mode, p);
}
FILE *ul_path_fopenf(struct path_cxt *pc, const char *mode, const char *path, ...)
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"));
- fd = dup_fd_cloexec(ul_path_get_dirfd(pc), STDERR_FILENO + 1);
+ dirfd = ul_path_get_dirfd(pc);
+ if (dirfd >= 0)
+ fd = dup_fd_cloexec(dirfd, STDERR_FILENO + 1);
}
if (fd < 0)
*/
DIR *ul_path_vopendirf(struct path_cxt *pc, const char *path, va_list ap)
{
- const char *p;
-
- p = ul_path_mkpath(pc, path, ap);
- if (!p)
- return NULL;
+ const char *p = ul_path_mkpath(pc, path, ap);
- return ul_path_opendir(pc, p);
+ return !p ? NULL : ul_path_opendir(pc, p);
}
/*
if (dirfd < 0)
return dirfd;
+ if (*path == '/')
+ path++;
+
return readlinkat(dirfd, path, buf, bufsiz);
}
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -errno;
-
- return ul_path_readlink(pc, buf, bufsiz, p);
+ 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 ul_path_vreadf(struct path_cxt *pc, char *buf, size_t len, const char *path, va_list ap)
{
- const char *p;
-
- p = ul_path_mkpath(pc, path, ap);
- if (!p)
- return -EINVAL;
+ const char *p = ul_path_mkpath(pc, path, ap);
- return ul_path_read(pc, buf, len, p);
+ 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, ...)
char buf[BUFSIZ];
int rc;
- *str = NULL;
+ if (!str)
+ return -EINVAL;
+ *str = NULL;
rc = ul_path_read(pc, buf, sizeof(buf) - 1, path);
- if (rc < 0 || !str)
- return rc;;
+ if (rc < 0)
+ return rc;
- /* Remove tailing newline (usuall in sysfs) */
+ /* Remove tailing newline (usual in sysfs) */
if (rc > 0 && *(buf + rc - 1) == '\n')
--rc;
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
-
- return ul_path_read_string(pc, str, p);
+ 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;;
+ return rc;
- /* Remove tailing newline (usuall in sysfs) */
+ /* Remove tailing newline (usual in sysfs) */
if (rc > 0 && *(buf + rc - 1) == '\n')
- --rc;
+ buf[--rc] = '\0';
+ else
+ buf[rc - 1] = '\0';
- buf[rc] = '\0';
return rc;
}
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
-
- return ul_path_read_buffer(pc, buf, bufsz, p);
+ 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, ...)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;;
-
- return ul_path_read_s64(pc, res, p);
+ 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)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
-
- return ul_path_read_u64(pc, res, p);
+ return !p ? -errno : ul_path_read_u64(pc, res, p);
}
int ul_path_read_s32(struct path_cxt *pc, int *res, const char *path)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
-
- return ul_path_read_s32(pc, res, p);
+ 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)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
-
- return ul_path_read_u32(pc, res, p);
+ 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)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
-
- return ul_path_read_majmin(pc, res, p);
+ 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)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
+ return !p ? -errno : ul_path_write_string(pc, str, p);
+}
- return 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)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return -EINVAL;
-
- return ul_path_write_u64(pc, num, p);
-
-}
+ return !p ? -errno : ul_path_write_u64(pc, num, p);
-static struct dirent *xreaddir(DIR *dp)
-{
- struct dirent *d;
-
- while ((d = readdir(dp))) {
- if (!strcmp(d->d_name, ".") ||
- !strcmp(d->d_name, ".."))
- continue;
-
- /* blacklist here? */
- break;
- }
- return d;
}
int ul_path_count_dirents(struct path_cxt *pc, const char *path)
p = ul_path_mkpath(pc, path, ap);
va_end(ap);
- if (!p)
- return 0;
-
- return ul_path_count_dirents(pc, p);
+ return !p ? -errno : ul_path_count_dirents(pc, p);
}
/*
FILE *f;
size_t setsize, len = maxcpus * 7;
char buf[len];
+ int rc;
*set = NULL;
if (!f)
return -errno;
- if (!fgets(buf, len, 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';
while((c = getopt_long(argc, argv, "p:h", longopts, NULL)) != -1) {
switch(c) {
case 'p':
- prefix = optarg, "failed to parse range start";
+ prefix = optarg;
break;
case 'h':
usage();
errx(EXIT_FAILURE, "<file> not defined");
file = argv[optind++];
- if (ul_path_read_string(pc, &res, file) != 0)
- err(EXIT_FAILURE, "read u64 failed");
+ 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 u64 failed");
+ 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) {