summaryrefslogtreecommitdiffstats
path: root/libblkid/sysfs1.c
diff options
context:
space:
mode:
Diffstat (limited to 'libblkid/sysfs1.c')
-rw-r--r--libblkid/sysfs1.c845
1 files changed, 0 insertions, 845 deletions
diff --git a/libblkid/sysfs1.c b/libblkid/sysfs1.c
deleted file mode 100644
index fd4ec6232..000000000
--- a/libblkid/sysfs1.c
+++ /dev/null
@@ -1,845 +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 <fcntl.h>
-#include <unistd.h>
-#include "c.h"
-#include "at.h"
-#include "pathnames.h"
-#include "sysfs.h"
-
-char *sysfs_devno_attribute_path(dev_t devno, char *buf,
- size_t bufsiz, const char *attr)
-{
- int len;
-
- if (attr)
- len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d/%s",
- major(devno), minor(devno), attr);
- else
- len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d",
- major(devno), minor(devno));
-
- return (len < 0 || (size_t) len + 1 > bufsiz) ? NULL : buf;
-}
-
-int sysfs_devno_has_attribute(dev_t devno, const char *attr)
-{
- char path[PATH_MAX];
- struct stat info;
-
- if (!sysfs_devno_attribute_path(devno, path, sizeof(path), attr))
- return 0;
- if (stat(path, &info) == 0)
- return 1;
- return 0;
-}
-
-char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz)
-{
- return sysfs_devno_attribute_path(devno, buf, bufsiz, NULL);
-}
-
-dev_t sysfs_devname_to_devno(const char *name, const char *parent)
-{
- char buf[PATH_MAX], *path = NULL;
- dev_t dev = 0;
-
- if (strncmp("/dev/", name, 5) == 0) {
- /*
- * Read from /dev
- */
- struct stat st;
-
- if (stat(name, &st) == 0)
- dev = st.st_rdev;
- else
- name += 5; /* unaccesible, or not node in /dev */
- }
-
- if (!dev && parent && strncmp("dm-", name, 3)) {
- /*
- * Create path to /sys/block/<parent>/<name>/dev
- */
- int len = snprintf(buf, sizeof(buf),
- _PATH_SYS_BLOCK "/%s/%s/dev", parent, name);
- if (len < 0 || (size_t) len + 1 > sizeof(buf))
- return 0;
- path = buf;
-
- } else if (!dev) {
- /*
- * Create path to /sys/block/<name>/dev
- */
- int len = snprintf(buf, sizeof(buf),
- _PATH_SYS_BLOCK "/%s/dev", name);
- if (len < 0 || (size_t) len + 1 > sizeof(buf))
- return 0;
- path = buf;
- }
-
- if (path) {
- /*
- * read devno from sysfs
- */
- FILE *f;
- int maj = 0, min = 0;
-
- f = fopen(path, "r");
- if (!f)
- return 0;
-
- if (fscanf(f, "%d:%d", &maj, &min) == 2)
- dev = makedev(maj, min);
- fclose(f);
- }
- 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;
-
- memset(cxt, 0, sizeof(*cxt));
- cxt->dir_fd = -1;
-
- if (!sysfs_devno_path(devno, path, sizeof(path)))
- goto err;
-
- fd = open(path, O_RDONLY);
- if (fd < 0)
- goto err;
- cxt->dir_fd = fd;
-
- cxt->dir_path = strdup(path);
- if (!cxt->dir_path)
- goto err;
- cxt->devno = devno;
- cxt->parent = parent;
- return 0;
-err:
- rc = errno > 0 ? -errno : -1;
- sysfs_deinit(cxt);
- return rc;
-}
-
-void sysfs_deinit(struct sysfs_cxt *cxt)
-{
- if (!cxt)
- return;
-
- if (cxt->dir_fd >= 0)
- close(cxt->dir_fd);
- free(cxt->dir_path);
-
- memset(cxt, 0, sizeof(*cxt));
-
- cxt->dir_fd = -1;
-}
-
-int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st)
-{
- int rc = fstat_at(cxt->dir_fd, cxt->dir_path, attr, st, 0);
-
- if (rc != 0 && errno == ENOENT &&
- strncmp(attr, "queue/", 6) == 0 && cxt->parent) {
-
- /* Exception for "queue/<attr>". These attributes are available
- * for parental devices only
- */
- return fstat_at(cxt->parent->dir_fd,
- cxt->parent->dir_path, attr, st, 0);
- }
- return rc;
-}
-
-int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr)
-{
- struct stat st;
-
- return sysfs_stat(cxt, attr, &st) == 0;
-}
-
-static int sysfs_open(struct sysfs_cxt *cxt, const char *attr)
-{
- int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, O_RDONLY);
-
- if (fd == -1 && errno == ENOENT &&
- strncmp(attr, "queue/", 6) == 0 && cxt->parent) {
-
- /* Exception for "queue/<attr>". These attributes are available
- * for parental devices only
- */
- fd = open_at(cxt->parent->dir_fd, cxt->dir_path, attr, O_RDONLY);
- }
- return fd;
-}
-
-ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr,
- char *buf, size_t bufsiz)
-{
- if (!cxt->dir_path)
- return -1;
-
- 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;
- int fd = -1;
-
- if (attr)
- fd = sysfs_open(cxt, attr);
-
- else if (cxt->dir_fd >= 0)
- /* 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;
-
- dir = fdopendir(fd);
- if (!dir) {
- close(fd);
- return NULL;
- }
- if (!attr)
- rewinddir(dir);
- return dir;
-}
-
-
-static FILE *sysfs_fopen(struct sysfs_cxt *cxt, const char *attr)
-{
- int fd = sysfs_open(cxt, attr);
-
- return fd < 0 ? NULL : fdopen(fd, "r");
-}
-
-
-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 sysfs_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
-{
- char path[256];
-
-#ifdef _DIRENT_HAVE_D_TYPE
- if (d->d_type != DT_DIR &&
- d->d_type != DT_LNK)
- 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 access(path, R_OK) == 0;
-}
-
-/*
- * Converts @partno (partition number) to devno of the partition.
- * The @cxt handles wholedisk device.
- *
- * Note that this code does not expect any special format of the
- * partitions devnames.
- */
-dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno)
-{
- DIR *dir;
- struct dirent *d;
- char path[256];
- dev_t devno = 0;
-
- dir = sysfs_opendir(cxt, NULL);
- if (!dir)
- return 0;
-
- while ((d = xreaddir(dir))) {
- int n, maj, min;
-
- if (!sysfs_is_partition_dirent(dir, d, NULL))
- continue;
-
- snprintf(path, sizeof(path), "%s/partition", d->d_name);
- if (sysfs_read_int(cxt, path, &n))
- continue;
-
- if (n == partno) {
- snprintf(path, sizeof(path), "%s/dev", d->d_name);
- if (sysfs_scanf(cxt, path, "%d:%d", &maj, &min) == 2)
- devno = makedev(maj, min);
- break;
- }
- }
-
- closedir(dir);
- return devno;
-}
-
-
-int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, const char *fmt, ...)
-{
- FILE *f = sysfs_fopen(cxt, attr);
- va_list ap;
- int rc;
-
- if (!f)
- return -EINVAL;
- va_start(ap, fmt);
- rc = vfscanf(f, fmt, ap);
- va_end(ap);
-
- fclose(f);
- return rc;
-}
-
-
-int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res)
-{
- int64_t x = 0;
-
- if (sysfs_scanf(cxt, attr, "%"SCNd64, &x) == 1) {
- if (res)
- *res = x;
- return 0;
- }
- return -1;
-}
-
-int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res)
-{
- uint64_t x = 0;
-
- if (sysfs_scanf(cxt, attr, "%"SCNu64, &x) == 1) {
- if (res)
- *res = x;
- return 0;
- }
- return -1;
-}
-
-int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res)
-{
- int x = 0;
-
- if (sysfs_scanf(cxt, attr, "%d", &x) == 1) {
- if (res)
- *res = x;
- return 0;
- }
- return -1;
-}
-
-char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr)
-{
- char buf[1024];
- return sysfs_scanf(cxt, attr, "%1023[^\n]", buf) == 1 ?
- strdup(buf) : NULL;
-}
-
-int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr)
-{
- DIR *dir;
- int r = 0;
-
- if (!(dir = sysfs_opendir(cxt, attr)))
- return 0;
-
- while (xreaddir(dir)) r++;
-
- closedir(dir);
- return r;
-}
-
-int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname)
-{
- DIR *dir;
- struct dirent *d;
- int r = 0;
-
- if (!(dir = sysfs_opendir(cxt, NULL)))
- return 0;
-
- while ((d = xreaddir(dir))) {
- if (sysfs_is_partition_dirent(dir, d, devname))
- r++;
- }
-
- closedir(dir);
- 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);
- closedir(dir);
- 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;
-}
-
-/* returns basename and keeps dirname in the @path */
-static char *stripoff_last_component(char *path)
-{
- char *p = strrchr(path, '/');
-
- if (!p)
- return NULL;
- *p = '\0';
- return ++p;
-}
-
-static int get_dm_wholedisk(struct sysfs_cxt *cxt, char *diskname,
- size_t len, dev_t *diskdevno)
-{
- int rc = 0;
- char *name;
-
- /* Note, sysfs_get_slave() returns the first slave only,
- * if there is more slaves, then return NULL
- */
- name = sysfs_get_slave(cxt);
- if (!name)
- return -1;
-
- if (diskname && len) {
- strncpy(diskname, name, len);
- diskname[len - 1] = '\0';
- }
-
- if (diskdevno) {
- *diskdevno = sysfs_devname_to_devno(name, NULL);
- if (!*diskdevno)
- rc = -1;
- }
-
- free(name);
- return rc;
-}
-
-int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
- size_t len, dev_t *diskdevno)
-{
- struct sysfs_cxt cxt;
- int is_part = 0;
-
- if (!dev || sysfs_init(&cxt, dev, NULL) != 0)
- return -1;
-
- is_part = sysfs_has_attribute(&cxt, "partition");
- if (!is_part) {
- /*
- * Extra case for partitions mapped by device-mapper.
- *
- * All regualar 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 = sysfs_strdup(&cxt, "dm/uuid");
- char *tmp = uuid;
- char *prefix = uuid ? strsep(&tmp, "-") : NULL;
-
- if (prefix && strncasecmp(prefix, "part", 4) == 0)
- is_part = 1;
- free(uuid);
-
- if (is_part &&
- get_dm_wholedisk(&cxt, diskname, len, diskdevno) == 0)
- /*
- * partitioned device, mapped by DM
- */
- goto done;
-
- is_part = 0;
- }
-
- if (!is_part) {
- /*
- * unpartitioned device
- */
- if (diskname && len) {
- if (!sysfs_get_devname(&cxt, diskname, len))
- goto err;
- }
- if (diskdevno)
- *diskdevno = dev;
-
- } 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;
- int linklen;
-
- linklen = sysfs_readlink(&cxt, NULL,
- linkpath, sizeof(linkpath) - 1);
- if (linklen < 0)
- goto err;
- linkpath[linklen] = '\0';
-
- stripoff_last_component(linkpath); /* dirname */
- name = stripoff_last_component(linkpath); /* basename */
- if (!name)
- goto err;
-
- if (diskname && len) {
- strncpy(diskname, name, len);
- diskname[len - 1] = '\0';
- }
-
- if (diskdevno) {
- *diskdevno = sysfs_devname_to_devno(name, NULL);
- if (!*diskdevno)
- goto err;
- }
- }
-
-done:
- sysfs_deinit(&cxt);
- return 0;
-err:
- sysfs_deinit(&cxt);
- return -1;
-}
-
-
-int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l)
-{
- char buf[PATH_MAX], *hctl;
- ssize_t len;
-
- if (!cxt)
- return -EINVAL;
- if (cxt->has_hctl)
- goto done;
-
- len = sysfs_readlink(cxt, "device", buf, sizeof(buf) - 1);
- if (len < 0)
- return len;
-
- buf[len] = '\0';
- hctl = strrchr(buf, '/') + 1;
- if (!hctl)
- return -1;
-
- if (sscanf(hctl, "%d:%d:%d:%d", &cxt->scsi_host, &cxt->scsi_channel,
- &cxt->scsi_target, &cxt->scsi_lun) != 4)
- return -1;
-
- cxt->has_hctl = 1;
-done:
- if (h)
- *h = cxt->scsi_host;
- if (c)
- *c = cxt->scsi_channel;
- if (t)
- *t = cxt->scsi_target;
- if (l)
- *l = cxt->scsi_lun;
- return 0;
-}
-
-
-static char *sysfs_scsi_host_attribute_path(struct sysfs_cxt *cxt,
- const char *type, char *buf, size_t bufsz, const char *attr)
-{
- int len;
- int host;
-
- if (sysfs_scsi_get_hctl(cxt, &host, NULL, NULL, NULL))
- return NULL;
-
- if (attr)
- len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d/%s",
- type, host, attr);
- else
- len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d",
- type, host);
-
- return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf;
-}
-
-char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt,
- const char *type, const char *attr)
-{
- char buf[1024];
- int rc;
- FILE *f;
-
- if (!attr || !type ||
- !sysfs_scsi_host_attribute_path(cxt, type, buf, sizeof(buf), attr))
- return NULL;
-
- if (!(f = fopen(buf, "r")))
- return NULL;
-
- rc = fscanf(f, "%1023[^\n]", buf);
- fclose(f);
-
- return rc == 1 ? strdup(buf) : NULL;
-}
-
-int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type)
-{
- char buf[PATH_MAX];
- struct stat st;
-
- if (!type || !sysfs_scsi_host_attribute_path(cxt, type,
- buf, sizeof(buf), NULL))
- return 0;
-
- return stat(buf, &st) == 0 && S_ISDIR(st.st_mode);
-}
-
-static char *sysfs_scsi_attribute_path(struct sysfs_cxt *cxt,
- char *buf, size_t bufsz, const char *attr)
-{
- int len, h, c, t, l;
-
- if (sysfs_scsi_get_hctl(cxt, &h, &c, &t, &l) != 0)
- return NULL;
-
- if (attr)
- len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d/%s",
- h,c,t,l, attr);
- else
- len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d",
- h,c,t,l);
- return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf;
-}
-
-int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr)
-{
- char path[PATH_MAX];
- struct stat st;
-
- if (!sysfs_scsi_attribute_path(cxt, path, sizeof(path), attr))
- return 0;
-
- return stat(path, &st) == 0;
-}
-
-int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern)
-{
- char path[PATH_MAX], linkc[PATH_MAX];
- struct stat st;
- ssize_t len;
-
- if (!sysfs_scsi_attribute_path(cxt, 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;
-}
-
-#ifdef TEST_PROGRAM_SYSFS
-#include <errno.h>
-#include <err.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv[])
-{
- struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
- char *devname;
- dev_t devno;
- char path[PATH_MAX];
- int i, is_part;
- uint64_t u64;
- ssize_t len;
-
- if (argc != 2)
- errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]);
-
- devname = argv[1];
- devno = sysfs_devname_to_devno(devname, NULL);
-
- if (!devno)
- err(EXIT_FAILURE, "failed to read devno");
-
- is_part = sysfs_devno_has_attribute(devno, "partition");
-
- printf("NAME: %s\n", devname);
- printf("DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(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", is_part ? "YES" : "NOT");
-
- if (sysfs_init(&cxt, devno, NULL))
- return EXIT_FAILURE;
-
- len = sysfs_readlink(&cxt, NULL, path, sizeof(path) - 1);
- if (len > 0) {
- path[len] = '\0';
- printf("DEVNOLINK: %s\n", path);
- }
-
- if (!is_part) {
- printf("First 5 partitions:\n");
- for (i = 1; i <= 5; i++) {
- dev_t dev = sysfs_partno_to_devno(&cxt, i);
- if (dev)
- printf("\t#%d %d:%d\n", i, major(dev), minor(dev));
- }
- }
-
- printf("SLAVES: %d\n", sysfs_count_dirents(&cxt, "slaves"));
-
- if (sysfs_read_u64(&cxt, "size", &u64))
- 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\n");
- else
- printf("SECTOR: %d\n", i);
-
- printf("DEVNAME: %s\n", sysfs_get_devname(&cxt, path, sizeof(path)));
-
- sysfs_deinit(&cxt);
- return EXIT_SUCCESS;
-}
-#endif