int main(int argc, char *argv[]) { struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; char *devname; dev_t devno; char path[PATH_MAX]; int i; 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"); 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"); 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); } 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; }
/* * Returns complete path to the device, the patch contains all all sybsystems * used for the device. */ char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz) { /* read /sys/dev/block/<maj>:<min> symlink */ ssize_t sz = sysfs_readlink(cxt, NULL, buf, bufsz); if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > bufsz) return NULL; buf[sz++] = '\0'; /* create absolute patch from the link */ memmove(buf + sizeof(_PATH_SYS_DEVBLOCK "/") - 1, buf, sz); memcpy(buf, _PATH_SYS_DEVBLOCK "/", sizeof(_PATH_SYS_DEVBLOCK "/") - 1); return buf; }
static int is_hotpluggable(const char* device) { struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; char devchain[PATH_MAX]; char subbuf[PATH_MAX]; dev_t devno; int rc = 0; ssize_t sz; char *sub; devno = sysfs_devname_to_devno(device, NULL); if (sysfs_init(&cxt, devno, NULL) != 0) return 0; /* check /sys/dev/block/<maj>:<min>/removable attribute */ if (sysfs_read_int(&cxt, "removable", &rc) == 0 && rc == 1) { verbose(_("%s: is removable device"), device); goto done; } /* read /sys/dev/block/<maj>:<min> symlink */ sz = sysfs_readlink(&cxt, NULL, devchain, sizeof(devchain)); if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > sizeof(devchain)) goto done; devchain[sz++] = '\0'; /* create absolute patch from the link */ memmove(devchain + sizeof(_PATH_SYS_DEVBLOCK "/") - 1, devchain, sz); memcpy(devchain, _PATH_SYS_DEVBLOCK "/", sizeof(_PATH_SYS_DEVBLOCK "/") - 1); while ((sub = get_subsystem(devchain, subbuf, sizeof(subbuf)))) { rc = is_hotpluggable_subsystem(sub); if (rc) { verbose(_("%s: connected by hotplug subsystem: %s"), device, sub); break; } } done: sysfs_deinit(&cxt); return rc; }
/* * 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; }
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, '/'); if (!hctl) return -1; hctl++; if (sscanf(hctl, "%u:%u:%u:%u", &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; }
/* * Returns by @diskdevno whole disk device devno and (optionaly) by * @diskname the whole disk device name. */ 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; }