]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - lib/sysfs.c
readprofile: check input file is not empty [asan]
[thirdparty/util-linux.git] / lib / sysfs.c
index 5b59952ebc96595905b16fb0c164ea4f4e535ffe..626451bddb3efa62492ef9c29013d545afa7b020 100644 (file)
 #include "sysfs.h"
 #include "fileutils.h"
 #include "all-io.h"
+#include "debug.h"
 
 static void sysfs_blkdev_deinit_path(struct path_cxt *pc);
 static int  sysfs_blkdev_enoent_redirect(struct path_cxt *pc, const char *path, int *dirfd);
-static dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char *parent);
+
+/*
+ * Debug stuff (based on include/debug.h)
+ */
+static UL_DEBUG_DEFINE_MASK(ulsysfs);
+UL_DEBUG_DEFINE_MASKNAMES(ulsysfs) = UL_DEBUG_EMPTY_MASKNAMES;
+
+#define ULSYSFS_DEBUG_INIT     (1 << 1)
+#define ULSYSFS_DEBUG_CXT      (1 << 2)
+
+#define DBG(m, x)       __UL_DBG(ulsysfs, ULSYSFS_DEBUG_, m, x)
+#define ON_DBG(m, x)    __UL_DBG_CALL(ulsysfs, ULSYSFS_DEBUG_, m, x)
+
+#define UL_DEBUG_CURRENT_MASK  UL_DEBUG_MASK(ulsysfs)
+#include "debugobj.h"
+
+void ul_sysfs_init_debug(void)
+{
+       if (ulsysfs_debug_mask)
+               return;
+       __UL_INIT_DEBUG_FROM_ENV(ulsysfs, ULSYSFS_DEBUG_, 0, ULSYSFS_DEBUG);
+}
+
+struct path_cxt *ul_new_sysfs_path(dev_t devno, struct path_cxt *parent, const char *prefix)
+{
+       struct path_cxt *pc = ul_new_path(NULL);
+
+       if (!pc)
+               return NULL;
+       if (prefix)
+               ul_path_set_prefix(pc, prefix);
+
+       if (sysfs_blkdev_init_path(pc, devno, parent) != 0) {
+               ul_unref_path(pc);
+               return NULL;
+       }
+
+       DBG(CXT, ul_debugobj(pc, "alloc"));
+       return pc;
+}
 
 /*
  * sysfs_blkdev_* is sysfs extension to ul_path_* API for block devices.
  *
+ * The function is possible to call in loop and without sysfs_blkdev_deinit_path().
+ * The sysfs_blkdev_deinit_path() is automatically called by ul_unref_path().
+ *
  */
 int sysfs_blkdev_init_path(struct path_cxt *pc, dev_t devno, struct path_cxt *parent)
 {
@@ -44,16 +87,22 @@ int sysfs_blkdev_init_path(struct path_cxt *pc, dev_t devno, struct path_cxt *pa
                return rc;
 
        /* initialize sysfs blkdev specific stuff */
-       blk = calloc(1, sizeof(struct sysfs_blkdev));
-       if (!blk)
-               return -ENOMEM;
+       blk = ul_path_get_dialect(pc);
+       if (!blk) {
+               DBG(CXT, ul_debugobj(pc, "alloc new sysfs handler"));
+               blk = calloc(1, sizeof(struct sysfs_blkdev));
+               if (!blk)
+                       return -ENOMEM;
 
-       blk->devno = devno;
-       ul_path_set_dialect(pc, blk, sysfs_blkdev_deinit_path);
+               ul_path_set_dialect(pc, blk, sysfs_blkdev_deinit_path);
+               ul_path_set_enoent_redirect(pc, sysfs_blkdev_enoent_redirect);
+       }
 
+       DBG(CXT, ul_debugobj(pc, "init sysfs stuff"));
+
+       blk->devno = devno;
        sysfs_blkdev_set_parent(pc, parent);
 
-       ul_path_set_enoent_redirect(pc, sysfs_blkdev_enoent_redirect);
        return 0;
 }
 
@@ -63,12 +112,17 @@ static void sysfs_blkdev_deinit_path(struct path_cxt *pc)
 
        if (!pc)
                return;
+
+       DBG(CXT, ul_debugobj(pc, "deinit"));
+
        blk = ul_path_get_dialect(pc);
        if (!blk)
                return;
 
        ul_ref_path(blk->parent);
        free(blk);
+
+       ul_path_set_dialect(pc, NULL, NULL);
 }
 
 int sysfs_blkdev_set_parent(struct path_cxt *pc, struct path_cxt *parent)
@@ -89,9 +143,16 @@ int sysfs_blkdev_set_parent(struct path_cxt *pc, struct path_cxt *parent)
        } else
                blk->parent = NULL;
 
+       DBG(CXT, ul_debugobj(pc, "new parent"));
        return 0;
 }
 
+struct path_cxt *sysfs_blkdev_get_parent(struct path_cxt *pc)
+{
+       struct sysfs_blkdev *blk = ul_path_get_dialect(pc);
+       return blk ? blk->parent : NULL;
+}
+
 /*
  * Redirects ENOENT errors to the parent, if the path is to the queue/
  * sysfs directory. For example
@@ -105,8 +166,10 @@ static int sysfs_blkdev_enoent_redirect(struct path_cxt *pc, const char *path, i
 
        if (blk && blk->parent && strncmp(path, "queue/", 6) == 0) {
                *dirfd = ul_path_get_dirfd(blk->parent);
-               if (*dirfd >= 0)
+               if (*dirfd >= 0) {
+                       DBG(CXT, ul_debugobj(pc, "%s redirected to parent", path));
                        return 0;
+               }
        }
        return 1;       /* no redirect */
 }
