]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - lib/path.c
kill: add missing ifdefs
[thirdparty/util-linux.git] / lib / path.c
index 9f351ed05f81e3332e3b4ac9cc6e92d76df90578..64bf7c6f02d1ce311029bc75c012699f6b064962 100644 (file)
@@ -25,6 +25,7 @@
 #include "all-io.h"
 #include "path.h"
 #include "debug.h"
+#include "strutils.h"
 
 /*
  * Debug stuff (based on include/debug.h)
@@ -48,7 +49,7 @@ void ul_path_init_debug(void)
        __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));
 
@@ -61,8 +62,14 @@ struct path_cxt *ul_new_path(const char *dir)
        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;
@@ -88,8 +95,7 @@ void ul_unref_path(struct path_cxt *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);
@@ -206,12 +212,35 @@ int ul_path_get_dirfd(struct path_cxt *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;
@@ -251,8 +280,7 @@ char *ul_path_get_abspath(struct path_cxt *pc, char *buf, size_t bufsz, const ch
 
                if (!tmp)
                        return NULL;
-               strncpy(buf, tmp, bufsz);
-               buf[bufsz - 1] = '\0';
+               xstrncpy(buf, tmp, bufsz);
        }
 
        return buf;
@@ -261,20 +289,27 @@ char *ul_path_get_abspath(struct path_cxt *pc, char *buf, size_t bufsz, const ch
 
 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;
 }
 
@@ -287,7 +322,33 @@ int ul_path_accessf(struct path_cxt *pc, int mode, const char *path, ...)
        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)
@@ -296,33 +357,33 @@ 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, ...)
@@ -383,13 +444,9 @@ FILE *ul_path_fopen(struct path_cxt *pc, const char *mode, 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, ...)
@@ -416,8 +473,12 @@ DIR *ul_path_opendir(struct path_cxt *pc, 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)
@@ -440,13 +501,9 @@ DIR *ul_path_opendir(struct path_cxt *pc, const char *path)
  */
 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);
 }
 
 /*
@@ -483,6 +540,9 @@ ssize_t ul_path_readlink(struct path_cxt *pc, char *buf, size_t bufsiz, const ch
        if (dirfd < 0)
                return dirfd;
 
+       if (*path == '/')
+               path++;
+
        return readlinkat(dirfd, path, buf, bufsiz);
 }
 
@@ -498,10 +558,7 @@ ssize_t ul_path_readlinkf(struct path_cxt *pc, char *buf, size_t bufsiz, const c
        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)
@@ -524,13 +581,9 @@ 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, ...)
@@ -557,13 +610,15 @@ int ul_path_read_string(struct path_cxt *pc, char **str, 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;
 
@@ -584,23 +639,21 @@ int ul_path_readf_string(struct path_cxt *pc, char **str, const char *path, ...)
        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;
 }
 
@@ -613,10 +666,7 @@ int ul_path_readf_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const cha
        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, ...)
@@ -680,10 +730,7 @@ int ul_path_readf_s64(struct path_cxt *pc, int64_t *res, const char *path, ...)
        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)
@@ -708,10 +755,7 @@ int ul_path_readf_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)
@@ -735,10 +779,7 @@ int ul_path_readf_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)
@@ -763,10 +804,7 @@ int ul_path_readf_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)
@@ -790,10 +828,7 @@ int ul_path_readf_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)
@@ -822,10 +857,29 @@ int ul_path_writef_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)
@@ -859,26 +913,8 @@ int ul_path_writef_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)
@@ -905,10 +941,7 @@ int ul_path_countf_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);
 }
 
 /*
@@ -936,6 +969,7 @@ static int ul_path_cpuparse(struct path_cxt *pc, cpu_set_t **set, int maxcpus, i
        FILE *f;
        size_t setsize, len = maxcpus * 7;
        char buf[len];
+       int rc;
 
        *set = NULL;
 
@@ -943,10 +977,12 @@ static int ul_path_cpuparse(struct path_cxt *pc, cpu_set_t **set, int maxcpus, i
        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';
@@ -1033,7 +1069,7 @@ int main(int argc, char *argv[])
        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();
@@ -1141,12 +1177,12 @@ int main(int argc, char *argv[])
                        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) {