chiark / gitweb /
[PATCH] minor grammer fixes for the udev_vs_devfs document
[elogind.git] / libsysfs / sysfs_utils.c
1 /*
2  * sysfs_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 #ifndef __KLIBC__
26 #include <mntent.h>
27 #endif
28
29 /**
30  * sysfs_get_mnt_path: Gets the mount point for specified filesystem.
31  * @fs_type: filesystem type to retrieve mount point
32  * @mnt_path: place to put the retrieved mount path
33  * @len: size of mnt_path
34  * returns 0 with success and -1 with error.
35  */
36 static int sysfs_get_fs_mnt_path(const unsigned char *fs_type, 
37                                 unsigned char *mnt_path, size_t len)
38 {
39 #ifdef __KLIBC__
40         strcpy(mnt_path, "/sys");
41         return 0;
42 #else
43         FILE *mnt;
44         struct mntent *mntent;
45         int ret = 0;
46         size_t dirlen = 0;
47
48         /* check arg */
49         if (fs_type == NULL || mnt_path == NULL) {
50                 errno = EINVAL;
51                 return -1;
52         }
53
54         if ((mnt = setmntent(SYSFS_PROC_MNTS, "r")) == NULL) {
55                 dprintf("Error getting mount information\n");
56                 return -1;
57         }
58         while (ret == 0 && dirlen == 0 && (mntent = getmntent(mnt)) != NULL) {
59                 if (strcmp(mntent->mnt_type, fs_type) == 0) {
60                         dirlen = strlen(mntent->mnt_dir);
61                         if (dirlen <= (len - 1)) {
62                                 strcpy(mnt_path, mntent->mnt_dir);
63                         } else {
64                                 dprintf("Error - mount path too long\n");
65                                 ret = -1;
66                         }
67                 }
68         }
69         endmntent(mnt);
70         if (dirlen == 0 && ret == 0) {
71                 dprintf("Filesystem %s not found!\n", fs_type);
72                 errno = EINVAL;
73                 ret = -1;
74         }
75         return ret;
76 #endif
77 }
78
79 /*
80  * sysfs_trailing_slash: checks if there's a trailing slash to path
81  * @path: path to check
82  * returns 1 if true and 0 if not
83  */
84 int sysfs_trailing_slash(unsigned char *path)
85 {
86         unsigned char *s = NULL;
87
88         if (path == NULL)
89                 return 0;
90         s = &path[strlen(path)-1];
91         if (strncmp(s, "/", 1) == 0)
92                 return 1;
93         return 0;
94 }
95
96 /*
97  * sysfs_get_mnt_path: Gets the sysfs mount point.
98  * @mnt_path: place to put "sysfs" mount point
99  * @len: size of mnt_path
100  * returns 0 with success and -1 with error.
101  */
102 int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len)
103 {
104         char *sysfs_path = NULL;
105         int ret = 0;
106
107         if (mnt_path == NULL) {
108                 errno = EINVAL;
109                 return -1;
110         }
111         sysfs_path = getenv(SYSFS_PATH_ENV);
112         if (sysfs_path != NULL) 
113                 strncpy(mnt_path, sysfs_path, len);
114         else
115                 ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len);
116
117         return ret;
118 }
119
120 /**
121  * sysfs_get_name_from_path: returns last name from a "/" delimited path
122  * @path: path to get name from
123  * @name: where to put name
124  * @len: size of name
125  */
126 int sysfs_get_name_from_path(const unsigned char *path, unsigned char *name, 
127                                                                 size_t len)
128 {
129         unsigned char tmp[SYSFS_PATH_MAX];
130         unsigned char *n = NULL;
131                                                                                 
132         if (path == NULL || name == NULL) {
133                 errno = EINVAL;
134                 return -1;
135         }
136         memset(tmp, 0, SYSFS_PATH_MAX);
137         strcpy(tmp, path);
138         n = strrchr(tmp, '/');
139         if (n == NULL) {
140                 errno = EINVAL;
141                 return -1;
142         }
143         if (*(n+1) == '\0') {
144                 *n = '\0';
145                 n = strrchr(tmp, '/');
146                 if (n == NULL) {
147                         errno = EINVAL;
148                         return -1;
149                 }
150         }
151         n++;
152         strncpy(name, n, len);
153         return 0;
154 }
155
156 /**
157  * sysfs_get_link: returns link source
158  * @path: symbolic link's path
159  * @target: where to put name
160  * @len: size of name
161  */
162 int sysfs_get_link(const unsigned char *path, unsigned char *target, size_t len)
163 {
164         unsigned char devdir[SYSFS_PATH_MAX];
165         unsigned char linkpath[SYSFS_PATH_MAX];
166         unsigned char *d = NULL, *s = NULL;
167         int slashes = 0, count = 0;
168
169         if (path == NULL || target == NULL) {
170                 errno = EINVAL;
171                 return -1;
172         }
173
174         memset(devdir, 0, SYSFS_PATH_MAX);
175         memset(linkpath, 0, SYSFS_PATH_MAX);
176         strncpy(devdir, path, SYSFS_PATH_MAX);
177
178         if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) {
179                 return -1;
180         }
181                                                                                 
182         d = linkpath;
183
184         /* getting rid of leading "../.." */    
185         while (*d == '/' || *d == '.') {
186                 if (*d == '/')
187                         slashes++;
188                 d++;
189         }
190
191         d--;
192
193         s = &devdir[strlen(devdir)-1];
194         while (s != NULL && count != (slashes+1)) {
195                 s--;
196                 if (*s == '/')
197                         count++;
198         }
199         
200         strncpy(s, d, (SYSFS_PATH_MAX-strlen(devdir)));
201         strncpy(target, devdir, len);
202
203         return 0;
204 }
205
206
207 /**
208  * sysfs_del_name: free function for sysfs_open_subsystem_list
209  * @name: memory area to be freed
210  */ 
211 static void sysfs_del_name(void *name)
212 {
213         free(name);
214 }
215
216
217 /**
218  * sysfs_close_list: generic list free routine
219  * @list: dlist to free
220  * Returns nothing
221  */
222 void sysfs_close_list(struct dlist *list)
223 {
224         if (list != NULL)
225                 dlist_destroy(list);
226 }
227
228 /**
229  * sysfs_open_subsystem_list: gets a list of all supported "name" subsystem
230  *      details from the system
231  * @name: name of the subsystem, eg., "bus", "class", "devices"
232  * Returns a dlist of supported names or NULL if subsystem not supported
233  */ 
234 struct dlist *sysfs_open_subsystem_list(unsigned char *name)
235 {
236         unsigned char sysfs_path[SYSFS_PATH_MAX], *subsys_name = NULL;
237         unsigned char *c = NULL;
238         struct sysfs_directory *dir = NULL, *cur = NULL;
239         struct dlist *list = NULL;
240         
241         if (name == NULL)
242                 return NULL;
243
244         if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
245                 dprintf("Error getting sysfs mount point\n");
246                 return NULL;
247         }
248         if (sysfs_trailing_slash(sysfs_path) == 0)
249                 strcat(sysfs_path, "/");
250         strcat(sysfs_path, name);
251         dir = sysfs_open_directory(sysfs_path);
252         if (dir == NULL) {
253                 dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
254                 return NULL;
255         }
256
257         if ((sysfs_read_dir_subdirs(dir)) != 0) {
258                 dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
259                 sysfs_close_directory(dir);
260                 return NULL;
261         }
262
263         if (dir->subdirs != NULL) {
264                 list = dlist_new_with_delete(SYSFS_NAME_LEN,
265                                 sysfs_del_name);
266                 if (list == NULL) {
267                         dprintf("Error creating list\n");
268                         sysfs_close_directory(dir);
269                         return NULL;
270                 }
271
272                 dlist_for_each_data(dir->subdirs, cur,
273                                 struct sysfs_directory) {
274                         subsys_name = (char *)calloc(1, SYSFS_NAME_LEN);
275                         strcpy(subsys_name, cur->name);
276                         dlist_unshift(list, subsys_name);
277                 }
278         }
279         sysfs_close_directory(dir);
280         /*
281          * We are now considering "block" as a "class". Hence, if the subsys
282          * name requested here is "class", verify if "block" is supported on
283          * this system and return the same.
284          */ 
285         if (strcmp(name, SYSFS_CLASS_NAME) == 0) {
286                 c = strstr(sysfs_path, SYSFS_CLASS_NAME);
287                 if (c == NULL)
288                         goto out;
289                 strcpy(c, SYSFS_BLOCK_NAME);
290                 if ((sysfs_path_is_dir(sysfs_path)) == 0) {
291                         subsys_name = (char *)calloc(1, SYSFS_NAME_LEN);
292                         strcpy(subsys_name, SYSFS_BLOCK_NAME);
293                         dlist_unshift(list, subsys_name);
294                 }
295         }
296 out:
297         return list;
298 }
299
300
301 /**
302  * sysfs_open_bus_devices_list: gets a list of all devices on "name" bus
303  * @name: name of the subsystem, eg., "pci", "scsi", "usb"
304  * Returns a dlist of supported names or NULL if subsystem not supported
305  */ 
306 struct dlist *sysfs_open_bus_devices_list(unsigned char *name)
307 {
308         unsigned char sysfs_path[SYSFS_PATH_MAX], *device_name = NULL;
309         struct sysfs_directory *dir = NULL;
310         struct sysfs_link *cur = NULL;
311         struct dlist *list = NULL;
312         
313         if (name == NULL)
314                 return NULL;
315
316         if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
317                 dprintf("Error getting sysfs mount point\n");
318                 return NULL;
319         }
320
321         if (sysfs_trailing_slash(sysfs_path) == 0)
322                 strcat(sysfs_path, "/");
323         strcat(sysfs_path, SYSFS_BUS_NAME);
324         strcat(sysfs_path, "/");
325         strcat(sysfs_path, name);
326         strcat(sysfs_path, "/");
327         strcat(sysfs_path, SYSFS_DEVICES_NAME);
328         dir = sysfs_open_directory(sysfs_path);
329         if (dir == NULL) {
330                 dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
331                 return NULL;
332         }
333
334         if ((sysfs_read_dir_links(dir)) != 0) {
335                 dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
336                 sysfs_close_directory(dir);
337                 return NULL;
338         }
339
340         if (dir->links != NULL) {
341                 list = dlist_new_with_delete(SYSFS_NAME_LEN,
342                                 sysfs_del_name);
343                 if (list == NULL) {
344                         dprintf("Error creating list\n");
345                         sysfs_close_directory(dir);
346                         return NULL;
347                 }
348
349                 dlist_for_each_data(dir->links, cur,
350                                 struct sysfs_link) {
351                         device_name = (char *)calloc(1, SYSFS_NAME_LEN);
352                         strcpy(device_name, cur->name);
353                         dlist_unshift(list, device_name);
354                 }
355         }
356         sysfs_close_directory(dir);
357         return list;
358 }
359
360 /**
361  * sysfs_path_is_dir: Check if the path supplied points to a directory
362  * @path: path to validate
363  * Returns 0 if path points to dir, 1 otherwise
364  */
365 int sysfs_path_is_dir(const unsigned char *path)
366 {
367         struct stat astats;
368
369         if (path == NULL) {
370                 errno = EINVAL;
371                 return 1;
372         }
373         if ((lstat(path, &astats)) != 0) {
374                 dprintf("stat() failed\n");
375                 return 1;
376         }
377         if (S_ISDIR(astats.st_mode))
378                 return 0;
379
380         return 1;
381 }
382
383 /**
384  * sysfs_path_is_link: Check if the path supplied points to a link
385  * @path: path to validate
386  * Returns 0 if path points to link, 1 otherwise
387  */
388 int sysfs_path_is_link(const unsigned char *path)
389 {
390         struct stat astats;
391
392         if (path == NULL) {
393                 errno = EINVAL;
394                 return 1;
395         }
396         if ((lstat(path, &astats)) != 0) {
397                 dprintf("stat() failed\n");
398                 return 1;
399         }
400         if (S_ISLNK(astats.st_mode))
401                 return 0;
402
403         return 1;
404 }
405
406 /**
407  * sysfs_path_is_file: Check if the path supplied points to a file
408  * @path: path to validate
409  * Returns 0 if path points to file, 1 otherwise
410  */
411 int sysfs_path_is_file(const unsigned char *path)
412 {
413         struct stat astats;
414
415         if (path == NULL) {
416                 errno = EINVAL;
417                 return 1;
418         }
419         if ((lstat(path, &astats)) != 0) {
420                 dprintf("stat() failed\n");
421                 return 1;
422         }
423         if (S_ISREG(astats.st_mode))
424                 return 0;
425
426         return 1;
427 }