chiark / gitweb /
udevcontrol: add max_childs command
[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-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 /**
27  * sysfs_remove_trailing_slash: Removes any trailing '/' in the given path
28  * @path: Path to look for the trailing '/'
29  * Returns 0 on success 1 on error
30  */ 
31 int sysfs_remove_trailing_slash(char *path)
32 {
33         size_t len;
34
35         if (!path) {
36                 errno = EINVAL;
37                 return 1;
38         }
39
40         len = strlen(path);
41         while (len > 0 && path[len-1] == '/')
42                 path[--len] = '\0';
43         return 0;
44 }
45
46 /*
47  * sysfs_get_mnt_path: Gets the sysfs mount point.
48  * @mnt_path: place to put "sysfs" mount point
49  * @len: size of mnt_path
50  * returns 0 with success and -1 with error.
51  */
52 int sysfs_get_mnt_path(char *mnt_path, size_t len)
53 {
54         static char sysfs_path[SYSFS_PATH_MAX] = "";
55         const char *sysfs_path_env;
56
57         /* evaluate only at the first call */
58         if (sysfs_path[0] == '\0') {
59                 /* possible overrride of real mount path */
60                 sysfs_path_env = getenv(SYSFS_PATH_ENV);
61                 if (sysfs_path_env != NULL) {
62                         safestrcpymax(mnt_path, sysfs_path_env, len);
63                         sysfs_remove_trailing_slash(mnt_path);
64                         return 0;
65                 }
66                 safestrcpymax(mnt_path, SYSFS_MNT_PATH, len);
67         }
68
69         return 0;
70 }
71
72 /**
73  * sysfs_get_name_from_path: returns last name from a "/" delimited path
74  * @path: path to get name from
75  * @name: where to put name
76  * @len: size of name
77  */
78 int sysfs_get_name_from_path(const char *path, char *name, size_t len)
79 {
80         char tmp[SYSFS_PATH_MAX];
81         char *n = NULL;
82
83         if (!path || !name || len == 0) {
84                 errno = EINVAL;
85                 return -1;
86         }
87         memset(tmp, 0, SYSFS_PATH_MAX);
88         safestrcpy(tmp, path);
89         n = strrchr(tmp, '/');
90         if (n == NULL) {
91                 errno = EINVAL;
92                 return -1;
93         }
94         if (*(n+1) == '\0') {
95                 *n = '\0';
96                 n = strrchr(tmp, '/');
97                 if (n == NULL) {
98                         errno = EINVAL;
99                         return -1;
100                 }
101         }
102         n++;
103         safestrcpymax(name, n, len);
104         return 0;
105 }
106
107 /**
108  * sysfs_get_link: returns link source
109  * @path: symbolic link's path
110  * @target: where to put name
111  * @len: size of name
112  */
113 int sysfs_get_link(const char *path, char *target, size_t len)
114 {
115         char devdir[SYSFS_PATH_MAX];
116         char linkpath[SYSFS_PATH_MAX];
117         char temp_path[SYSFS_PATH_MAX];
118         char *d = NULL, *s = NULL;
119         int slashes = 0, count = 0;
120
121         if (!path || !target || len == 0) {
122                 errno = EINVAL;
123                 return -1;
124         }
125
126         memset(devdir, 0, SYSFS_PATH_MAX);
127         memset(linkpath, 0, SYSFS_PATH_MAX);
128         memset(temp_path, 0, SYSFS_PATH_MAX);
129         safestrcpy(devdir, path);
130
131         if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) {
132                 return -1;
133         }
134         d = linkpath;
135         /*
136          * Three cases here:
137          * 1. relative path => format ../..
138          * 2. absolute path => format /abcd/efgh
139          * 3. relative path _from_ this dir => format abcd/efgh
140          */
141         switch (*d) {
142                 case '.': 
143                         /*
144                          * handle the case where link is of type ./abcd/xxx
145                          */
146                         safestrcpy(temp_path, devdir);
147                         if (*(d+1) == '/')
148                                 d += 2;
149                         else if (*(d+1) == '.')
150                                 goto parse_path;
151                         s = strrchr(temp_path, '/');
152                         if (s != NULL) {
153                                 *(s+1) = '\0';
154                                 safestrcat(temp_path, d);
155                         } else {
156                                 safestrcpy(temp_path, d);
157                         }
158                         safestrcpymax(target, temp_path, len);
159                         break;
160                         /*
161                          * relative path, getting rid of leading "../.."
162                          */
163 parse_path:
164                         while (*d == '/' || *d == '.') {
165                                 if (*d == '/')
166                                         slashes++;
167                                 d++;
168                         }
169                         d--;
170                         s = &devdir[strlen(devdir)-1];
171                         while (s != NULL && count != (slashes+1)) {
172                                 s--;
173                                 if (*s == '/')
174                                         count++;
175                         }
176                         safestrcpymax(s, d, (SYSFS_PATH_MAX-strlen(devdir)));
177                         safestrcpymax(target, devdir, len);
178                         break;
179                 case '/':
180                         /* absolute path - copy as is */
181                         safestrcpymax(target, linkpath, len);
182                         break;
183                 default:
184                         /* relative path from this directory */
185                         safestrcpy(temp_path, devdir);
186                         s = strrchr(temp_path, '/');
187                         if (s != NULL) {
188                                 *(s+1) = '\0';
189                                 safestrcat(temp_path, linkpath);
190                         } else {
191                                 safestrcpy(temp_path, linkpath);
192                         }
193                         safestrcpymax(target, temp_path, len);
194         }
195         return 0;
196 }
197
198 /**
199  * sysfs_close_list: generic list free routine
200  * @list: dlist to free
201  * Returns nothing
202  */
203 void sysfs_close_list(struct dlist *list)
204 {
205         if (list)
206                 dlist_destroy(list);
207 }
208
209 /**
210  * sysfs_open_directory_list: gets a list of all directories under "path"
211  * @path: path to read
212  * Returns a dlist of supported names or NULL no directories (errno is set
213  *      in case of error
214  */
215 struct dlist *sysfs_open_directory_list(const char *path)
216 {
217         if (!path)
218                 return NULL;
219
220         return (read_dir_subdirs(path));
221 }
222
223 /**
224  * sysfs_path_is_dir: Check if the path supplied points to a directory
225  * @path: path to validate
226  * Returns 0 if path points to dir, 1 otherwise
227  */
228 int sysfs_path_is_dir(const char *path)
229 {
230         struct stat astats;
231
232         if (!path) {
233                 errno = EINVAL;
234                 return 1;
235         }
236         if ((lstat(path, &astats)) != 0) {
237                 dprintf("stat() failed\n");
238                 return 1;
239         }
240         if (S_ISDIR(astats.st_mode))
241                 return 0;
242
243         return 1;
244 }
245
246 /**
247  * sysfs_path_is_link: Check if the path supplied points to a link
248  * @path: path to validate
249  * Returns 0 if path points to link, 1 otherwise
250  */
251 int sysfs_path_is_link(const char *path)
252 {
253         struct stat astats;
254
255         if (!path) {
256                 errno = EINVAL;
257                 return 1;
258         }
259         if ((lstat(path, &astats)) != 0) {
260                 dprintf("stat() failed\n");
261                 return 1;
262         }
263         if (S_ISLNK(astats.st_mode))
264                 return 0;
265
266         return 1;
267 }
268
269 /**
270  * sysfs_path_is_file: Check if the path supplied points to a file
271  * @path: path to validate
272  * Returns 0 if path points to file, 1 otherwise
273  */
274 int sysfs_path_is_file(const char *path)
275 {
276         struct stat astats;
277
278         if (!path) {
279                 errno = EINVAL;
280                 return 1;
281         }
282         if ((lstat(path, &astats)) != 0) {
283                 dprintf("stat() failed\n");
284                 return 1;
285         }
286         if (S_ISREG(astats.st_mode))
287                 return 0;
288
289         return 1;
290 }