chiark / gitweb /
[PATCH] man file update
[elogind.git] / libsysfs / sysfs_device.c
1 /*
2  * sysfs_device.c
3  *
4  * Generic device 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_device: closes and cleans up a device
28  * @dev = device to clean up
29  */
30 void sysfs_close_device(struct sysfs_device *dev)
31 {
32         if (dev != NULL) {
33                 dev->next = NULL;
34                 dev->driver = NULL;
35                 if (dev->directory != NULL)
36                         sysfs_close_directory(dev->directory);
37                 dev->children = NULL;
38                 free(dev);
39         }
40 }
41
42 /**
43  * alloc_device: allocates and initializes device structure
44  * returns struct sysfs_device
45  */
46 static struct sysfs_device *alloc_device(void)
47 {
48         return (struct sysfs_device *)calloc(1, sizeof(struct sysfs_device));
49 }
50
51 /**
52  * sysfs_get_device_attr: searches dev's attributes by name
53  * @dev: device to look through
54  * @name: attribute name to get
55  * returns sysfs_attribute reference with success or NULL with error.
56  */
57 struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
58                                                 const char *name)
59 {
60         struct sysfs_attribute *cur = NULL;
61         char attrname[SYSFS_NAME_LEN];
62
63         if (dev == NULL || dev->directory == NULL || name == NULL) {
64                 errno = EINVAL;
65                 return NULL;
66         }
67         for (cur = dev->directory->attributes; cur != NULL; cur = cur->next) {
68                 if ((sysfs_get_name_from_path(cur->path, attrname, 
69                     SYSFS_NAME_LEN)) != 0) 
70                         continue;
71                 if (strcmp(name, attrname) != 0)
72                         continue;
73
74                 return cur;
75         }
76
77         return NULL;
78 }
79
80 /**
81  * sysfs_open_device: opens and populates device structure
82  * @path: path to device, this is the /sys/devices/ path
83  * returns sysfs_device structure with success or NULL with error
84  */
85 struct sysfs_device *sysfs_open_device(const char *path)
86 {
87         struct sysfs_device *dev = NULL;
88         struct sysfs_directory *sdir = NULL;
89         char *p = NULL;
90
91         if (path == NULL) {
92                 errno = EINVAL;
93                 return NULL;
94         }
95         dev = alloc_device();   
96         if (dev == NULL) {
97                 dprintf(stderr, "Error allocating device at %s\n", path);
98                 return NULL;
99         }
100         sdir = sysfs_open_directory(path);
101         if (sdir == NULL) {
102                 dprintf(stderr, "Invalid device at %s\n", path);
103                 errno = EINVAL;
104                 sysfs_close_device(dev);
105                 return NULL;
106         }
107         if ((sysfs_read_directory(sdir)) != 0) {
108                 dprintf(stderr, "Error reading device directory at %s\n", path);
109                 sysfs_close_directory(sdir);
110                 sysfs_close_device(dev);
111                 return NULL;
112         }
113         dev->directory = sdir;
114         sysfs_get_name_from_path(sdir->path, dev->bus_id, SYSFS_NAME_LEN);
115         /* get device name */
116         p = sysfs_get_value_from_attributes(sdir->attributes,   
117                                                         SYSFS_NAME_ATTRIBUTE);
118         if (p != NULL) {
119                 strncpy(dev->name, p, SYSFS_NAME_LEN);
120                 p = dev->name + strlen(dev->name) - 1;
121                 if ((strlen(dev->name) > 0) && *p == '\n')
122                         *p = '\0';
123         }
124
125         return dev;
126 }
127
128 /**
129  * sysfs_close_device_tree: closes every device in the supplied tree, 
130  *      closing children only.
131  * @devroot: device root of tree.
132  */
133 void sysfs_close_device_tree(struct sysfs_device *devroot)
134 {
135         if (devroot != NULL) {
136                 if (devroot->children != NULL) {
137                         struct sysfs_device *child = NULL, *next = NULL;
138         
139                         for (child = devroot->children; child != NULL;
140                              child = next) {
141                                 next = child->next;
142                                 sysfs_close_device_tree(child);
143                         }
144                 }
145                 sysfs_close_device(devroot);
146         }
147 }
148
149 /**
150  * add_device_child_to_parent: adds child device to parent
151  * @parent: parent device.
152  * @child: child device to add.
153  */
154 static void add_device_child_to_parent(struct sysfs_device *parent,
155                                         struct sysfs_device *child)
156 {
157         if (parent != NULL && child != NULL) {
158                 child->next = parent->children;
159                 parent->children = child;
160                 child->parent = parent;
161         }
162 }
163
164 /**
165  * sysfs_open_device_tree: opens root device and all of its children,
166  *      creating a tree of devices. Only opens children.
167  * @path: sysfs path to devices
168  * returns struct sysfs_device and its children with success or NULL with
169  *      error.
170  */
171 struct sysfs_device *sysfs_open_device_tree(const char *path)
172 {
173         struct sysfs_device *rootdev = NULL, *new = NULL;
174         struct sysfs_directory *cur = NULL;
175
176         if (path == NULL) {
177                 errno = EINVAL;
178                 return NULL;
179         }
180         rootdev = sysfs_open_device(path);
181         if (rootdev == NULL) {
182                 dprintf(stderr, "Error opening root device at %s\n", path);
183                 return NULL;
184         }
185         cur = rootdev->directory->subdirs;
186         while (cur != NULL) {
187                 new = sysfs_open_device_tree(cur->path);
188                 if (new == NULL) {
189                         dprintf(stderr, "Error opening device tree at %s\n",
190                                 cur->path);
191                         sysfs_close_device_tree(rootdev);
192                         return NULL;
193                 }
194                 add_device_child_to_parent(rootdev, new);       
195                 cur = cur->next;
196         }
197
198         return rootdev;
199 }