예제 #1
0
static int _md_sysfs_attribute_snprintf(char *path, size_t size,
					struct dev_types *dt,
					struct device *blkdev,
					const char *attribute)
{
	const char *sysfs_dir = dm_sysfs_dir();
	struct stat info;
	dev_t dev = blkdev->dev;
	int ret = -1;

	if (!sysfs_dir || !*sysfs_dir)
		return ret;

	if (MAJOR(dev) == dt->blkext_major) {
		/* lookup parent MD device from blkext partition */
		if (!dev_get_primary_dev(dt, blkdev, &dev))
			return ret;
	}

	if (MAJOR(dev) != dt->md_major)
		return ret;

	ret = dm_snprintf(path, size, "%s/dev/block/%d:%d/md/%s", sysfs_dir,
			  (int)MAJOR(dev), (int)MINOR(dev), attribute);
	if (ret < 0) {
		log_error("dm_snprintf md %s failed", attribute);
		return ret;
	}

	if (stat(path, &info) == -1) {
		if (errno != ENOENT) {
			log_sys_error("stat", path);
			return ret;
		}
		/* old sysfs structure */
		ret = dm_snprintf(path, size, "%s/block/md%d/md/%s",
				  sysfs_dir, (int)MINOR(dev), attribute);
		if (ret < 0) {
			log_error("dm_snprintf old md %s failed", attribute);
			return ret;
		}
	}

	return ret;
}
예제 #2
0
파일: vdo_manip.c 프로젝트: tasleson/lvm2
static int _sysfs_get_kvdo_value(const char *dm_name, const char *vdo_param, uint64_t *value)
{
	char path[PATH_MAX];
	char temp[64];
	int fd, size, r = 0;

	if (dm_snprintf(path, sizeof(path), "%skvdo/%s/%s",
			dm_sysfs_dir(), dm_name, vdo_param) < 0) {
		log_error("Failed to build kmod path.");
		return 0;
	}

	if ((fd = open(path, O_RDONLY)) < 0) {
		if (errno != ENOENT)
			log_sys_error("open", path);
		else
			log_sys_debug("open", path);
		goto bad;
	}

	if ((size = read(fd, temp, sizeof(temp) - 1)) < 0) {
		log_sys_error("read", path);
		goto bad;
	}
	temp[size] = 0;
	errno = 0;
	*value = strtoll(temp, NULL, 0);
	if (errno) {
		log_sys_error("strtool", path);
		goto bad;
	}

	r = 1;
bad:
	if (fd >= 0 && close(fd))
		log_sys_error("close", path);

	return r;
}
예제 #3
0
static unsigned long _dev_topology_attribute(struct dev_types *dt,
					     const char *attribute,
					     struct device *dev,
					     unsigned long default_value)
{
	const char *sysfs_dir = dm_sysfs_dir();
	char path[PATH_MAX], buffer[64];
	FILE *fp;
	struct stat info;
	dev_t uninitialized_var(primary);
	unsigned long result = default_value;
	unsigned long value = 0UL;

	if (!attribute || !*attribute)
		goto_out;

	if (!sysfs_dir || !*sysfs_dir)
		goto_out;

	if (!_snprintf_attr(path, sizeof(path), sysfs_dir, attribute, dev->dev))
                goto_out;

	/*
	 * check if the desired sysfs attribute exists
	 * - if not: either the kernel doesn't have topology support
	 *   or the device could be a partition
	 */
	if (stat(path, &info) == -1) {
		if (errno != ENOENT) {
			log_sys_debug("stat", path);
			goto out;
		}
		if (!dev_get_primary_dev(dt, dev, &primary))
			goto out;

		/* get attribute from partition's primary device */
		if (!_snprintf_attr(path, sizeof(path), sysfs_dir, attribute, primary))
			goto_out;

		if (stat(path, &info) == -1) {
			if (errno != ENOENT)
				log_sys_debug("stat", path);
			goto out;
		}
	}

	if (!(fp = fopen(path, "r"))) {
		log_sys_debug("fopen", path);
		goto out;
	}

	if (!fgets(buffer, sizeof(buffer), fp)) {
		log_sys_debug("fgets", path);
		goto out_close;
	}

	if (sscanf(buffer, "%lu", &value) != 1) {
		log_warn("sysfs file %s not in expected format: %s", path, buffer);
		goto out_close;
	}

	log_very_verbose("Device %s: %s is %lu%s.",
			 dev_name(dev), attribute, result, default_value ? "" : " bytes");

	result = value >> SECTOR_SHIFT;

out_close:
	if (fclose(fp))
		log_sys_debug("fclose", path);

out:
	return result;
}
예제 #4
0
/*
 * Get primary dev for the dev supplied.
 *
 * We can get a primary device for a partition either by:
 *   A: knowing the number of partitions allowed for the dev and also
 *      which major:minor number represents the primary and partition device
 *      (by using the dev_types->dev_type_array)
 *   B: by the existence of the 'partition' sysfs attribute
 *      (/dev/block/<major>:<minor>/partition)
 *
 * Method A is tried first, then method B as a fallback if A fails.
 *
 * N.B. Method B can only do the decision based on the pure existence of
 *      the 'partition' sysfs item. There's no direct scan for partition
 *      tables whatsoever!
 *
 * Returns:
 *   0 on error
 *   1 if the dev is already a primary dev, primary dev in 'result'
 *   2 if the dev is a partition, primary dev in 'result'
 */
