tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

init_sysfs.c (4161B)


      1 /*
      2  * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
      3  *	              2008 Jaroslav Kysela <perex@perex.cz>
      4  *
      5  *	This program is free software; you can redistribute it and/or modify it
      6  *	under the terms of the GNU General Public License as published by the
      7  *	Free Software Foundation version 2 of the License.
      8  * 
      9  *	This program is distributed in the hope that it will be useful, but
     10  *	WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *	General Public License for more details.
     13  * 
     14  *	You should have received a copy of the GNU General Public License along
     15  *	with this program; if not, write to the Free Software Foundation, Inc.,
     16  *	51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
     17  *
     18  */
     19 
     20 
     21 static char sysfs_path[PATH_SIZE];
     22 
     23 /* attribute value cache */
     24 static LIST_HEAD(attr_list);
     25 struct sysfs_attr {
     26 	struct list_head node;
     27 	char path[PATH_SIZE];
     28 	char *value;			/* points to value_local if value is cached */
     29 	char value_local[NAME_SIZE];
     30 };
     31 
     32 static int sysfs_init(void)
     33 {
     34 	const char *env;
     35 	char sysfs_test[PATH_SIZE];
     36 
     37 	env = getenv("SYSFS_PATH");
     38 	if (env) {
     39 		strlcpy(sysfs_path, env, sizeof(sysfs_path));
     40 		remove_trailing_chars(sysfs_path, '/');
     41 	} else
     42 		strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
     43 	dbg("sysfs_path='%s'", sysfs_path);
     44 
     45 	strlcpy(sysfs_test, sysfs_path, sizeof(sysfs_test));
     46 
     47 	INIT_LIST_HEAD(&attr_list);
     48 	return 0;
     49 }
     50 
     51 static void sysfs_cleanup(void)
     52 {
     53 	struct sysfs_attr *attr_loop;
     54 	struct sysfs_attr *attr_temp;
     55 
     56 	list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) {
     57 		list_del(&attr_loop->node);
     58 		free(attr_loop);
     59 	}
     60 }
     61 
     62 static char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
     63 {
     64 	char path_full[PATH_SIZE];
     65 	const char *path;
     66 	char value[NAME_SIZE];
     67 	struct sysfs_attr *attr_loop;
     68 	struct sysfs_attr *attr;
     69 	struct stat statbuf;
     70 	int fd;
     71 	ssize_t size;
     72 	size_t sysfs_len;
     73 
     74 	dbg("open '%s'/'%s'", devpath, attr_name);
     75 	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
     76 	path = &path_full[sysfs_len];
     77 	strlcat(path_full, devpath, sizeof(path_full));
     78 	strlcat(path_full, "/", sizeof(path_full));
     79 	strlcat(path_full, attr_name, sizeof(path_full));
     80 
     81 	/* look for attribute in cache */
     82 	list_for_each_entry(attr_loop, &attr_list, node) {
     83 		if (strcmp(attr_loop->path, path) == 0) {
     84 			dbg("found in cache '%s'", attr_loop->path);
     85 			return attr_loop->value;
     86 		}
     87 	}
     88 
     89 	/* store attribute in cache (also negatives are kept in cache) */
     90 	dbg("new uncached attribute '%s'", path_full);
     91 	attr = malloc(sizeof(struct sysfs_attr));
     92 	if (attr == NULL)
     93 		return NULL;
     94 	memset(attr, 0x00, sizeof(struct sysfs_attr));
     95 	strlcpy(attr->path, path, sizeof(attr->path));
     96 	dbg("add to cache '%s'", path_full);
     97 	list_add(&attr->node, &attr_list);
     98 
     99 	if (lstat(path_full, &statbuf) != 0) {
    100 		dbg("stat '%s' failed: %s", path_full, strerror(errno));
    101 		goto out;
    102 	}
    103 
    104 	if (S_ISLNK(statbuf.st_mode)) {
    105 		/* links return the last element of the target path */
    106 		char link_target[PATH_SIZE + 1];
    107 		int len;
    108 		const char *pos;
    109 
    110 		len = readlink(path_full, link_target, sizeof(link_target) - 1);
    111 		if (len > 0) {
    112 			link_target[len] = '\0';
    113 			pos = strrchr(link_target, '/');
    114 			if (pos != NULL) {
    115 				dbg("cache '%s' with link value '%s'", path_full, pos+1);
    116 				strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local));
    117 				attr->value = attr->value_local;
    118 			}
    119 		}
    120 		goto out;
    121 	}
    122 
    123 	/* skip directories */
    124 	if (S_ISDIR(statbuf.st_mode))
    125 		goto out;
    126 
    127 	/* skip non-readable files */
    128 	if ((statbuf.st_mode & S_IRUSR) == 0)
    129 		goto out;
    130 
    131 	/* read attribute value */
    132 	fd = open(path_full, O_RDONLY);
    133 	if (fd < 0) {
    134 		dbg("attribute '%s' does not exist", path_full);
    135 		goto out;
    136 	}
    137 	size = read(fd, value, sizeof(value));
    138 	close(fd);
    139 	if (size < 0)
    140 		goto out;
    141 	if (size == sizeof(value))
    142 		goto out;
    143 
    144 	/* got a valid value, store and return it */
    145 	value[size] = '\0';
    146 	remove_trailing_chars(value, '\n');
    147 	dbg("cache '%s' with attribute value '%s'", path_full, value);
    148 	strlcpy(attr->value_local, value, sizeof(attr->value_local));
    149 	attr->value = attr->value_local;
    150 
    151 out:
    152 	return attr->value;
    153 }