chiark / gitweb /
[PATCH] udev/libsysfs cross compile fixes
[elogind.git] / libsysfs / sysfs_class.c
1 /*
2  * sysfs_class.c
3  *
4  * Generic class utility functions for libsysfs
5  *
6  * Copyright (C) 2003 International Business Machines, Inc.
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 /**
27  * sysfs_close_class_device: closes a single class device.
28  * @dev: class device to close.
29  */
30 void sysfs_close_class_device(struct sysfs_class_device *dev)
31 {
32         if (dev != NULL) {
33                 if (dev->directory != NULL)
34                         sysfs_close_directory(dev->directory);
35                 if (dev->sysdevice != NULL)
36                         sysfs_close_device(dev->sysdevice);
37                 if (dev->driver != NULL)
38                         sysfs_close_driver(dev->driver);
39                 free(dev);
40         }
41 }
42
43 /**
44  * sysfs_close_class: close single class
45  * @class: class structure
46  */
47 void sysfs_close_class(struct sysfs_class *cls)
48 {
49         struct sysfs_class_device *cur = NULL, *next = NULL;
50
51         if (cls != NULL) {
52                 if (cls->directory != NULL)
53                         sysfs_close_directory(cls->directory);
54                 for (cur = cls->devices; cur != NULL; cur = next) {
55                         next = cur->next;
56                         sysfs_close_class_device(cur);
57                 }
58                 free(cls);
59         }
60 }
61
62 /**
63  * alloc_class_device: mallocs and initializes new class device struct.
64  * returns sysfs_class_device or NULL.
65  */
66 static struct sysfs_class_device *alloc_class_device(void)
67 {
68         return (struct sysfs_class_device *)
69                                 calloc(1, sizeof(struct sysfs_class_device));
70 }
71
72 /**
73  * alloc_class: mallocs new class structure
74  * returns sysfs_class struct or NULL
75  */
76 static struct sysfs_class *alloc_class(void)
77 {
78         return (struct sysfs_class *)calloc(1, sizeof(struct sysfs_class));
79 }
80
81 /**
82  * open_class_dir: opens up sysfs class directory
83  * returns sysfs_directory struct with success and NULL with error
84  */
85 static struct sysfs_directory *open_class_dir(const char *name)
86 {
87         struct sysfs_directory *classdir = NULL;
88         char classpath[SYSFS_PATH_MAX];
89
90         if (name == NULL) {
91                 errno = EINVAL;
92                 return NULL;
93         }
94
95         memset(classpath, 0, SYSFS_PATH_MAX);
96         if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) {
97                 dprintf(stderr, "Sysfs not supported on this system\n");
98                 return NULL;
99         }
100
101         strcat(classpath, SYSFS_CLASS_DIR);
102         strcat(classpath, "/");
103         strcat(classpath, name);
104         classdir = sysfs_open_directory(classpath);
105         if (classdir == NULL) {
106                 errno = EINVAL;
107                 dprintf(stderr,"Class %s not supported on this system\n",
108                         name);
109                 return NULL;
110         }
111         if ((sysfs_read_directory(classdir)) != 0) {
112                 dprintf(stderr, "Error reading %s class dir %s\n", name, 
113                         classpath);
114                 sysfs_close_directory(classdir);
115                 return NULL;
116         }
117
118         return classdir;
119 }
120
121 /**
122  * sysfs_open_class_device: Opens and populates class device
123  * @path: path to class device.
124  * returns struct sysfs_class_device with success and NULL with error.
125  */
126 struct sysfs_class_device *sysfs_open_class_device(const char *path)
127 {
128         struct sysfs_class_device *cdev = NULL;
129         struct sysfs_directory *dir = NULL, *cur = NULL;
130         struct sysfs_dlink *curl = NULL;
131         struct sysfs_device *sdev = NULL;
132         struct sysfs_driver *drv = NULL;
133         char temp[SYSFS_NAME_LEN];
134
135         if (path == NULL) {
136                 errno = EINVAL;
137                 return NULL;
138         }
139         cdev = alloc_class_device();
140         if (cdev == NULL) {
141                 perror("malloc");
142                 return NULL;
143         }
144         memset(temp, 0, SYSFS_NAME_LEN);
145         if ((sysfs_get_name_from_path(path, temp, SYSFS_NAME_LEN)) != 0) {
146                 errno = EINVAL;
147                 dprintf(stderr, "Invalid class device path %s\n", path);
148                 sysfs_close_class_device(cdev);
149                 return NULL;
150         }
151         strcpy(cdev->name, temp);
152
153         dir = sysfs_open_directory(path);
154         if (dir == NULL) {
155                 dprintf(stderr, "Error opening class device at %s\n", path);
156                 sysfs_close_class_device(cdev);
157                 return NULL;
158         }
159         if ((sysfs_read_directory(dir)) != 0) {
160                 dprintf(stderr, "Error reading class device at %s\n", path);
161                 sysfs_close_directory(dir);
162                 sysfs_close_class_device(cdev);
163                 return NULL;
164         }
165         cdev->directory = dir;
166
167         cur = cdev->directory->subdirs;
168         while(cur != NULL) {
169                 sysfs_read_directory(cur);
170                 cur = cur->next;
171         }
172         /* get driver and device, if implemented */
173         curl = cdev->directory->links;
174         while (curl != NULL) {
175                 if (strncmp(curl->name, SYSFS_DEVICES_NAME, 6) == 0) {
176                         sdev = sysfs_open_device(curl->target->path);
177                         if (sdev != NULL) {
178                                 cdev->sysdevice = sdev;
179                                 if (cdev->driver != NULL) 
180                                         sdev->driver = cdev->driver;
181                         }
182                 } else if (strncmp(curl->name, SYSFS_DRIVERS_NAME, 6) == 0) {
183                         drv = sysfs_open_driver(curl->target->path);
184                         if (drv != NULL) {
185                                 cdev->driver = drv;
186                                 if (cdev->sysdevice != NULL) 
187                                         drv->device = cdev->sysdevice;
188                         }
189                 }
190                 curl = curl->next;
191         }
192         return cdev;
193 }
194
195 /**
196  * add_dev_to_class: adds a class device to class list
197  * @class: class to add the device
198  * @dev: device to add
199  */
200 static void add_dev_to_class(struct sysfs_class *cls, 
201                                         struct sysfs_class_device *dev)
202 {
203         if (cls != NULL && dev != NULL) {
204                 dev->next = cls->devices;
205                 cls->devices = dev;
206         }
207 }
208
209 /**
210  * get_all_class_devices: gets all devices for class
211  * @class: class to get devices for
212  * returns 0 with success and -1 with failure
213  */
214 static int get_all_class_devices(struct sysfs_class *cls)
215 {
216         struct sysfs_class_device *dev = NULL;
217         struct sysfs_directory *cur = NULL, *next = NULL;
218
219         if (cls == NULL || cls->directory == NULL) {
220                 errno = EINVAL;
221                 return -1;
222         }
223         for (cur = cls->directory->subdirs; cur != NULL; cur = next) {
224                 next = cur->next;
225                 dev = sysfs_open_class_device(cur->path);
226                 if (dev == NULL) {
227                         dprintf(stderr, "Error opening device at %s\n",
228                                 cur->path);
229                         continue;
230                 }
231                 add_dev_to_class(cls, dev);
232         }
233                         
234         return 0;
235 }
236
237 /**
238  * sysfs_open_class: opens specific class and all its devices on system
239  * returns sysfs_class structure with success or NULL with error.
240  */
241 struct sysfs_class *sysfs_open_class(const char *name)
242 {
243         struct sysfs_class *cls = NULL;
244         struct sysfs_directory *classdir = NULL;
245
246         if (name == NULL) {
247                 errno = EINVAL;
248                 return NULL;
249         }
250
251         cls = alloc_class();
252         if (cls == NULL) {
253                 perror("malloc");
254                 return NULL;
255         }
256         strcpy(cls->name, name);        
257         classdir = open_class_dir(name);
258         if (classdir == NULL) {
259                 dprintf(stderr,
260                         "Invalid class, %s not supported on this system\n",
261                         name);
262                 sysfs_close_class(cls);
263                 return NULL;
264         }
265         cls->directory = classdir;
266         if ((get_all_class_devices(cls)) != 0) {
267                 dprintf(stderr, "Error reading %s class devices\n", name);
268                 sysfs_close_class(cls);
269                 return NULL;
270         }
271
272         return cls;
273 }