Blame usr/sysfs.c

Packit Service 646995
/*
Packit Service 646995
 * This is from udev-121's udev_sysfs.c
Packit Service 646995
 *
Packit Service 646995
 * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
Packit Service 646995
 *
Packit Service 646995
 *	This program is free software; you can redistribute it and/or modify it
Packit Service 646995
 *	under the terms of the GNU General Public License as published by the
Packit Service 646995
 *	Free Software Foundation version 2 of the License.
Packit Service 646995
 *
Packit Service 646995
 *	This program is distributed in the hope that it will be useful, but
Packit Service 646995
 *	WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 646995
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 646995
 *	General Public License for more details.
Packit Service 646995
 *
Packit Service 646995
 *	You should have received a copy of the GNU General Public License along
Packit Service 646995
 *	with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 646995
 *	51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Packit Service 646995
 *
Packit Service 646995
 */
Packit Service 646995
Packit Service 646995
Packit Service 646995
#include <stdlib.h>
Packit Service 646995
#include <stdio.h>
Packit Service 646995
#include <stddef.h>
Packit Service 646995
#include <unistd.h>
Packit Service 646995
#include <fcntl.h>
Packit Service 646995
#include <ctype.h>
Packit Service 646995
#include <errno.h>
Packit Service 646995
#include <limits.h>
Packit Service 646995
#include <inttypes.h>
Packit Service 646995
#include <sys/stat.h>
Packit Service 646995
Packit Service 646995
#include "log.h"
Packit Service 646995
#include "sysdeps.h"
Packit Service 646995
#include "sysfs.h"
Packit Service 646995
Packit Service 646995
/*
Packit Service 646995
 * We take this file from udev so we want to make as few changes are possible,
Packit Service 646995
 * so we can maintain patches.
Packit Service 646995
 *
Packit Service 646995
 * This is from udev_utils_string.c
Packit Service 646995
 */
