summaryrefslogtreecommitdiffstats
path: root/utils/lib/sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/lib/sysfs.c')
-rw-r--r--utils/lib/sysfs.c1127
1 files changed, 0 insertions, 1127 deletions
diff --git a/utils/lib/sysfs.c b/utils/lib/sysfs.c
deleted file mode 100644
index 5b4de2c..0000000
--- a/utils/lib/sysfs.c
+++ /dev/null
@@ -1,1127 +0,0 @@
-/*
- * No copyright is claimed. This code is in the public domain; do with
- * it what you wish.
- *
- * Written by Karel Zak <kzak@redhat.com>
- */
-#include <ctype.h>
-#include <libgen.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "c.h"
-#include "pathnames.h"
-#include "sysfs.h"
-#include "fileutils.h"
-#include "all-io.h"
-#include "debug.h"
-#include "strutils.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);
-
-/*
- * 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)
-{
- struct sysfs_blkdev *blk;
- int rc;
- char buf[sizeof(_PATH_SYS_DEVBLOCK)
- + sizeof(stringify_value(UINT32_MAX)) * 2
- + 3];
-
- /* define path to devno stuff */
- snprintf(buf, sizeof(buf), _PATH_SYS_DEVBLOCK "/%d:%d", major(devno), minor(devno));
- rc = ul_path_set_dir(pc, buf);
- if (rc)
- return rc;
-
- /* make sure path exists */
- rc = ul_path_get_dirfd(pc);
- if (rc < 0)
- return rc;
-
- /* initialize sysfs blkdev specific stuff */
- 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;
-
- 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);
-
- return 0;
-}
-
-static void sysfs_blkdev_deinit_path(struct path_cxt *pc)
-{
- struct sysfs_blkdev *blk;
-
- if (!pc)
- return;
-
- DBG(CXT, ul_debugobj(pc, "deinit"));
-
- blk = ul_path_get_dialect(pc);
- if (!blk)
- return;
-
- ul_unref_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)
-{
- struct sysfs_blkdev *blk = ul_path_get_dialect(pc);
-
- if (!pc || !blk)
- return -EINVAL;
-
- if (blk->parent) {
- ul_unref_path(blk->parent);
- blk->parent = NULL;
- }
-
- if (parent) {
- ul_ref_path(parent);
- blk->parent = 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
- *
- * /sys/dev/block/8:1/queue/logical_block_size redirects to
- * /sys/dev/block/8:0/queue/logical_block_size
- */
-static int sysfs_blkdev_enoent_redirect(struct path_cxt *pc, const char *path, int *dirfd)
-{
- struct sysfs_blkdev *blk = ul_path_get_dialect(pc);
-
- if (blk && blk->parent && strncmp(path, "queue/", 6) == 0) {
- *dirfd = ul_path_get_dirfd(blk->parent);
- if (*dirfd >= 0) {
- DBG(CXT, ul_debugobj(pc, "%s redirected to parent", path));
- return 0;
- }
- }
- return 1; /* no redirect */
-}
-
-char *sysfs_blkdev_get_name(struct path_cxt *pc, char *buf, size_t bufsiz)
-{
- char link[PATH_MAX];
- char *name;
- ssize_t sz;
-
- /* read /sys/dev/block/<maj:min> link */
- sz = ul_path_readlink(pc, link, sizeof(link) - 1, NULL);
- if (sz < 0)
- return NULL;
- link[sz] = '\0';
-
- name = strrchr(link, '/');
- if (!name)
- return NULL;
-
- name++;
- sz = strlen(name);
- if ((size_t) sz + 1 > bufsiz)
- return NULL;
-
- memcpy(buf, name, sz + 1);
- sysfs_devname_sys_to_dev(buf);
- return buf;
-}
-
-int sysfs_blkdev_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
-{
- char path[NAME_MAX + 6 + 1];
-
-#ifdef _DIRENT_HAVE_D_TYPE
- if (d->d_type != DT_DIR &&
- d->d_type != DT_LNK &&
- d->d_type != DT_UNKNOWN)
- return 0;
-#endif
- if (parent_name) {
- const char *p = parent_name;
- size_t len;
-
- /* /dev/sda --> "sda" */
- if (*parent_name == '/') {
- p = strrchr(parent_name, '/');
- if (!p)
- return 0;
- p++;
- }
-
- len = strlen(p);
- if (strlen(d->d_name) <= len)
- return 0;
-
- /* partitions subdir name is
- * "<parent>[:digit:]" or "<parent>p[:digit:]"
- */
- return strncmp(p, d->d_name, len) == 0 &&
- ((*(d->d_name + len) == 'p' && isdigit(*(d->d_name + len + 1)))
- || isdigit(*(d->d_name + len)));
- }
-
- /* Cannot use /partition file, not supported on old sysfs */
- snprintf(path, sizeof(path), "%s/start", d->d_name);
-
- return faccessat(dirfd(dir), path, R_OK, 0) == 0;
-}
-
-int sysfs_blkdev_count_partitions(struct path_cxt *pc, const char *devname)
-{
- DIR *dir;
- struct dirent *d;
- int r = 0;
-
- dir = ul_path_opendir(pc, NULL);
- if (!dir)
- return 0;
-
- while ((d = xreaddir(dir))) {
- if (sysfs_blkdev_is_partition_dirent(dir, d, devname))
- r++;
- }
-
- closedir(dir);
- return r;
-}
-
-/*
- * Converts @partno (partition number) to devno of the partition.
- * The @pc handles wholedisk device.
- *
- * Note that this code does not expect any special format of the
- * partitions devnames.
- */
-dev_t sysfs_blkdev_partno_to_devno(struct path_cxt *pc, int partno)
-{
- DIR *dir;
- struct dirent *d;
- dev_t devno = 0;
-
- dir = ul_path_opendir(pc, NULL);
- if (!dir)
- return 0;
-
- while ((d = xreaddir(dir))) {
- int n;
-
- if (!sysfs_blkdev_is_partition_dirent(dir, d, NULL))
- continue;
-
- if (ul_path_readf_s32(pc, &n, "%s/partition", d->d_name))
- continue;
-
- if (n == partno) {
- if (ul_path_readf_majmin(pc, &devno, "%s/dev", d->d_name) == 0)
- break;
- }
- }
-
- closedir(dir);
- DBG(CXT, ul_debugobj(pc, "partno (%d) -> devno (%d)", (int) partno, (int) devno));
- return devno;
-}
-
-
-/*
- * Returns slave name if there is only one slave, otherwise returns NULL.
- * The result should be deallocated by free().
- */
-char *sysfs_blkdev_get_slave(struct path_cxt *pc)
-{
- DIR *dir;
- struct dirent *d;
- char *name = NULL;
-
- dir = ul_path_opendir(pc, "slaves");
- if (!dir)
- return NULL;
-
- while ((d = xreaddir(dir))) {
- if (name)
- goto err; /* more slaves */
- name = strdup(d->d_name);
- }
-
- closedir(dir);
- return name;
-err:
- free(name);
- closedir(dir);
- return NULL;
-}
-
-
-#define SUBSYSTEM_LINKNAME "/subsystem"
-
-/*
- * For example:
- *
- * chain: /sys/dev/block/../../devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/ \
- * 1-1.2:1.0/host65/target65:0:0/65:0:0:0/block/sdb
- *
- * The function check if <chain>/subsystem symlink exists, if yes then returns
- * basename of the readlink result, and remove the last subdirectory from the
- * <chain> path.
- */
-static char *get_subsystem(char *chain, char *buf, size_t bufsz)
-{
- size_t len;
- char *p;
-
- if (!chain || !*chain)
- return NULL;
-
- len = strlen(chain);
- if (len + sizeof(SUBSYSTEM_LINKNAME) > PATH_MAX)
- return NULL;
-
- do {
- ssize_t sz;
-
- /* append "/subsystem" to the path */
- memcpy(chain + len, SUBSYSTEM_LINKNAME, sizeof(SUBSYSTEM_LINKNAME));
-
- /* try if subsystem symlink exists */
- sz = readlink(chain, buf, bufsz - 1);
-
- /* remove last subsystem from chain */
- chain[len] = '\0';
- p = strrchr(chain, '/');
- if (p) {
- *p = '\0';
- len = p - chain;
- }
-
- if (sz > 0) {
- /* we found symlink to subsystem, return basename */
- buf[sz] = '\0';
- return basename(buf);
- }
-
- } while (p);
-
- return NULL;
-}
-
-/*
- * Returns complete path to the device, the patch contains all subsystems
- * used for the device.
- */
-char *sysfs_blkdev_get_devchain(struct path_cxt *pc, char *buf, size_t bufsz)
-{
- /* read /sys/dev/block/<maj>:<min> symlink */
- ssize_t sz = ul_path_readlink(pc, buf, bufsz, NULL);
- const char *prefix;
- size_t psz = 0;
-
- if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > bufsz)
- return NULL;
-
- buf[sz++] = '\0';
- prefix = ul_path_get_prefix(pc);
- if (prefix)
- psz = strlen(prefix);
-
- /* create absolute patch from the link */
- memmove(buf + psz + sizeof(_PATH_SYS_DEVBLOCK "/") - 1, buf, sz);
- if (prefix)
- memcpy(buf, prefix, psz);
-
- memcpy(buf + psz, _PATH_SYS_DEVBLOCK "/", sizeof(_PATH_SYS_DEVBLOCK "/") - 1);
- return buf;
-}
-
-/*
- * The @subsys returns the next subsystem in the chain. Function modifies
- * @devchain string.
- *
- * Returns: 0 in success, <0 on error, 1 on end of chain
- */
-int sysfs_blkdev_next_subsystem(struct path_cxt *pc __attribute__((unused)),
- char *devchain, char **subsys)
-{
- char subbuf[PATH_MAX];
- char *sub;
-
- if (!subsys || !devchain)
- return -EINVAL;
-
- *subsys = NULL;
-
- while ((sub = get_subsystem(devchain, subbuf, sizeof(subbuf)))) {
- *subsys = strdup(sub);
- if (!*subsys)
- return -ENOMEM;
- return 0;
- }
-
- return 1;
-}
-
-
-static int is_hotpluggable_subsystem(const char *name)
-{
- static const char * const hotplug_subsystems[] = {
- "usb",
- "ieee1394",
- "pcmcia",
- "mmc",
- "ccw"
- };
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(hotplug_subsystems); i++)
- if (strcmp(name, hotplug_subsystems[i]) == 0)
- return 1;
-
- return 0;
-}
-
-int sysfs_blkdev_is_hotpluggable(struct path_cxt *pc)
-{
- char buf[PATH_MAX], *chain, *sub;
- int rc = 0;
-
-
- /* check /sys/dev/block/<maj>:<min>/removable attribute */
- if (ul_path_read_s32(pc, &rc, "removable") == 0 && rc == 1)
- return 1;
-
- chain = sysfs_blkdev_get_devchain(pc, buf, sizeof(buf));
-
- while (chain && sysfs_blkdev_next_subsystem(pc, chain, &sub) == 0) {
- rc = is_hotpluggable_subsystem(sub);
- if (rc) {
- free(sub);
- break;
- }
- free(sub);
- }
-
- return rc;
-}
-
-static int get_dm_wholedisk(struct path_cxt *pc, char *diskname,
- size_t len, dev_t *diskdevno)
-{
- int rc = 0;
- char *name;
-
- /* Note, sysfs_blkdev_get_slave() returns the first slave only,
- * if there is more slaves, then return NULL
- */
- name = sysfs_blkdev_get_slave(pc);
- if (!name)
- return -1;
-
- if (diskname && len)
- xstrncpy(diskname, name, len);
-
- if (diskdevno) {
- *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
- if (!*diskdevno)
- rc = -1;
- }
-
- free(name);
- return rc;
-}
-
-/*
- * Returns by @diskdevno whole disk device devno and (optionally) by
- * @diskname the whole disk device name.
- */
-int sysfs_blkdev_get_wholedisk( struct path_cxt *pc,
- char *diskname,
- size_t len,
- dev_t *diskdevno)
-{
- int is_part = 0;
-
- if (!pc)
- return -1;
-
- is_part = ul_path_access(pc, F_OK, "partition") == 0;
- if (!is_part) {
- /*
- * Extra case for partitions mapped by device-mapper.
- *
- * All regular partitions (added by BLKPG ioctl or kernel PT
- * parser) have the /sys/.../partition file. The partitions
- * mapped by DM don't have such file, but they have "part"
- * prefix in DM UUID.
- */
- char *uuid = NULL, *tmp, *prefix;
-
- ul_path_read_string(pc, &uuid, "dm/uuid");
- tmp = uuid;
- prefix = uuid ? strsep(&tmp, "-") : NULL;
-
- if (prefix && strncasecmp(prefix, "part", 4) == 0)
- is_part = 1;
- free(uuid);
-
- if (is_part &&
- get_dm_wholedisk(pc, diskname, len, diskdevno) == 0)
- /*
- * partitioned device, mapped by DM
- */
- goto done;
-
- is_part = 0;
- }
-
- if (!is_part) {
- /*
- * unpartitioned device
- */
- if (diskname && !sysfs_blkdev_get_name(pc, diskname, len))
- goto err;
- if (diskdevno)
- *diskdevno = sysfs_blkdev_get_devno(pc);
-
- } else {
- /*
- * partitioned device
- * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1
- * - dirname ../../block/sda/sda1 = ../../block/sda
- * - basename ../../block/sda = sda
- */
- char linkpath[PATH_MAX];
- char *name;
- ssize_t linklen;
-
- linklen = ul_path_readlink(pc, linkpath, sizeof(linkpath) - 1, NULL);
- if (linklen < 0)
- goto err;
- linkpath[linklen] = '\0';
-
- stripoff_last_component(linkpath); /* dirname */
- name = stripoff_last_component(linkpath); /* basename */
- if (!name)
- goto err;
-
- sysfs_devname_sys_to_dev(name);
- if (diskname && len)
- xstrncpy(diskname, name, len);
-
- if (diskdevno) {
- *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
- if (!*diskdevno)
- goto err;
- }
- }
-
-done:
- return 0;
-err:
- return -1;
-}
-
-int sysfs_devno_to_wholedisk(dev_t devno, char *diskname,
- size_t len, dev_t *diskdevno)
-{
- struct path_cxt *pc;
- int rc = 0;
-
- if (!devno)
- return -EINVAL;
- pc = ul_new_sysfs_path(devno, NULL, NULL);
- if (!pc)
- return -ENOMEM;
-
- rc = sysfs_blkdev_get_wholedisk(pc, diskname, len, diskdevno);
- ul_unref_path(pc);
- return rc;
-}
-
-/*
- * Returns 1 if the device is private device mapper device. The @uuid
- * (if not NULL) returns DM device UUID, use free() to deallocate.
- */
-int sysfs_devno_is_dm_private(dev_t devno, char **uuid)
-{
- struct path_cxt *pc = NULL;
- char *id = NULL;
- int rc = 0;
-
- pc = ul_new_sysfs_path(devno, NULL, NULL);
- if (!pc)
- goto done;
- if (ul_path_read_string(pc, &id, "dm/uuid") <= 0 || !id)
- goto done;
-
- /* Private LVM devices use "LVM-<uuid>-<name>" uuid format (important
- * is the "LVM" prefix and "-<name>" postfix).
- */
- if (strncmp(id, "LVM-", 4) == 0) {
- char *p = strrchr(id + 4, '-');
-
- if (p && *(p + 1))
- rc = 1;
-
- /* Private Stratis devices prefix the UUID with "stratis-1-private"
- */
- } else if (strncmp(id, "stratis-1-private", 17) == 0) {
- rc = 1;
- }
-done:
- ul_unref_path(pc);
- if (uuid)
- *uuid = id;
- else
- free(id);
- return rc;
-}
-
-/*
- * Return 0 or 1, or < 0 in case of error
- */
-int sysfs_devno_is_wholedisk(dev_t devno)
-{
- dev_t disk;
-
- if (sysfs_devno_to_wholedisk(devno, NULL, 0, &disk) != 0)
- return -1;
-
- return devno == disk;
-}
-
-
-int sysfs_blkdev_scsi_get_hctl(struct path_cxt *pc, int *h, int *c, int *t, int *l)
-{
- char buf[PATH_MAX], *hctl;
- struct sysfs_blkdev *blk;
- ssize_t len;
-
- blk = ul_path_get_dialect(pc);
-
- if (!blk || blk->hctl_error)
- return -EINVAL;
- if (blk->has_hctl)
- goto done;
-
- blk->hctl_error = 1;
- len = ul_path_readlink(pc, buf, sizeof(buf) - 1, "device");
- if (len < 0)
- return len;
-
- buf[len] = '\0';
- hctl = strrchr(buf, '/');
- if (!hctl)
- return -1;
- hctl++;
-
- if (sscanf(hctl, "%u:%u:%u:%u", &blk->scsi_host, &blk->scsi_channel,
- &blk->scsi_target, &blk->scsi_lun) != 4)
- return -1;
-
- blk->has_hctl = 1;
-done:
- if (h)
- *h = blk->scsi_host;
- if (c)
- *c = blk->scsi_channel;
- if (t)
- *t = blk->scsi_target;
- if (l)
- *l = blk->scsi_lun;
-
- blk->hctl_error = 0;
- return 0;
-}
-
-
-static char *scsi_host_attribute_path(
- struct path_cxt *pc,
- const char *type,
- char *buf,
- size_t bufsz,
- const char *attr)
-{
- int len;
- int host;
- const char *prefix;
-
- if (sysfs_blkdev_scsi_get_hctl(pc, &host, NULL, NULL, NULL))
- return NULL;
-
- prefix = ul_path_get_prefix(pc);
- if (!prefix)
- prefix = "";
-
- if (attr)
- len = snprintf(buf, bufsz, "%s%s/%s_host/host%d/%s",
- prefix, _PATH_SYS_CLASS, type, host, attr);
- else
- len = snprintf(buf, bufsz, "%s%s/%s_host/host%d",
- prefix, _PATH_SYS_CLASS, type, host);
-
- return (len < 0 || (size_t) len >= bufsz) ? NULL : buf;
-}
-
-char *sysfs_blkdev_scsi_host_strdup_attribute(struct path_cxt *pc,
- const char *type, const char *attr)
-{
- char buf[1024];
- int rc;
- FILE *f;
-
- if (!attr || !type ||
- !scsi_host_attribute_path(pc, type, buf, sizeof(buf), attr))
- return NULL;
-
- if (!(f = fopen(buf, "r" UL_CLOEXECSTR)))
- return NULL;
-
- rc = fscanf(f, "%1023[^\n]", buf);
- fclose(f);
-
- return rc == 1 ? strdup(buf) : NULL;
-}
-
-int sysfs_blkdev_scsi_host_is(struct path_cxt *pc, const char *type)
-{
- char buf[PATH_MAX];
- struct stat st;
-
- if (!type || !scsi_host_attribute_path(pc, type,
- buf, sizeof(buf), NULL))
- return 0;
-
- return stat(buf, &st) == 0 && S_ISDIR(st.st_mode);
-}
-
-static char *scsi_attribute_path(struct path_cxt *pc,
- char *buf, size_t bufsz, const char *attr)
-{
- int len, h, c, t, l;
- const char *prefix;
-
- if (sysfs_blkdev_scsi_get_hctl(pc, &h, &c, &t, &l) != 0)
- return NULL;
-
- prefix = ul_path_get_prefix(pc);
- if (!prefix)
- prefix = "";
-
- if (attr)
- len = snprintf(buf, bufsz, "%s%s/devices/%d:%d:%d:%d/%s",
- prefix, _PATH_SYS_SCSI,
- h,c,t,l, attr);
- else
- len = snprintf(buf, bufsz, "%s%s/devices/%d:%d:%d:%d",
- prefix, _PATH_SYS_SCSI,
- h,c,t,l);
- return (len < 0 || (size_t) len >= bufsz) ? NULL : buf;
-}
-
-int sysfs_blkdev_scsi_has_attribute(struct path_cxt *pc, const char *attr)
-{
- char path[PATH_MAX];
- struct stat st;
-
- if (!scsi_attribute_path(pc, path, sizeof(path), attr))
- return 0;
-
- return stat(path, &st) == 0;
-}
-
-int sysfs_blkdev_scsi_path_contains(struct path_cxt *pc, const char *pattern)
-{
- char path[PATH_MAX], linkc[PATH_MAX];
- struct stat st;
- ssize_t len;
-
- if (!scsi_attribute_path(pc, path, sizeof(path), NULL))
- return 0;
-
- if (stat(path, &st) != 0)
- return 0;
-
- len = readlink(path, linkc, sizeof(linkc) - 1);
- if (len < 0)
- return 0;
-
- linkc[len] = '\0';
- return strstr(linkc, pattern) != NULL;
-}
-
-static dev_t read_devno(const char *path)
-{
- FILE *f;
- int maj = 0, min = 0;
- dev_t dev = 0;
-
- f = fopen(path, "r" UL_CLOEXECSTR);
- if (!f)
- return 0;
-
- if (fscanf(f, "%d:%d", &maj, &min) == 2)
- dev = makedev(maj, min);
- fclose(f);
- return dev;
-}
-
-int sysfs_devname_is_hidden(const char *prefix, const char *name)
-{
- char buf[PATH_MAX];
- int rc = 0, hidden = 0, len;
- FILE *f;
-
- if (strncmp("/dev/", name, 5) == 0)
- return 0;
-
- if (!prefix)
- prefix = "";
- /*
- * Create path to /sys/block/<name>/hidden
- */
- len = snprintf(buf, sizeof(buf),
- "%s" _PATH_SYS_BLOCK "/%s/hidden",
- prefix, name);
-
- if (len < 0 || (size_t) len + 1 > sizeof(buf))
- return 0;
-
- f = fopen(buf, "r" UL_CLOEXECSTR);
- if (!f)
- return 0;
-
- rc = fscanf(f, "%d", &hidden);
- fclose(f);
-
- return rc == 1 ? hidden : 0;
-}
-
-
-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 */
- dev_t dev = 0;
- int len;
-
- if (!prefix)
- prefix = "";
-
- assert(name);
-
- if (strncmp("/dev/", name, 5) == 0) {
- /*
- * Read from /dev
- */
- struct stat st;
-
- if (stat(name, &st) == 0) {
- dev = st.st_rdev;
- goto done;
- }
- name += 5; /* unaccessible, or not node in /dev */
- }
-
- _name = strdup(name);
- if (!_name)
- goto done;
- sysfs_devname_dev_to_sys(_name);
-
- if (parent && strncmp("dm-", name, 3) != 0) {
- /*
- * Create path to /sys/block/<parent>/<name>/dev
- */
- char *_parent = strdup(parent);
-
- if (!_parent) {
- free(_parent);
- goto done;
- }
- sysfs_devname_dev_to_sys(_parent);
- len = snprintf(buf, sizeof(buf),
- "%s" _PATH_SYS_BLOCK "/%s/%s/dev",
- prefix, _parent, _name);
- free(_parent);
- if (len < 0 || (size_t) len >= sizeof(buf))
- goto done;
-
- /* don't try anything else for dm-* */
- dev = read_devno(buf);
- goto done;
- }
-
- /*
- * Read from /sys/block/<sysname>/dev
- */
- len = snprintf(buf, sizeof(buf),
- "%s" _PATH_SYS_BLOCK "/%s/dev",
- prefix, _name);
- if (len < 0 || (size_t) len >= sizeof(buf))
- goto done;
- dev = read_devno(buf);
-
- if (!dev) {
- /*
- * Read from /sys/block/<sysname>/device/dev
- */
- len = snprintf(buf, sizeof(buf),
- "%s" _PATH_SYS_BLOCK "/%s/device/dev",
- prefix, _name);
- if (len < 0 || (size_t) len >= sizeof(buf))
- goto done;
- dev = read_devno(buf);
- }
-done:
- free(_name);
- return dev;
-}
-
-dev_t sysfs_devname_to_devno(const char *name)
-{
- return __sysfs_devname_to_devno(NULL, name, NULL);
-}
-
-char *sysfs_blkdev_get_path(struct path_cxt *pc, char *buf, size_t bufsiz)
-{
- const char *name = sysfs_blkdev_get_name(pc, buf, bufsiz);
- char *res = NULL;
- size_t sz;
- struct stat st;
-
- if (!name)
- goto done;
-
- sz = strlen(name);
- if (sz + sizeof("/dev/") > bufsiz)
- goto done;
-
- /* create the final "/dev/<name>" string */
- memmove(buf + 5, name, sz + 1);
- memcpy(buf, "/dev/", 5);
-
- if (!stat(buf, &st) && S_ISBLK(st.st_mode) && st.st_rdev == sysfs_blkdev_get_devno(pc))
- res = buf;
-done:
- return res;
-}
-
-dev_t sysfs_blkdev_get_devno(struct path_cxt *pc)
-{
- return ((struct sysfs_blkdev *) ul_path_get_dialect(pc))->devno;
-}
-
-/*
- * Returns devname (e.g. "/dev/sda1") for the given devno.
- *
- * Please, use more robust blkid_devno_to_devname() in your applications.
- */
-char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz)
-{
- struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
- char *res = NULL;
-
- if (pc) {
- res = sysfs_blkdev_get_path(pc, buf, bufsiz);
- 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_sysfs_path(devno, NULL, NULL);
- char *res = NULL;
-
- if (pc) {
- res = sysfs_blkdev_get_name(pc, buf, bufsiz);
- ul_unref_path(pc);
- }
- return res;
-}
-
-int sysfs_devno_count_partitions(dev_t devno)
-{
- struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
- int n = 0;
-
- if (pc) {
- char buf[PATH_MAX + 1];
- char *name = sysfs_blkdev_get_name(pc, buf, sizeof(buf));
-
- n = sysfs_blkdev_count_partitions(pc, name);
- ul_unref_path(pc);
- }
- return n;
-}
-
-
-#ifdef TEST_PROGRAM_SYSFS
-#include <errno.h>
-#include <err.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv[])
-{
- struct path_cxt *pc;
- char *devname;
- dev_t devno, disk_devno;
- char path[PATH_MAX], *sub, *chain;
- char diskname[32];
- int i, is_part, rc = EXIT_SUCCESS;
- uint64_t u64;
-
- if (argc != 2)
- errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]);
-
- ul_sysfs_init_debug();
-
- devname = argv[1];
- devno = sysfs_devname_to_devno(devname);
-
- if (!devno)
- err(EXIT_FAILURE, "failed to read devno");
-
- printf("non-context:\n");
- printf(" DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno));
- printf(" DEVNAME: %s\n", sysfs_devno_to_devname(devno, path, sizeof(path)));
- printf(" DEVPATH: %s\n", sysfs_devno_to_devpath(devno, path, sizeof(path)));
-
- sysfs_devno_to_wholedisk(devno, diskname, sizeof(diskname), &disk_devno);
- 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_sysfs_path(devno, NULL, NULL);
- if (!pc)
- goto done;
-
- printf("context based:\n");
- devno = sysfs_blkdev_get_devno(pc);
- printf(" DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno));
- printf(" DEVNAME: %s\n", sysfs_blkdev_get_name(pc, path, sizeof(path)));
- printf(" DEVPATH: %s\n", sysfs_blkdev_get_path(pc, path, sizeof(path)));
-
- sysfs_devno_to_wholedisk(devno, diskname, sizeof(diskname), &disk_devno);
- printf(" WHOLEDISK-DEVNO: %u (%d:%d)\n", (unsigned int) disk_devno, major(disk_devno), minor(disk_devno));
- printf(" WHOLEDISK-DEVNAME: %s\n", diskname);
-
- is_part = ul_path_access(pc, F_OK, "partition") == 0;
- printf(" PARTITION: %s\n", is_part ? "YES" : "NOT");
-
- if (is_part && disk_devno) {
- 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");
- printf(" SLAVES: %d\n", ul_path_count_dirents(pc, "slaves"));
-
- if (!is_part) {
- printf("First 5 partitions:\n");
- for (i = 1; i <= 5; i++) {
- dev_t dev = sysfs_blkdev_partno_to_devno(pc, i);
- if (dev)
- printf("\t#%d %d:%d\n", i, major(dev), minor(dev));
- }
- }
-
- if (ul_path_read_u64(pc, &u64, "size") != 0)
- printf(" (!) read SIZE failed\n");
- else
- printf(" SIZE: %jd\n", u64);
-
- if (ul_path_read_s32(pc, &i, "queue/hw_sector_size"))
- printf(" (!) read SECTOR failed\n");
- else
- printf(" SECTOR: %d\n", i);
-
-
- chain = sysfs_blkdev_get_devchain(pc, path, sizeof(path));
- printf(" SUBSUSTEMS:\n");
-
- while (chain && sysfs_blkdev_next_subsystem(pc, chain, &sub) == 0) {
- printf("\t%s\n", sub);
- free(sub);
- }
-
- rc = EXIT_SUCCESS;
-done:
- ul_unref_path(pc);
- return rc;
-}
-#endif /* TEST_PROGRAM_SYSFS */