summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sysfs.h10
-rw-r--r--lib/sysfs.c136
2 files changed, 130 insertions, 16 deletions
diff --git a/include/sysfs.h b/include/sysfs.h
index 5190ac482..a26e0a72e 100644
--- a/include/sysfs.h
+++ b/include/sysfs.h
@@ -27,9 +27,10 @@ struct sysfs_cxt {
extern char *sysfs_devno_attribute_path(dev_t devno, char *buf,
- size_t buflen, const char *attr);
+ size_t bufsiz, const char *attr);
extern int sysfs_devno_has_attribute(dev_t devno, const char *attr);
-extern char *sysfs_devno_path(dev_t devno, char *buf, size_t buflen);
+extern char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz);
+extern char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz);
extern dev_t sysfs_devname_to_devno(const char *name, const char *parent);
extern int sysfs_init(struct sysfs_cxt *cxt, dev_t devno,
@@ -39,6 +40,8 @@ extern void sysfs_deinit(struct sysfs_cxt *cxt);
extern DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr);
extern int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st);
+extern ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr,
+ char *buf, size_t bufsiz);
extern int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr);
extern int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr,
@@ -49,10 +52,13 @@ extern int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res)
extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res);
extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res);
+extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz);
+
extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr);
extern int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr);
extern int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname);
+extern char *sysfs_get_slave(struct sysfs_cxt *cxt);
extern int sysfs_is_partition_dirent(DIR *dir, struct dirent *d,
const char *parent_name);
diff --git a/lib/sysfs.c b/lib/sysfs.c
index 3b8052390..1f64c641d 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -8,18 +8,18 @@
#include "sysfs.h"
char *sysfs_devno_attribute_path(dev_t devno, char *buf,
- size_t buflen, const char *attr)
+ size_t bufsiz, const char *attr)
{
int len;
if (attr)
- len = snprintf(buf, buflen, _PATH_SYS_DEVBLOCK "/%d:%d/%s",
+ len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d/%s",
major(devno), minor(devno), attr);
else
- len = snprintf(buf, buflen, _PATH_SYS_DEVBLOCK "/%d:%d",
+ len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d",
major(devno), minor(devno));
- return (len < 0 || len + 1 > buflen) ? NULL : buf;
+ return (len < 0 || len + 1 > bufsiz) ? NULL : buf;
}
int sysfs_devno_has_attribute(dev_t devno, const char *attr)
@@ -34,9 +34,9 @@ int sysfs_devno_has_attribute(dev_t devno, const char *attr)
return 0;
}
-char *sysfs_devno_path(dev_t devno, char *buf, size_t buflen)
+char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz)
{
- return sysfs_devno_attribute_path(devno, buf, buflen, NULL);
+ return sysfs_devno_attribute_path(devno, buf, bufsiz, NULL);
}
dev_t sysfs_devname_to_devno(const char *name, const char *parent)
@@ -95,22 +95,61 @@ dev_t sysfs_devname_to_devno(const char *name, const char *parent)
return dev;
}
+/*
+ * Returns devname (e.g. "/dev/sda1") for the given devno.
+ *
+ * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min>
+ * symlinks.
+ *
+ * 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 sysfs_cxt cxt;
+ char *name;
+ size_t sz;
+ struct stat st;
+
+ if (sysfs_init(&cxt, devno, NULL))
+ return NULL;
+
+ name = sysfs_get_devname(&cxt, buf, bufsiz);
+ sysfs_deinit(&cxt);
+
+ if (!name)
+ return NULL;
+
+ sz = strlen(name);
+
+ if (sz + sizeof("/dev/") > bufsiz)
+ return NULL;
+
+ /* 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 == devno)
+ return buf;
+
+ return NULL;
+}
+
int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent)
{
char path[PATH_MAX];
int fd, rc = 0;
+ memset(cxt, 0, sizeof(*cxt));
+
if (!sysfs_devno_path(devno, path, sizeof(path)))
goto err;
fd = open(path, O_RDONLY);
if (fd < 0)
goto err;
-#ifndef HAVE_FSTATAT
cxt->dir_path = strdup(path);
if (!cxt->dir_path)
goto err;
-#endif
cxt->devno = devno;
cxt->dir_fd = fd;
cxt->parent = parent;
@@ -131,9 +170,7 @@ void sysfs_deinit(struct sysfs_cxt *cxt)
cxt->devno = 0;
cxt->dir_fd = -1;
cxt->parent = NULL;
-#ifndef HAVE_FSTATAT
free(cxt->dir_path);
-#endif
}
int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st)
@@ -174,6 +211,16 @@ static int sysfs_open(struct sysfs_cxt *cxt, const char *attr)
return fd;
}
+ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr,
+ char *buf, size_t bufsiz)
+{
+ if (attr)
+ return readlink_at(cxt->dir_fd, cxt->dir_path, attr, buf, bufsiz);
+
+ /* read /sys/dev/block/<maj:min> link */
+ return readlink(cxt->dir_path, buf, bufsiz);
+}
+
DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr)
{
DIR *dir;
@@ -181,13 +228,12 @@ DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr)
if (attr)
fd = sysfs_open(cxt, attr);
- else {
+ else
/* request to open root of device in sysfs (/sys/block/<dev>)
* -- we cannot use cxt->sysfs_fd directly, because closedir()
* will close this our persistent file descriptor.
*/
fd = dup(cxt->dir_fd);
- }
if (fd < 0)
return NULL;
@@ -259,6 +305,7 @@ int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, const char *fmt, ...)
return rc;
}
+
int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res)
{
int64_t x = 0;
@@ -334,6 +381,57 @@ int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname)
return r;
}
+/*
+ * Returns slave name if there is only one slave, otherwise returns NULL.
+ * The result should be deallocated by free().
+ */
+char *sysfs_get_slave(struct sysfs_cxt *cxt)
+{
+ DIR *dir;
+ struct dirent *d;
+ char *name = NULL;
+
+ if (!(dir = sysfs_opendir(cxt, "slaves")))
+ return NULL;
+
+ while ((d = xreaddir(dir))) {
+ if (name)
+ goto err; /* more slaves */
+
+ name = strdup(d->d_name);
+ }
+
+ closedir(dir);
+ return name;
+err:
+ free(name);
+ return NULL;
+}
+
+/*
+ * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min>
+ * symlinks.
+ */
+char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz)
+{
+ char *name = NULL;
+ ssize_t sz;
+
+ sz = sysfs_readlink(cxt, NULL, buf, bufsiz - 1);
+ if (sz < 0)
+ return NULL;
+
+ buf[sz] = '\0';
+ name = strrchr(buf, '/');
+ if (!name)
+ return NULL;
+
+ name++;
+ sz = strlen(name);
+
+ memmove(buf, name, sz + 1);
+ return buf;
+}
#ifdef TEST_PROGRAM
#include <errno.h>
@@ -348,6 +446,7 @@ int main(int argc, char *argv[])
char path[PATH_MAX];
int i;
uint64_t u64;
+ ssize_t len;
if (argc != 2)
errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]);
@@ -361,23 +460,32 @@ int main(int argc, char *argv[])
printf("NAME: %s\n", devname);
printf("DEVNO: %u\n", (unsigned int) devno);
printf("DEVNOPATH: %s\n", sysfs_devno_path(devno, path, sizeof(path)));
+ printf("DEVPATH: %s\n", sysfs_devno_to_devpath(devno, path, sizeof(path)));
printf("PARTITION: %s\n",
sysfs_devno_has_attribute(devno, "partition") ? "YES" : "NOT");
sysfs_init(&cxt, devno, NULL);
+ len = sysfs_readlink(&cxt, NULL, path, sizeof(path) - 1);
+ if (len > 0) {
+ path[len] = '\0';
+ printf("DEVNOLINK: %s\n", path);
+ }
+
printf("SLAVES: %d\n", sysfs_count_dirents(&cxt, "slaves"));
if (sysfs_read_u64(&cxt, "size", &u64))
- printf("read SIZE failed");
+ printf("read SIZE failed\n");
else
printf("SIZE: %jd\n", u64);
if (sysfs_read_int(&cxt, "queue/hw_sector_size", &i))
- printf("read SECTOR failed");
+ printf("read SECTOR failed\n");
else
printf("SECTOR: %d\n", i);
+ printf("DEVNAME: %s\n", sysfs_get_devname(&cxt, path, sizeof(path)));
+
return EXIT_SUCCESS;
}
#endif