mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
[PATCH] big libsysfs diet (pre 2.0 version)
This commit is contained in:
parent
8d1b4df219
commit
f385ff6512
1
Makefile
1
Makefile
@ -129,7 +129,6 @@ HEADERS = \
|
||||
list.h
|
||||
|
||||
SYSFS_OBJS = \
|
||||
libsysfs/sysfs_bus.o \
|
||||
libsysfs/sysfs_class.o \
|
||||
libsysfs/sysfs_device.o \
|
||||
libsysfs/sysfs_dir.o \
|
||||
|
@ -27,19 +27,37 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <mntent.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* external library functions */
|
||||
extern int isascii(int c);
|
||||
#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1)
|
||||
#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1)
|
||||
|
||||
#define safestrcpymax(to, from, max) \
|
||||
do { \
|
||||
to[max-1] = '\0'; \
|
||||
strncpy(to, from, max-1); \
|
||||
} while (0)
|
||||
|
||||
#define safestrcatmax(to, from, max) \
|
||||
do { \
|
||||
to[max-1] = '\0'; \
|
||||
strncat(to, from, max - strlen(to)-1); \
|
||||
} while (0)
|
||||
|
||||
extern struct sysfs_attribute *get_attribute(void *dev, const char *name);
|
||||
extern struct dlist *read_dir_subdirs(const char *path);
|
||||
extern struct dlist *read_dir_links(const char *path);
|
||||
extern struct dlist *get_attributes_list(void *dev);
|
||||
|
||||
/* Debugging */
|
||||
#ifdef DEBUG
|
||||
#include "../logging.h"
|
||||
#define dprintf(format, arg...) dbg(format, ##arg)
|
||||
#define dprintf(format, arg...) dbg(format, ## arg)
|
||||
#else
|
||||
#define dprintf(format, arg...) do { } while (0)
|
||||
#endif
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Header Definitions for libsysfs
|
||||
*
|
||||
* Copyright (C) IBM Corp. 2003
|
||||
* Copyright (C) IBM Corp. 2004-2005
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -27,27 +27,6 @@
|
||||
#include <string.h>
|
||||
#include "dlist.h"
|
||||
|
||||
/*
|
||||
* Defines to prevent buffer overruns
|
||||
*/
|
||||
#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1)
|
||||
#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1)
|
||||
|
||||
#define safestrcpymax(to, from, max) \
|
||||
do { \
|
||||
to[max-1] = '\0'; \
|
||||
strncpy(to, from, max-1); \
|
||||
} while (0)
|
||||
|
||||
#define safestrcatmax(to, from, max) \
|
||||
do { \
|
||||
to[max-1] = '\0'; \
|
||||
strncat(to, from, max - strlen(to)-1); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Generic #defines go here..
|
||||
*/
|
||||
#define SYSFS_FSTYPE_NAME "sysfs"
|
||||
#define SYSFS_PROC_MNTS "/proc/mounts"
|
||||
#define SYSFS_BUS_NAME "bus"
|
||||
@ -55,106 +34,92 @@ do { \
|
||||
#define SYSFS_BLOCK_NAME "block"
|
||||
#define SYSFS_DEVICES_NAME "devices"
|
||||
#define SYSFS_DRIVERS_NAME "drivers"
|
||||
#define SYSFS_MODULE_NAME "module"
|
||||
#define SYSFS_NAME_ATTRIBUTE "name"
|
||||
#define SYSFS_UNKNOWN "unknown"
|
||||
#define SYSFS_PATH_ENV "SYSFS_PATH"
|
||||
|
||||
#define SYSFS_PATH_MAX 255
|
||||
#define SYSFS_NAME_LEN 50
|
||||
#define SYSFS_BUS_ID_SIZE 20
|
||||
#define SYSFS_PATH_MAX 256
|
||||
#define SYSFS_NAME_LEN 64
|
||||
#define SYSFS_BUS_ID_SIZE 32
|
||||
|
||||
#define SYSFS_METHOD_SHOW 0x01 /* attr can be read by user */
|
||||
#define SYSFS_METHOD_STORE 0x02 /* attr can be changed by user */
|
||||
enum sysfs_attribute_method {
|
||||
SYSFS_METHOD_SHOW = 0x01, /* attr can be read by user */
|
||||
SYSFS_METHOD_STORE = 0x02, /* attr can be changed by user */
|
||||
};
|
||||
|
||||
/* NOTE: statically define mnt path for sysfs */
|
||||
#define SYSFS_MNT_PATH "/sys"
|
||||
|
||||
/*
|
||||
* NOTE: We have the statically allocated "name" as the first element of all
|
||||
* NOTE:
|
||||
* 1. We have the statically allocated "name" as the first element of all
|
||||
* the structures. This feature is used in the "sorter" function for dlists
|
||||
* 2. As is the case with attrlist
|
||||
* 3. As is the case with path
|
||||
*/
|
||||
|
||||
struct sysfs_attribute {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
char *value;
|
||||
unsigned short len; /* value length */
|
||||
unsigned short method; /* show and store */
|
||||
};
|
||||
|
||||
struct sysfs_link {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
char target[SYSFS_PATH_MAX];
|
||||
};
|
||||
|
||||
struct sysfs_directory {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
|
||||
/* Private: for internal use only */
|
||||
struct dlist *subdirs;
|
||||
struct dlist *links;
|
||||
struct dlist *attributes;
|
||||
unsigned short len; /* value length */
|
||||
enum sysfs_attribute_method method; /* show and store */
|
||||
};
|
||||
|
||||
struct sysfs_driver {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
struct dlist *attrlist;
|
||||
char bus[SYSFS_NAME_LEN];
|
||||
|
||||
/* Private: for internal use only */
|
||||
struct dlist *devices;
|
||||
struct sysfs_directory *directory;
|
||||
};
|
||||
|
||||
struct sysfs_device {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
struct dlist *attrlist;
|
||||
char bus_id[SYSFS_NAME_LEN];
|
||||
char bus[SYSFS_NAME_LEN];
|
||||
char driver_name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
|
||||
/* Private: for internal use only */
|
||||
struct sysfs_device *parent;
|
||||
/* NOTE - we still don't populate this */
|
||||
struct dlist *children;
|
||||
struct sysfs_directory *directory;
|
||||
};
|
||||
|
||||
struct sysfs_root_device {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
|
||||
/* Private: for internal use only */
|
||||
struct dlist *devices;
|
||||
struct sysfs_directory *directory;
|
||||
};
|
||||
|
||||
/* NOTE: not used as of now */
|
||||
struct sysfs_bus {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
struct dlist *attrlist;
|
||||
|
||||
/* Private: for internal use only */
|
||||
struct dlist *drivers;
|
||||
struct dlist *devices;
|
||||
struct sysfs_directory *directory;
|
||||
};
|
||||
|
||||
struct sysfs_class_device {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char classname[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
struct dlist *attrlist;
|
||||
char classname[SYSFS_NAME_LEN];
|
||||
|
||||
/* Private: for internal use only */
|
||||
struct sysfs_class_device *parent;
|
||||
struct sysfs_device *sysdevice; /* NULL if virtual */
|
||||
struct sysfs_driver *driver; /* NULL if not implemented */
|
||||
struct sysfs_directory *directory;
|
||||
};
|
||||
|
||||
/* NOTE: not used as of now */
|
||||
struct sysfs_class {
|
||||
char name[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
struct dlist *attrlist;
|
||||
|
||||
/* Private: for internal use only */
|
||||
struct dlist *devices;
|
||||
struct sysfs_directory *directory;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -171,43 +136,15 @@ extern int sysfs_path_is_dir(const char *path);
|
||||
extern int sysfs_path_is_link(const char *path);
|
||||
extern int sysfs_path_is_file(const char *path);
|
||||
extern int sysfs_get_link(const char *path, char *target, size_t len);
|
||||
extern struct dlist *sysfs_open_subsystem_list(char *name);
|
||||
extern struct dlist *sysfs_open_bus_devices_list(char *name);
|
||||
extern struct dlist *sysfs_open_directory_list(const char *path);
|
||||
extern void sysfs_close_list(struct dlist *list);
|
||||
|
||||
/* sysfs directory and file access */
|
||||
extern void sysfs_close_attribute(struct sysfs_attribute *sysattr);
|
||||
extern struct sysfs_attribute *sysfs_open_attribute(const char *path);
|
||||
extern int sysfs_read_attribute(struct sysfs_attribute *sysattr);
|
||||
extern int sysfs_read_attribute_value(const char *attrpath,
|
||||
char *value, size_t vsize);
|
||||
extern int sysfs_write_attribute(struct sysfs_attribute *sysattr,
|
||||
const char *new_value, size_t len);
|
||||
extern char *sysfs_get_value_from_attributes(struct dlist *attr,
|
||||
const char *name);
|
||||
extern int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir);
|
||||
extern int sysfs_refresh_dir_links(struct sysfs_directory *sysdir);
|
||||
extern int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir);
|
||||
extern void sysfs_close_directory(struct sysfs_directory *sysdir);
|
||||
extern struct sysfs_directory *sysfs_open_directory(const char *path);
|
||||
extern int sysfs_read_dir_attributes(struct sysfs_directory *sysdir);
|
||||
extern int sysfs_read_dir_links(struct sysfs_directory *sysdir);
|
||||
extern int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir);
|
||||
extern int sysfs_read_directory(struct sysfs_directory *sysdir);
|
||||
extern int sysfs_read_all_subdirs(struct sysfs_directory *sysdir);
|
||||
extern struct sysfs_directory *sysfs_get_subdirectory
|
||||
(struct sysfs_directory *dir, char *subname);
|
||||
extern void sysfs_close_link(struct sysfs_link *ln);
|
||||
extern struct sysfs_link *sysfs_open_link(const char *lnpath);
|
||||
extern struct sysfs_link *sysfs_get_directory_link
|
||||
(struct sysfs_directory *dir, char *linkname);
|
||||
extern struct sysfs_link *sysfs_get_subdirectory_link
|
||||
(struct sysfs_directory *dir, char *linkname);
|
||||
extern struct sysfs_attribute *sysfs_get_directory_attribute
|
||||
(struct sysfs_directory *dir, char *attrname);
|
||||
extern struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir);
|
||||
extern struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir);
|
||||
extern struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir);
|
||||
|
||||
/* sysfs driver access */
|
||||
extern void sysfs_close_driver(struct sysfs_driver *driver);
|
||||
@ -218,19 +155,8 @@ extern struct sysfs_attribute *sysfs_get_driver_attr
|
||||
(struct sysfs_driver *drv, const char *name);
|
||||
extern struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver);
|
||||
extern struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver);
|
||||
extern struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver);
|
||||
extern struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver);
|
||||
extern struct sysfs_device *sysfs_get_driver_device
|
||||
(struct sysfs_driver *driver, const char *name);
|
||||
extern struct dlist *sysfs_refresh_driver_attributes
|
||||
(struct sysfs_driver *driver);
|
||||
extern struct sysfs_attribute *sysfs_open_driver_attr
|
||||
(const char *bus, const char *drv, const char *attrib);
|
||||
|
||||
/* generic sysfs device access */
|
||||
extern void sysfs_close_root_device(struct sysfs_root_device *root);
|
||||
extern struct sysfs_root_device *sysfs_open_root_device(const char *name);
|
||||
extern struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root);
|
||||
extern void sysfs_close_device_tree(struct sysfs_device *device);
|
||||
extern struct sysfs_device *sysfs_open_device_tree(const char *path);
|
||||
extern void sysfs_close_device(struct sysfs_device *dev);
|
||||
@ -241,27 +167,8 @@ extern struct sysfs_device *sysfs_open_device_path(const char *path);
|
||||
extern int sysfs_get_device_bus(struct sysfs_device *dev);
|
||||
extern struct sysfs_attribute *sysfs_get_device_attr
|
||||
(struct sysfs_device *dev, const char *name);
|
||||
extern struct dlist *sysfs_get_device_attributes(struct sysfs_device *device);
|
||||
extern struct dlist *sysfs_refresh_device_attributes
|
||||
(struct sysfs_device *device);
|
||||
extern struct sysfs_attribute *sysfs_open_device_attr(const char *bus,
|
||||
const char *bus_id, const char *attrib);
|
||||
|
||||
/* generic sysfs bus access */
|
||||
extern void sysfs_close_bus(struct sysfs_bus *bus);
|
||||
extern struct sysfs_bus *sysfs_open_bus(const char *name);
|
||||
extern struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus,
|
||||
char *id);
|
||||
extern struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus,
|
||||
char *drvname);
|
||||
extern struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus);
|
||||
extern struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus);
|
||||
extern struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus);
|
||||
extern struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus);
|
||||
extern struct sysfs_attribute *sysfs_get_bus_attribute
|
||||
(struct sysfs_bus *bus, char *attrname);
|
||||
extern int sysfs_find_driver_bus(const char *driver, char *busname,
|
||||
size_t bsize);
|
||||
extern struct dlist *sysfs_get_device_attributes
|
||||
(struct sysfs_device *dev);
|
||||
|
||||
/* generic sysfs class access */
|
||||
extern void sysfs_close_class_device(struct sysfs_class_device *dev);
|
||||
@ -269,26 +176,14 @@ extern struct sysfs_class_device *sysfs_open_class_device_path
|
||||
(const char *path);
|
||||
extern struct sysfs_class_device *sysfs_open_class_device
|
||||
(const char *classname, const char *name);
|
||||
extern struct sysfs_device *sysfs_get_classdev_device
|
||||
(struct sysfs_class_device *clsdev);
|
||||
extern struct sysfs_driver *sysfs_get_classdev_driver
|
||||
(struct sysfs_class_device *clsdev);
|
||||
extern struct sysfs_class_device *sysfs_get_classdev_parent
|
||||
(struct sysfs_class_device *clsdev);
|
||||
extern void sysfs_close_class(struct sysfs_class *cls);
|
||||
extern struct sysfs_class *sysfs_open_class(const char *name);
|
||||
extern struct dlist *sysfs_get_class_devices(struct sysfs_class *cls);
|
||||
extern struct sysfs_class_device *sysfs_get_class_device
|
||||
(struct sysfs_class *cls, char *name);
|
||||
extern struct dlist *sysfs_get_classdev_attributes
|
||||
(struct sysfs_class_device *cdev);
|
||||
extern struct dlist *sysfs_refresh_classdev_attributes
|
||||
(struct sysfs_class_device *cdev);
|
||||
extern struct sysfs_attribute *sysfs_get_classdev_attr
|
||||
(struct sysfs_class_device *clsdev, const char *name);
|
||||
extern struct sysfs_attribute *sysfs_open_classdev_attr
|
||||
(const char *classname, const char *dev,
|
||||
const char *attrib);
|
||||
extern struct dlist *sysfs_get_classdev_attributes
|
||||
(struct sysfs_class_device *clsdev);
|
||||
extern struct sysfs_device *sysfs_get_classdev_device
|
||||
(struct sysfs_class_device *clsdev);
|
||||
|
||||
/**
|
||||
* sort_list: sorter function to keep list elements sorted in alphabetical
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Generic class utility functions for libsysfs
|
||||
*
|
||||
* Copyright (C) IBM Corp. 2003
|
||||
* Copyright (C) IBM Corp. 2003-2005
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -23,95 +23,50 @@
|
||||
#include "libsysfs.h"
|
||||
#include "sysfs.h"
|
||||
|
||||
static void sysfs_close_cls_dev(void *dev)
|
||||
{
|
||||
sysfs_close_class_device((struct sysfs_class_device *)dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* class_name_equal: compares class_devices' name
|
||||
* @a: class_name looking for
|
||||
* @b: sysfs_class_device being compared
|
||||
*/
|
||||
static int class_name_equal(void *a, void *b)
|
||||
{
|
||||
if (a == NULL || b == NULL)
|
||||
return 0;
|
||||
|
||||
if (strcmp(((char *)a), ((struct sysfs_class_device *)b)->name) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_close_class_device: closes a single class device.
|
||||
* @dev: class device to close.
|
||||
*/
|
||||
void sysfs_close_class_device(struct sysfs_class_device *dev)
|
||||
{
|
||||
if (dev != NULL) {
|
||||
if (dev->directory != NULL)
|
||||
sysfs_close_directory(dev->directory);
|
||||
if (dev->sysdevice != NULL)
|
||||
sysfs_close_device(dev->sysdevice);
|
||||
if (dev->driver != NULL)
|
||||
sysfs_close_driver(dev->driver);
|
||||
if (dev->parent != NULL)
|
||||
if (dev) {
|
||||
if (dev->parent)
|
||||
sysfs_close_class_device(dev->parent);
|
||||
if (dev->sysdevice)
|
||||
sysfs_close_device(dev->sysdevice);
|
||||
if (dev->attrlist)
|
||||
dlist_destroy(dev->attrlist);
|
||||
free(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_close_class: close single class
|
||||
* @cls: class structure
|
||||
*/
|
||||
void sysfs_close_class(struct sysfs_class *cls)
|
||||
{
|
||||
if (cls != NULL) {
|
||||
if (cls->directory != NULL)
|
||||
sysfs_close_directory(cls->directory);
|
||||
if (cls->devices != NULL)
|
||||
dlist_destroy(cls->devices);
|
||||
free(cls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_class_device: mallocs and initializes new class device struct.
|
||||
* returns sysfs_class_device or NULL.
|
||||
*/
|
||||
static struct sysfs_class_device *alloc_class_device(void)
|
||||
{
|
||||
return (struct sysfs_class_device *)
|
||||
calloc(1, sizeof(struct sysfs_class_device));
|
||||
struct sysfs_class_device *dev;
|
||||
|
||||
dev = calloc(1, sizeof(struct sysfs_class_device));
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_class: mallocs new class structure
|
||||
* returns sysfs_class struct or NULL
|
||||
*/
|
||||
static struct sysfs_class *alloc_class(void)
|
||||
{
|
||||
return (struct sysfs_class *)calloc(1, sizeof(struct sysfs_class));
|
||||
}
|
||||
|
||||
/**
|
||||
* set_classdev_classname: Grabs classname from path
|
||||
* @cdev: class device to set
|
||||
* Returns nothing
|
||||
*/
|
||||
static void set_classdev_classname(struct sysfs_class_device *cdev)
|
||||
{
|
||||
char *c = NULL, *e = NULL;
|
||||
char *c, *e;
|
||||
int count = 0;
|
||||
|
||||
c = strstr(cdev->path, SYSFS_CLASS_NAME);
|
||||
if (c == NULL) {
|
||||
c = strstr(cdev->path, SYSFS_BLOCK_NAME);
|
||||
} else {
|
||||
c = strchr(c, '/');
|
||||
c = strstr(c, "/");
|
||||
}
|
||||
|
||||
if (c == NULL)
|
||||
@ -135,9 +90,9 @@ static void set_classdev_classname(struct sysfs_class_device *cdev)
|
||||
*/
|
||||
struct sysfs_class_device *sysfs_open_class_device_path(const char *path)
|
||||
{
|
||||
struct sysfs_class_device *cdev = NULL;
|
||||
struct sysfs_class_device *cdev;
|
||||
|
||||
if (path == NULL) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@ -146,11 +101,11 @@ struct sysfs_class_device *sysfs_open_class_device_path(const char *path)
|
||||
return NULL;
|
||||
}
|
||||
cdev = alloc_class_device();
|
||||
if (cdev == NULL) {
|
||||
if (!cdev) {
|
||||
dprintf("calloc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_get_name_from_path(path, cdev->name, SYSFS_NAME_LEN)) != 0) {
|
||||
if (sysfs_get_name_from_path(path, cdev->name, SYSFS_NAME_LEN)) {
|
||||
errno = EINVAL;
|
||||
dprintf("Error getting class device name\n");
|
||||
sysfs_close_class_device(cdev);
|
||||
@ -168,245 +123,6 @@ struct sysfs_class_device *sysfs_open_class_device_path(const char *path)
|
||||
return cdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_class_devices: gets all devices for class
|
||||
* @cls: class to get devices for
|
||||
* returns dlist of class_devices with success and NULL with error
|
||||
*/
|
||||
struct dlist *sysfs_get_class_devices(struct sysfs_class *cls)
|
||||
{
|
||||
struct sysfs_class_device *dev = NULL;
|
||||
struct sysfs_directory *cur = NULL;
|
||||
|
||||
if (cls == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cls->devices != NULL)
|
||||
return cls->devices;
|
||||
|
||||
if (cls->directory == NULL) {
|
||||
cls->directory = sysfs_open_directory(cls->path);
|
||||
if (cls->directory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((sysfs_read_dir_subdirs(cls->directory)) != 0)
|
||||
return NULL;
|
||||
|
||||
if (cls->directory->subdirs != NULL) {
|
||||
dlist_for_each_data(cls->directory->subdirs, cur,
|
||||
struct sysfs_directory) {
|
||||
dev = sysfs_open_class_device_path(cur->path);
|
||||
if (dev == NULL) {
|
||||
dprintf("Error opening device at %s\n",
|
||||
cur->path);
|
||||
continue;
|
||||
}
|
||||
if (cls->devices == NULL)
|
||||
cls->devices = dlist_new_with_delete
|
||||
(sizeof(struct sysfs_class_device),
|
||||
sysfs_close_cls_dev);
|
||||
dlist_unshift_sorted(cls->devices, dev, sort_list);
|
||||
}
|
||||
}
|
||||
return cls->devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_class: opens specific class and all its devices on system
|
||||
* returns sysfs_class structure with success or NULL with error.
|
||||
*/
|
||||
struct sysfs_class *sysfs_open_class(const char *name)
|
||||
{
|
||||
struct sysfs_class *cls = NULL;
|
||||
char classpath[SYSFS_PATH_MAX];
|
||||
|
||||
if (name == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(classpath, 0, SYSFS_PATH_MAX);
|
||||
if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) {
|
||||
dprintf("Sysfs not supported on this system\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We shall now treat "block" also as a class. Hence, check here
|
||||
* if "name" is "block" and proceed accordingly
|
||||
*/
|
||||
if (strcmp(name, SYSFS_BLOCK_NAME) == 0) {
|
||||
safestrcat(classpath, "/");
|
||||
safestrcat(classpath, SYSFS_BLOCK_NAME);
|
||||
} else {
|
||||
safestrcat(classpath, "/");
|
||||
safestrcat(classpath, SYSFS_CLASS_NAME);
|
||||
safestrcat(classpath, "/");
|
||||
safestrcat(classpath, name);
|
||||
}
|
||||
if ((sysfs_path_is_dir(classpath)) != 0) {
|
||||
dprintf("Class %s not found on the system\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cls = alloc_class();
|
||||
if (cls == NULL) {
|
||||
dprintf("calloc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
safestrcpy(cls->name, name);
|
||||
safestrcpy(cls->path, classpath);
|
||||
if ((sysfs_remove_trailing_slash(cls->path)) != 0) {
|
||||
dprintf("Invalid path to class device %s\n", cls->path);
|
||||
sysfs_close_class(cls);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cls;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_class_device: Get specific class device using the device's id
|
||||
* @class: class to find device on
|
||||
* @name: class name of the device
|
||||
*/
|
||||
struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *cls,
|
||||
char *name)
|
||||
{
|
||||
if (cls == NULL || name == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cls->devices == NULL) {
|
||||
cls->devices = sysfs_get_class_devices(cls);
|
||||
if (cls->devices == NULL)
|
||||
return NULL;
|
||||
}
|
||||
return (struct sysfs_class_device *)dlist_find_custom(cls->devices,
|
||||
name, class_name_equal);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_classdev_device: returns the sysfs_device corresponding to
|
||||
* sysfs_class_device, if present
|
||||
* @clsdev: class device whose sysfs_device is required
|
||||
* Returns sysfs_device on success, NULL on error or if device is not
|
||||
* implemented
|
||||
*/
|
||||
struct sysfs_device *sysfs_get_classdev_device
|
||||
(struct sysfs_class_device *clsdev)
|
||||
{
|
||||
struct sysfs_link *devlink = NULL;
|
||||
char devpath[SYSFS_PATH_MAX];
|
||||
|
||||
if (clsdev == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
safestrcpy(devpath, clsdev->path);
|
||||
safestrcat(devpath, "/device");
|
||||
if ((sysfs_path_is_link(devpath)) != 0) {
|
||||
if (clsdev->sysdevice != NULL) {
|
||||
sysfs_close_device(clsdev->sysdevice);
|
||||
clsdev->sysdevice = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (clsdev->directory == NULL) {
|
||||
clsdev->directory = sysfs_open_directory(clsdev->path);
|
||||
if (clsdev->directory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
devlink = sysfs_get_directory_link(clsdev->directory, "device");
|
||||
if (devlink == NULL) {
|
||||
if (clsdev->sysdevice != NULL) {
|
||||
dprintf("Device link no longer exists\n");
|
||||
sysfs_close_device(clsdev->sysdevice);
|
||||
clsdev->sysdevice = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (clsdev->sysdevice != NULL) {
|
||||
if (!strncmp(devlink->target, clsdev->sysdevice->path,
|
||||
SYSFS_PATH_MAX))
|
||||
/* sysdevice hasn't changed */
|
||||
return (clsdev->sysdevice);
|
||||
else
|
||||
/* come here only if the device link for has changed */
|
||||
sysfs_close_device(clsdev->sysdevice);
|
||||
}
|
||||
|
||||
clsdev->sysdevice = sysfs_open_device_path(devlink->target);
|
||||
if (clsdev->sysdevice == NULL)
|
||||
return NULL;
|
||||
|
||||
return (clsdev->sysdevice);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_classdev_driver: returns the sysfs_driver corresponding to
|
||||
* sysfs_class_device, if present
|
||||
* @clsdev: class device whose sysfs_device is required
|
||||
* Returns sysfs_driver on success, NULL on error or if driver is not
|
||||
* implemented
|
||||
*/
|
||||
struct sysfs_driver *sysfs_get_classdev_driver
|
||||
(struct sysfs_class_device *clsdev)
|
||||
{
|
||||
struct sysfs_link *drvlink = NULL;
|
||||
char drvpath[SYSFS_PATH_MAX];
|
||||
|
||||
if (clsdev == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
safestrcpy(drvpath, clsdev->path);
|
||||
safestrcat(drvpath, "/driver");
|
||||
if ((sysfs_path_is_link(drvpath)) != 0) {
|
||||
if (clsdev->driver != NULL) {
|
||||
sysfs_close_driver(clsdev->driver);
|
||||
clsdev->driver = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (clsdev->directory == NULL) {
|
||||
clsdev->directory = sysfs_open_directory(clsdev->path);
|
||||
if (clsdev->directory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
drvlink = sysfs_get_directory_link(clsdev->directory, "driver");
|
||||
if (drvlink == NULL) {
|
||||
if (clsdev->driver != NULL) {
|
||||
dprintf("Driver link no longer exists\n");
|
||||
sysfs_close_driver(clsdev->driver);
|
||||
clsdev->driver = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (clsdev->driver != NULL) {
|
||||
if (!strncmp(drvlink->target, clsdev->driver->path,
|
||||
SYSFS_PATH_MAX))
|
||||
/* driver hasn't changed */
|
||||
return (clsdev->driver);
|
||||
else
|
||||
/* come here only if the device link for has changed */
|
||||
sysfs_close_driver(clsdev->driver);
|
||||
}
|
||||
|
||||
clsdev->driver = sysfs_open_driver_path(drvlink->target);
|
||||
if (clsdev->driver == NULL)
|
||||
return NULL;
|
||||
|
||||
return (clsdev->driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_blockdev_parent: Get the parent class device for a "block" subsystem
|
||||
* device if present
|
||||
@ -415,7 +131,8 @@ struct sysfs_driver *sysfs_get_classdev_driver
|
||||
*/
|
||||
static int get_blockdev_parent(struct sysfs_class_device *clsdev)
|
||||
{
|
||||
char parent_path[SYSFS_PATH_MAX], *c = NULL;
|
||||
char parent_path[SYSFS_PATH_MAX];
|
||||
char *c;
|
||||
|
||||
safestrcpy(parent_path, clsdev->path);
|
||||
c = strstr(parent_path, SYSFS_BLOCK_NAME);
|
||||
@ -430,20 +147,20 @@ static int get_blockdev_parent(struct sysfs_class_device *clsdev)
|
||||
else
|
||||
goto errout;
|
||||
|
||||
/* validate whether the given class device is a partition or not */
|
||||
if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) {
|
||||
dprintf("%s not a partition\n", clsdev->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
c = strchr(c, '/');
|
||||
/* validate whether the given class device is a partition or not */
|
||||
if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) {
|
||||
dprintf("%s not a partition\n", clsdev->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
c = strchr(c, '/');
|
||||
if (c == NULL)
|
||||
goto errout;
|
||||
|
||||
*c = '\0';
|
||||
|
||||
|
||||
clsdev->parent = sysfs_open_class_device_path(parent_path);
|
||||
if (clsdev->parent == NULL) {
|
||||
if (!clsdev->parent) {
|
||||
dprintf("Error opening the parent class device at %s\n",
|
||||
parent_path);
|
||||
return 1;
|
||||
@ -466,19 +183,19 @@ errout:
|
||||
struct sysfs_class_device *sysfs_get_classdev_parent
|
||||
(struct sysfs_class_device *clsdev)
|
||||
{
|
||||
if (clsdev == NULL) {
|
||||
if (!clsdev) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (clsdev->parent != NULL)
|
||||
if (clsdev->parent)
|
||||
return (clsdev->parent);
|
||||
|
||||
/*
|
||||
|
||||
/*
|
||||
* As of now, only block devices have a parent child heirarchy in sysfs
|
||||
* We do not know, if, in the future, more classes will have a similar
|
||||
* structure. Hence, we now call a specialized function for block and
|
||||
* later we can add support functions for other subsystems as required.
|
||||
*/
|
||||
*/
|
||||
if (!(strncmp(clsdev->classname, SYSFS_BLOCK_NAME,
|
||||
sizeof(SYSFS_BLOCK_NAME)))) {
|
||||
if ((get_blockdev_parent(clsdev)) == 0)
|
||||
@ -499,13 +216,13 @@ struct sysfs_class_device *sysfs_get_classdev_parent
|
||||
static int get_classdev_path(const char *classname, const char *clsdev,
|
||||
char *path, size_t len)
|
||||
{
|
||||
if (classname == NULL || clsdev == NULL || path == NULL) {
|
||||
if (!classname || !clsdev || !path) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (sysfs_get_mnt_path(path, len) != 0) {
|
||||
dprintf("Error getting sysfs mount path\n");
|
||||
return -1;
|
||||
if (sysfs_get_mnt_path(path, len) != 0) {
|
||||
dprintf("Error getting sysfs mount path\n");
|
||||
return -1;
|
||||
}
|
||||
if (strncmp(classname, SYSFS_BLOCK_NAME,
|
||||
sizeof(SYSFS_BLOCK_NAME)) == 0) {
|
||||
@ -535,9 +252,9 @@ struct sysfs_class_device *sysfs_open_class_device
|
||||
(const char *classname, const char *name)
|
||||
{
|
||||
char devpath[SYSFS_PATH_MAX];
|
||||
struct sysfs_class_device *cdev = NULL;
|
||||
struct sysfs_class_device *cdev;
|
||||
|
||||
if (classname == NULL || name == NULL) {
|
||||
if (!classname || !name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@ -549,9 +266,9 @@ struct sysfs_class_device *sysfs_open_class_device
|
||||
name, classname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
cdev = sysfs_open_class_device_path(devpath);
|
||||
if (cdev == NULL) {
|
||||
if (!cdev) {
|
||||
dprintf("Error getting class device %s from class %s\n",
|
||||
name, classname);
|
||||
return NULL;
|
||||
@ -559,57 +276,6 @@ struct sysfs_class_device *sysfs_open_class_device
|
||||
return cdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_classdev_attributes: returns a dlist of attributes for
|
||||
* the requested class_device
|
||||
* @cdev: sysfs_class_dev for which attributes are needed
|
||||
* returns a dlist of attributes if exists, NULL otherwise
|
||||
*/
|
||||
struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *cdev)
|
||||
{
|
||||
if (cdev == NULL)
|
||||
return NULL;
|
||||
|
||||
if (cdev->directory == NULL) {
|
||||
cdev->directory = sysfs_open_directory(cdev->path);
|
||||
if (cdev->directory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
if (cdev->directory->attributes == NULL) {
|
||||
if ((sysfs_read_dir_attributes(cdev->directory)) != 0)
|
||||
return NULL;
|
||||
}
|
||||
return (cdev->directory->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_refresh_clsassdev_attributes: refreshes the driver's list of attributes
|
||||
* @clsdev: sysfs_class_device whose attributes to refresh
|
||||
*
|
||||
* NOTE: Upon return, prior references to sysfs_attributes for this classdev
|
||||
* _may_ not be valid
|
||||
*
|
||||
* Returns list of attributes on success and NULL on failure
|
||||
*/
|
||||
struct dlist *sysfs_refresh_classdev_attributes
|
||||
(struct sysfs_class_device *clsdev)
|
||||
{
|
||||
if (clsdev == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (clsdev->directory == NULL)
|
||||
return (sysfs_get_classdev_attributes(clsdev));
|
||||
|
||||
if ((sysfs_refresh_dir_attributes(clsdev->directory)) != 0) {
|
||||
dprintf("Error refreshing class_device attributes\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (clsdev->directory->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_classdev_attr: searches class device's attributes by name
|
||||
* @clsdev: class device to look through
|
||||
@ -619,90 +285,53 @@ struct dlist *sysfs_refresh_classdev_attributes
|
||||
struct sysfs_attribute *sysfs_get_classdev_attr
|
||||
(struct sysfs_class_device *clsdev, const char *name)
|
||||
{
|
||||
struct sysfs_attribute *cur = NULL;
|
||||
struct sysfs_directory *sdir = NULL;
|
||||
struct dlist *attrlist = NULL;
|
||||
|
||||
if (clsdev == NULL || name == NULL) {
|
||||
if (!clsdev || !name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, see if it's in the current directory. Then look at
|
||||
* subdirs since class devices can have subdirs of attributes.
|
||||
*/
|
||||
attrlist = sysfs_get_classdev_attributes(clsdev);
|
||||
if (attrlist != NULL) {
|
||||
cur = sysfs_get_directory_attribute(clsdev->directory,
|
||||
(char *)name);
|
||||
if (cur != NULL)
|
||||
return cur;
|
||||
}
|
||||
|
||||
if (clsdev->directory == NULL)
|
||||
return NULL;
|
||||
|
||||
if (clsdev->directory->subdirs == NULL)
|
||||
if ((sysfs_read_dir_subdirs(clsdev->directory)) != 0 ||
|
||||
clsdev->directory->subdirs == NULL)
|
||||
return NULL;
|
||||
|
||||
if (clsdev->directory->subdirs != NULL) {
|
||||
dlist_for_each_data(clsdev->directory->subdirs, sdir,
|
||||
struct sysfs_directory) {
|
||||
if ((sysfs_path_is_dir(sdir->path)) != 0)
|
||||
continue;
|
||||
cur = sysfs_get_directory_attribute(sdir,
|
||||
(char *)name);
|
||||
if (cur == NULL)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return cur;
|
||||
return get_attribute(clsdev, (char *)name);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_classdev_attr: read an attribute for a given class device
|
||||
* @classname: name of the class on which to look
|
||||
* @dev: class device name for which the attribute has to be read
|
||||
* @attrib: attribute to read
|
||||
* Returns sysfs_attribute * on SUCCESS and NULL on error
|
||||
*
|
||||
* NOTE:
|
||||
* A call to sysfs_close_attribute() is required to close the
|
||||
* attribute returned and to free memory
|
||||
* sysfs_get_classdev_attributes: gets list of classdev attributes
|
||||
* @clsdev: class device whose attributes list is needed
|
||||
* returns dlist of attributes on success or NULL on error
|
||||
*/
|
||||
struct sysfs_attribute *sysfs_open_classdev_attr(const char *classname,
|
||||
const char *dev, const char *attrib)
|
||||
struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *clsdev)
|
||||
{
|
||||
struct sysfs_attribute *attribute = NULL;
|
||||
char path[SYSFS_PATH_MAX];
|
||||
|
||||
if (classname == NULL || dev == NULL || attrib == NULL) {
|
||||
if (!clsdev) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
memset(path, 0, SYSFS_PATH_MAX);
|
||||
if ((get_classdev_path(classname, dev, path, SYSFS_PATH_MAX)) != 0) {
|
||||
dprintf("Error getting to device %s on class %s\n",
|
||||
dev, classname);
|
||||
return NULL;
|
||||
}
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, attrib);
|
||||
attribute = sysfs_open_attribute(path);
|
||||
if (attribute == NULL) {
|
||||
dprintf("Error opening attribute %s on class device %s\n",
|
||||
attrib, dev);
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_read_attribute(attribute)) != 0) {
|
||||
dprintf("Error reading attribute %s for class device %s\n",
|
||||
attrib, dev);
|
||||
sysfs_close_attribute(attribute);
|
||||
return NULL;
|
||||
}
|
||||
return attribute;
|
||||
return get_attributes_list(clsdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_classdev_device: gets the sysfs_device associated with the
|
||||
* given sysfs_class_device
|
||||
* @clsdev: class device whose associated sysfs_device is needed
|
||||
* returns struct sysfs_device * on success or NULL on error
|
||||
*/
|
||||
struct sysfs_device *sysfs_get_classdev_device
|
||||
(struct sysfs_class_device *clsdev)
|
||||
{
|
||||
char linkpath[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX];
|
||||
|
||||
if (!clsdev) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (clsdev->sysdevice)
|
||||
return clsdev->sysdevice;
|
||||
|
||||
memset(linkpath, 0, SYSFS_PATH_MAX);
|
||||
safestrcpy(linkpath, clsdev->path);
|
||||
safestrcat(linkpath, "/device");
|
||||
if (!sysfs_path_is_link(linkpath)) {
|
||||
memset(devpath, 0, SYSFS_PATH_MAX);
|
||||
if (!sysfs_get_link(linkpath, devpath, SYSFS_PATH_MAX))
|
||||
clsdev->sysdevice = sysfs_open_device_path(devpath);
|
||||
}
|
||||
return clsdev->sysdevice;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Generic device utility functions for libsysfs
|
||||
*
|
||||
* Copyright (C) IBM Corp. 2003
|
||||
* Copyright (C) IBM Corp. 2003-2005
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -24,48 +24,64 @@
|
||||
#include "sysfs.h"
|
||||
|
||||
/**
|
||||
* get_dev_driver: fills in the dev->driver_name field, but searches by
|
||||
* opening subsystem. Only to be used if no driver link exists in
|
||||
* device directory.
|
||||
*
|
||||
* Returns 0 on SUCCESS and 1 on error
|
||||
* get_dev_driver: fills in the dev->driver_name field
|
||||
* Returns 0 on SUCCESS and -1 on error
|
||||
*/
|
||||
static int get_dev_driver(struct sysfs_device *dev)
|
||||
{
|
||||
struct dlist *drvlist = NULL;
|
||||
char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX];
|
||||
char *drv = NULL, *c = NULL;
|
||||
|
||||
if (dev == NULL) {
|
||||
struct dlist *drvlist;
|
||||
char path[SYSFS_PATH_MAX];
|
||||
char devpath[SYSFS_PATH_MAX];
|
||||
char *drv = NULL, *c;
|
||||
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
if (dev->bus[0] == '\0')
|
||||
return 1;
|
||||
|
||||
memset(path, 0, SYSFS_PATH_MAX);
|
||||
memset(devpath, 0, SYSFS_PATH_MAX);
|
||||
safestrcpy(path, SYSFS_BUS_NAME);
|
||||
safestrcpymax(path, dev->path, SYSFS_PATH_MAX);
|
||||
safestrcatmax(path, "/driver", SYSFS_PATH_MAX);
|
||||
if (!sysfs_path_is_link(path)) {
|
||||
if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) {
|
||||
if (sysfs_get_name_from_path(devpath,
|
||||
dev->driver_name, SYSFS_NAME_LEN))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Devices on on earlier kernels do not have the "driver" link.
|
||||
* Look it up in the bus directory.
|
||||
*/
|
||||
if (dev->bus[0] == '\0')
|
||||
return -1;
|
||||
memset(path, 0, SYSFS_PATH_MAX);
|
||||
memset(devpath, 0, SYSFS_PATH_MAX);
|
||||
safestrcpy(path, dev->path);
|
||||
c = strstr(path, SYSFS_DEVICES_NAME);
|
||||
if (c == NULL) {
|
||||
dprintf("Invalid path to device - %s\n", dev->path);
|
||||
return -1;
|
||||
} else
|
||||
*c = '\0';
|
||||
safestrcat(path, SYSFS_BUS_NAME);
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, dev->bus);
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, SYSFS_DRIVERS_NAME);
|
||||
|
||||
safestrcpy(devpath, dev->path);
|
||||
c = strstr(devpath, SYSFS_DEVICES_NAME);
|
||||
if (c == NULL)
|
||||
return 1;
|
||||
*c = '\0';
|
||||
safestrcatmax(c, path, (sizeof(devpath) - strlen(devpath)));
|
||||
|
||||
drvlist = sysfs_open_subsystem_list(path);
|
||||
if (drvlist != NULL) {
|
||||
drvlist = sysfs_open_directory_list(path);
|
||||
if (drvlist) {
|
||||
dlist_for_each_data(drvlist, drv, char) {
|
||||
safestrcpy(path, devpath);
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, drv);
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, dev->bus_id);
|
||||
if (sysfs_path_is_link(path) == 0) {
|
||||
safestrcpy(devpath, path);
|
||||
safestrcat(devpath, "/");
|
||||
safestrcat(devpath, drv);
|
||||
safestrcat(devpath, "/");
|
||||
safestrcat(devpath, dev->bus_id);
|
||||
if (sysfs_path_is_link(devpath) == 0) {
|
||||
safestrcpy(dev->driver_name, drv);
|
||||
sysfs_close_list(drvlist);
|
||||
return 0;
|
||||
@ -73,35 +89,9 @@ static int get_dev_driver(struct sysfs_device *dev)
|
||||
}
|
||||
sysfs_close_list(drvlist);
|
||||
}
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_device_driver_name: gets device's driver name, searches for driver
|
||||
* link first before going the brute force route.
|
||||
* @dev: device to retrieve driver
|
||||
* returns 0 with success and 1 with error
|
||||
*/
|
||||
static int get_device_driver_name(struct sysfs_device *dev)
|
||||
{
|
||||
char devpath[SYSFS_PATH_MAX], drvpath[SYSFS_PATH_MAX];
|
||||
|
||||
if (dev == NULL) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
memset(devpath, 0, SYSFS_PATH_MAX);
|
||||
memset(drvpath, 0, SYSFS_PATH_MAX);
|
||||
safestrcpy(devpath, dev->path);
|
||||
safestrcat(devpath, "/driver");
|
||||
|
||||
if ((sysfs_get_link(devpath, drvpath, SYSFS_PATH_MAX)) != 0)
|
||||
return(get_dev_driver(dev));
|
||||
|
||||
return (sysfs_get_name_from_path(drvpath, dev->driver_name,
|
||||
SYSFS_NAME_LEN));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_device_bus: retrieves the bus name the device is on, checks path
|
||||
* to bus' link to make sure it has correct device.
|
||||
@ -110,31 +100,49 @@ static int get_device_driver_name(struct sysfs_device *dev)
|
||||
*/
|
||||
int sysfs_get_device_bus(struct sysfs_device *dev)
|
||||
{
|
||||
char subsys[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX];
|
||||
char target[SYSFS_PATH_MAX], *bus = NULL, *c = NULL;
|
||||
struct dlist *buslist = NULL;
|
||||
char devpath[SYSFS_PATH_MAX];
|
||||
char subsys[SYSFS_NAME_LEN];
|
||||
char path[SYSFS_PATH_MAX];
|
||||
char target[SYSFS_PATH_MAX];
|
||||
char *bus = NULL, *c;
|
||||
struct dlist *buslist;
|
||||
|
||||
if (dev == NULL) {
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(path, 0, SYSFS_PATH_MAX);
|
||||
memset(devpath, 0, SYSFS_PATH_MAX);
|
||||
safestrcpymax(path, dev->path, SYSFS_PATH_MAX);
|
||||
safestrcatmax(path, "/bus", SYSFS_PATH_MAX);
|
||||
if (!sysfs_path_is_link(path)) {
|
||||
if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) {
|
||||
if (sysfs_get_name_from_path(devpath,
|
||||
dev->bus, SYSFS_NAME_LEN))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Devices on on earlier kernels do not have the "bus" link.
|
||||
* Look it up in the bus directory.
|
||||
*/
|
||||
memset(subsys, 0, SYSFS_NAME_LEN);
|
||||
safestrcpy(subsys, SYSFS_BUS_NAME); /* subsys = bus */
|
||||
buslist = sysfs_open_subsystem_list(subsys);
|
||||
if (buslist != NULL) {
|
||||
safestrcpy(subsys, dev->path);
|
||||
c = strstr(subsys, SYSFS_DEVICES_NAME);
|
||||
if (c == NULL) {
|
||||
dprintf("Invalid path to device - %s\n", dev->path);
|
||||
return -1;
|
||||
} else
|
||||
*c = '\0';
|
||||
safestrcat(subsys, SYSFS_BUS_NAME);
|
||||
buslist = sysfs_open_directory_list(subsys);
|
||||
if (buslist) {
|
||||
dlist_for_each_data(buslist, bus, char) {
|
||||
memset(path, 0, SYSFS_PATH_MAX);
|
||||
safestrcpy(path, dev->path);
|
||||
c = strstr(path, "/devices");
|
||||
if (c == NULL) {
|
||||
dprintf("Invalid path to device %s\n", path);
|
||||
sysfs_close_list(buslist);
|
||||
return -1;
|
||||
}
|
||||
*c = '\0';
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, SYSFS_BUS_NAME);
|
||||
safestrcpy(path, subsys);
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, bus);
|
||||
safestrcat(path, "/");
|
||||
@ -143,8 +151,8 @@ int sysfs_get_device_bus(struct sysfs_device *dev)
|
||||
safestrcat(path, dev->bus_id);
|
||||
if ((sysfs_path_is_link(path)) == 0) {
|
||||
memset(target, 0, SYSFS_PATH_MAX);
|
||||
if ((sysfs_get_link(path, target,
|
||||
SYSFS_PATH_MAX)) != 0) {
|
||||
if (sysfs_get_link(path, target,
|
||||
SYSFS_PATH_MAX)) {
|
||||
dprintf("Error getting link target\n");
|
||||
sysfs_close_list(buslist);
|
||||
return -1;
|
||||
@ -156,10 +164,10 @@ int sysfs_get_device_bus(struct sysfs_device *dev)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
sysfs_close_list(buslist);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
sysfs_close_list(buslist);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,8 +177,8 @@ int sysfs_get_device_bus(struct sysfs_device *dev)
|
||||
*/
|
||||
void sysfs_close_device_tree(struct sysfs_device *devroot)
|
||||
{
|
||||
if (devroot != NULL) {
|
||||
if (devroot->children != NULL) {
|
||||
if (devroot) {
|
||||
if (devroot->children) {
|
||||
struct sysfs_device *child = NULL;
|
||||
|
||||
dlist_for_each_data(devroot->children, child,
|
||||
@ -182,27 +190,19 @@ void sysfs_close_device_tree(struct sysfs_device *devroot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_close_dev_tree: routine for dlist integration
|
||||
*/
|
||||
static void sysfs_close_dev_tree(void *dev)
|
||||
{
|
||||
sysfs_close_device_tree((struct sysfs_device *)dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_close_device: closes and cleans up a device
|
||||
* @dev = device to clean up
|
||||
*/
|
||||
void sysfs_close_device(struct sysfs_device *dev)
|
||||
{
|
||||
if (dev != NULL) {
|
||||
if (dev->parent != NULL)
|
||||
if (dev) {
|
||||
if (dev->parent)
|
||||
sysfs_close_device(dev->parent);
|
||||
if (dev->directory != NULL)
|
||||
sysfs_close_directory(dev->directory);
|
||||
if (dev->children != NULL && dev->children->count == 0)
|
||||
if (dev->children && dev->children->count)
|
||||
dlist_destroy(dev->children);
|
||||
if (dev->attrlist)
|
||||
dlist_destroy(dev->attrlist);
|
||||
free(dev);
|
||||
}
|
||||
}
|
||||
@ -213,36 +213,7 @@ void sysfs_close_device(struct sysfs_device *dev)
|
||||
*/
|
||||
static struct sysfs_device *alloc_device(void)
|
||||
{
|
||||
return (struct sysfs_device *)calloc(1, sizeof(struct sysfs_device));
|
||||
}
|
||||
|
||||
/**
|
||||
* open_device_dir: opens up sysfs_directory for specific root dev
|
||||
* @name: name of root
|
||||
* returns struct sysfs_directory with success and NULL with error
|
||||
*/
|
||||
static struct sysfs_directory *open_device_dir(const char *path)
|
||||
{
|
||||
struct sysfs_directory *rdir = NULL;
|
||||
|
||||
if (path == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rdir = sysfs_open_directory(path);
|
||||
if (rdir == NULL) {
|
||||
errno = EINVAL;
|
||||
dprintf ("Device %s not supported on this system\n", path);
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_read_dir_subdirs(rdir)) != 0) {
|
||||
dprintf ("Error reading device at dir %s\n", path);
|
||||
sysfs_close_directory(rdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rdir;
|
||||
return (struct sysfs_device *) calloc(1, sizeof(struct sysfs_device));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,45 +223,44 @@ static struct sysfs_directory *open_device_dir(const char *path)
|
||||
*/
|
||||
struct sysfs_device *sysfs_open_device_path(const char *path)
|
||||
{
|
||||
struct sysfs_device *dev = NULL;
|
||||
struct sysfs_device *dev;
|
||||
|
||||
if (path == NULL) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_path_is_dir(path)) != 0) {
|
||||
if (sysfs_path_is_dir(path)) {
|
||||
dprintf("Incorrect path to device: %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
dev = alloc_device();
|
||||
if (dev == NULL) {
|
||||
dev = alloc_device();
|
||||
if (!dev) {
|
||||
dprintf("Error allocating device at %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_get_name_from_path(path, dev->bus_id,
|
||||
SYSFS_NAME_LEN)) != 0) {
|
||||
if (sysfs_get_name_from_path(path, dev->bus_id, SYSFS_NAME_LEN)) {
|
||||
errno = EINVAL;
|
||||
dprintf("Error getting device bus_id\n");
|
||||
sysfs_close_device(dev);
|
||||
return NULL;
|
||||
}
|
||||
safestrcpy(dev->path, path);
|
||||
if ((sysfs_remove_trailing_slash(dev->path)) != 0) {
|
||||
if (sysfs_remove_trailing_slash(dev->path)) {
|
||||
dprintf("Invalid path to device %s\n", dev->path);
|
||||
sysfs_close_device(dev);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
/*
|
||||
* The "name" attribute no longer exists... return the device's
|
||||
* sysfs representation instead, in the "dev->name" field, which
|
||||
* implies that the dev->name and dev->bus_id contain same data.
|
||||
*/
|
||||
safestrcpy(dev->name, dev->bus_id);
|
||||
|
||||
if (sysfs_get_device_bus(dev) != 0)
|
||||
|
||||
if (sysfs_get_device_bus(dev))
|
||||
dprintf("Could not get device bus\n");
|
||||
|
||||
if (get_device_driver_name(dev) != 0) {
|
||||
|
||||
if (get_dev_driver(dev)) {
|
||||
dprintf("Could not get device %s's driver\n", dev->bus_id);
|
||||
safestrcpy(dev->driver_name, SYSFS_UNKNOWN);
|
||||
}
|
||||
@ -298,207 +268,6 @@ struct sysfs_device *sysfs_open_device_path(const char *path)
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_device_tree: opens root device and all of its children,
|
||||
* creating a tree of devices. Only opens children.
|
||||
* @path: sysfs path to devices
|
||||
* returns struct sysfs_device and its children with success or NULL with
|
||||
* error.
|
||||
*/
|
||||
struct sysfs_device *sysfs_open_device_tree(const char *path)
|
||||
{
|
||||
struct sysfs_device *rootdev = NULL, *new = NULL;
|
||||
struct sysfs_directory *cur = NULL;
|
||||
|
||||
if (path == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
rootdev = sysfs_open_device_path(path);
|
||||
if (rootdev == NULL) {
|
||||
dprintf("Error opening root device at %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
if (rootdev->directory == NULL) {
|
||||
rootdev->directory = open_device_dir(rootdev->path);
|
||||
if (rootdev->directory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
if (rootdev->directory->subdirs != NULL) {
|
||||
dlist_for_each_data(rootdev->directory->subdirs, cur,
|
||||
struct sysfs_directory) {
|
||||
new = sysfs_open_device_tree(cur->path);
|
||||
if (new == NULL) {
|
||||
dprintf("Error opening device tree at %s\n",
|
||||
cur->path);
|
||||
sysfs_close_device_tree(rootdev);
|
||||
return NULL;
|
||||
}
|
||||
if (rootdev->children == NULL)
|
||||
rootdev->children = dlist_new_with_delete
|
||||
(sizeof(struct sysfs_device),
|
||||
sysfs_close_dev_tree);
|
||||
dlist_unshift_sorted(rootdev->children,
|
||||
new, sort_list);
|
||||
}
|
||||
}
|
||||
|
||||
return rootdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_close_root_device: closes root and all devices
|
||||
* @root: root device to close
|
||||
*/
|
||||
void sysfs_close_root_device(struct sysfs_root_device *root)
|
||||
{
|
||||
if (root != NULL) {
|
||||
if (root->devices != NULL)
|
||||
dlist_destroy(root->devices);
|
||||
if (root->directory != NULL)
|
||||
sysfs_close_directory(root->directory);
|
||||
free(root);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_root_devices: opens up all the devices under this root device
|
||||
* @root: root device to open devices for
|
||||
* returns dlist of devices with success and NULL with error
|
||||
*/
|
||||
struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root)
|
||||
{
|
||||
struct sysfs_device *dev = NULL;
|
||||
struct sysfs_directory *cur = NULL;
|
||||
|
||||
if (root == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (root->directory == NULL) {
|
||||
root->directory = open_device_dir(root->path);
|
||||
if (root->directory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (root->directory->subdirs == NULL)
|
||||
return 0;
|
||||
|
||||
dlist_for_each_data(root->directory->subdirs, cur,
|
||||
struct sysfs_directory) {
|
||||
dev = sysfs_open_device_tree(cur->path);
|
||||
if (dev == NULL) {
|
||||
dprintf ("Error opening device at %s\n", cur->path);
|
||||
continue;
|
||||
}
|
||||
if (root->devices == NULL)
|
||||
root->devices = dlist_new_with_delete
|
||||
(sizeof(struct sysfs_device),
|
||||
sysfs_close_dev_tree);
|
||||
dlist_unshift_sorted(root->devices, dev, sort_list);
|
||||
}
|
||||
|
||||
return root->devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_root_device: opens sysfs devices root and all of its
|
||||
* devices.
|
||||
* @name: name of /sys/devices/root to open
|
||||
* returns struct sysfs_root_device if success and NULL with error
|
||||
*/
|
||||
struct sysfs_root_device *sysfs_open_root_device(const char *name)
|
||||
{
|
||||
struct sysfs_root_device *root = NULL;
|
||||
char rootpath[SYSFS_PATH_MAX];
|
||||
|
||||
if (name == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(rootpath, 0, SYSFS_PATH_MAX);
|
||||
if (sysfs_get_mnt_path(rootpath, SYSFS_PATH_MAX) != 0) {
|
||||
dprintf ("Sysfs not supported on this system\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
safestrcat(rootpath, "/");
|
||||
safestrcat(rootpath, SYSFS_DEVICES_NAME);
|
||||
safestrcat(rootpath, "/");
|
||||
safestrcat(rootpath, name);
|
||||
if ((sysfs_path_is_dir(rootpath)) != 0) {
|
||||
errno = EINVAL;
|
||||
dprintf("Invalid root device: %s\n", name);
|
||||
return NULL;
|
||||
}
|
||||
root = (struct sysfs_root_device *)calloc
|
||||
(1, sizeof(struct sysfs_root_device));
|
||||
if (root == NULL) {
|
||||
dprintf("calloc failure\n");
|
||||
return NULL;
|
||||
}
|
||||
safestrcpy(root->name, name);
|
||||
safestrcpy(root->path, rootpath);
|
||||
if ((sysfs_remove_trailing_slash(root->path)) != 0) {
|
||||
dprintf("Invalid path to root device %s\n", root->path);
|
||||
sysfs_close_root_device(root);
|
||||
return NULL;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_device_attributes: returns a dlist of attributes corresponding to
|
||||
* the specific device
|
||||
* @device: struct sysfs_device * for which attributes are to be returned
|
||||
*/
|
||||
struct dlist *sysfs_get_device_attributes(struct sysfs_device *device)
|
||||
{
|
||||
if (device == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (device->directory == NULL) {
|
||||
device->directory = sysfs_open_directory(device->path);
|
||||
if (device->directory == NULL)
|
||||
return NULL;
|
||||
}
|
||||
if (device->directory->attributes == NULL) {
|
||||
if ((sysfs_read_dir_attributes(device->directory)) != 0)
|
||||
return NULL;
|
||||
}
|
||||
return (device->directory->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_refresh_device_attributes: refreshes the device's list of attributes
|
||||
* @device: sysfs_device whose attributes to refresh
|
||||
*
|
||||
* NOTE: Upon return, prior references to sysfs_attributes for this device
|
||||
* _may_ not be valid
|
||||
*
|
||||
* Returns list of attributes on success and NULL on failure
|
||||
*/
|
||||
struct dlist *sysfs_refresh_device_attributes(struct sysfs_device *device)
|
||||
{
|
||||
if (device == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (device->directory == NULL)
|
||||
return (sysfs_get_device_attributes(device));
|
||||
|
||||
if ((sysfs_refresh_dir_attributes(device->directory)) != 0) {
|
||||
dprintf("Error refreshing device attributes\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (device->directory->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_device_attr: searches dev's attributes by name
|
||||
* @dev: device to look through
|
||||
@ -508,18 +277,25 @@ struct dlist *sysfs_refresh_device_attributes(struct sysfs_device *device)
|
||||
struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
|
||||
const char *name)
|
||||
{
|
||||
struct dlist *attrlist = NULL;
|
||||
|
||||
if (dev == NULL || name == NULL) {
|
||||
if (!dev || !name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
attrlist = sysfs_get_device_attributes(dev);
|
||||
if (attrlist == NULL)
|
||||
return NULL;
|
||||
return get_attribute(dev, (char *)name);
|
||||
}
|
||||
|
||||
return sysfs_get_directory_attribute(dev->directory, (char *)name);
|
||||
/**
|
||||
* sysfs_get_device_attributes: gets list of device attributes
|
||||
* @dev: device whose attributes list is needed
|
||||
* returns dlist of attributes on success or NULL on error
|
||||
*/
|
||||
struct dlist *sysfs_get_device_attributes(struct sysfs_device *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return get_attributes_list(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -535,13 +311,13 @@ static int get_device_absolute_path(const char *device, const char *bus,
|
||||
{
|
||||
char bus_path[SYSFS_PATH_MAX];
|
||||
|
||||
if (device == NULL || path == NULL) {
|
||||
if (!device || !path) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(bus_path, 0, SYSFS_PATH_MAX);
|
||||
if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX) != 0) {
|
||||
if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX)) {
|
||||
dprintf ("Sysfs not supported on this system\n");
|
||||
return -1;
|
||||
}
|
||||
@ -557,7 +333,7 @@ static int get_device_absolute_path(const char *device, const char *bus,
|
||||
* We now are at /sys/bus/"bus_name"/devices/"device" which is a link.
|
||||
* Now read this link to reach to the device.
|
||||
*/
|
||||
if ((sysfs_get_link(bus_path, path, psize)) != 0) {
|
||||
if (sysfs_get_link(bus_path, path, psize)) {
|
||||
dprintf("Error getting to device %s\n", device);
|
||||
return -1;
|
||||
}
|
||||
@ -578,21 +354,21 @@ static int get_device_absolute_path(const char *device, const char *bus,
|
||||
struct sysfs_device *sysfs_open_device(const char *bus, const char *bus_id)
|
||||
{
|
||||
char sysfs_path[SYSFS_PATH_MAX];
|
||||
struct sysfs_device *device = NULL;
|
||||
struct sysfs_device *device;
|
||||
|
||||
if (bus_id == NULL || bus == NULL) {
|
||||
if (!bus_id || !bus) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
memset(sysfs_path, 0, SYSFS_PATH_MAX);
|
||||
if ((get_device_absolute_path(bus_id, bus, sysfs_path,
|
||||
SYSFS_PATH_MAX)) != 0) {
|
||||
if (get_device_absolute_path(bus_id, bus, sysfs_path,
|
||||
SYSFS_PATH_MAX)) {
|
||||
dprintf("Error getting to device %s\n", bus_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device = sysfs_open_device_path(sysfs_path);
|
||||
if (device == NULL) {
|
||||
if (!device) {
|
||||
dprintf("Error opening device %s\n", bus_id);
|
||||
return NULL;
|
||||
}
|
||||
@ -608,20 +384,20 @@ struct sysfs_device *sysfs_open_device(const char *bus, const char *bus_id)
|
||||
*/
|
||||
struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev)
|
||||
{
|
||||
char ppath[SYSFS_PATH_MAX], *tmp = NULL;
|
||||
char ppath[SYSFS_PATH_MAX], *tmp;
|
||||
|
||||
if (dev == NULL) {
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dev->parent != NULL)
|
||||
if (dev->parent)
|
||||
return (dev->parent);
|
||||
|
||||
memset(ppath, 0, SYSFS_PATH_MAX);
|
||||
safestrcpy(ppath, dev->path);
|
||||
tmp = strrchr(ppath, '/');
|
||||
if (tmp == NULL) {
|
||||
if (!tmp) {
|
||||
dprintf("Invalid path to device %s\n", ppath);
|
||||
return NULL;
|
||||
}
|
||||
@ -634,68 +410,22 @@ struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev)
|
||||
}
|
||||
}
|
||||
*tmp = '\0';
|
||||
|
||||
|
||||
/*
|
||||
* All "devices" have the "detach_state" attribute - validate here
|
||||
*/
|
||||
safestrcat(ppath, "/detach_state");
|
||||
if ((sysfs_path_is_file(ppath)) != 0) {
|
||||
if (sysfs_path_is_file(ppath)) {
|
||||
dprintf("Device at %s does not have a parent\n", dev->path);
|
||||
return NULL;
|
||||
}
|
||||
tmp = strrchr(ppath, '/');
|
||||
*tmp = '\0';
|
||||
dev->parent = sysfs_open_device_path(ppath);
|
||||
if (dev->parent == NULL) {
|
||||
if (!dev->parent) {
|
||||
dprintf("Error opening device %s's parent at %s\n",
|
||||
dev->bus_id, ppath);
|
||||
return NULL;
|
||||
}
|
||||
return (dev->parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs_open_device_attr: open the given device's attribute
|
||||
* @bus: Bus on which to look
|
||||
* @dev_id: device for which attribute is required
|
||||
* @attrname: name of the attribute to look for
|
||||
* Returns struct sysfs_attribute on success and NULL on failure
|
||||
*
|
||||
* NOTE:
|
||||
* A call to sysfs_close_attribute() is required to close
|
||||
* the attribute returned and free memory.
|
||||
*/
|
||||
struct sysfs_attribute *sysfs_open_device_attr(const char *bus,
|
||||
const char *bus_id, const char *attrib)
|
||||
{
|
||||
struct sysfs_attribute *attribute = NULL;
|
||||
char devpath[SYSFS_PATH_MAX];
|
||||
|
||||
if (bus == NULL || bus_id == NULL || attrib == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(devpath, 0, SYSFS_PATH_MAX);
|
||||
if ((get_device_absolute_path(bus_id, bus, devpath,
|
||||
SYSFS_PATH_MAX)) != 0) {
|
||||
dprintf("Error getting to device %s\n", bus_id);
|
||||
return NULL;
|
||||
}
|
||||
safestrcat(devpath, "/");
|
||||
safestrcat(devpath, attrib);
|
||||
attribute = sysfs_open_attribute(devpath);
|
||||
if (attribute == NULL) {
|
||||
dprintf("Error opening attribute %s for device %s\n",
|
||||
attrib, bus_id);
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_read_attribute(attribute)) != 0) {
|
||||
dprintf("Error reading attribute %s for device %s\n",
|
||||
attrib, bus_id);
|
||||
sysfs_close_attribute(attribute);
|
||||
return NULL;
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
|
||||
|
1080
libsysfs/sysfs_dir.c
1080
libsysfs/sysfs_dir.c
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Driver utility functions for libsysfs
|
||||
*
|
||||
* Copyright (C) IBM Corp. 2003
|
||||
* Copyright (C) IBM Corp. 2003-2005
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -28,42 +28,20 @@ static void sysfs_close_driver_device(void *device)
|
||||
sysfs_close_device((struct sysfs_device *)device);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* sysfs_close_driver: closes driver and deletes device lists too
|
||||
* @driver: driver to close
|
||||
*/
|
||||
*/
|
||||
void sysfs_close_driver(struct sysfs_driver *driver)
|
||||
{
|
||||
if (driver != NULL) {
|
||||
if (driver->devices != NULL)
|
||||
if (driver) {
|
||||
if (driver->devices)
|
||||
dlist_destroy(driver->devices);
|
||||
if (driver->directory != NULL)
|
||||
sysfs_close_directory(driver->directory);
|
||||
if (driver->attrlist)
|
||||
dlist_destroy(driver->attrlist);
|
||||
free(driver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* open_driver_dir: Open the sysfs_directory for this driver
|
||||
* @driver: Driver whose directory to be opened
|
||||
* Returns 0 on success and 1 on failure
|
||||
*/
|
||||
static int open_driver_dir(struct sysfs_driver *driver)
|
||||
{
|
||||
if (driver == NULL) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
if (driver->directory == NULL) {
|
||||
driver->directory = sysfs_open_directory(driver->path);
|
||||
if (driver->directory == NULL) {
|
||||
dprintf("Error opening driver directory at %s\n",
|
||||
driver->path);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_driver: allocates and initializes driver
|
||||
@ -74,6 +52,65 @@ static struct sysfs_driver *alloc_driver(void)
|
||||
return (struct sysfs_driver *)calloc(1, sizeof(struct sysfs_driver));
|
||||
}
|
||||
|
||||
/**
|
||||
* get_driver_bus: gets bus the driver is on
|
||||
* Returns 0 on success and 1 on error
|
||||
*/
|
||||
static int get_driver_bus(struct sysfs_driver *drv)
|
||||
{
|
||||
char drvpath[SYSFS_PATH_MAX], *c = NULL;
|
||||
|
||||
if (!drv) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
safestrcpy(drvpath, drv->path);
|
||||
c = strstr(drvpath, SYSFS_DRIVERS_NAME);
|
||||
if (c == NULL)
|
||||
return 1;
|
||||
*--c = '\0';
|
||||
c = strstr(drvpath, SYSFS_BUS_NAME);
|
||||
if (c == NULL)
|
||||
return 1;
|
||||
c = strstr(c, "/");
|
||||
if (c == NULL)
|
||||
return 1;
|
||||
c++;
|
||||
safestrcpy(drv->bus, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_attr: searches drv's attributes by name
|
||||
* @drv: driver to look through
|
||||
* @name: attribute name to get
|
||||
* returns sysfs_attribute reference with success or NULL with error.
|
||||
*/
|
||||
struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
|
||||
const char *name)
|
||||
{
|
||||
if (!drv || !name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return get_attribute(drv, (char *)name);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_attributes: gets list of driver attributes
|
||||
* @dev: driver whose attributes list is needed
|
||||
* returns dlist of attributes on success or NULL on error
|
||||
*/
|
||||
struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *drv)
|
||||
{
|
||||
if (!drv) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return get_attributes_list(drv);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_driver_path: opens and initializes driver structure
|
||||
* @path: path to driver directory
|
||||
@ -83,238 +120,39 @@ struct sysfs_driver *sysfs_open_driver_path(const char *path)
|
||||
{
|
||||
struct sysfs_driver *driver = NULL;
|
||||
|
||||
if (path == NULL) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_path_is_dir(path)) != 0) {
|
||||
if (sysfs_path_is_dir(path)) {
|
||||
dprintf("Invalid path to driver: %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
driver = alloc_driver();
|
||||
if (driver == NULL) {
|
||||
if (!driver) {
|
||||
dprintf("Error allocating driver at %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_get_name_from_path(path, driver->name,
|
||||
SYSFS_NAME_LEN)) != 0) {
|
||||
if (sysfs_get_name_from_path(path, driver->name, SYSFS_NAME_LEN)) {
|
||||
dprintf("Error getting driver name from path\n");
|
||||
free(driver);
|
||||
return NULL;
|
||||
}
|
||||
safestrcpy(driver->path, path);
|
||||
if ((sysfs_remove_trailing_slash(driver->path)) != 0) {
|
||||
if (sysfs_remove_trailing_slash(driver->path)) {
|
||||
dprintf("Invalid path to driver %s\n", driver->path);
|
||||
sysfs_close_driver(driver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (get_driver_bus(driver)) {
|
||||
dprintf("Could not get the bus driver is on\n");
|
||||
sysfs_close_driver(driver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_attributes: gets list of attributes for the given driver
|
||||
* @driver: sysfs_driver for which attributes are required
|
||||
* returns a dlist of attributes corresponding to the driver if present
|
||||
* NULL otherwise
|
||||
*/
|
||||
struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver)
|
||||
{
|
||||
if (driver == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver->directory == NULL) {
|
||||
if ((open_driver_dir(driver)) == 1)
|
||||
return NULL;
|
||||
}
|
||||
if (driver->directory->attributes == NULL) {
|
||||
if ((sysfs_read_dir_attributes(driver->directory)) != 0)
|
||||
return NULL;
|
||||
}
|
||||
return(driver->directory->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_refresh_driver_attributes: refreshes the driver's list of attributes
|
||||
* @driver: sysfs_driver whose attributes to refresh
|
||||
*
|
||||
* NOTE: Upon return, prior references to sysfs_attributes for this driver
|
||||
* _may_ not be valid
|
||||
*
|
||||
* Returns list of attributes on success and NULL on failure
|
||||
*/
|
||||
struct dlist *sysfs_refresh_driver_attributes(struct sysfs_driver *driver)
|
||||
{
|
||||
if (driver == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (driver->directory == NULL)
|
||||
return (sysfs_get_driver_attributes(driver));
|
||||
|
||||
if ((sysfs_refresh_dir_attributes(driver->directory)) != 0) {
|
||||
dprintf("Error refreshing driver attributes\n");
|
||||
return NULL;
|
||||
}
|
||||
return (driver->directory->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_attr: searches driver's attributes by name
|
||||
* @drv: driver to look through
|
||||
* @name: attribute name to get
|
||||
* returns sysfs_attribute reference on success or NULL with error
|
||||
*/
|
||||
struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
|
||||
const char *name)
|
||||
{
|
||||
struct dlist *attrlist = NULL;
|
||||
|
||||
if (drv == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
attrlist = sysfs_get_driver_attributes(drv);
|
||||
if (attrlist == NULL)
|
||||
return NULL;
|
||||
|
||||
return sysfs_get_directory_attribute(drv->directory, (char *)name);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_links: gets list of links from the given driver
|
||||
* @driver: sysfs_driver for which links list is required
|
||||
* returns a dlist of links corresponding to the driver if present
|
||||
* NULL otherwise
|
||||
*/
|
||||
struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver)
|
||||
{
|
||||
if (driver == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver->directory == NULL)
|
||||
if ((open_driver_dir(driver)) == 1)
|
||||
return NULL;
|
||||
|
||||
if (driver->directory->links == NULL)
|
||||
if ((sysfs_read_dir_links(driver->directory)) != 0)
|
||||
return NULL;
|
||||
|
||||
return(driver->directory->links);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_devices: open up the list of devices this driver supports
|
||||
* @driver: sysfs_driver for which devices are needed
|
||||
* Returns dlist of devices on SUCCESS or NULL with ERROR
|
||||
*/
|
||||
struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver)
|
||||
{
|
||||
struct sysfs_link *curlink = NULL;
|
||||
struct sysfs_device *device = NULL;
|
||||
|
||||
if (driver == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver->devices != NULL)
|
||||
return (driver->devices);
|
||||
|
||||
if (driver->directory == NULL || driver->directory->links == NULL) {
|
||||
struct dlist *list = NULL;
|
||||
list = sysfs_get_driver_links(driver);
|
||||
}
|
||||
|
||||
if (driver->directory->links != NULL) {
|
||||
dlist_for_each_data(driver->directory->links, curlink,
|
||||
struct sysfs_link) {
|
||||
device = sysfs_open_device_path(curlink->target);
|
||||
if (device == NULL) {
|
||||
dprintf("Error opening device at %s\n",
|
||||
curlink->target);
|
||||
return NULL;
|
||||
}
|
||||
if (driver->devices == NULL)
|
||||
driver->devices = dlist_new_with_delete
|
||||
(sizeof(struct sysfs_device),
|
||||
sysfs_close_driver_device);
|
||||
dlist_unshift_sorted(driver->devices, device,
|
||||
sort_list);
|
||||
}
|
||||
}
|
||||
return (driver->devices);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_refresh_driver_devices: Refreshes drivers list of devices
|
||||
* @driver: sysfs_driver whose devices list needs to be refreshed
|
||||
*
|
||||
* NOTE: Upon return from this function, prior sysfs_device references from
|
||||
* this driver's list of devices _may_ not be valid
|
||||
*
|
||||
* Returns dlist of devices on success and NULL on failure
|
||||
*/
|
||||
struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver)
|
||||
{
|
||||
if (driver == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver->devices != NULL) {
|
||||
dlist_destroy(driver->devices);
|
||||
driver->devices = NULL;
|
||||
}
|
||||
|
||||
if (driver->directory == NULL)
|
||||
return (sysfs_get_driver_devices(driver));
|
||||
|
||||
if ((sysfs_refresh_dir_links(driver->directory)) != 0) {
|
||||
dprintf("Error refreshing driver links\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (sysfs_get_driver_devices(driver));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_device: looks up a device from a list of driver's devices
|
||||
* and returns its sysfs_device corresponding to it
|
||||
* @driver: sysfs_driver on which to search
|
||||
* @name: name of the device to search
|
||||
* Returns a sysfs_device if found, NULL otherwise
|
||||
*/
|
||||
struct sysfs_device *sysfs_get_driver_device(struct sysfs_driver *driver,
|
||||
const char *name)
|
||||
{
|
||||
struct sysfs_device *device = NULL;
|
||||
struct dlist *devlist = NULL;
|
||||
|
||||
if (driver == NULL || name == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver->devices == NULL) {
|
||||
devlist = sysfs_get_driver_devices(driver);
|
||||
if (devlist == NULL) {
|
||||
dprintf("Error getting driver devices\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
dlist_for_each_data(driver->devices, device, struct sysfs_device) {
|
||||
if (!(strncmp(device->name, name, SYSFS_NAME_LEN)))
|
||||
return device;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_driver_path: looks up the bus the driver is on and builds path to
|
||||
* the driver.
|
||||
@ -327,11 +165,11 @@ struct sysfs_device *sysfs_get_driver_device(struct sysfs_driver *driver,
|
||||
static int get_driver_path(const char *bus, const char *drv,
|
||||
char *path, size_t psize)
|
||||
{
|
||||
if (bus == NULL || drv == NULL || path == NULL || psize == 0) {
|
||||
if (!bus || !drv || !path || psize == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (sysfs_get_mnt_path(path, psize) != 0) {
|
||||
if (sysfs_get_mnt_path(path, psize)) {
|
||||
dprintf("Error getting sysfs mount path\n");
|
||||
return -1;
|
||||
}
|
||||
@ -346,50 +184,6 @@ static int get_driver_path(const char *bus, const char *drv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_driver_attr: read the user supplied driver attribute
|
||||
* @bus: bus on which to look
|
||||
* @drv: driver whose attribute has to be read
|
||||
* @attrib: Attribute to be read
|
||||
* Returns struct sysfs_attribute on success and NULL on failure
|
||||
*
|
||||
* NOTE:
|
||||
* A call to sysfs_close_attribute() is required to close the
|
||||
* attribute returned and to free memory
|
||||
*/
|
||||
struct sysfs_attribute *sysfs_open_driver_attr(const char *bus,
|
||||
const char *drv, const char *attrib)
|
||||
{
|
||||
struct sysfs_attribute *attribute = NULL;
|
||||
char path[SYSFS_PATH_MAX];
|
||||
|
||||
if (bus == NULL || drv == NULL || attrib == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(path, 0, SYSFS_PATH_MAX);
|
||||
if ((get_driver_path(bus, drv, path, SYSFS_PATH_MAX)) != 0) {
|
||||
dprintf("Error getting to driver %s\n", drv);
|
||||
return NULL;
|
||||
}
|
||||
safestrcat(path, "/");
|
||||
safestrcat(path, attrib);
|
||||
attribute = sysfs_open_attribute(path);
|
||||
if (attribute == NULL) {
|
||||
dprintf("Error opening attribute %s for driver %s\n",
|
||||
attrib, drv);
|
||||
return NULL;
|
||||
}
|
||||
if ((sysfs_read_attribute(attribute)) != 0) {
|
||||
dprintf("Error reading attribute %s for driver %s\n",
|
||||
attrib, drv);
|
||||
sysfs_close_attribute(attribute);
|
||||
return NULL;
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_driver: open driver by name, given its bus
|
||||
* @bus_name: Name of the bus
|
||||
@ -402,21 +196,66 @@ struct sysfs_driver *sysfs_open_driver(const char *bus_name,
|
||||
char path[SYSFS_PATH_MAX];
|
||||
struct sysfs_driver *driver = NULL;
|
||||
|
||||
if (drv_name == NULL || bus_name == NULL) {
|
||||
if (!drv_name || !bus_name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(path, 0, SYSFS_PATH_MAX);
|
||||
if ((get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) != 0) {
|
||||
if (get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) {
|
||||
dprintf("Error getting to driver %s\n", drv_name);
|
||||
return NULL;
|
||||
}
|
||||
driver = sysfs_open_driver_path(path);
|
||||
if (driver == NULL) {
|
||||
if (!driver) {
|
||||
dprintf("Error opening driver at %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_driver_devices: gets list of devices that use the driver
|
||||
* @drv: sysfs_driver whose device list is needed
|
||||
* Returns dlist of struct sysfs_device on success and NULL on failure
|
||||
*/
|
||||
struct dlist *sysfs_get_driver_devices(struct sysfs_driver *drv)
|
||||
{
|
||||
char *ln = NULL;
|
||||
struct dlist *linklist = NULL;
|
||||
struct sysfs_device *dev = NULL;
|
||||
|
||||
if (!drv) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
linklist = read_dir_links(drv->path);
|
||||
if (linklist) {
|
||||
dlist_for_each_data(linklist, ln, char) {
|
||||
|
||||
if (!strncmp(ln, SYSFS_MODULE_NAME, strlen(ln)))
|
||||
continue;
|
||||
|
||||
dev = sysfs_open_device(drv->bus, ln);
|
||||
if (!dev) {
|
||||
dprintf("Error opening driver's device\n");
|
||||
sysfs_close_list(linklist);
|
||||
return NULL;
|
||||
}
|
||||
if (!drv->devices) {
|
||||
drv->devices = dlist_new_with_delete
|
||||
(sizeof(struct sysfs_device),
|
||||
sysfs_close_driver_device);
|
||||
if (!drv->devices) {
|
||||
dprintf("Error creating device list\n");
|
||||
sysfs_close_list(linklist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
dlist_unshift_sorted(drv->devices, dev, sort_list);
|
||||
}
|
||||
sysfs_close_list(linklist);
|
||||
}
|
||||
return drv->devices;
|
||||
}
|
||||
|
@ -23,12 +23,6 @@
|
||||
#include "libsysfs.h"
|
||||
#include "sysfs.h"
|
||||
|
||||
static int sort_char(void *new, void *old)
|
||||
{
|
||||
return ((strncmp((char *)new, (char *)old,
|
||||
strlen((char *)new))) < 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_remove_trailing_slash: Removes any trailing '/' in the given path
|
||||
* @path: Path to look for the trailing '/'
|
||||
@ -38,7 +32,7 @@ int sysfs_remove_trailing_slash(char *path)
|
||||
{
|
||||
char *c = NULL;
|
||||
|
||||
if (path == NULL) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
@ -53,54 +47,6 @@ int sysfs_remove_trailing_slash(char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_get_fs_mnt_path: Gets the mount point for specified filesystem.
|
||||
* @fs_type: filesystem type to retrieve mount point
|
||||
* @mnt_path: place to put the retrieved mount path
|
||||
* @len: size of mnt_path
|
||||
* returns 0 with success and -1 with error.
|
||||
*/
|
||||
static int sysfs_get_fs_mnt_path(const char *fs_type,
|
||||
char *mnt_path, size_t len)
|
||||
{
|
||||
FILE *mnt;
|
||||
struct mntent *mntent;
|
||||
int ret = 0;
|
||||
size_t dirlen = 0;
|
||||
|
||||
/* check arg */
|
||||
if (fs_type == NULL || mnt_path == NULL || len == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((mnt = setmntent(SYSFS_PROC_MNTS, "r")) == NULL) {
|
||||
dprintf("Error getting mount information\n");
|
||||
return -1;
|
||||
}
|
||||
while (ret == 0 && dirlen == 0 && (mntent = getmntent(mnt)) != NULL) {
|
||||
if (strcmp(mntent->mnt_type, fs_type) == 0) {
|
||||
dirlen = strlen(mntent->mnt_dir);
|
||||
if (dirlen <= (len - 1)) {
|
||||
safestrcpymax(mnt_path, mntent->mnt_dir, len);
|
||||
} else {
|
||||
dprintf("Error - mount path too long\n");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
endmntent(mnt);
|
||||
if (dirlen == 0 && ret == 0) {
|
||||
dprintf("Filesystem %s not found!\n", fs_type);
|
||||
errno = EINVAL;
|
||||
ret = -1;
|
||||
}
|
||||
if ((sysfs_remove_trailing_slash(mnt_path)) != 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs_get_mnt_path: Gets the sysfs mount point.
|
||||
* @mnt_path: place to put "sysfs" mount point
|
||||
@ -109,22 +55,21 @@ static int sysfs_get_fs_mnt_path(const char *fs_type,
|
||||
*/
|
||||
int sysfs_get_mnt_path(char *mnt_path, size_t len)
|
||||
{
|
||||
char *sysfs_path = NULL;
|
||||
int ret = 0;
|
||||
static char sysfs_path[SYSFS_PATH_MAX] = "";
|
||||
const char *sysfs_path_env;
|
||||
|
||||
if (mnt_path == NULL || len == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
/* evaluate only at the first call */
|
||||
if (sysfs_path[0] == '\0') {
|
||||
/* possible overrride of real mount path */
|
||||
sysfs_path_env = getenv(SYSFS_PATH_ENV);
|
||||
if (sysfs_path_env != NULL) {
|
||||
safestrcpymax(mnt_path, sysfs_path_env, len);
|
||||
return 0;
|
||||
}
|
||||
safestrcpymax(mnt_path, SYSFS_MNT_PATH, len);
|
||||
}
|
||||
sysfs_path = getenv(SYSFS_PATH_ENV);
|
||||
if (sysfs_path != NULL) {
|
||||
safestrcpymax(mnt_path, sysfs_path, len);
|
||||
if ((sysfs_remove_trailing_slash(mnt_path)) != 0)
|
||||
return 1;
|
||||
} else
|
||||
ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,8 +82,8 @@ int sysfs_get_name_from_path(const char *path, char *name, size_t len)
|
||||
{
|
||||
char tmp[SYSFS_PATH_MAX];
|
||||
char *n = NULL;
|
||||
|
||||
if (path == NULL || name == NULL || len == 0) {
|
||||
|
||||
if (!path || !name || len == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -161,7 +106,7 @@ int sysfs_get_name_from_path(const char *path, char *name, size_t len)
|
||||
safestrcpymax(name, n, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sysfs_get_link: returns link source
|
||||
* @path: symbolic link's path
|
||||
@ -176,7 +121,7 @@ int sysfs_get_link(const char *path, char *target, size_t len)
|
||||
char *d = NULL, *s = NULL;
|
||||
int slashes = 0, count = 0;
|
||||
|
||||
if (path == NULL || target == NULL || len == 0) {
|
||||
if (!path || !target || len == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -190,15 +135,15 @@ int sysfs_get_link(const char *path, char *target, size_t len)
|
||||
return -1;
|
||||
}
|
||||
d = linkpath;
|
||||
/*
|
||||
/*
|
||||
* Three cases here:
|
||||
* 1. relative path => format ../..
|
||||
* 2. absolute path => format /abcd/efgh
|
||||
* 3. relative path _from_ this dir => format abcd/efgh
|
||||
*/
|
||||
*/
|
||||
switch (*d) {
|
||||
case '.':
|
||||
/*
|
||||
/*
|
||||
* handle the case where link is of type ./abcd/xxx
|
||||
*/
|
||||
safestrcpy(temp_path, devdir);
|
||||
@ -215,9 +160,8 @@ int sysfs_get_link(const char *path, char *target, size_t len)
|
||||
}
|
||||
safestrcpymax(target, temp_path, len);
|
||||
break;
|
||||
/*
|
||||
* relative path
|
||||
* getting rid of leading "../.."
|
||||
/*
|
||||
* relative path, getting rid of leading "../.."
|
||||
*/
|
||||
parse_path:
|
||||
while (*d == '/' || *d == '.') {
|
||||
@ -254,16 +198,6 @@ parse_path:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_del_name: free function for sysfs_open_subsystem_list
|
||||
* @name: memory area to be freed
|
||||
*/
|
||||
static void sysfs_del_name(void *name)
|
||||
{
|
||||
free(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sysfs_close_list: generic list free routine
|
||||
* @list: dlist to free
|
||||
@ -271,142 +205,22 @@ static void sysfs_del_name(void *name)
|
||||
*/
|
||||
void sysfs_close_list(struct dlist *list)
|
||||
{
|
||||
if (list != NULL)
|
||||
if (list)
|
||||
dlist_destroy(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_open_subsystem_list: gets a list of all supported "name" subsystem
|
||||
* details from the system
|
||||
* @name: name of the subsystem, eg., "bus", "class", "devices"
|
||||
* Returns a dlist of supported names or NULL if subsystem not supported
|
||||
*/
|
||||
struct dlist *sysfs_open_subsystem_list(char *name)
|
||||
* sysfs_open_directory_list: gets a list of all directories under "path"
|
||||
* @path: path to read
|
||||
* Returns a dlist of supported names or NULL no directories (errno is set
|
||||
* in case of error
|
||||
*/
|
||||
struct dlist *sysfs_open_directory_list(const char *path)
|
||||
{
|
||||
char sysfs_path[SYSFS_PATH_MAX], *subsys_name = NULL;
|
||||
char *c = NULL;
|
||||
struct sysfs_directory *dir = NULL, *cur = NULL;
|
||||
struct dlist *list = NULL;
|
||||
|
||||
if (name == NULL)
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
|
||||
dprintf("Error getting sysfs mount point\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
safestrcat(sysfs_path, "/");
|
||||
safestrcat(sysfs_path, name);
|
||||
dir = sysfs_open_directory(sysfs_path);
|
||||
if (dir == NULL) {
|
||||
dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((sysfs_read_dir_subdirs(dir)) != 0) {
|
||||
dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
|
||||
sysfs_close_directory(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dir->subdirs != NULL) {
|
||||
list = dlist_new_with_delete(SYSFS_NAME_LEN,
|
||||
sysfs_del_name);
|
||||
if (list == NULL) {
|
||||
dprintf("Error creating list\n");
|
||||
sysfs_close_directory(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dlist_for_each_data(dir->subdirs, cur,
|
||||
struct sysfs_directory) {
|
||||
subsys_name = (char *)calloc(1, SYSFS_NAME_LEN);
|
||||
safestrcpymax(subsys_name, cur->name, SYSFS_NAME_LEN);
|
||||
dlist_unshift_sorted(list, subsys_name, sort_char);
|
||||
}
|
||||
}
|
||||
sysfs_close_directory(dir);
|
||||
/*
|
||||
* We are now considering "block" as a "class". Hence, if the subsys
|
||||
* name requested here is "class", verify if "block" is supported on
|
||||
* this system and return the same.
|
||||
*/
|
||||
if (strcmp(name, SYSFS_CLASS_NAME) == 0) {
|
||||
c = strstr(sysfs_path, SYSFS_CLASS_NAME);
|
||||
if (c == NULL)
|
||||
goto out;
|
||||
*c = '\0';
|
||||
safestrcpymax(c, SYSFS_BLOCK_NAME,
|
||||
sizeof(sysfs_path) - strlen(sysfs_path));
|
||||
if ((sysfs_path_is_dir(sysfs_path)) == 0) {
|
||||
subsys_name = (char *)calloc(1, SYSFS_NAME_LEN);
|
||||
safestrcpymax(subsys_name, SYSFS_BLOCK_NAME,
|
||||
SYSFS_NAME_LEN);
|
||||
dlist_unshift_sorted(list, subsys_name, sort_char);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sysfs_open_bus_devices_list: gets a list of all devices on "name" bus
|
||||
* @name: name of the subsystem, eg., "pci", "scsi", "usb"
|
||||
* Returns a dlist of supported names or NULL if subsystem not supported
|
||||
*/
|
||||
struct dlist *sysfs_open_bus_devices_list(char *name)
|
||||
{
|
||||
char sysfs_path[SYSFS_PATH_MAX], *device_name = NULL;
|
||||
struct sysfs_directory *dir = NULL;
|
||||
struct sysfs_link *cur = NULL;
|
||||
struct dlist *list = NULL;
|
||||
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
|
||||
dprintf("Error getting sysfs mount point\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
safestrcat(sysfs_path, "/");
|
||||
safestrcat(sysfs_path, SYSFS_BUS_NAME);
|
||||
safestrcat(sysfs_path, "/");
|
||||
safestrcat(sysfs_path, name);
|
||||
safestrcat(sysfs_path, "/");
|
||||
safestrcat(sysfs_path, SYSFS_DEVICES_NAME);
|
||||
dir = sysfs_open_directory(sysfs_path);
|
||||
if (dir == NULL) {
|
||||
dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((sysfs_read_dir_links(dir)) != 0) {
|
||||
dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
|
||||
sysfs_close_directory(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dir->links != NULL) {
|
||||
list = dlist_new_with_delete(SYSFS_NAME_LEN,
|
||||
sysfs_del_name);
|
||||
if (list == NULL) {
|
||||
dprintf("Error creating list\n");
|
||||
sysfs_close_directory(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dlist_for_each_data(dir->links, cur,
|
||||
struct sysfs_link) {
|
||||
device_name = (char *)calloc(1, SYSFS_NAME_LEN);
|
||||
safestrcpymax(device_name, cur->name, SYSFS_NAME_LEN);
|
||||
dlist_unshift_sorted(list, device_name, sort_char);
|
||||
}
|
||||
}
|
||||
sysfs_close_directory(dir);
|
||||
return list;
|
||||
return (read_dir_subdirs(path));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -418,7 +232,7 @@ int sysfs_path_is_dir(const char *path)
|
||||
{
|
||||
struct stat astats;
|
||||
|
||||
if (path == NULL) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
@ -428,7 +242,7 @@ int sysfs_path_is_dir(const char *path)
|
||||
}
|
||||
if (S_ISDIR(astats.st_mode))
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -441,7 +255,7 @@ int sysfs_path_is_link(const char *path)
|
||||
{
|
||||
struct stat astats;
|
||||
|
||||
if (path == NULL) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
@ -451,7 +265,7 @@ int sysfs_path_is_link(const char *path)
|
||||
}
|
||||
if (S_ISLNK(astats.st_mode))
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -464,7 +278,7 @@ int sysfs_path_is_file(const char *path)
|
||||
{
|
||||
struct stat astats;
|
||||
|
||||
if (path == NULL) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
@ -474,6 +288,6 @@ int sysfs_path_is_file(const char *path)
|
||||
}
|
||||
if (S_ISREG(astats.st_mode))
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -47,10 +47,6 @@ attributes along the device chain. Useful for finding
|
||||
unique attributes to compose a rule.
|
||||
.RB Needs " \-p " specified.
|
||||
.TP
|
||||
.B \-s
|
||||
Print all sysfs devices with the major/minor number, the physical device and
|
||||
the bus value.
|
||||
.TP
|
||||
.B \-h
|
||||
Print help text.
|
||||
.SH "FILES"
|
||||
|
99
udevinfo.c
99
udevinfo.c
@ -49,26 +49,13 @@ void log_message (int level, const char *format, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int print_all_attributes(const char *path)
|
||||
static void print_all_attributes(struct dlist *attr_list)
|
||||
{
|
||||
struct dlist *attributes;
|
||||
struct sysfs_attribute *attr;
|
||||
struct sysfs_directory *sysfs_dir;
|
||||
char value[SYSFS_VALUE_SIZE];
|
||||
int len;
|
||||
int retval = 0;
|
||||
|
||||
sysfs_dir = sysfs_open_directory(path);
|
||||
if (sysfs_dir == NULL)
|
||||
return -1;
|
||||
|
||||
attributes = sysfs_get_dir_attributes(sysfs_dir);
|
||||
if (attributes == NULL) {
|
||||
retval = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dlist_for_each_data(attributes, attr, struct sysfs_attribute) {
|
||||
dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
|
||||
if (attr->value != NULL) {
|
||||
strfieldcpy(value, attr->value);
|
||||
len = strlen(value);
|
||||
@ -92,11 +79,6 @@ static int print_all_attributes(const char *path)
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
exit:
|
||||
sysfs_close_directory(sysfs_dir);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int print_record(struct udevice *udev)
|
||||
@ -123,6 +105,7 @@ static int print_device_chain(const char *path)
|
||||
struct sysfs_attribute *attr;
|
||||
struct sysfs_device *sysfs_dev;
|
||||
struct sysfs_device *sysfs_dev_parent;
|
||||
struct dlist *attr_list;
|
||||
int retval = 0;
|
||||
|
||||
/* get the class dev */
|
||||
@ -147,11 +130,14 @@ static int print_device_chain(const char *path)
|
||||
/* open sysfs class device directory and print all attributes */
|
||||
printf(" looking at class device '%s':\n", class_dev->path);
|
||||
printf(" SUBSYSTEM=\"%s\"\n", class_dev->classname);
|
||||
if (print_all_attributes(class_dev->path) != 0) {
|
||||
|
||||
attr_list = sysfs_get_classdev_attributes(class_dev);
|
||||
if (attr_list == NULL) {
|
||||
printf("couldn't open class device directory\n");
|
||||
retval = -1;
|
||||
goto exit;
|
||||
}
|
||||
print_all_attributes(attr_list);
|
||||
|
||||
/* get the device link (if parent exists look here) */
|
||||
class_dev_parent = sysfs_get_classdev_parent(class_dev);
|
||||
@ -165,13 +151,20 @@ static int print_device_chain(const char *path)
|
||||
|
||||
/* look the device chain upwards */
|
||||
while (sysfs_dev != NULL) {
|
||||
attr_list = sysfs_get_device_attributes(sysfs_dev);
|
||||
if (attr_list == NULL) {
|
||||
printf("couldn't open device directory\n");
|
||||
retval = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
|
||||
printf(" BUS=\"%s\"\n", sysfs_dev->bus);
|
||||
printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
|
||||
printf(" DRIVER=\"%s\"\n", sysfs_dev->driver_name);
|
||||
|
||||
/* open sysfs device directory and print all attributes */
|
||||
print_all_attributes(sysfs_dev->path);
|
||||
print_all_attributes(attr_list);
|
||||
|
||||
sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
|
||||
if (sysfs_dev_parent == NULL)
|
||||
@ -185,65 +178,9 @@ exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* print all class/main block devices with major/minor, physical device, driver and bus */
|
||||
static int print_sysfs_devices(void)
|
||||
{
|
||||
struct dlist *subsyslist;
|
||||
char *class;
|
||||
|
||||
subsyslist = sysfs_open_subsystem_list("class");
|
||||
if (!subsyslist)
|
||||
return -1;
|
||||
|
||||
dlist_for_each_data(subsyslist, class, char) {
|
||||
struct sysfs_class *cls;
|
||||
struct dlist *class_devices;
|
||||
struct sysfs_class_device *class_dev;
|
||||
struct sysfs_device *phys_dev;
|
||||
unsigned int major, minor;
|
||||
|
||||
cls = sysfs_open_class(class);
|
||||
if (!cls)
|
||||
continue;
|
||||
|
||||
class_devices = sysfs_get_class_devices(cls);
|
||||
if (!class_devices)
|
||||
continue;
|
||||
|
||||
dlist_for_each_data(class_devices, class_dev, struct sysfs_class_device) {
|
||||
struct sysfs_attribute *attr;
|
||||
|
||||
printf("\n");
|
||||
printf("DEVPATH '%s'\n", class_dev->path);
|
||||
printf("SUBSYSTEM '%s'\n", class_dev->classname);
|
||||
|
||||
attr = sysfs_get_classdev_attr(class_dev, "dev");
|
||||
if (attr) {
|
||||
sscanf(attr->value, "%u:%u", &major, &minor);
|
||||
printf("MAJOR %u\n", major);
|
||||
printf("MINOR %u\n", minor);
|
||||
}
|
||||
|
||||
phys_dev = sysfs_get_classdev_device(class_dev);
|
||||
if (phys_dev) {
|
||||
printf("PHYSDEVPATH '%s'\n", phys_dev->path);
|
||||
if (phys_dev->bus[0] != '\0')
|
||||
printf("PHYSDEVBUS '%s'\n", phys_dev->bus);
|
||||
|
||||
if (phys_dev->driver_name[0] != '\0')
|
||||
printf("PHYSDEVDRIVER '%s'\n", phys_dev->driver_name);
|
||||
}
|
||||
}
|
||||
sysfs_close_class(cls);
|
||||
}
|
||||
sysfs_close_list(subsyslist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_options(int argc, char *argv[])
|
||||
{
|
||||
static const char short_options[] = "an:p:q:rsVh";
|
||||
static const char short_options[] = "an:p:q:rVh";
|
||||
int option;
|
||||
int retval = 1;
|
||||
struct udevice udev;
|
||||
@ -304,10 +241,6 @@ static int process_options(int argc, char *argv[])
|
||||
root = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
print_sysfs_devices();
|
||||
exit(0);
|
||||
|
||||
case 'a':
|
||||
attributes = 1;
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user