int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
{
	const char *sysfs_dir = dm_sysfs_dir();
	int major = (int) MAJOR(dev->dev);
	int minor = (int) MINOR(dev->dev);
	char path[PATH_MAX];
	char temp_path[PATH_MAX];
	char buffer[64];
	struct stat info;
	FILE *fp = NULL;
	int parts, residue, size, ret = 0;

	/*
	 * Try to get the primary dev out of the
	 * list of known device types first.
	 */
	if ((parts = dt->dev_type_array[major].max_partitions) > 1) {
		if ((residue = minor % parts)) {
			*result = MKDEV((dev_t)major, (minor - residue));
			ret = 2;
		} else {
			*result = dev->dev;
			ret = 1; /* dev is not a partition! */
		}
		goto out;
	}

	/*
	 * If we can't get the primary dev out of the list of known device
	 * types, try to look at sysfs directly then. This is more complex
	 * way and it also requires certain sysfs layout to be present
	 * which might not be there in old kernels!
	 */

	/* check if dev is a partition */
	if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition",
			sysfs_dir, major, minor) < 0) {
		log_error("dm_snprintf partition failed");
		goto out;
	}

	if (stat(path, &info) == -1) {
		if (errno != ENOENT)
			log_sys_error("stat", path);
		*result = dev->dev;
		ret = 1;
		goto out; /* dev is not a partition! */

	}

	/*
	 * extract parent's path from the partition's symlink, e.g.:
	 * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
	 * - dirname ../../block/md0/md0p1 = ../../block/md0
	 * - basename ../../block/md0/md0  = md0
	 * Parent's 'dev' sysfs attribute  = /sys/block/md0/dev
	 */
	if ((size = readlink(dirname(path), temp_path, sizeof(temp_path) - 1)) < 0) {
		log_sys_error("readlink", path);
		goto out;
	}

	temp_path[size] = '\0';

	if (dm_snprintf(path, sizeof(path), "%s/block/%s/dev",
			sysfs_dir, basename(dirname(temp_path))) < 0) {
		log_error("dm_snprintf dev failed");
		goto out;
	}

	/* finally, parse 'dev' attribute and create corresponding dev_t */
	if (stat(path, &info) == -1) {
		if (errno == ENOENT)
			log_error("sysfs file %s does not exist", path);
		else
			log_sys_error("stat", path);
		goto out;
	}

	fp = fopen(path, "r");
	if (!fp) {
		log_sys_error("fopen", path);
		goto out;
	}

	if (!fgets(buffer, sizeof(buffer), fp)) {
		log_sys_error("fgets", path);
		goto out;
	}

	if (sscanf(buffer, "%d:%d", &major, &minor) != 2) {
		log_error("sysfs file %s not in expected MAJ:MIN format: %s",
			  path, buffer);
		goto out;
	}
	*result = MKDEV((dev_t)major, minor);
	ret = 2;
out:
	if (fp && fclose(fp))
		log_sys_error("fclose", path);

	return ret;
}