static int has_discard(const char *devname, struct sysfs_cxt *wholedisk) { struct sysfs_cxt cxt, *parent = NULL; uint64_t dg = 0; dev_t disk = 0, dev; int rc; dev = sysfs_devname_to_devno(devname, NULL); if (!dev) return 1; /* * This is tricky to read the info from sys/, because the queue * atrributes are provided for whole devices (disk) only. We're trying * to reuse the whole-disk sysfs context to optimize this stuff (as * system usually have just one disk only). */ if (sysfs_devno_to_wholedisk(dev, NULL, 0, &disk) || !disk) return 1; if (dev != disk) { if (wholedisk->devno != disk) { sysfs_deinit(wholedisk); if (sysfs_init(wholedisk, disk, NULL)) return 1; } parent = wholedisk; } rc = sysfs_init(&cxt, dev, parent); if (!rc) rc = sysfs_read_u64(&cxt, "queue/discard_granularity", &dg); sysfs_deinit(&cxt); return rc == 0 && dg > 0; }
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 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; }
static int has_discard(const char *devname, struct path_cxt **wholedisk) { struct path_cxt *pc = NULL; uint64_t dg = 0; dev_t disk = 0, dev; int rc = -1; dev = sysfs_devname_to_devno(devname); if (!dev) goto fail; pc = ul_new_sysfs_path(dev, NULL, NULL); if (!pc) goto fail; /* * This is tricky to read the info from sys/, because the queue * attributes are provided for whole devices (disk) only. We're trying * to reuse the whole-disk sysfs context to optimize this stuff (as * system usually have just one disk only). */ rc = sysfs_blkdev_get_wholedisk(pc, NULL, 0, &disk); if (rc != 0 || !disk) goto fail; if (dev != disk) { /* Partition, try reuse whole-disk context if valid for the * current device, otherwise create new context for the * whole-disk. */ if (*wholedisk && sysfs_blkdev_get_devno(*wholedisk) != disk) { ul_unref_path(*wholedisk); *wholedisk = NULL; } if (!*wholedisk) { *wholedisk = ul_new_sysfs_path(disk, NULL, NULL); if (!*wholedisk) goto fail; } sysfs_blkdev_set_parent(pc, *wholedisk); } rc = ul_path_read_u64(pc, &dg, "queue/discard_granularity"); ul_unref_path(pc); return rc == 0 && dg > 0; fail: ul_unref_path(pc); return 1; }
static int is_hotpluggable(const struct eject_control *ctl) { struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; dev_t devno; int rc = 0; devno = sysfs_devname_to_devno(ctl->device, NULL); if (sysfs_init(&cxt, devno, NULL) != 0) return 0; rc = sysfs_is_hotpluggable(&cxt); sysfs_deinit(&cxt); return rc; }
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; }
static int umount_partitions(const char *disk, int checkonly) { struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; dev_t devno; DIR *dir = NULL; struct dirent *d; int count = 0; devno = sysfs_devname_to_devno(disk, NULL); if (sysfs_init(&cxt, devno, NULL) != 0) return 0; /* open /sys/block/<wholedisk> */ if (!(dir = sysfs_opendir(&cxt, NULL))) goto done; /* scan for partition subdirs */ while ((d = readdir(dir))) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; if (sysfs_is_partition_dirent(dir, d, disk)) { char *mnt = NULL; char *dev = find_device(d->d_name); if (dev && device_get_mountpoint(&dev, &mnt) == 0) { verbose(_("%s: mounted on %s"), dev, mnt); if (!checkonly) umount_one(mnt); count++; } free(dev); free(mnt); } } done: if (dir) closedir(dir); sysfs_deinit(&cxt); return count; }
/* * @lc: context * * Returns pointer to the sysfs context (see lib/sysfs.c) */ struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc) { if (!lc || !*lc->device || (lc->flags & LOOPDEV_FL_NOSYSFS)) return NULL; if (!lc->sysfs.devno) { dev_t devno = sysfs_devname_to_devno(lc->device, NULL); if (!devno) { DBG(lc, loopdev_debug("sysfs: failed devname to devno")); return NULL; } if (sysfs_init(&lc->sysfs, devno, NULL)) { DBG(lc, loopdev_debug("sysfs: init failed")); return NULL; } } return &lc->sysfs; }
char *next_proc_partition(FILE **f) { char line[128 + 1]; if (!*f) { *f = fopen(_PATH_PROC_PARTITIONS, "r"); if (!*f) { warn(_("cannot open %s"), _PATH_PROC_PARTITIONS); return NULL; } } while (fgets(line, sizeof(line), *f)) { char buf[PATH_MAX], *cn; dev_t devno; if (sscanf(line, " %*d %*d %*d %128[^\n ]", buf) != 1) continue; devno = sysfs_devname_to_devno(buf, NULL); if (devno <= 0) continue; if (sysfs_devno_is_lvm_private(devno) || sysfs_devno_is_wholedisk(devno) <= 0) continue; if (!sysfs_devno_to_devpath(devno, buf, sizeof(buf))) continue; cn = canonicalize_path(buf); if (!cn) continue; if (!is_ide_cdrom_or_tape(cn)) return cn; } fclose(*f); *f = NULL; return NULL; }
/* * 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; }