diff options
Diffstat (limited to 'libblkid/sysfs1.c')
-rw-r--r-- | libblkid/sysfs1.c | 845 |
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 |