Packit Service 646995
static void remove_trailing_chars(char *path, char c)
Packit Service 646995
{
Packit Service 646995
	size_t len;
Packit Service 646995
Packit Service 646995
	len = strlen(path);
Packit Service 646995
	while (len > 0 && path[len-1] == c)
Packit Service 646995
		path[--len] = '\0';
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
/* this converts udevs logging to ours. */
Packit Service 646995
#define dbg(format, arg...)						\
Packit Service 646995
	do {								\
Packit Service 646995
		log_debug(3, "%s: " format, __FUNCTION__,## arg);	\
Packit Service 646995
	} while (0)
Packit Service 646995
Packit Service 646995
/*
Packit Service 646995
 * Begin udev_sysfs.c code
Packit Service 646995
 */
Packit Service 646995
char sysfs_path[PATH_SIZE];
Packit Service 646995
Packit Service 646995
/* device cache */
Packit Service 646995
static LIST_HEAD(dev_list);
Packit Service 646995
Packit Service 646995
int sysfs_init(void)
Packit Service 646995
{
Packit Service 646995
	const char *env;
Packit Service 646995
Packit Service 646995
	env = getenv("SYSFS_PATH");
Packit Service 646995
	if (env) {
Packit Service 646995
		strlcpy(sysfs_path, env, sizeof(sysfs_path));
Packit Service 646995
		remove_trailing_chars(sysfs_path, '/');
Packit Service 646995
	} else
Packit Service 646995
		strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
Packit Service 646995
	dbg("sysfs_path='%s'", sysfs_path);
Packit Service 646995
Packit Service 646995
	INIT_LIST_HEAD(&dev_list);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
void sysfs_cleanup(void)
Packit Service 646995
{
Packit Service 646995
	struct sysfs_device *dev_loop;
Packit Service 646995
	struct sysfs_device *dev_temp;
Packit Service 646995
Packit Service 646995
	list_for_each_entry_safe(dev_loop, dev_temp, &dev_list, node) {
Packit Service 646995
		list_del_init(&dev_loop->node);
Packit Service 646995
		free(dev_loop);
Packit Service 646995
	}
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
Packit Service 646995
			     const char *subsystem, const char *driver)
Packit Service 646995
{
Packit Service 646995
	char *pos;
Packit Service 646995
Packit Service 646995
	strlcpy(dev->devpath, devpath, sizeof(dev->devpath));
Packit Service 646995
	if (subsystem != NULL)
Packit Service 646995
		strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
Packit Service 646995
	if (driver != NULL)
Packit Service 646995
		strlcpy(dev->driver, driver, sizeof(dev->driver));
Packit Service 646995
Packit Service 646995
	/* set kernel name */
Packit Service 646995
	pos = strrchr(dev->devpath, '/');
Packit Service 646995
	if (pos == NULL)
Packit Service 646995
		return;
Packit Service 646995
	strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel));
Packit Service 646995
	dbg("kernel='%s'", dev->kernel);
Packit Service 646995
Packit Service 646995
	/* some devices have '!' in their name, change that to '/' */
Packit Service 646995
	pos = dev->kernel;
Packit Service 646995
	while (pos[0] != '\0') {
Packit Service 646995
		if (pos[0] == '!')
Packit Service 646995
			pos[0] = '/';
Packit Service 646995
		pos++;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* get kernel number */
Packit Service 646995
	pos = &dev->kernel[strlen(dev->kernel)];
Packit Service 646995
	while (isdigit(pos[-1]))
Packit Service 646995
		pos--;
Packit Service 646995
	strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number));
Packit Service 646995
	dbg("kernel_number='%s'", dev->kernel_number);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_resolve_link(char *devpath, size_t size)
Packit Service 646995
{
Packit Service 646995
	char link_path[PATH_SIZE];
Packit Service 646995
	char link_target[PATH_SIZE];
Packit Service 646995
	int len;
Packit Service 646995
	int i;
Packit Service 646995
	int back;
Packit Service 646995
Packit Service 646995
	strlcpy(link_path, sysfs_path, sizeof(link_path));
Packit Service 646995
	strlcat(link_path, devpath, sizeof(link_path));
Packit Service 646995
	len = readlink(link_path, link_target, sizeof(link_target) - 1);
Packit Service 646995
	if (len <= 0)
Packit Service 646995
		return -1;
Packit Service 646995
	link_target[len] = '\0';
Packit Service 646995
	dbg("path link '%s' points to '%s'", devpath, link_target);
Packit Service 646995
Packit Service 646995
	for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
Packit Service 646995
		;
Packit Service 646995
	dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back);
Packit Service 646995
	for (i = 0; i <= back; i++) {
Packit Service 646995
		char *pos = strrchr(devpath, '/');
Packit Service 646995
Packit Service 646995
		if (pos == NULL)
Packit Service 646995
			return -1;
Packit Service 646995
		pos[0] = '\0';
Packit Service 646995
	}
Packit Service 646995
	dbg("after moving back '%s'", devpath);
Packit Service 646995
	strlcat(devpath, "/", size);
Packit Service 646995
	strlcat(devpath, &link_target[back * 3], size);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
struct sysfs_device *sysfs_device_get(const char *devpath)
Packit Service 646995
{
Packit Service 646995
	char path[PATH_SIZE];
Packit Service 646995
	char devpath_real[PATH_SIZE];
Packit Service 646995
	struct sysfs_device *dev;
Packit Service 646995
	struct sysfs_device *dev_loop;
Packit Service 646995
	struct stat statbuf;
Packit Service 646995
	char link_path[PATH_SIZE];
Packit Service 646995
	char link_target[PATH_SIZE];
Packit Service 646995
	int len;
Packit Service 646995
	char *pos;
Packit Service 646995
Packit Service 646995
	/* we handle only these devpathes */
Packit Service 646995
	if (devpath != NULL &&
Packit Service 646995
	    strncmp(devpath, "/devices/", 9) != 0 &&
Packit Service 646995
	    strncmp(devpath, "/subsystem/", 11) != 0 &&
Packit Service 646995
	    strncmp(devpath, "/module/", 8) != 0 &&
Packit Service 646995
	    strncmp(devpath, "/bus/", 5) != 0 &&
Packit Service 646995
	    strncmp(devpath, "/class/", 7) != 0 &&
Packit Service 646995
	    strncmp(devpath, "/block/", 7) != 0)
Packit Service 646995
		return NULL;
Packit Service 646995
Packit Service 646995
	dbg("open '%s'", devpath);
Packit Service 646995
	strlcpy(devpath_real, devpath, sizeof(devpath_real));
Packit Service 646995
	remove_trailing_chars(devpath_real, '/');
Packit Service 646995
	if (devpath[0] == '\0' )
Packit Service 646995
		return NULL;
Packit Service 646995
Packit Service 646995
	/* look for device already in cache (we never put an untranslated path in the cache) */
Packit Service 646995
	list_for_each_entry(dev_loop, &dev_list, node) {
Packit Service 646995
		if (strcmp(dev_loop->devpath, devpath_real) == 0) {
Packit Service 646995
			dbg("found in cache '%s'", dev_loop->devpath);
Packit Service 646995
			return dev_loop;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* if we got a link, resolve it to the real device */
Packit Service 646995
	strlcpy(path, sysfs_path, sizeof(path));
Packit Service 646995
	strlcat(path, devpath_real, sizeof(path));
Packit Service 646995
	if (lstat(path, &statbuf) != 0) {
Packit Service 646995
		dbg("stat '%s' failed: %s", path, strerror(errno));
Packit Service 646995
		return NULL;
Packit Service 646995
	}
Packit Service 646995
	if (S_ISLNK(statbuf.st_mode)) {
Packit Service 646995
		if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0)
Packit Service 646995
			return NULL;
Packit Service 646995
Packit Service 646995
		/* now look for device in cache after path translation */
Packit Service 646995
		list_for_each_entry(dev_loop, &dev_list, node) {
Packit Service 646995
			if (strcmp(dev_loop->devpath, devpath_real) == 0) {
Packit Service 646995
				dbg("found in cache '%s'", dev_loop->devpath);
Packit Service 646995
				return dev_loop;
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* it is a new device */
Packit Service 646995
	dbg("new uncached device '%s'", devpath_real);
Packit Service 646995
	dev = malloc(sizeof(struct sysfs_device));
Packit Service 646995
	if (dev == NULL)
Packit Service 646995
		return NULL;
Packit Service 646995
	memset(dev, 0x00, sizeof(struct sysfs_device));
Packit Service 646995
Packit Service 646995
	sysfs_device_set_values(dev, devpath_real, NULL, NULL);
Packit Service 646995
Packit Service 646995
	/* get subsystem name */
Packit Service 646995
	strlcpy(link_path, sysfs_path, sizeof(link_path));
Packit Service 646995
	strlcat(link_path, dev->devpath, sizeof(link_path));
Packit Service 646995
	strlcat(link_path, "/subsystem", sizeof(link_path));
Packit Service 646995
	len = readlink(link_path, link_target, sizeof(link_target) - 1);
Packit Service 646995
	if (len > 0) {
Packit Service 646995
		/* get subsystem from "subsystem" link */
Packit Service 646995
		link_target[len] = '\0';
Packit Service 646995
		dbg("subsystem link '%s' points to '%s'", link_path, link_target);
Packit Service 646995
		pos = strrchr(link_target, '/');
Packit Service 646995
		if (pos != NULL)
Packit Service 646995
			strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
Packit Service 646995
	} else if (strstr(dev->devpath, "/drivers/") != NULL) {
Packit Service 646995
		strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem));
Packit Service 646995
	} else if (strncmp(dev->devpath, "/module/", 8) == 0) {
Packit Service 646995
		strlcpy(dev->subsystem, "module", sizeof(dev->subsystem));
Packit Service 646995
	} else if (strncmp(dev->devpath, "/subsystem/", 11) == 0) {
Packit Service 646995
		pos = strrchr(dev->devpath, '/');
Packit Service 646995
		if (pos == &dev->devpath[10])
Packit Service 646995
			strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem));
Packit Service 646995
	} else if (strncmp(dev->devpath, "/class/", 7) == 0) {
Packit Service 646995
		pos = strrchr(dev->devpath, '/');
Packit Service 646995
		if (pos == &dev->devpath[6])
Packit Service 646995
			strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem));
Packit Service 646995
	} else if (strncmp(dev->devpath, "/bus/", 5) == 0) {
Packit Service 646995
		pos = strrchr(dev->devpath, '/');
Packit Service 646995
		if (pos == &dev->devpath[4])
Packit Service 646995
			strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem));
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* get driver name */
Packit Service 646995
	strlcpy(link_path, sysfs_path, sizeof(link_path));
