chiark / gitweb /
[PATCH] add IGNORE rule type
[elogind.git] / libsysfs / sysfs_driver.c
1 /*
2  * sysfs_driver.c
3  *
4  * Driver utility functions for libsysfs
5  *
6  * Copyright (C) IBM Corp. 2003
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
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  */ 
35 void sysfs_close_driver(struct sysfs_driver *driver)
36 {
37         if (driver != NULL) {
38                 if (driver->devices != NULL) 
39                         dlist_destroy(driver->devices);
40                 if (driver->directory != NULL)
41                         sysfs_close_directory(driver->directory);
42                 free(driver);
43         }
44 }
45                 
46 /**
47  * open_driver_dir: Open the sysfs_directory for this driver
48  * @driver: Driver whose directory to be opened
49  * Returns 0 on success and 1 on failure
50  */ 
51 static int open_driver_dir(struct sysfs_driver *driver)
52 {
53         if (driver == NULL) {
54                 errno = EINVAL;
55                 return 1;
56         }
57         if (driver->directory == NULL) {
58                 driver->directory = sysfs_open_directory(driver->path);
59                 if (driver->directory == NULL) {
60                         dprintf("Error opening driver directory at %s\n", 
61                                         driver->path);
62                         return 1;
63                 }
64         }
65         return 0;
66 }
67
68 /**
69  * alloc_driver: allocates and initializes driver
70  * returns struct sysfs_driver with success and NULL with error.
71  */
72 static struct sysfs_driver *alloc_driver(void)
73 {
74         return (struct sysfs_driver *)calloc(1, sizeof(struct sysfs_driver));
75 }
76
77 /**
78  * sysfs_open_driver_path: opens and initializes driver structure
79  * @path: path to driver directory
80  * returns struct sysfs_driver with success and NULL with error
81  */
82 struct sysfs_driver *sysfs_open_driver_path(const unsigned char *path)
83 {
84         struct sysfs_driver *driver = NULL;
85
86         if (path == NULL) {
87                 errno = EINVAL;
88                 return NULL;
89         }
90         if ((sysfs_path_is_dir(path)) != 0) {
91                 dprintf("Invalid path to driver: %s\n", path);
92                 return NULL;
93         }
94         driver = alloc_driver();
95         if (driver == NULL) {
96                 dprintf("Error allocating driver at %s\n", path);
97                 return NULL;
98         }
99         if ((sysfs_get_name_from_path(path, driver->name, 
100                                         SYSFS_NAME_LEN)) != 0) {
101                 dprintf("Error getting driver name from path\n");
102                 free(driver);
103                 return NULL;
104         }
105         strcpy(driver->path, path);
106         
107         return driver;
108 }
109
110 /**
111  * sysfs_get_driver_attributes: gets list of attributes for the given driver
112  * @driver: sysfs_driver for which attributes are required
113  * returns a dlist of attributes corresponding to the driver if present
114  *      NULL otherwise
115  */
116 struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver)
117 {
118         if (driver == NULL) {
119                 errno = EINVAL;
120                 return NULL;
121         }
122
123         if (driver->directory == NULL) {
124                 if ((open_driver_dir(driver)) == 1) 
125                         return NULL;
126         }
127         if (driver->directory->attributes == NULL) {
128                 if ((sysfs_read_dir_attributes(driver->directory)) != 0) {
129                         dprintf("Error reading driver attributes\n");
130                         return NULL;
131                 }
132         } else {
133                 if ((sysfs_path_is_dir(driver->path)) != 0) {
134                         dprintf("Driver at %s no longer exists\n", 
135                                                         driver->path);
136                         return NULL;
137                 }
138                 if ((sysfs_refresh_attributes
139                                 (driver->directory->attributes)) != 0) {
140                         dprintf("Error refreshing driver attributes\n");
141                         return NULL;
142                 }
143         }
144         return(driver->directory->attributes);
145 }
146
147 /**
148  * sysfs_get_driver_attr: searches driver's attributes by name
149  * @drv: driver to look through
150  * @name: attribute name to get
151  * returns sysfs_attribute reference on success or NULL with error
152  */ 
153 struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
154                                         const unsigned char *name)
155 {
156         struct sysfs_attribute *cur = NULL;
157         struct dlist *attrlist = NULL;
158
159         if (drv == NULL) {
160                 errno = EINVAL;
161                 return NULL;
162         }
163         
164         attrlist = sysfs_get_driver_attributes(drv);
165         if (attrlist != NULL) 
166                 cur = sysfs_get_directory_attribute(drv->directory,
167                                                 (unsigned char *)name);
168         return cur;
169 }
170
171 /**
172  * sysfs_get_driver_links: gets list of links from the given driver
173  * @driver: sysfs_driver for which links list is required
174  * returns a dlist of links corresponding to the driver if present
175  *      NULL otherwise
176  */
177 struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver)
178 {
179         if (driver == NULL) {
180                 errno = EINVAL;
181                 return NULL;
182         }
183         if (driver->directory == NULL) {
184                 if ((open_driver_dir(driver)) == 1)
185                         return NULL;
186                 if ((sysfs_read_dir_links(driver->directory)) != 0) 
187                         return NULL;
188         }
189         return(driver->directory->links);
190 }
191
192 /**
193  * sysfs_get_driver_devices: open up the list of devices this driver supports
194  * @driver: sysfs_driver for which devices are needed
195  * Returns dlist of devices on SUCCESS or NULL with ERROR
196  */ 
197 struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver)
198 {
199         struct sysfs_link *curlink = NULL;
200         struct sysfs_device *device = NULL;
201
202         if (driver == NULL) {
203                 errno = EINVAL;
204                 return NULL;
205         }
206         
207         if (driver->devices != NULL)
208                 return (driver->devices);
209
210         if (driver->directory == NULL) {
211                 if ((open_driver_dir(driver)) == 1) 
212                         return NULL;
213                 if ((sysfs_read_dir_links(driver->directory)) != 0) 
214                         return NULL;
215         }
216         if (driver->directory->links != NULL) {
217                 dlist_for_each_data(driver->directory->links, curlink, 
218                                                 struct sysfs_link) {
219                         device = sysfs_open_device_path(curlink->target);
220                         if (device == NULL) {
221                                 dprintf("Error opening device at %s\n", 
222                                                 curlink->target);
223                                 return NULL;
224                         }
225                         strcpy(device->driver_name, driver->name);
226                         if (driver->devices == NULL) 
227                                 driver->devices = dlist_new_with_delete
228                                                 (sizeof(struct sysfs_device),
229                                                  sysfs_close_driver_device);
230                         dlist_unshift(driver->devices, device);
231                 }
232         }
233         return (driver->devices);
234 }
235
236 /**
237  * sysfs_get_driver_device: looks up a device from a list of driver's devices
238  *      and returns its sysfs_device corresponding to it
239  * @driver: sysfs_driver on which to search
240  * @name: name of the device to search
241  * Returns a sysfs_device if found, NULL otherwise
242  */
243 struct sysfs_device *sysfs_get_driver_device(struct sysfs_driver *driver,
244                                 const unsigned char *name)
245 {
246         struct sysfs_device *device = NULL;
247         struct dlist *devlist = NULL;
248
249         if (driver == NULL || name == NULL) {
250                 errno = EINVAL;
251                 return NULL;
252         }
253
254         if (driver->devices == NULL) {
255                 devlist = sysfs_get_driver_devices(driver);
256                 if (devlist == NULL) {
257                         dprintf("Error getting driver devices\n");
258                         return NULL;
259                 }
260         }
261         dlist_for_each_data(driver->devices, device, struct sysfs_device) {
262                 if (!(strncmp(device->name, name, SYSFS_NAME_LEN)))
263                         return device;
264         }
265         return NULL;
266 }
267
268 /**
269  * get_driver_path: looks up the bus the driver is on and builds path to
270  *              the driver.
271  * @bus: bus on which to search
272  * @drv: driver to look for
273  * @path: buffer to return path to driver
274  * @psize: size of "path"
275  * Returns 0 on success and -1 on error
276  */
277 static int get_driver_path(const unsigned char *bus, 
278                 const unsigned char *drv, unsigned char *path, size_t psize)
279 {
280         if (bus == NULL || drv == NULL || path == NULL) {
281                 errno = EINVAL;
282                 return -1;
283         }
284         if (sysfs_get_mnt_path(path, psize) != 0) {
285                 dprintf("Error getting sysfs mount path\n");
286                 return -1;
287         }
288         if (sysfs_trailing_slash(path) == 0)
289                 strcat(path, "/");
290         strcat(path, SYSFS_BUS_NAME);
291         strcat(path, "/");
292         strcat(path, bus);
293         strcat(path, "/");
294         strcat(path, SYSFS_DRIVERS_NAME);
295         strcat(path, "/");
296         strcat(path, drv);
297         return 0;
298 }
299
300 /**
301  * sysfs_open_driver_attr: read the user supplied driver attribute
302  * @bus: bus on which to look 
303  * @drv: driver whose attribute has to be read
304  * @attrib: Attribute to be read
305  * Returns struct sysfs_attribute on success and NULL on failure
306  *
307  * NOTE:
308  *      A call to sysfs_close_attribute() is required to close the
309  *      attribute returned and to free memory
310  */ 
311 struct sysfs_attribute *sysfs_open_driver_attr(const unsigned char *bus, 
312                 const unsigned char *drv, const unsigned char *attrib)
313 {
314         struct sysfs_attribute *attribute = NULL;
315         unsigned char path[SYSFS_PATH_MAX];
316
317         if (bus == NULL || drv == NULL || attrib == NULL) {
318                 errno = EINVAL;
319                 return NULL;
320         }
321
322         memset(path, 0, SYSFS_PATH_MAX);
323         if ((get_driver_path(bus, drv, path, SYSFS_PATH_MAX)) != 0) {
324                 dprintf("Error getting to driver %s\n", drv);
325                 return NULL;
326         }
327         strcat(path, "/");
328         strcat(path, attrib);
329         attribute = sysfs_open_attribute(path);
330         if (attribute == NULL) {
331                 dprintf("Error opening attribute %s for driver %s\n",
332                                 attrib, drv);
333                 return NULL;
334         }
335         if ((sysfs_read_attribute(attribute)) != 0) {
336                 dprintf("Error reading attribute %s for driver %s\n", 
337                                 attrib, drv);
338                 sysfs_close_attribute(attribute);
339                 return NULL;
340         }
341         return attribute;
342 }
343
344 /**
345  * sysfs_open_driver: open driver by name, given its bus
346  * @drv_name: Name of the driver
347  * @bus_name: Name of the bus
348  * Returns the sysfs_driver reference on success and NULL on failure
349  */
350 struct sysfs_driver *sysfs_open_driver(const unsigned char *drv_name,
351                                 const unsigned char *bus_name)
352 {
353         unsigned char path[SYSFS_PATH_MAX];
354         struct sysfs_driver *driver = NULL;
355
356         if (drv_name == NULL || bus_name == NULL) {
357                 errno = EINVAL;
358                 return NULL;
359         }
360
361         memset(path, 0, SYSFS_PATH_MAX);
362         if ((get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) != 0) {
363                 dprintf("Error getting to driver %s\n", drv_name);
364                 return NULL;
365         }
366         driver = sysfs_open_driver_path(path);
367         if (driver == NULL) {
368                 dprintf("Error opening driver at %s\n", path);
369                 return NULL;
370         }
371         return driver;
372 }
373