1 /*
2 * sysfs_driver.c
3 *
4 * Driver utility functions for libsysfs
5 *
6 * Copyright (C) IBM Corp. 2003-2005
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23 #include "libsysfs.h"
24 #include "sysfs.h"
25
sysfs_close_driver_device(void * device)26 static void sysfs_close_driver_device(void *device)
27 {
28 sysfs_close_device((struct sysfs_device *)device);
29 }
30
31 /**
32 * sysfs_close_driver: closes driver and deletes device lists too
33 * @driver: driver to close
34 */
sysfs_close_driver(struct sysfs_driver * driver)35 void sysfs_close_driver(struct sysfs_driver *driver)
36 {
37 if (driver) {
38 if (driver->devices)
39 dlist_destroy(driver->devices);
40 if (driver->attrlist)
41 dlist_destroy(driver->attrlist);
42 if (driver->module)
43 sysfs_close_module(driver->module);
44 free(driver);
45 }
46 }
47
48 /**
49 * alloc_driver: allocates and initializes driver
50 * returns struct sysfs_driver with success and NULL with error.
51 */
alloc_driver(void)52 static struct sysfs_driver *alloc_driver(void)
53 {
54 return (struct sysfs_driver *)calloc(1, sizeof(struct sysfs_driver));
55 }
56
57 /**
58 * get_driver_bus: gets bus the driver is on
59 * Returns 0 on success and 1 on error
60 */
get_driver_bus(struct sysfs_driver * drv)61 static int get_driver_bus(struct sysfs_driver *drv)
62 {
63 char drvpath[SYSFS_PATH_MAX], *c = NULL;
64
65 if (!drv) {
66 errno = EINVAL;
67 return 1;
68 }
69
70 safestrcpy(drvpath, drv->path);
71 c = strstr(drvpath, SYSFS_DRIVERS_NAME);
72 if (c == NULL)
73 return 1;
74 *--c = '\0';
75 c = strstr(drvpath, SYSFS_BUS_NAME);
76 if (c == NULL)
77 return 1;
78 c = strstr(c, "/");
79 if (c == NULL)
80 return 1;
81 c++;
82 safestrcpy(drv->bus, c);
83 return 0;
84 }
85
86 /**
87 * sysfs_get_driver_attr: searches drv's attributes by name
88 * @drv: driver to look through
89 * @name: attribute name to get
90 * returns sysfs_attribute reference with success or NULL with error.
91 */
sysfs_get_driver_attr(struct sysfs_driver * drv,const char * name)92 struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
93 const char *name)
94 {
95 if (!drv || !name) {
96 errno = EINVAL;
97 return NULL;
98 }
99 return get_attribute(drv, (char *)name);
100 }
101
102 /**
103 * sysfs_get_driver_attributes: gets list of driver attributes
104 * @dev: driver whose attributes list is needed
105 * returns dlist of attributes on success or NULL on error
106 */
sysfs_get_driver_attributes(struct sysfs_driver * drv)107 struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *drv)
108 {
109 if (!drv) {
110 errno = EINVAL;
111 return NULL;
112 }
113 return get_dev_attributes_list(drv);
114 }
115
116 /**
117 * sysfs_open_driver_path: opens and initializes driver structure
118 * @path: path to driver directory
119 * returns struct sysfs_driver with success and NULL with error
120 */
sysfs_open_driver_path(const char * path)121 struct sysfs_driver *sysfs_open_driver_path(const char *path)
122 {
123 struct sysfs_driver *driver = NULL;
124
125 if (!path) {
126 errno = EINVAL;
127 return NULL;
128 }
129 if (sysfs_path_is_dir(path)) {
130 dprintf("Invalid path to driver: %s\n", path);
131 return NULL;
132 }
133 driver = alloc_driver();
134 if (!driver) {
135 dprintf("Error allocating driver at %s\n", path);
136 return NULL;
137 }
138 if (sysfs_get_name_from_path(path, driver->name, SYSFS_NAME_LEN)) {
139 dprintf("Error getting driver name from path\n");
140 free(driver);
141 return NULL;
142 }
143 safestrcpy(driver->path, path);
144 if (sysfs_remove_trailing_slash(driver->path)) {
145 dprintf("Invalid path to driver %s\n", driver->path);
146 sysfs_close_driver(driver);
147 return NULL;
148 }
149 if (get_driver_bus(driver)) {
150 dprintf("Could not get the bus driver is on\n");
151 sysfs_close_driver(driver);
152 return NULL;
153 }
154
155 return driver;
156 }
157
158 /**
159 * get_driver_path: looks up the bus the driver is on and builds path to
160 * the driver.
161 * @bus: bus on which to search
162 * @drv: driver to look for
163 * @path: buffer to return path to driver
164 * @psize: size of "path"
165 * Returns 0 on success and -1 on error
166 */
get_driver_path(const char * bus,const char * drv,char * path,size_t psize)167 static int get_driver_path(const char *bus, const char *drv,
168 char *path, size_t psize)
169 {
170 if (!bus || !drv || !path || psize == 0) {
171 errno = EINVAL;
172 return -1;
173 }
174 if (sysfs_get_mnt_path(path, psize)) {
175 dprintf("Error getting sysfs mount path\n");
176 return -1;
177 }
178 safestrcatmax(path, "/", psize);
179 safestrcatmax(path, SYSFS_BUS_NAME, psize);
180 safestrcatmax(path, "/", psize);
181 safestrcatmax(path, bus, psize);
182 safestrcatmax(path, "/", psize);
183 safestrcatmax(path, SYSFS_DRIVERS_NAME, psize);
184 safestrcatmax(path, "/", psize);
185 safestrcatmax(path, drv, psize);
186 return 0;
187 }
188
189 /**
190 * sysfs_open_driver: open driver by name, given its bus
191 * @bus_name: Name of the bus
192 * @drv_name: Name of the driver
193 * Returns the sysfs_driver reference on success and NULL on failure
194 */
sysfs_open_driver(const char * bus_name,const char * drv_name)195 struct sysfs_driver *sysfs_open_driver(const char *bus_name,
196 const char *drv_name)
197 {
198 char path[SYSFS_PATH_MAX];
199 struct sysfs_driver *driver = NULL;
200
201 if (!drv_name || !bus_name) {
202 errno = EINVAL;
203 return NULL;
204 }
205
206 memset(path, 0, SYSFS_PATH_MAX);
207 if (get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) {
208 dprintf("Error getting to driver %s\n", drv_name);
209 return NULL;
210 }
211 driver = sysfs_open_driver_path(path);
212 if (!driver) {
213 dprintf("Error opening driver at %s\n", path);
214 return NULL;
215 }
216 return driver;
217 }
218
219 /**
220 * sysfs_get_driver_devices: gets list of devices that use the driver
221 * @drv: sysfs_driver whose device list is needed
222 * Returns dlist of struct sysfs_device on success and NULL on failure
223 */
sysfs_get_driver_devices(struct sysfs_driver * drv)224 struct dlist *sysfs_get_driver_devices(struct sysfs_driver *drv)
225 {
226 char *ln = NULL;
227 struct dlist *linklist = NULL;
228 struct sysfs_device *dev = NULL;
229
230 if (!drv) {
231 errno = EINVAL;
232 return NULL;
233 }
234
235 linklist = read_dir_links(drv->path);
236 if (linklist) {
237 dlist_for_each_data(linklist, ln, char) {
238
239 if (!strncmp(ln, SYSFS_MODULE_NAME, strlen(ln)))
240 continue;
241
242 dev = sysfs_open_device(drv->bus, ln);
243 if (!dev) {
244 dprintf("Error opening driver's device\n");
245 sysfs_close_list(linklist);
246 return NULL;
247 }
248 if (!drv->devices) {
249 drv->devices = dlist_new_with_delete
250 (sizeof(struct sysfs_device),
251 sysfs_close_driver_device);
252 if (!drv->devices) {
253 dprintf("Error creating device list\n");
254 sysfs_close_list(linklist);
255 return NULL;
256 }
257 }
258 dlist_unshift_sorted(drv->devices, dev, sort_list);
259 }
260 sysfs_close_list(linklist);
261 }
262 return drv->devices;
263 }
264
265 /**
266 * sysfs_get_driver_module: gets the module being used by this driver
267 * @drv: sysfs_driver whose "module" is needed
268 * Returns sysfs_module on success and NULL on failure
269 */
sysfs_get_driver_module(struct sysfs_driver * drv)270 struct sysfs_module *sysfs_get_driver_module(struct sysfs_driver *drv)
271 {
272 char path[SYSFS_PATH_MAX], mod_path[SYSFS_PATH_MAX];
273
274 if (!drv) {
275 errno = EINVAL;
276 return NULL;
277 }
278
279 memset(path, 0, SYSFS_PATH_MAX);
280 safestrcpy(path, drv->path);
281 safestrcat(path, "/");
282 safestrcat(path, SYSFS_MODULE_NAME);
283 if (!sysfs_path_is_link(path)) {
284 memset(mod_path, 0, SYSFS_PATH_MAX);
285 if (!sysfs_get_link(path, mod_path, SYSFS_PATH_MAX))
286 drv->module = sysfs_open_module_path(mod_path);
287 }
288 return drv->module;
289 }
290