Packit Service 646995
	strlcat(link_path, dev->devpath, sizeof(link_path));
Packit Service 646995
	strlcat(link_path, "/driver", sizeof(link_path));
Packit Service 646995
	len = readlink(link_path, link_target, sizeof(link_target) - 1);
Packit Service 646995
	if (len > 0) {
Packit Service 646995
		link_target[len] = '\0';
Packit Service 646995
		dbg("driver link '%s' points to '%s'", link_path, link_target);
Packit Service 646995
		pos = strrchr(link_target, '/');
Packit Service 646995
		if (pos != NULL)
Packit Service 646995
			strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'", dev->devpath, dev->subsystem, dev->driver);
Packit Service 646995
	list_add(&dev->node, &dev_list);
Packit Service 646995
Packit Service 646995
	return dev;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
Packit Service 646995
{
Packit Service 646995
	char parent_devpath[PATH_SIZE];
Packit Service 646995
	char *pos;
Packit Service 646995
Packit Service 646995
	dbg("open '%s'", dev->devpath);
Packit Service 646995
Packit Service 646995
	/* look if we already know the parent */
Packit Service 646995
	if (dev->parent != NULL)
Packit Service 646995
		return dev->parent;
Packit Service 646995
Packit Service 646995
	strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
Packit Service 646995
	dbg("'%s'", parent_devpath);
Packit Service 646995
Packit Service 646995
	/* strip last element */
Packit Service 646995
	pos = strrchr(parent_devpath, '/');
Packit Service 646995
	if (pos == NULL || pos == parent_devpath)
Packit Service 646995
		return NULL;
Packit Service 646995
	pos[0] = '\0';
Packit Service 646995
Packit Service 646995
	if (strncmp(parent_devpath, "/class", 6) == 0) {
Packit Service 646995
		pos = strrchr(parent_devpath, '/');
Packit Service 646995
		if (pos == &parent_devpath[6] || pos == parent_devpath) {
Packit Service 646995
			dbg("/class top level, look for device link");
Packit Service 646995
			goto device_link;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
	if (strcmp(parent_devpath, "/block") == 0) {
Packit Service 646995
		dbg("/block top level, look for device link");
Packit Service 646995
		goto device_link;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* are we at the top level? */
Packit Service 646995
	pos = strrchr(parent_devpath, '/');
Packit Service 646995
	if (pos == NULL || pos == parent_devpath)
Packit Service 646995
		return NULL;
Packit Service 646995
Packit Service 646995
	/* get parent and remember it */
Packit Service 646995
	dev->parent = sysfs_device_get(parent_devpath);
Packit Service 646995
	return dev->parent;
Packit Service 646995
Packit Service 646995
device_link:
Packit Service 646995
	strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
Packit Service 646995
	strlcat(parent_devpath, "/device", sizeof(parent_devpath));
Packit Service 646995
	if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0)
Packit Service 646995
		return NULL;
Packit Service 646995
Packit Service 646995
	/* get parent and remember it */
Packit Service 646995
	dev->parent = sysfs_device_get(parent_devpath);
Packit Service 646995
	return dev->parent;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem)
Packit Service 646995
{
Packit Service 646995
	struct sysfs_device *dev_parent;
Packit Service 646995
Packit Service 646995
	dev_parent = sysfs_device_get_parent(dev);
Packit Service 646995
	while (dev_parent != NULL) {
Packit Service 646995
		if (strcmp(dev_parent->subsystem, subsystem) == 0)
Packit Service 646995
			return dev_parent;
Packit Service 646995
		dev_parent = sysfs_device_get_parent(dev_parent);
Packit Service 646995
	}
Packit Service 646995
	return NULL;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
Packit Service 646995
{
Packit Service 646995
	char path_full[PATH_SIZE];
Packit Service 646995
	char value[NAME_SIZE] = { '\0', };
Packit Service 646995
	struct stat statbuf;
Packit Service 646995
	int fd;
Packit Service 646995
	ssize_t size;
Packit Service 646995
	size_t sysfs_len;
Packit Service 646995
Packit Service 646995
	dbg("open '%s'/'%s'", devpath, attr_name);
Packit Service 646995
	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
Packit Service 646995
	if(sysfs_len >= sizeof(path_full))
Packit Service 646995
		sysfs_len = sizeof(path_full) - 1;
Packit Service 646995
	strlcat(path_full, devpath, sizeof(path_full));
Packit Service 646995
	strlcat(path_full, "/", sizeof(path_full));
Packit Service 646995
	strlcat(path_full, attr_name, sizeof(path_full));
Packit Service 646995
Packit Service 646995
	if (lstat(path_full, &statbuf) != 0) {
Packit Service 646995
		dbg("stat '%s' failed: %s", path_full, strerror(errno));
Packit Service 646995
		goto out;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (S_ISLNK(statbuf.st_mode)) {
Packit Service 646995
		/* links return the last element of the target path */
Packit Service 646995
		char link_target[PATH_SIZE];
Packit Service 646995
		int len;
Packit Service 646995
		const char *pos;
Packit Service 646995
Packit Service 646995
		len = readlink(path_full, link_target, sizeof(link_target) - 1);
Packit Service 646995
		if (len > 0) {
Packit Service 646995
			link_target[len] = '\0';
Packit Service 646995
			pos = strrchr(link_target, '/');
Packit Service 646995
			if (pos != NULL) {
Packit Service 646995
				dbg("cache '%s' with link value '%s'", path_full, value);
Packit Service 646995
				strlcpy(value, &pos[1], NAME_SIZE);
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
		goto out;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* skip directories */
Packit Service 646995
	if (S_ISDIR(statbuf.st_mode))
Packit Service 646995
		goto out;
Packit Service 646995
Packit Service 646995
	/* skip non-readable files */
Packit Service 646995
	if ((statbuf.st_mode & S_IRUSR) == 0)
Packit Service 646995
		goto out;
Packit Service 646995
Packit Service 646995
	/* read attribute value */
Packit Service 646995
	fd = open(path_full, O_RDONLY);
Packit Service 646995
	if (fd < 0) {
Packit Service 646995
		dbg("attribute '%s' can not be opened", path_full);
Packit Service 646995
		goto out;
Packit Service 646995
	}
Packit Service 646995
	size = read(fd, value, sizeof(value));
Packit Service 646995
	close(fd);
Packit Service 646995
	if (size < 0)
Packit Service 646995
		goto out;
Packit Service 646995
	if (size == sizeof(value))
Packit Service 646995
		goto out;
Packit Service 646995
Packit Service 646995
	/* got a valid value, store and return it */
Packit Service 646995
	value[size] = '\0';
Packit Service 646995
	remove_trailing_chars(value, '\n');
Packit Service 646995
Packit Service 646995
out:
Packit Service 646995
	if (value[0] == '\0')
Packit Service 646995
		return NULL;
Packit Service 646995
	return strdup(value);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len, const char *subsystem, const char *id)
Packit Service 646995
{
Packit Service 646995
	size_t sysfs_len;
Packit Service 646995
	char path_full[PATH_SIZE];
Packit Service 646995
	char *path;
Packit Service 646995
	struct stat statbuf;
Packit Service 646995
Packit Service 646995
	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
Packit Service 646995
	path = &path_full[sysfs_len];
Packit Service 646995
Packit Service 646995
	if (strcmp(subsystem, "subsystem") == 0) {
Packit Service 646995
		strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
Packit Service 646995
		strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
		if (stat(path_full, &statbuf) == 0)
Packit Service 646995
			goto found;
Packit Service 646995
Packit Service 646995
		strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
Packit Service 646995
		strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
		if (stat(path_full, &statbuf) == 0)
Packit Service 646995
			goto found;
Packit Service 646995
		goto out;
Packit Service 646995
Packit Service 646995
		strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
Packit Service 646995
		strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
		if (stat(path_full, &statbuf) == 0)
Packit Service 646995
			goto found;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (strcmp(subsystem, "module") == 0) {
Packit Service 646995
		strlcpy(path, "/module/", sizeof(path_full) - sysfs_len);
Packit Service 646995
		strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
		if (stat(path_full, &statbuf) == 0)
Packit Service 646995
			goto found;
Packit Service 646995
		goto out;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (strcmp(subsystem, "drivers") == 0) {
Packit Service 646995
		char subsys[NAME_SIZE];
Packit Service 646995
		char *driver;
Packit Service 646995
Packit Service 646995
		strlcpy(subsys, id, sizeof(subsys));
Packit Service 646995
		driver = strchr(subsys, ':');
Packit Service 646995
		if (driver != NULL) {
Packit Service 646995
			driver[0] = '\0';
Packit Service 646995
			driver = &driver[1];
Packit Service 646995
			strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
Packit Service 646995
			strlcat(path, subsys, sizeof(path_full) - sysfs_len);
Packit Service 646995
			strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
Packit Service 646995
			strlcat(path, driver, sizeof(path_full) - sysfs_len);
Packit Service 646995
			if (stat(path_full, &statbuf) == 0)
Packit Service 646995
				goto found;
Packit Service 646995
Packit Service 646995
			strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
Packit Service 646995
			strlcat(path, subsys, sizeof(path_full) - sysfs_len);
Packit Service 646995
			strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
Packit Service 646995
			strlcat(path, driver, sizeof(path_full) - sysfs_len);
Packit Service 646995
			if (stat(path_full, &statbuf) == 0)
Packit Service 646995
				goto found;
Packit Service 646995
		}
Packit Service 646995
		goto out;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
	if (stat(path_full, &statbuf) == 0)
Packit Service 646995
		goto found;
Packit Service 646995
Packit Service 646995
	strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
	if (stat(path_full, &statbuf) == 0)
Packit Service 646995
		goto found;
Packit Service 646995
Packit Service 646995
	strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, "/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
	if (stat(path_full, &statbuf) == 0)
Packit Service 646995
		goto found;
Packit Service 646995
Packit Service 646995
	strlcpy(path, "/firmware/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, "/", sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcat(path, id, sizeof(path_full) - sysfs_len);
Packit Service 646995
	if (stat(path_full, &statbuf) == 0)
Packit Service 646995
		goto found;
Packit Service 646995
Packit Service 646995
out:
Packit Service 646995
	return 0;
Packit Service 646995
found:
Packit Service 646995
	if (S_ISLNK(statbuf.st_mode))
Packit Service 646995
		sysfs_resolve_link(path, sizeof(path_full) - sysfs_len);
Packit Service 646995
	strlcpy(devpath_full, path, len);
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
Packit Service 646995
char *sysfs_get_value(const char *id, char *subsys, char *param)
Packit Service 646995
{
Packit Service 646995
	char devpath[PATH_SIZE];
Packit Service 646995
	char *sysfs_value;
Packit Service 646995
Packit Service 646995
	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit Service 646995
					       subsys, id)) {
Packit Service 646995
		log_debug(3, "Could not lookup devpath for %s %s",
Packit Service 646995
			  subsys, id);
Packit Service 646995
		return NULL;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	sysfs_value = sysfs_attr_get_value(devpath, param);
Packit Service 646995
	if (!sysfs_value) {
Packit Service 646995
		log_debug(3, "Could not read attr %s on path %s",
Packit Service 646995
			  param, devpath);
Packit Service 646995
		return NULL;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (!strncmp(sysfs_value, "<NULL>", 6) ||
Packit Service 646995
	    !strncmp(sysfs_value, "(null)", 6)) {
Packit Service 646995
		free(sysfs_value);
Packit Service 646995
		return NULL;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return sysfs_value;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_get_uint(char *id, char *subsys, char *param,
Packit Service 646995
		   unsigned int *value)
Packit Service 646995
{
Packit Service 646995
	char *sysfs_value;
Packit Service 646995
Packit Service 646995
	*value = -1;
Packit Service 646995
	sysfs_value = sysfs_get_value(id, subsys, param);
Packit Service 646995
	if (!sysfs_value)
Packit Service 646995
		return EIO;
Packit Service 646995
Packit Service 646995
	errno = 0;
Packit Service 646995
	*value = strtoul(sysfs_value, NULL, 0);
Packit Service 646995
	free(sysfs_value);
Packit Service 646995
	if (errno)
Packit Service 646995
		return errno;
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_get_int(const char *id, char *subsys, char *param, int *value)
Packit Service 646995
{
Packit Service 646995
	char *sysfs_value;
Packit Service 646995
Packit Service 646995
	*value = -1;
Packit Service 646995
	sysfs_value = sysfs_get_value(id, subsys, param);
Packit Service 646995
	if (!sysfs_value)
Packit Service 646995
		return EIO;
Packit Service 646995
Packit Service 646995
	*value = atoi(sysfs_value);
Packit Service 646995
	free(sysfs_value);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_get_str(char *id, char *subsys, char *param, char *value,
Packit Service 646995
		  int value_size)
Packit Service 646995
{
Packit Service 646995
	char *sysfs_value;
Packit Service 646995
	int len;
Packit Service 646995
Packit Service 646995
	value[0] = '\0';
Packit Service 646995
	sysfs_value = sysfs_get_value(id, subsys, param);
Packit Service 646995
	if (!sysfs_value || !strlen(sysfs_value))
Packit Service 646995
		return EIO;
Packit Service 646995
Packit Service 646995
	len = strlen(sysfs_value);
Packit Service 646995
	if (len && (sysfs_value[len - 1] == '\n'))
Packit Service 646995
		sysfs_value[len - 1] = '\0';
Packit Service 646995
	strncpy(value, sysfs_value, value_size);
Packit Service 646995
	value[value_size - 1] = '\0';
Packit Service 646995
	free(sysfs_value);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_get_uint64(char *id, char *subsys, char *param, uint64_t *value)
Packit Service 646995
{
Packit Service 646995
	char *sysfs_value;
Packit Service 646995
Packit Service 646995
	*value = -1;
Packit Service 646995
	sysfs_value = sysfs_get_value(id, subsys, param);
Packit Service 646995
	if (!sysfs_value)
Packit Service 646995
		return EIO;
Packit Service 646995
Packit Service 646995
	if (sscanf(sysfs_value, "%" PRIu64 "\n", value) != 1) {
Packit Service 646995
		free(sysfs_value);
Packit Service 646995
		return EINVAL;
Packit Service 646995
	}
Packit Service 646995
	free(sysfs_value);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_get_uint8(char *id, char *subsys, char *param,
Packit Service 646995
		    uint8_t *value)
Packit Service 646995
{
Packit Service 646995
	char *sysfs_value;
Packit Service 646995
Packit Service 646995
	*value = -1;
Packit Service 646995
	sysfs_value = sysfs_get_value(id, subsys, param);
Packit Service 646995
	if (!sysfs_value)
Packit Service 646995
		return EIO;
Packit Service 646995
Packit Service 646995
	*value = (uint8_t)atoi(sysfs_value);
Packit Service 646995
	free(sysfs_value);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_get_uint16(char *id, char *subsys, char *param,
Packit Service 646995
		     uint16_t *value)
Packit Service 646995
{
Packit Service 646995
	char *sysfs_value;
Packit Service 646995
Packit Service 646995
	*value = -1;
Packit Service 646995
	sysfs_value = sysfs_get_value(id, subsys, param);
Packit Service 646995
	if (!sysfs_value)
Packit Service 646995
		return EIO;
Packit Service 646995
Packit Service 646995
	*value = (uint16_t)atoi(sysfs_value);
Packit Service 646995
	free(sysfs_value);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int sysfs_set_param(char *id, char *subsys, char *attr_name,
Packit Service 646995
		    char *write_buf, ssize_t buf_size)
Packit Service 646995
{
Packit Service 646995
	struct stat statbuf;
Packit Service 646995
	char devpath[PATH_SIZE];
Packit Service 646995
	size_t sysfs_len;
Packit Service 646995
	char path_full[PATH_SIZE];
Packit Service 646995
	int rc = 0, fd;
Packit Service 646995
Packit Service 646995
	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit Service 646995
					       subsys, id)) {
Packit Service 646995
		log_debug(3, "Could not lookup devpath for %s %s",
Packit Service 646995
			  subsys, id);
Packit Service 646995
		return EIO;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
Packit Service 646995
	if(sysfs_len >= sizeof(path_full))
Packit Service 646995
		sysfs_len = sizeof(path_full) - 1;
Packit Service 646995
	strlcat(path_full, devpath, sizeof(path_full));
Packit Service 646995
	strlcat(path_full, "/", sizeof(path_full));
Packit Service 646995
	strlcat(path_full, attr_name, sizeof(path_full));
Packit Service 646995
Packit Service 646995
	if (lstat(path_full, &statbuf)) {
Packit Service 646995
		log_debug(3, "Could not stat %s", path_full);
Packit Service 646995
		return errno;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if ((statbuf.st_mode & S_IWUSR) == 0) {
Packit Service 646995
		log_error("Could not write to %s. Invalid permissions.",
Packit Service 646995
			  path_full);
Packit Service 646995
		return EACCES;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	fd = open(path_full, O_WRONLY);
Packit Service 646995
	if (fd < 0) {
Packit Service 646995
		log_error("Could not open %s err %d", path_full, errno);
Packit Service 646995
		return errno;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (write(fd, write_buf, buf_size) == -1)
Packit Service 646995
		rc = errno;
Packit Service 646995
	close(fd);
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
char *sysfs_get_uevent_field(const char *path, const char *field)
Packit Service 646995
{
Packit Service 646995
	char *uevent_path = NULL;
Packit Service 646995
	FILE *f = NULL;
Packit Service 646995
	char *line, buffer[1024];
Packit Service 646995
	char *ff, *d;
Packit Service 646995
	char *out = NULL;
Packit Service 646995
Packit Service 646995
	uevent_path = calloc(1, PATH_MAX);
Packit Service 646995
	if (!uevent_path)
Packit Service 646995
		return NULL;
Packit Service 646995
	snprintf(uevent_path, PATH_MAX, "%s/uevent", path);
Packit Service 646995
Packit Service 646995
	f = fopen(uevent_path, "r");
Packit Service 646995
	if (!f)
Packit Service 646995
		goto out;
Packit Service 646995
	while ((line = fgets(buffer, sizeof (buffer), f))) {
Packit Service 646995
		ff = strtok(line, "=");
Packit Service 646995
		d = strtok(NULL, "\n");
Packit Service 646995
		if (strcmp(ff, field))
Packit Service 646995
			continue;
Packit Service 646995
		out = strdup(d);
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
	fclose(f);
Packit Service 646995
out:
Packit Service 646995
	free(uevent_path);
Packit Service 646995
	return out;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
char *sysfs_get_uevent_devtype(const char *path)
Packit Service 646995
{
Packit Service 646995
	return sysfs_get_uevent_field(path, "DEVTYPE");
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
char *sysfs_get_uevent_devname(const char *path)
Packit Service 646995
{
Packit Service 646995
	return sysfs_get_uevent_field(path, "DEVNAME");
Packit Service 646995
}