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 */
sysfs_remove_trailing_slash(char * path)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 */
sysfs_get_mnt_path(char * mnt_path,size_t len)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 if (len == 0 || mnt_path == NULL)
58 return -1;
59
60 /* evaluate only at the first call */
61 if (sysfs_path[0] == '\0') {
62 /* possible overrride of real mount path */
63 sysfs_path_env = getenv(SYSFS_PATH_ENV);
64 if (sysfs_path_env != NULL) {
65 safestrcpymax(mnt_path, sysfs_path_env, len);
66 sysfs_remove_trailing_slash(mnt_path);
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 */
sysfs_get_name_from_path(const char * path,char * name,size_t len)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 */
sysfs_get_link(const char * path,char * target,size_t len)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 */
sysfs_close_list(struct dlist * list)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 */
sysfs_open_directory_list(const char * path)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_open_link_list: gets a list of all links under "path"
228 * @path: path to read
229 * Returns a dlist of supported links or NULL no directories (errno is set
230 * in case of error
231 */
sysfs_open_link_list(const char * path)232 struct dlist *sysfs_open_link_list(const char *path)
233 {
234 if (!path)
235 return NULL;
236
237 return (read_dir_links(path));
238 }
239
240 /**
241 * sysfs_path_is_dir: Check if the path supplied points to a directory
242 * @path: path to validate
243 * Returns 0 if path points to dir, 1 otherwise
244 */
sysfs_path_is_dir(const char * path)245 int sysfs_path_is_dir(const char *path)
246 {
247 struct stat astats;
248
249 if (!path) {
250 errno = EINVAL;
251 return 1;
252 }
253 if ((lstat(path, &astats)) != 0) {
254 dprintf("stat() failed\n");
255 return 1;
256 }
257 if (S_ISDIR(astats.st_mode))
258 return 0;
259
260 return 1;
261 }
262
263 /**
264 * sysfs_path_is_link: Check if the path supplied points to a link
265 * @path: path to validate
266 * Returns 0 if path points to link, 1 otherwise
267 */
sysfs_path_is_link(const char * path)268 int sysfs_path_is_link(const char *path)
269 {
270 struct stat astats;
271
272 if (!path) {
273 errno = EINVAL;
274 return 1;
275 }
276 if ((lstat(path, &astats)) != 0) {
277 dprintf("stat() failed\n");
278 return 1;
279 }
280 if (S_ISLNK(astats.st_mode))
281 return 0;
282
283 return 1;
284 }
285
286 /**
287 * sysfs_path_is_file: Check if the path supplied points to a file
288 * @path: path to validate
289 * Returns 0 if path points to file, 1 otherwise
290 */
sysfs_path_is_file(const char * path)291 int sysfs_path_is_file(const char *path)
292 {
293 struct stat astats;
294
295 if (!path) {
296 errno = EINVAL;
297 return 1;
298 }
299 if ((lstat(path, &astats)) != 0) {
300 dprintf("stat() failed\n");
301 return 1;
302 }
303 if (S_ISREG(astats.st_mode))
304 return 0;
305
306 return 1;
307 }
308