#define declare_sysfs_get_str(fname) \
extern int \
sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
-{ \
- char *attr; \
-\
- attr = sysfs_attr_get_value(dev->devpath, #fname); \
- if (!attr) \
- return 1; \
- if (strlcpy(buff, attr, len) != strlen(attr)) \
- return 2; \
- strchop(buff); \
- return 0; \
+{ \
+ int size; \
+ \
+ size = sysfs_attr_get_value(dev->devpath, #fname, buff, len); \
+ if (!size) { \
+ condlog(3, "%s: attribute %s not found in sysfs", \
+ dev->kernel, #fname); \
+ return 1; \
+ } \
+ if (size == len) { \
+ condlog(3, "%s: overflow in attribute %s", \
+ dev->kernel, #fname); \
+ return 2; \
+ } \
+ strchop(buff); \
+ return 0; \
}
declare_sysfs_get_str(devtype);
declare_sysfs_get_str(model);
declare_sysfs_get_str(rev);
declare_sysfs_get_str(state);
-
-int
-sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len)
-{
- char *attr;
-
- attr = sysfs_attr_get_value(dev->devpath, "dev");
- if (!attr) {
- condlog(3, "%s: no 'dev' attribute in sysfs", dev->kernel);
- return 1;
- }
- if (strlcpy(buff, attr, len) != strlen(attr)) {
- condlog(3, "%s: overflow in 'dev' attribute", dev->kernel);
- return 2;
- }
- return 0;
-}
+declare_sysfs_get_str(dev);
int
sysfs_get_timeout(struct sysfs_device *dev, unsigned int *timeout)
{
- char *attr;
- char attr_path[SYSFS_PATH_SIZE];
+ char attr_path[SYSFS_PATH_SIZE], attr[NAME_SIZE];
+ size_t len;
int r;
unsigned int t;
if (safe_sprintf(attr_path, "%s/device", dev->devpath))
return 1;
- attr = sysfs_attr_get_value(dev->devpath, "timeout");
- if (!attr)
+ len = sysfs_attr_get_value(dev->devpath, "timeout", attr, NAME_SIZE);
+ if (!len) {
+ condlog(3, "%s: No timeout value in sysfs", dev->devpath);
return 1;
+ }
r = sscanf(attr, "%u\n", &t);
- if (r != 1)
+ if (r != 1) {
+ condlog(3, "%s: Cannot parse timeout attribute '%s'",
+ dev->devpath, attr);
return 1;
+ }
*timeout = t * 1000;
int
sysfs_get_size (struct sysfs_device * dev, unsigned long long * size)
{
- char *attr;
+ char attr[NAME_SIZE];
+ size_t len;
int r;
- attr = sysfs_attr_get_value(dev->devpath, "size");
- if (!attr)
+ len = sysfs_attr_get_value(dev->devpath, "size", attr, NAME_SIZE);
+ if (!len) {
+ condlog(3, "%s: No size attribute in sysfs", dev->devpath);
return 1;
+ }
r = sscanf(attr, "%llu\n", size);
- if (r != 1)
+ if (r != 1) {
+ condlog(3, "%s: Cannot parse size attribute '%s'",
+ dev->devpath, attr);
return 1;
+ }
return 0;
}
unsigned int host, unsigned int channel,
unsigned int target)
{
- char attr_path[SYSFS_PATH_SIZE], *attr;
+ char attr_path[SYSFS_PATH_SIZE];
+ size_t len;
if (safe_sprintf(attr_path,
"/class/fc_transport/target%i:%i:%i",
return 1;
}
- attr = sysfs_attr_get_value(attr_path, "node_name");
- if (attr) {
- strlcpy(node, attr, strlen(attr));
- return 0;
- }
+ len = sysfs_attr_get_value(attr_path, "node_name", node, NODE_NAME_SIZE);
+ if (!len)
+ return 1;
- return 1;
+ return 0;
}
static int
if (mpp->dev_loss){
snprintf(value, 11, "%u", mpp->dev_loss);
if (sysfs_attr_set_value(attr_path, "dev_loss_tmo",
- value))
+ value, 11))
return 1;
}
if (mpp->fast_io_fail){
else
snprintf(value, 11, "%u", mpp->fast_io_fail);
if (sysfs_attr_set_value(attr_path, "fast_io_fail_tmo",
- value))
+ value, 11))
return 1;
}
}
static int
common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev)
{
- char *attr;
+ size_t len;
- attr = sysfs_attr_get_value(dev->devpath, "dev");
- if (!attr) {
+ len = sysfs_attr_get_value(dev->devpath, "dev",
+ pp->dev_t, BLK_DEV_SIZE);
+ if (!len) {
condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
return 1;
}
- strlcpy(pp->dev_t, attr, BLK_DEV_SIZE);
condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
char sysfs_path[PATH_SIZE];
-/* attribute value cache */
-static LIST_HEAD(attr_list);
-struct sysfs_attr {
- struct list_head node;
- char path[PATH_SIZE];
- char *value; /* points to value_local if value is cached */
- char value_local[NAME_SIZE];
-};
-
/* list of sysfs devices */
static LIST_HEAD(sysfs_dev_list);
struct sysfs_dev {
strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
dbg("sysfs_path='%s'", sysfs_path);
- INIT_LIST_HEAD(&attr_list);
INIT_LIST_HEAD(&sysfs_dev_list);
return 0;
}
void sysfs_cleanup(void)
{
- struct sysfs_attr *attr_loop;
- struct sysfs_attr *attr_temp;
-
struct sysfs_dev *sysdev_loop;
struct sysfs_dev *sysdev_temp;
- list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) {
- list_del(&attr_loop->node);
- free(attr_loop);
- }
-
list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) {
list_del(&sysdev_loop->node);
free(sysdev_loop);
return;
}
-int
-sysfs_attr_set_value(const char *devpath, const char *attr_name,
- const char *value)
+size_t sysfs_attr_get_value(const char *devpath, const char *attr_name,
+ char *attr_value, int attr_len)
{
char path_full[PATH_SIZE];
- int sysfs_len;
+ const char *path;
struct stat statbuf;
- int fd, value_len, ret = -1;
+ int fd;
+ ssize_t size;
+ size_t sysfs_len;
+
+ if (!attr_value || !attr_len)
+ return 0;
+
+ attr_value[0] = '\0';
+ size = 0;
dbg("open '%s'/'%s'", devpath, attr_name);
- sysfs_len = snprintf(path_full, PATH_SIZE, "%s%s/%s", sysfs_path,
- devpath, attr_name);
- if (sysfs_len >= PATH_SIZE || sysfs_len < 0) {
- if (sysfs_len < 0)
- dbg("cannot copy sysfs path %s%s/%s : %s", sysfs_path,
- devpath, attr_name, strerror(errno));
- else
- dbg("sysfs_path %s%s/%s too large", sysfs_path,
- devpath, attr_name);
- goto out;
- }
+ sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+ if(sysfs_len >= sizeof(path_full))
+ sysfs_len = sizeof(path_full) - 1;
+ path = &path_full[sysfs_len];
+ strlcat(path_full, devpath, sizeof(path_full));
+ strlcat(path_full, "/", sizeof(path_full));
+ strlcat(path_full, attr_name, sizeof(path_full));
if (stat(path_full, &statbuf) != 0) {
- dbg("stat '%s' failed: %s" path_full, strerror(errno));
+ dbg("stat '%s' failed: %s", path_full, strerror(errno));
goto out;
}
/* skip directories */
- if (S_ISDIR(statbuf.st_mode))
- goto out;
+ if (S_ISDIR(statbuf.st_mode))
+ goto out;
- if ((statbuf.st_mode & S_IWUSR) == 0)
+ /* skip non-readable files */
+ if ((statbuf.st_mode & S_IRUSR) == 0)
goto out;
- fd = open(path_full, O_WRONLY);
+ /* read attribute value */
+ fd = open(path_full, O_RDONLY);
if (fd < 0) {
dbg("attribute '%s' can not be opened: %s",
path_full, strerror(errno));
goto out;
}
- value_len = strlen(value) + 1;
- ret = write(fd, value, value_len);
- if (ret == value_len)
- ret = 0;
- else if (ret < 0)
- dbg("write to %s failed: %s", path_full, strerror(errno));
- else {
- dbg("tried to write %d to %s. Wrote %d\n", value_len,
- path_full, ret);
- ret = -1;
- }
+ size = read(fd, attr_value, attr_len);
close(fd);
+ if (size < 0)
+ goto out;
+ if (size == attr_len) {
+ dbg("overflow in attribute '%s', truncating", path_full);
+ size--;
+ }
+
+ /* got a valid value, store and return it */
+ attr_value[size] = '\0';
+ remove_trailing_chars(attr_value, '\n');
+
out:
- return ret;
+ return size;
}
-
-char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
+ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name,
+ const char *value, int value_len)
{
char path_full[PATH_SIZE];
- const char *path;
- char value[NAME_SIZE];
- struct sysfs_attr *attr_loop;
- struct sysfs_attr *attr = NULL;
struct stat statbuf;
int fd;
- ssize_t size;
+ ssize_t size = 0;
size_t sysfs_len;
- dbg("open '%s'/'%s'", devpath, attr_name);
- sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
- if(sysfs_len >= sizeof(path_full))
- sysfs_len = sizeof(path_full) - 1;
- path = &path_full[sysfs_len];
- strlcat(path_full, devpath, sizeof(path_full));
- strlcat(path_full, "/", sizeof(path_full));
- strlcat(path_full, attr_name, sizeof(path_full));
-
- /* look for attribute in cache */
- list_for_each_entry(attr_loop, &attr_list, node) {
- if (strcmp(attr_loop->path, path) == 0) {
- dbg("found in cache '%s'", attr_loop->path);
- attr = attr_loop;
- }
- }
- if (!attr) {
- /* store attribute in cache */
- dbg("new uncached attribute '%s'", path_full);
- attr = malloc(sizeof(struct sysfs_attr));
- if (attr == NULL)
- return NULL;
- memset(attr, 0x00, sizeof(struct sysfs_attr));
- strlcpy(attr->path, path, sizeof(attr->path));
- dbg("add to cache '%s'", path_full);
- list_add(&attr->node, &attr_list);
- } else {
- /* clear old value */
- if(attr->value)
- memset(attr->value, 0x00, sizeof(attr->value));
- }
+ if (!attr_name || !value || !value_len)
+ return 0;
- if (lstat(path_full, &statbuf) != 0) {
- dbg("stat '%s' failed: %s", path_full, strerror(errno));
+ dbg("open '%s'/'%s'", devpath, attr_name);
+ sysfs_len = snprintf(path_full, PATH_SIZE, "%s%s/%s", sysfs_path,
+ devpath, attr_name);
+ if (sysfs_len >= PATH_SIZE || sysfs_len < 0) {
+ if (sysfs_len < 0)
+ dbg("cannot copy sysfs path %s%s/%s : %s", sysfs_path,
+ devpath, attr_name, strerror(errno));
+ else
+ dbg("sysfs_path %s%s/%s too large", sysfs_path,
+ devpath, attr_name);
goto out;
}
- if (S_ISLNK(statbuf.st_mode)) {
- /* links return the last element of the target path */
- char link_target[PATH_SIZE];
- int len;
- const char *pos;
-
- len = readlink(path_full, link_target, sizeof(link_target));
- if (len > 0) {
- link_target[len] = '\0';
- pos = strrchr(link_target, '/');
- if (pos != NULL) {
- dbg("cache '%s' with link value '%s'",
- path_full, value);
- strlcpy(attr->value_local, &pos[1],
- sizeof(attr->value_local));
- attr->value = attr->value_local;
- }
- }
+ if (stat(path_full, &statbuf) != 0) {
+ dbg("stat '%s' failed: %s", path_full, strerror(errno));
goto out;
}
if (S_ISDIR(statbuf.st_mode))
goto out;
- /* skip non-readable files */
- if ((statbuf.st_mode & S_IRUSR) == 0)
+ /* skip non-writeable files */
+ if ((statbuf.st_mode & S_IWUSR) == 0)
goto out;
/* read attribute value */
- fd = open(path_full, O_RDONLY);
+ fd = open(path_full, O_WRONLY);
if (fd < 0) {
dbg("attribute '%s' can not be opened: %s",
path_full, strerror(errno));
goto out;
}
- size = read(fd, value, sizeof(value));
- close(fd);
+ size = write(fd, value, value_len);
if (size < 0)
- goto out;
- if (size == sizeof(value)) {
- dbg("overflow in attribute '%s', truncating", path_full);
- size--;
+ dbg("write to %s failed: %s", path_full, strerror(errno));
+ else if (size < value_len) {
+ dbg("tried to write %d to %s. Wrote %d\n", value_len,
+ path_full, size);
+ size = -1;
}
-
- /* got a valid value, store and return it */
- value[size] = '\0';
- remove_trailing_chars(value, '\n');
- dbg("cache '%s' with attribute value '%s'", path_full, value);
- strlcpy(attr->value_local, value, sizeof(attr->value_local));
- attr->value = attr->value_local;
+ close(fd);
out:
- return attr && attr->value && strlen(attr->value) ? attr->value : NULL;
+ return size;
}