@@ -244,6 +307,7 @@ dev_t sysfs_blkdev_partno_to_devno(struct path_cxt *pc, int partno)
        }
 
        closedir(dir);
+       DBG(CXT, ul_debugobj(pc, "partno (%d) -> devno (%d)", (int) partno, (int) devno));
        return devno;
 }
 
@@ -536,7 +600,7 @@ int sysfs_blkdev_get_wholedisk(     struct path_cxt *pc,
         }
 
         if (diskdevno) {
-            *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), diskname, NULL);
+            *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
             if (!*diskdevno)
                 goto err;
         }
@@ -556,13 +620,11 @@ int sysfs_devno_to_wholedisk(dev_t devno, char *diskname,
 
        if (!devno)
                return -EINVAL;
-       pc = ul_new_path(NULL);
+       pc = ul_new_sysfs_path(devno, NULL, NULL);
        if (!pc)
                return -ENOMEM;
 
-       rc = sysfs_blkdev_init_path(pc, devno, NULL);
-       if (!rc)
-               rc = sysfs_blkdev_get_wholedisk(pc, diskname, len, diskdevno);
+       rc = sysfs_blkdev_get_wholedisk(pc, diskname, len, diskdevno);
        ul_unref_path(pc);
        return rc;
 }
@@ -577,11 +639,9 @@ int sysfs_devno_is_dm_private(dev_t devno, char **uuid)
        char *id = NULL;
        int rc = 0;
 
-       pc = ul_new_path(NULL);
+       pc = ul_new_sysfs_path(devno, NULL, NULL);
        if (!pc)
                goto done;
-       if (sysfs_blkdev_init_path(pc, devno, NULL) != 0)
-               goto done;
        if (ul_path_read_string(pc, &id, "dm/uuid") <= 0 || !id)
                goto done;
 
@@ -750,7 +810,7 @@ static char *scsi_attribute_path(struct path_cxt *pc,
        return (len < 0 || (size_t) len >= bufsz) ? NULL : buf;
 }
 
-int sysfs_scsi_has_attribute(struct path_cxt *pc, const char *attr)
+int sysfs_blkdev_scsi_has_attribute(struct path_cxt *pc, const char *attr)
 {
        char path[PATH_MAX];
        struct stat st;
@@ -761,7 +821,7 @@ int sysfs_scsi_has_attribute(struct path_cxt *pc, const char *attr)
        return stat(path, &st) == 0;
 }
 
-int sysfs_scsi_path_contains(struct path_cxt *pc, const char *pattern)
+int sysfs_blkdev_scsi_path_contains(struct path_cxt *pc, const char *pattern)
 {
        char path[PATH_MAX], linkc[PATH_MAX];
        struct stat st;
@@ -797,7 +857,7 @@ static dev_t read_devno(const char *path)
        return dev;
 }
 
-static dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char *parent)
+dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char *parent)
 {
        char buf[PATH_MAX];
        char *_name = NULL;     /* name as encoded in sysfs */
@@ -807,6 +867,8 @@ static dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, cons
        if (!prefix)
                prefix = "";
 
+       assert(name);
+
        if (strncmp("/dev/", name, 5) == 0) {
                /*
                 * Read from /dev
@@ -915,25 +977,25 @@ dev_t sysfs_blkdev_get_devno(struct path_cxt *pc)
  */
 char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz)
 {
-       struct path_cxt *pc = ul_new_path(NULL);
+       struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
        char *res = NULL;
 
-       if (sysfs_blkdev_init_path(pc, devno, NULL) == 0)
+       if (pc) {
                res = sysfs_blkdev_get_path(pc, buf, bufsiz);
-
-       ul_unref_path(pc);
+               ul_unref_path(pc);
+       }
        return res;
 }
 
 char *sysfs_devno_to_devname(dev_t devno, char *buf, size_t bufsiz)
 {
-       struct path_cxt *pc = ul_new_path(NULL);
+       struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
        char *res = NULL;
 
-       if (sysfs_blkdev_init_path(pc, devno, NULL) == 0)
+       if (pc) {
                res = sysfs_blkdev_get_name(pc, buf, bufsiz);
-
-       ul_unref_path(pc);
+               ul_unref_path(pc);
+       }
        return res;
 }
 
@@ -957,6 +1019,8 @@ int main(int argc, char *argv[])
        if (argc != 2)
                errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]);
 
+       ul_sysfs_init_debug();
+
        devname = argv[1];
        devno = sysfs_devname_to_devno(devname);
 
@@ -972,8 +1036,8 @@ int main(int argc, char *argv[])
        printf(" WHOLEDISK-DEVNO:   %u (%d:%d)\n", (unsigned int) disk_devno, major(disk_devno), minor(disk_devno));
        printf(" WHOLEDISK-DEVNAME: %s\n", diskname);
 
-       pc = ul_new_path(NULL);
-       if (sysfs_blkdev_init_path(pc, devno, NULL) != 0)
+       pc = ul_new_sysfs_path(devno, NULL, NULL);
+       if (!pc)
                goto done;
 
        printf("context based:\n");
@@ -990,10 +1054,10 @@ int main(int argc, char *argv[])
        printf(" PARTITION: %s\n", is_part ? "YES" : "NOT");
 
        if (is_part && disk_devno) {
-               struct path_cxt *disk_pc =  ul_new_path(NULL);
-
-               sysfs_blkdev_init_path(disk_pc, disk_devno, NULL);
+               struct path_cxt *disk_pc =  ul_new_sysfs_path(disk_devno, NULL, NULL);
                sysfs_blkdev_set_parent(pc, disk_pc);
+
+               ul_unref_path(disk_pc);
        }
 
        printf(" HOTPLUG: %s\n", sysfs_blkdev_is_hotpluggable(pc) ? "yes" : "no");