chiark / gitweb /
[PATCH] new version of libsysfs patch
[elogind.git] / libsysfs / sysfs_utils.c
1 /*
2  * syfs_utils.c
3  *
4  * System 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 /**
27  * sysfs_get_mnt_path: Gets the mount point for specified filesystem.
28  * @fs_type: filesystem type to retrieve mount point
29  * @mnt_path: place to put the retrieved mount path
30  * @len: size of mnt_path
31  * returns 0 with success and -1 with error.
32  */
33 static int sysfs_get_fs_mnt_path(const unsigned char *fs_type, 
34                                 unsigned char *mnt_path, size_t len)
35 {
36         FILE *mnt;
37         struct mntent *mntent;
38         int ret = 0;
39         size_t dirlen = 0;
40
41         /* check arg */
42         if (fs_type == NULL || mnt_path == NULL) {
43                 errno = EINVAL;
44                 return -1;
45         }
46
47         if ((mnt = setmntent(SYSFS_PROC_MNTS, "r")) == NULL) {
48                 dprintf("Error getting mount information\n");
49                 return -1;
50         }
51         while (ret == 0 && dirlen == 0 && (mntent = getmntent(mnt)) != NULL) {
52                 if (strcmp(mntent->mnt_type, fs_type) == 0) {
53                         dirlen = strlen(mntent->mnt_dir);
54                         if (dirlen <= (len - 1)) {
55                                 strcpy(mnt_path, mntent->mnt_dir);
56                         } else {
57                                 dprintf("Error - mount path too long\n");
58                                 ret = -1;
59                         }
60                 }
61         }
62         endmntent(mnt);
63         if (dirlen == 0 && ret == 0) {
64                 dprintf("Filesystem %s not found!\n", fs_type);
65                 errno = EINVAL;
66                 ret = -1;
67         }
68         return ret;
69 }
70
71 /*
72  * sysfs_get_mnt_path: Gets the sysfs mount point.
73  * @mnt_path: place to put "sysfs" mount point
74  * @len: size of mnt_path
75  * returns 0 with success and -1 with error.
76  */
77 int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len)
78 {
79         int ret = -1;
80
81         if (mnt_path != NULL)
82                 ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len);
83         else
84                 errno = EINVAL;
85
86         return ret;
87 }
88
89 /**
90  * sysfs_get_name_from_path: returns last name from a "/" delimited path
91  * @path: path to get name from
92  * @name: where to put name
93  * @len: size of name
94  */
95 int sysfs_get_name_from_path(const unsigned char *path, unsigned char *name, 
96                                                                 size_t len)
97 {
98         unsigned char *n = NULL;
99                                                                                 
100         if (path == NULL || name == NULL) {
101                 errno = EINVAL;
102                 return -1;
103         }
104         n = strrchr(path, '/');
105         if (n == NULL) {
106                 errno = EINVAL;
107                 return -1;
108         }
109         n++;
110         strncpy(name, n, len);
111
112         return 0;
113 }
114
115 /**
116  * sysfs_get_link: returns link source
117  * @path: symbolic link's path
118  * @target: where to put name
119  * @len: size of name
120  */
121 int sysfs_get_link(const unsigned char *path, unsigned char *target, size_t len)
122 {
123         unsigned char devdir[SYSFS_PATH_MAX];
124         unsigned char linkpath[SYSFS_PATH_MAX];
125         unsigned char *d = NULL;
126
127         if (path == NULL || target == NULL) {
128                 errno = EINVAL;
129                 return -1;
130         }
131
132         memset(devdir, 0, SYSFS_PATH_MAX);
133         memset(linkpath, 0, SYSFS_PATH_MAX);
134
135         if ((sysfs_get_mnt_path(devdir, SYSFS_PATH_MAX)) != 0) {
136                 dprintf("Sysfs not supported on this system\n");
137                 return -1;
138         }
139                                                                         
140         if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) {
141                 return -1;
142         }
143                                                                                 
144         d = linkpath;
145
146         /* getting rid of leading "../.." */    
147         while (*d == '/' || *d == '.')
148                 d++;
149
150         d--;
151         
152         strcat(devdir, d);
153         strncpy(target, devdir, len);
154
155         return 0;
156 }
157
158
159 /**
160  * sysfs_del_name: free function for sysfs_open_subsystem_list
161  * @name: memory area to be freed
162  */ 
163 void sysfs_del_name(void *name)
164 {
165         free(name);
166 }
167
168
169 /**
170  * sysfs_close_list: generic list free routine
171  * @list: dlist to free
172  * Returns nothing
173  */
174 void sysfs_close_list(struct dlist *list)
175 {
176         if (list != NULL)
177                 dlist_destroy(list);
178 }
179
180 /**
181  * sysfs_open_subsystem_list: gets a list of all supported "name" subsystem
182  *      details from the system
183  * @name: name of the subsystem, eg., "bus", "class", "devices"
184  * Returns a dlist of supported names or NULL if subsystem not supported
185  */ 
186 struct dlist *sysfs_open_subsystem_list(unsigned char *name)
187 {
188         unsigned char sysfs_path[SYSFS_PATH_MAX], *subsys_name = NULL;
189         struct sysfs_directory *dir = NULL, *cur = NULL;
190         struct dlist *list = NULL;
191         
192         if (name == NULL)
193                 return NULL;
194
195         if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
196                 dprintf("Error getting sysfs mount point\n");
197                 return NULL;
198         }
199
200         strcat(sysfs_path, name);
201         dir = sysfs_open_directory(sysfs_path);
202         if (dir == NULL) {
203                 dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
204                 return NULL;
205         }
206
207         if (sysfs_read_directory(dir) != 0) {
208                 dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
209                 sysfs_close_directory(dir);
210                 return NULL;
211         }
212
213         if (dir->subdirs != NULL) {
214                 list = dlist_new_with_delete(SYSFS_NAME_LEN,
215                                 sysfs_del_name);
216                 if (list == NULL) {
217                         dprintf("Error creating list\n");
218                         sysfs_close_directory(dir);
219                         return NULL;
220                 }
221
222                 dlist_for_each_data(dir->subdirs, cur,
223                                 struct sysfs_directory) {
224                         subsys_name = (char *)calloc(1, SYSFS_NAME_LEN);
225                         strcpy(subsys_name, cur->name);
226                         dlist_unshift(list, subsys_name);
227                 }
228         }
229         sysfs_close_directory(dir);
230         return list;
231 }
232
233
234 /**
235  * sysfs_open_bus_devices_list: gets a list of all devices on "name" bus
236  * @name: name of the subsystem, eg., "pci", "scsi", "usb"
237  * Returns a dlist of supported names or NULL if subsystem not supported
238  */ 
239 struct dlist *sysfs_open_bus_devices_list(unsigned char *name)
240 {
241         unsigned char sysfs_path[SYSFS_PATH_MAX], *device_name = NULL;
242         struct sysfs_directory *dir = NULL;
243         struct sysfs_link *cur = NULL;
244         struct dlist *list = NULL;
245         
246         if (name == NULL)
247                 return NULL;
248
249         if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
250                 dprintf("Error getting sysfs mount point\n");
251                 return NULL;
252         }
253
254         strcat(sysfs_path, SYSFS_BUS_DIR);
255         strcat(sysfs_path, "/");
256         strcat(sysfs_path, name);
257         strcat(sysfs_path, SYSFS_DEVICES_DIR);
258         dir = sysfs_open_directory(sysfs_path);
259         if (dir == NULL) {
260                 dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
261                 return NULL;
262         }
263
264         if (sysfs_read_directory(dir) != 0) {
265                 dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
266                 sysfs_close_directory(dir);
267                 return NULL;
268         }
269
270         if (dir->links != NULL) {
271                 list = dlist_new_with_delete(SYSFS_NAME_LEN,
272                                 sysfs_del_name);
273                 if (list == NULL) {
274                         dprintf("Error creating list\n");
275                         sysfs_close_directory(dir);
276                         return NULL;
277                 }
278
279                 dlist_for_each_data(dir->links, cur,
280                                 struct sysfs_link) {
281                         device_name = (char *)calloc(1, SYSFS_NAME_LEN);
282                         strcpy(device_name, cur->name);
283                         dlist_unshift(list, device_name);
284                 }
285         }
286         sysfs_close_directory(dir);
287         return list;
288 }
289