Beispiel #1
0
static int get_partition_start(int fd, int partno, uint64_t *start)
{
	struct stat st;
	struct sysfs_cxt disk = UL_SYSFSCXT_EMPTY,
			 part = UL_SYSFSCXT_EMPTY;
	dev_t devno = 0;
	int rc = -1;

	/*
	 * wholedisk
	 */
	if (fstat(fd, &st) || !S_ISBLK(st.st_mode))
		goto done;
	devno = st.st_rdev;
	if (sysfs_init(&disk, devno, NULL))
		goto done;
	/*
	 * partition
	 */
	devno = sysfs_partno_to_devno(&disk, partno);
	if (!devno)
		goto done;
	if (sysfs_init(&part, devno, &disk))
		goto done;
	if (sysfs_read_u64(&part, "start", start))
		goto done;

	rc = 0;
done:
	sysfs_deinit(&part);
	sysfs_deinit(&disk);
	return rc;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/*
 * Returns 1 if the device is private LVM device.
 */
int sysfs_devno_is_lvm_private(dev_t devno)
{
    struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
    char *uuid = NULL;
    int rc = 0;

    if (sysfs_init(&cxt, devno, NULL) != 0)
        return 0;

    uuid = sysfs_strdup(&cxt, "dm/uuid");

    /* Private LVM devices use "LVM-<uuid>-<name>" uuid format (important
     * is the "LVM" prefix and "-<name>" postfix).
     */
    if (uuid && strncmp(uuid, "LVM-", 4) == 0) {
        char *p = strrchr(uuid + 4, '-');

        if (p && *(p + 1))
            rc = 1;
    }

    sysfs_deinit(&cxt);
    free(uuid);
    return rc;
}
Beispiel #4
0
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|O_CLOEXEC);
    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;
}
Beispiel #5
0
/*
 * 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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
/*
 * @lc: context
 * @device: device name, absolute device path or NULL to reset the current setting
 *
 * Sets device, absolute paths (e.g. "/dev/loop<N>") are unchanged, device
 * names ("loop<N>") are converted to the path (/dev/loop<N> or to
 * /dev/loop/<N>)
 *
 * Returns: <0 on error, 0 on success
 */
int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
{
	if (!lc)
		return -EINVAL;

	if (lc->fd >= 0)
		close(lc->fd);
	lc->fd = -1;
	lc->mode = 0;
	lc->has_info = 0;
	lc->info_failed = 0;
	*lc->device = '\0';
	memset(&lc->info, 0, sizeof(lc->info));

	/* set new */
	if (device) {
		if (*device != '/') {
			const char *dir = _PATH_DEV;

			/* compose device name for /dev/loop<n> or /dev/loop/<n> */
			if (lc->flags & LOOPDEV_FL_DEVSUBDIR) {
				if (strlen(device) < 5)
					return -1;
				device += 4;
				dir = _PATH_DEV_LOOP "/";	/* _PATH_DEV uses tailing slash */
			}
			snprintf(lc->device, sizeof(lc->device), "%s%s",
				dir, device);
		} else {
			strncpy(lc->device, device, sizeof(lc->device));
			lc->device[sizeof(lc->device) - 1] = '\0';
		}
		DBG(lc, loopdev_debug("%s successfully assigned", device));
	}

	sysfs_deinit(&lc->sysfs);
	return 0;
}
Beispiel #11
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;
}