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