chiark / gitweb /
[PATCH] big libsysfs diet (pre 2.0 version)
[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-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
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) {
38                 if (driver->devices) 
39                         dlist_destroy(driver->devices);
40                 if (driver->attrlist)
41                         dlist_destroy(driver->attrlist);
42                 free(driver);
43         }
44 }
45
46 /**
47  * alloc_driver: allocates and initializes driver
48  * returns struct sysfs_driver with success and NULL with error.
49  */
50 static struct sysfs_driver *alloc_driver(void)
51 {
52         return (struct sysfs_driver *)calloc(1, sizeof(struct sysfs_driver));
53 }
54
55 /**
56  * get_driver_bus: gets bus the driver is on
57  * Returns 0 on success and 1 on error
58  */
59 static int get_driver_bus(struct sysfs_driver *drv)
60 {
61         char drvpath[SYSFS_PATH_MAX], *c = NULL;
62         
63         if (!drv) {
64                 errno = EINVAL;
65                 return 1;
66         }
67
68         safestrcpy(drvpath, drv->path);
69         c = strstr(drvpath, SYSFS_DRIVERS_NAME);
70         if (c == NULL)
71                 return 1;
72         *--c = '\0';
73         c = strstr(drvpath, SYSFS_BUS_NAME);
74         if (c == NULL)
75                 return 1;
76         c = strstr(c, "/");
77         if (c == NULL)
78                 return 1;
79         c++;
80         safestrcpy(drv->bus, c);
81         return 0;
82 }
83
84 /**
85  * sysfs_get_driver_attr: searches drv's attributes by name
86  * @drv: driver to look through
87  * @name: attribute name to get
88  * returns sysfs_attribute reference with success or NULL with error.
89  */
90 struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
91                                                 const char *name)
92 {
93         if (!drv || !name) {
94                 errno = EINVAL;
95                 return NULL;
96         }
97         return get_attribute(drv, (char *)name);
98 }
99
100 /**
101  * sysfs_get_driver_attributes: gets list of driver attributes
102  * @dev: driver whose attributes list is needed
103  * returns dlist of attributes on success or NULL on error
104  */
105 struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *drv)
106 {
107         if (!drv) {
108                 errno = EINVAL;
109                 return NULL;
110         }
111         return get_attributes_list(drv);
112 }
113
114 /**
115  * sysfs_open_driver_path: opens and initializes driver structure
116  * @path: path to driver directory
117  * returns struct sysfs_driver with success and NULL with error
118  */
119 struct sysfs_driver *sysfs_open_driver_path(const char *path)
120 {
121         struct sysfs_driver *driver = NULL;
122
123         if (!path) {
124                 errno = EINVAL;
125                 return NULL;
126         }
127         if (sysfs_path_is_dir(path)) {
128                 dprintf("Invalid path to driver: %s\n", path);
129                 return NULL;
130         }
131         driver = alloc_driver();
132         if (!driver) {
133                 dprintf("Error allocating driver at %s\n", path);
134                 return NULL;
135         }
136         if (sysfs_get_name_from_path(path, driver->name, SYSFS_NAME_LEN)) {
137                 dprintf("Error getting driver name from path\n");
138                 free(driver);
139                 return NULL;
140         }
141         safestrcpy(driver->path, path);
142         if (sysfs_remove_trailing_slash(driver->path)) {
143                 dprintf("Invalid path to driver %s\n", driver->path);
144                 sysfs_close_driver(driver);
145                 return NULL;
146         }
147         if (get_driver_bus(driver)) {
148                 dprintf("Could not get the bus driver is on\n");
149                 sysfs_close_driver(driver);
150                 return NULL;
151         }
152
153         return driver;
154 }
155
156 /**
157  * get_driver_path: looks up the bus the driver is on and builds path to
158  *              the driver.
159  * @bus: bus on which to search
160  * @drv: driver to look for
161  * @path: buffer to return path to driver
162  * @psize: size of "path"
163  * Returns 0 on success and -1 on error
164  */
165 static int get_driver_path(const char *bus, const char *drv, 
166                         char *path, size_t psize)
167 {
168         if (!bus || !drv || !path || psize == 0) {
169                 errno = EINVAL;
170                 return -1;
171         }
172         if (sysfs_get_mnt_path(path, psize)) {
173                 dprintf("Error getting sysfs mount path\n");
174                 return -1;
175         }
176         safestrcatmax(path, "/", psize);
177         safestrcatmax(path, SYSFS_BUS_NAME, psize);
178         safestrcatmax(path, "/", psize);
179         safestrcatmax(path, bus, psize);
180         safestrcatmax(path, "/", psize);
181         safestrcatmax(path, SYSFS_DRIVERS_NAME, psize);
182         safestrcatmax(path, "/", psize);
183         safestrcatmax(path, drv, psize);
184         return 0;
185 }
186
187 /**
188  * sysfs_open_driver: open driver by name, given its bus
189  * @bus_name: Name of the bus
190  * @drv_name: Name of the driver
191  * Returns the sysfs_driver reference on success and NULL on failure
192  */
193 struct sysfs_driver *sysfs_open_driver(const char *bus_name, 
194                         const char *drv_name)
195 {
196         char path[SYSFS_PATH_MAX];
197         struct sysfs_driver *driver = NULL;
198
199         if (!drv_name || !bus_name) {
200                 errno = EINVAL;
201                 return NULL;
202         }
203
204         memset(path, 0, SYSFS_PATH_MAX);
205         if (get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) {
206                 dprintf("Error getting to driver %s\n", drv_name);
207                 return NULL;
208         }
209         driver = sysfs_open_driver_path(path);
210         if (!driver) {
211                 dprintf("Error opening driver at %s\n", path);
212                 return NULL;
213         }
214         return driver;
215 }
216
217 /**
218  * sysfs_get_driver_devices: gets list of devices that use the driver
219  * @drv: sysfs_driver whose device list is needed
220  * Returns dlist of struct sysfs_device on success and NULL on failure
221  */
222 struct dlist *sysfs_get_driver_devices(struct sysfs_driver *drv)
223 {
224         char *ln = NULL;
225         struct dlist *linklist = NULL;
226         struct sysfs_device *dev = NULL;
227
228         if (!drv) {
229                 errno = EINVAL;
230                 return NULL;
231         }
232
233         linklist = read_dir_links(drv->path);
234         if (linklist) {
235                 dlist_for_each_data(linklist, ln, char) {
236                         
237                         if (!strncmp(ln, SYSFS_MODULE_NAME, strlen(ln)))
238                                 continue;
239
240                         dev = sysfs_open_device(drv->bus, ln);
241                         if (!dev) {
242                                 dprintf("Error opening driver's device\n");
243                                 sysfs_close_list(linklist);
244                                 return NULL;
245                         }
246                         if (!drv->devices) {
247                                 drv->devices = dlist_new_with_delete
248                                         (sizeof(struct sysfs_device),
249                                          sysfs_close_driver_device);
250                                 if (!drv->devices) {
251                                         dprintf("Error creating device list\n");
252                                         sysfs_close_list(linklist);
253                                         return NULL;
254                                 }
255                         }
256                         dlist_unshift_sorted(drv->devices, dev, sort_list);
257                 }
258                 sysfs_close_list(linklist);
259         }
260         return drv->devices;
261 }