chiark / gitweb /
[PATCH] udev_volume_id: add Reiser4 support
[elogind.git] / libsysfs / sysfs_dir.c
1 /*
2  * sysfs_dir.c
3  *
4  * Directory 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_del_attribute: routine for dlist integration
28  */
29 static void sysfs_del_attribute(void *attr)
30 {
31         sysfs_close_attribute((struct sysfs_attribute *)attr);
32 }
33
34 /**
35  * sysfs_del_link: routine for dlist integration
36  */
37 static void sysfs_del_link(void *ln)
38 {
39         sysfs_close_link((struct sysfs_link *)ln);
40 }
41
42 /**
43  * sysfs_del_dir: routine for dlist integration
44  */
45 static void sysfs_del_directory(void *dir)
46 {
47         sysfs_close_directory((struct sysfs_directory *)dir);
48 }
49
50 /**
51  * dir_attribute_name_equal: compares dir attributes by name
52  * @a: attribute name for comparison
53  * @b: sysfs_attribute to be compared.
54  * returns 1 if a==b->name or 0 if not equal
55  */
56 static int dir_attribute_name_equal(void *a, void *b)
57 {
58         if (a == NULL || b == NULL)
59                 return 0;
60
61         if (strcmp(((char *)a), ((struct sysfs_attribute *)b)->name) == 0)
62                 return 1;
63
64         return 0;
65 }
66
67 /**
68  * dir_link_name_equal: compares dir links by name
69  * @a: link name for comparison
70  * @b: sysfs_link to be compared.
71  * returns 1 if a==b->name or 0 if not equal
72  */
73 static int dir_link_name_equal(void *a, void *b)
74 {
75         if (a == NULL || b == NULL)
76                 return 0;
77
78         if (strcmp(((char *)a), ((struct sysfs_link *)b)->name) == 0)
79                 return 1;
80
81         return 0;
82 }
83
84 /**
85  * dir_subdir_name_equal: compares subdirs by name
86  * @a: name of subdirectory to compare
87  * @b: sysfs_directory subdirectory to be compared
88  * returns 1 if a==b->name or 0 if not equal
89  */
90 static int dir_subdir_name_equal(void *a, void *b)
91 {
92         if (a == NULL || b == NULL)
93                 return 0;
94
95         if (strcmp(((char *)a), ((struct sysfs_directory *)b)->name) == 0)
96                 return 1;
97
98         return 0;
99 }
100
101 /**
102  * sysfs_close_attribute: closes and cleans up attribute
103  * @sysattr: attribute to close.
104  */
105 void sysfs_close_attribute(struct sysfs_attribute *sysattr)
106 {
107         if (sysattr != NULL) {
108                 if (sysattr->value != NULL)
109                         free(sysattr->value);
110                 free(sysattr);
111         }
112 }
113
114 /**
115  * alloc_attribute: allocates and initializes attribute structure
116  * returns struct sysfs_attribute with success and NULL with error.
117  */
118 static struct sysfs_attribute *alloc_attribute(void)
119 {
120         return (struct sysfs_attribute *)
121                         calloc(1, sizeof(struct sysfs_attribute));
122 }
123
124 /**
125  * sysfs_open_attribute: creates sysfs_attribute structure
126  * @path: path to attribute.
127  * returns sysfs_attribute struct with success and NULL with error.
128  */
129 struct sysfs_attribute *sysfs_open_attribute(const char *path)
130 {
131         struct sysfs_attribute *sysattr = NULL;
132         struct stat fileinfo;
133         
134         if (path == NULL) {
135                 errno = EINVAL;
136                 return NULL;
137         }
138         sysattr = alloc_attribute();
139         if (sysattr == NULL) {
140                 dprintf("Error allocating attribute at %s\n", path);
141                 return NULL;
142         }
143         if (sysfs_get_name_from_path(path, sysattr->name, 
144                                 SYSFS_NAME_LEN) != 0) {
145                 dprintf("Error retrieving attrib name from path: %s\n", path);
146                 sysfs_close_attribute(sysattr);
147                 return NULL;
148         }
149         safestrcpy(sysattr->path, path);
150         if ((stat(sysattr->path, &fileinfo)) != 0) {
151                 dprintf("Stat failed: No such attribute?\n");
152                 sysattr->method = 0;
153                 free(sysattr);
154                 sysattr = NULL;
155         } else {
156                 if (fileinfo.st_mode & S_IRUSR)
157                         sysattr->method |= SYSFS_METHOD_SHOW;
158                 if (fileinfo.st_mode & S_IWUSR)
159                         sysattr->method |= SYSFS_METHOD_STORE;
160         }
161
162         return sysattr;
163 }
164
165 /**
166  * sysfs_write_attribute: write value to the attribute
167  * @sysattr: attribute to write
168  * @new_value: value to write
169  * @len: length of "new_value"
170  * returns 0 with success and -1 with error.
171  */
172 int sysfs_write_attribute(struct sysfs_attribute *sysattr,
173                 const char *new_value, size_t len)
174 {
175         int fd;
176         int length;
177         
178         if (sysattr == NULL || new_value == NULL || len == 0) {
179                 errno = EINVAL;
180                 return -1;
181         }
182         
183         if (!(sysattr->method & SYSFS_METHOD_STORE)) {
184                 dprintf ("Store method not supported for attribute %s\n",
185                         sysattr->path);
186                 errno = EACCES;
187                 return -1;
188         }
189         if (sysattr->method & SYSFS_METHOD_SHOW) {
190                 /*
191                  * read attribute again to see if we can get an updated value 
192                  */
193                 if ((sysfs_read_attribute(sysattr)) != 0) {
194                         dprintf("Error reading attribute\n");
195                         return -1;
196                 }
197                 if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) {
198                         dprintf("Attr %s already has the requested value %s\n",
199                                         sysattr->name, new_value);
200                         return 0;       
201                 }
202         }
203         /* 
204          * open O_WRONLY since some attributes have no "read" but only
205          * "write" permission 
206          */ 
207         if ((fd = open(sysattr->path, O_WRONLY)) < 0) {
208                 dprintf("Error reading attribute %s\n", sysattr->path);
209                 return -1;
210         }
211
212         length = write(fd, new_value, len);
213         if (length < 0) {
214                 dprintf("Error writing to the attribute %s - invalid value?\n",
215                         sysattr->name);
216                 close(fd);
217                 return -1;
218         } else if ((unsigned int)length != len) {
219                 dprintf("Could not write %d bytes to attribute %s\n", 
220                                         len, sysattr->name);
221                 /* 
222                  * since we could not write user supplied number of bytes,
223                  * restore the old value if one available
224                  */
225                 if (sysattr->method & SYSFS_METHOD_SHOW) {
226                         length = write(fd, sysattr->value, sysattr->len);
227                         close(fd);
228                         return -1;
229                 }
230         }
231         
232         /*
233          * Validate length that has been copied. Alloc appropriate area
234          * in sysfs_attribute. Verify first if the attribute supports reading
235          * (show method). If it does not, do not bother
236          */ 
237         if (sysattr->method & SYSFS_METHOD_SHOW) {
238                 if (length != sysattr->len) {
239                         sysattr->value = (char *)realloc
240                                 (sysattr->value, length);
241                         sysattr->len = length;
242                         safestrcpymax(sysattr->value, new_value, length);
243                 } else {
244                         /*"length" of the new value is same as old one */ 
245                         safestrcpymax(sysattr->value, new_value, length);
246                 }
247         }
248                         
249         close(fd);      
250         return 0;
251 }
252
253 /**
254  * sysfs_read_attribute: reads value from attribute
255  * @sysattr: attribute to read
256  * returns 0 with success and -1 with error.
257  */
258 int sysfs_read_attribute(struct sysfs_attribute *sysattr)
259 {
260         char *fbuf = NULL;
261         char *vbuf = NULL;
262         ssize_t length = 0;
263         long pgsize = 0;
264         int fd;
265
266         if (sysattr == NULL) {
267                 errno = EINVAL;
268                 return -1;
269         }
270         if (!(sysattr->method & SYSFS_METHOD_SHOW)) {
271                 dprintf("Show method not supported for attribute %s\n",
272                         sysattr->path);
273                 errno = EACCES;
274                 return -1;
275         }
276         pgsize = sysconf(_SC_PAGESIZE);
277         fbuf = (char *)calloc(1, pgsize+1);
278         if (fbuf == NULL) {
279                 dprintf("calloc failed\n");
280                 return -1;
281         }
282         if ((fd = open(sysattr->path, O_RDONLY)) < 0) {
283                 dprintf("Error reading attribute %s\n", sysattr->path);
284                 free(fbuf);
285                 return -1;
286         }
287         length = read(fd, fbuf, pgsize);
288         if (length < 0) {
289                 dprintf("Error reading from attribute %s\n", sysattr->path);
290                 close(fd);
291                 free(fbuf);
292                 return -1;
293         }
294         if (sysattr->len > 0) {
295                 if ((sysattr->len == length) && 
296                                 (!(strncmp(sysattr->value, fbuf, length)))) {
297                         close(fd);
298                         free(fbuf);
299                         return 0;
300                 }
301                 free(sysattr->value);
302         }
303         sysattr->len = length;
304         close(fd);
305         vbuf = (char *)realloc(fbuf, length+1);
306         if (vbuf == NULL) {
307                 dprintf("realloc failed\n");
308                 free(fbuf);
309                 return -1;
310         }
311         sysattr->value = vbuf;
312
313         return 0;
314 }
315
316 /**
317  * sysfs_read_attribute_value: given path to attribute, return its value.
318  *      values can be up to a pagesize, if buffer is smaller the value will 
319  *      be truncated. 
320  * @attrpath: sysfs path to attribute
321  * @value: buffer to put value
322  * @vsize: size of value buffer
323  * returns 0 with success and -1 with error.
324  */
325 int sysfs_read_attribute_value(const char *attrpath, 
326                                         char *value, size_t vsize)
327 {
328         struct sysfs_attribute *attr = NULL;
329         size_t length = 0;
330
331         if (attrpath == NULL || value == NULL || vsize == 0) {
332                 errno = EINVAL;
333                 return -1;
334         }
335
336         attr = sysfs_open_attribute(attrpath);
337         if (attr == NULL) {
338                 dprintf("Invalid attribute path %s\n", attrpath);
339                 errno = EINVAL;
340                 return -1;
341         }
342         if((sysfs_read_attribute(attr)) != 0 || attr->value == NULL) {
343                 dprintf("Error reading from attribute %s\n", attrpath);
344                 sysfs_close_attribute(attr);
345                 return -1;
346         }
347         length = strlen(attr->value);
348         if (length > vsize) 
349                 dprintf("Value length %d is larger than supplied buffer %d\n",
350                         length, vsize);
351         safestrcpymax(value, attr->value, vsize);
352         sysfs_close_attribute(attr);
353
354         return 0;
355 }
356
357 /**
358  * sysfs_get_value_from_attrbutes: given a linked list of attributes and an 
359  *      attribute name, return its value
360  * @attr: attribute to search
361  * @name: name to look for
362  * returns char * value - could be NULL
363  */
364 char *sysfs_get_value_from_attributes(struct dlist *attr, const char *name)
365 {       
366         struct sysfs_attribute *cur = NULL;
367         
368         if (attr == NULL || name == NULL) {
369                 errno = EINVAL;
370                 return NULL;
371         }
372         dlist_for_each_data(attr, cur, struct sysfs_attribute) {
373                 if (strcmp(cur->name, name) == 0)
374                         return cur->value;
375         }
376         return NULL;
377 }
378
379 /**
380  * sysfs_close_link: closes and cleans up link.
381  * @ln: link to close.
382  */
383 void sysfs_close_link(struct sysfs_link *ln)
384 {
385         if (ln != NULL) 
386                 free(ln);
387 }
388
389 /**
390  * sysfs_close_directory: closes directory, cleans up attributes and links
391  * @sysdir: sysfs_directory to close
392  */
393 void sysfs_close_directory(struct sysfs_directory *sysdir)
394 {
395         if (sysdir != NULL) {
396                 if (sysdir->subdirs != NULL) 
397                         dlist_destroy(sysdir->subdirs);
398                 if (sysdir->links != NULL)
399                         dlist_destroy(sysdir->links);
400                 if (sysdir->attributes != NULL) 
401                         dlist_destroy(sysdir->attributes);
402                 free(sysdir);
403                 sysdir = NULL;
404         }
405 }
406
407 /**
408  * alloc_directory: allocates and initializes directory structure
409  * returns struct sysfs_directory with success or NULL with error.
410  */
411 static struct sysfs_directory *alloc_directory(void)
412 {
413         return (struct sysfs_directory *)
414                         calloc(1, sizeof(struct sysfs_directory));
415 }
416
417 /**
418  * alloc_link: allocates and initializes link structure
419  * returns struct sysfs_link with success or NULL with error.
420  */
421 static struct sysfs_link *alloc_link(void)
422 {
423         return (struct sysfs_link *)calloc(1, sizeof(struct sysfs_link));
424 }
425
426 /**
427  * sysfs_read_all_subdirs: calls sysfs_read_directory for all subdirs
428  * @sysdir: directory whose subdirs need reading.
429  * returns 0 with success and -1 with error.
430  */
431 int sysfs_read_all_subdirs(struct sysfs_directory *sysdir)
432 {
433         struct sysfs_directory *cursub = NULL;
434         int retval = 0;
435
436         if (sysdir == NULL) {
437                 errno = EINVAL;
438                 return -1;
439         }
440         if (sysdir->subdirs == NULL) 
441                 if ((sysfs_read_dir_subdirs(sysdir)) != 0) 
442                         return 0;
443         if (sysdir->subdirs != NULL) {
444                 dlist_for_each_data(sysdir->subdirs, cursub, 
445                                                 struct sysfs_directory) {
446                         if ((sysfs_read_dir_subdirs(cursub)) != 0) {
447                                 dprintf ("Error reading subdirectory %s\n",
448                                                 cursub->name);
449                                 retval = -1;
450                         }
451                 }
452         }
453         if (!retval)
454                 errno = 0;
455         return retval;
456 }
457
458 /**
459  * sysfs_open_directory: opens a sysfs directory, creates dir struct, and
460  *              returns.
461  * @path: path of directory to open.
462  * returns: struct sysfs_directory * with success and NULL on error.
463  */
464 struct sysfs_directory *sysfs_open_directory(const char *path)
465 {
466         struct sysfs_directory *sdir = NULL;
467
468         if (path == NULL) {
469                 errno = EINVAL;
470                 return NULL;
471         }
472
473         if (sysfs_path_is_dir(path) != 0) {
474                 dprintf("Invalid path to directory %s\n", path);
475                 errno = EINVAL;
476                 return NULL;
477         }
478
479         sdir = alloc_directory();
480         if (sdir == NULL) {
481                 dprintf("Error allocating directory %s\n", path);
482                 return NULL;
483         }
484         if (sysfs_get_name_from_path(path, sdir->name, SYSFS_NAME_LEN) != 0) {
485                 dprintf("Error getting directory name from path: %s\n", path);
486                 sysfs_close_directory(sdir);
487                 return NULL;
488         }
489         safestrcpy(sdir->path, path);
490
491         return sdir;
492 }
493
494 /**
495  * sysfs_open_link: opens a sysfs link, creates struct, and returns
496  * @path: path of link to open.
497  * returns: struct sysfs_link * with success and NULL on error.
498  */
499 struct sysfs_link *sysfs_open_link(const char *linkpath)
500 {
501         struct sysfs_link *ln = NULL;
502
503         if (linkpath == NULL || strlen(linkpath) > SYSFS_PATH_MAX) {
504                 errno = EINVAL;
505                 return NULL;
506         }
507
508         ln = alloc_link();
509         if (ln == NULL) {
510                 dprintf("Error allocating link %s\n", linkpath);
511                 return NULL;
512         }
513         safestrcpy(ln->path, linkpath);
514         if ((sysfs_get_name_from_path(linkpath, ln->name, SYSFS_NAME_LEN)) != 0
515             || (sysfs_get_link(linkpath, ln->target, SYSFS_PATH_MAX)) != 0) {
516                 sysfs_close_link(ln);
517                 errno = EINVAL;
518                 dprintf("Invalid link path %s\n", linkpath);
519                 return NULL;
520         }
521
522         return ln;
523 }
524
525 /**
526  * add_attribute: open and add attribute at path to given directory
527  * @sysdir: directory to add attribute to
528  * @path: path to attribute
529  * returns 0 with success and -1 with error.
530  */
531 static int add_attribute(struct sysfs_directory *sysdir, const char *path)
532 {
533         struct sysfs_attribute *attr = NULL;
534
535         attr = sysfs_open_attribute(path);
536         if (attr == NULL) {
537                 dprintf("Error opening attribute %s\n", path);
538                 return -1;
539         }
540         if (attr->method & SYSFS_METHOD_SHOW) {
541                 if ((sysfs_read_attribute(attr)) != 0) {
542                         dprintf("Error reading attribute %s\n", path);
543                         sysfs_close_attribute(attr);
544                         return 0;
545                 }
546         }
547                                                 
548         if (sysdir->attributes == NULL) {
549                 sysdir->attributes = dlist_new_with_delete
550                         (sizeof(struct sysfs_attribute), sysfs_del_attribute);
551         }
552         dlist_unshift_sorted(sysdir->attributes, attr, sort_list);
553
554         return 0;
555 }
556
557 /**
558  * add_subdirectory: open and add subdirectory at path to given directory
559  * @sysdir: directory to add subdir to
560  * @path: path to subdirectory
561  * returns 0 with success and -1 with error.
562  */
563 static int add_subdirectory(struct sysfs_directory *sysdir, const char *path)
564 {
565         struct sysfs_directory *subdir = NULL;
566
567         subdir = sysfs_open_directory(path);
568         if (subdir == NULL) {
569                 dprintf("Error opening directory %s\n", path);
570                 return -1;
571         }
572         if (sysdir->subdirs == NULL)
573                 sysdir->subdirs = dlist_new_with_delete
574                         (sizeof(struct sysfs_directory), sysfs_del_directory);
575         dlist_unshift_sorted(sysdir->subdirs, subdir, sort_list);
576         return 0;
577 }
578
579 /**
580  * add_link: open and add link at path to given directory
581  * @sysdir: directory to add link to
582  * @path: path to link
583  * returns 0 with success and -1 with error.
584  */
585 static int add_link(struct sysfs_directory *sysdir, const char *path)
586 {
587         struct sysfs_link *ln = NULL;
588
589         ln = sysfs_open_link(path);
590         if (ln == NULL) {
591                 dprintf("Error opening link %s\n", path);
592                 return -1;
593         }
594         if (sysdir->links == NULL)
595                 sysdir->links = dlist_new_with_delete
596                                 (sizeof(struct sysfs_link), sysfs_del_link);
597         dlist_unshift_sorted(sysdir->links, ln, sort_list);
598         return 0;
599 }
600
601 /**
602  * sysfs_read_dir_attributes: grabs attributes for the given directory
603  * @sysdir: sysfs directory to open
604  * returns 0 with success and -1 with error.
605  */
606 int sysfs_read_dir_attributes(struct sysfs_directory *sysdir)
607 {
608         DIR *dir = NULL;
609         struct dirent *dirent = NULL;
610         char file_path[SYSFS_PATH_MAX];
611         int retval = 0;
612
613         if (sysdir == NULL) {
614                 errno = EINVAL;
615                 return -1;
616         }
617         dir = opendir(sysdir->path);
618         if (dir == NULL) {
619                 dprintf("Error opening directory %s\n", sysdir->path);
620                 return -1;
621         }
622         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
623                 if (0 == strcmp(dirent->d_name, "."))
624                          continue;
625                 if (0 == strcmp(dirent->d_name, ".."))
626                         continue;
627                 memset(file_path, 0, SYSFS_PATH_MAX);
628                 safestrcpy(file_path, sysdir->path);
629                 safestrcat(file_path, "/");
630                 safestrcat(file_path, dirent->d_name);
631                 if ((sysfs_path_is_file(file_path)) == 0)
632                         retval = add_attribute(sysdir, file_path);
633         }
634         closedir(dir);
635         if (!retval)
636                 errno = 0;
637         return(retval);
638 }
639
640 /**
641  * sysfs_read_dir_links: grabs links in a specific directory
642  * @sysdir: sysfs directory to read links
643  * returns 0 with success and -1 with error.
644  */
645 int sysfs_read_dir_links(struct sysfs_directory *sysdir)
646 {
647         DIR *dir = NULL;
648         struct dirent *dirent = NULL;
649         char file_path[SYSFS_PATH_MAX];
650         int retval = 0;
651
652         if (sysdir == NULL) {
653                 errno = EINVAL;
654                 return -1;
655         }
656         dir = opendir(sysdir->path);
657         if (dir == NULL) {
658                 dprintf("Error opening directory %s\n", sysdir->path);
659                 return -1;
660         }
661         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
662                 if (0 == strcmp(dirent->d_name, "."))
663                          continue;
664                 if (0 == strcmp(dirent->d_name, ".."))
665                         continue;
666                 memset(file_path, 0, SYSFS_PATH_MAX);
667                 safestrcpy(file_path, sysdir->path);
668                 safestrcat(file_path, "/");
669                 safestrcat(file_path, dirent->d_name);
670                 if ((sysfs_path_is_link(file_path)) == 0) {
671                         retval = add_link(sysdir, file_path);
672                         if (retval != 0)
673                                 break;
674                 }
675         }
676         closedir(dir);
677         if (!retval)
678                 errno = 0;
679         return(retval);
680 }
681
682 /**
683  * sysfs_read_dir_subdirs: grabs subdirs in a specific directory
684  * @sysdir: sysfs directory to read links
685  * returns 0 with success and -1 with error.
686  */
687 int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir)
688 {
689         DIR *dir = NULL;
690         struct dirent *dirent = NULL;
691         char file_path[SYSFS_PATH_MAX];
692         int retval = 0;
693
694         if (sysdir == NULL) {
695                 errno = EINVAL;
696                 return -1;
697         }
698         dir = opendir(sysdir->path);
699         if (dir == NULL) {
700                 dprintf("Error opening directory %s\n", sysdir->path);
701                 return -1;
702         }
703         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
704                 if (0 == strcmp(dirent->d_name, "."))
705                          continue;
706                 if (0 == strcmp(dirent->d_name, ".."))
707                         continue;
708                 memset(file_path, 0, SYSFS_PATH_MAX);
709                 safestrcpy(file_path, sysdir->path);
710                 safestrcat(file_path, "/");
711                 safestrcat(file_path, dirent->d_name);
712                 if ((sysfs_path_is_dir(file_path)) == 0)
713                         retval = add_subdirectory(sysdir, file_path);
714         }
715         closedir(dir);
716         if (!retval)
717                 errno = 0;
718         return(retval);
719 }
720
721 /**
722  * sysfs_read_directory: grabs attributes, links, and subdirectories
723  * @sysdir: sysfs directory to open
724  * returns 0 with success and -1 with error.
725  */
726 int sysfs_read_directory(struct sysfs_directory *sysdir)
727 {
728         DIR *dir = NULL;
729         struct dirent *dirent = NULL;
730         struct stat astats;
731         char file_path[SYSFS_PATH_MAX];
732         int retval = 0;
733
734         if (sysdir == NULL) {
735                 errno = EINVAL;
736                 return -1;
737         }
738         dir = opendir(sysdir->path);
739         if (dir == NULL) {
740                 dprintf("Error opening directory %s\n", sysdir->path);
741                 return -1;
742         }
743         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
744                 if (0 == strcmp(dirent->d_name, "."))
745                          continue;
746                 if (0 == strcmp(dirent->d_name, ".."))
747                         continue;
748                 memset(file_path, 0, SYSFS_PATH_MAX);
749                 safestrcpy(file_path, sysdir->path);
750                 safestrcat(file_path, "/");
751                 safestrcat(file_path, dirent->d_name);
752                 if ((lstat(file_path, &astats)) != 0) {
753                         dprintf("stat failed\n");
754                         continue;
755                 }
756                 if (S_ISDIR(astats.st_mode)) 
757                         retval = add_subdirectory(sysdir, file_path);
758
759                 else if (S_ISLNK(astats.st_mode))
760                         retval = add_link(sysdir, file_path);
761
762                 else if (S_ISREG(astats.st_mode))
763                         retval = add_attribute(sysdir, file_path);
764         }
765         closedir(dir);
766         if (!retval)
767                 errno = 0;
768         return(retval);
769 }
770
771 /**
772  * sysfs_refresh_dir_attributes: Refresh attributes list
773  * @sysdir: directory whose list of attributes to refresh
774  * Returns 0 on success, 1 on failure
775  */
776 int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir)
777 {
778         if (sysdir == NULL) {
779                 errno = EINVAL;
780                 return 1;
781         }
782         if ((sysfs_path_is_dir(sysdir->path)) != 0) {
783                 dprintf("Invalid path to directory %s\n", sysdir->path);
784                 errno = EINVAL;
785                 return 1;
786         }
787         if (sysdir->attributes != NULL) {
788                 dlist_destroy(sysdir->attributes);
789                 sysdir->attributes = NULL;
790         }
791         if ((sysfs_read_dir_attributes(sysdir)) != 0) {
792                 dprintf("Error refreshing attributes for directory %s\n", 
793                                                         sysdir->path);
794                 return 1;
795         }
796         errno = 0;
797         return 0;
798 }
799
800 /**
801  * sysfs_refresh_dir_links: Refresh links list
802  * @sysdir: directory whose list of links to refresh
803  * Returns 0 on success, 1 on failure
804  */
805 int sysfs_refresh_dir_links(struct sysfs_directory *sysdir)
806 {
807         if (sysdir == NULL) {
808                 errno = EINVAL;
809                 return 1;
810         }
811         if ((sysfs_path_is_dir(sysdir->path)) != 0) {
812                 dprintf("Invalid path to directory %s\n", sysdir->path);
813                 errno = EINVAL;
814                 return 1;
815         }
816         if (sysdir->links != NULL) {
817                 dlist_destroy(sysdir->links);
818                 sysdir->links = NULL;
819         }
820         if ((sysfs_read_dir_links(sysdir)) != 0) {
821                 dprintf("Error refreshing links for directory %s\n", 
822                                                         sysdir->path);
823                 return 1;
824         }
825         errno = 0;
826         return 0;
827 }
828
829 /**
830  * sysfs_refresh_dir_subdirs: Refresh subdirs list
831  * @sysdir: directory whose list of subdirs to refresh
832  * Returns 0 on success, 1 on failure
833  */
834 int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir)
835 {
836         if (sysdir == NULL) {
837                 errno = EINVAL;
838                 return 1;
839         }
840         if ((sysfs_path_is_dir(sysdir->path)) != 0) {
841                 dprintf("Invalid path to directory %s\n", sysdir->path);
842                 errno = EINVAL;
843                 return 1;
844         }
845         if (sysdir->subdirs != NULL) {
846                 dlist_destroy(sysdir->subdirs);
847                 sysdir->subdirs = NULL;
848         }
849         if ((sysfs_read_dir_subdirs(sysdir)) != 0) {
850                 dprintf("Error refreshing subdirs for directory %s\n", 
851                                                         sysdir->path);
852                 return 1;
853         }
854         errno = 0;
855         return 0;
856 }
857
858 /**
859  * sysfs_get_directory_attribute: retrieves attribute attrname from current
860  *      directory only
861  * @dir: directory to retrieve attribute from
862  * @attrname: name of attribute to look for
863  *
864  * NOTE: Since we know the attribute to look for, this routine looks for the
865  *      attribute if it was created _after_ the attrlist was read initially.
866  *      
867  * returns sysfs_attribute if found and NULL if not found
868  */
869 struct sysfs_attribute *sysfs_get_directory_attribute
870                         (struct sysfs_directory *dir, char *attrname)
871 {
872         struct sysfs_attribute *attr = NULL;
873         char new_path[SYSFS_PATH_MAX];
874         
875         if (dir == NULL || attrname == NULL) {
876                 errno = EINVAL;
877                 return NULL;
878         }
879
880         if (dir->attributes == NULL) 
881                 if ((sysfs_read_dir_attributes(dir) != 0) 
882                     || (dir->attributes == NULL))
883                         return NULL;
884
885         attr = (struct sysfs_attribute *)dlist_find_custom
886                         (dir->attributes, attrname, dir_attribute_name_equal);
887         if (attr != NULL) {
888                 if ((attr->method & SYSFS_METHOD_SHOW) &&
889                         (sysfs_read_attribute(attr)) != 0) {
890                         dprintf("Error reading attribute %s\n", attr->name);
891                         return NULL;
892                 }
893         } else {
894                 memset(new_path, 0, SYSFS_PATH_MAX);
895                 safestrcpy(new_path, dir->path);
896                 safestrcat(new_path, "/");
897                 safestrcat(new_path, attrname);
898                 if ((sysfs_path_is_file(new_path)) == 0) {
899                         if ((add_attribute(dir, new_path)) == 0) {
900                                 attr = (struct sysfs_attribute *)
901                                         dlist_find_custom(dir->attributes,
902                                         attrname, dir_attribute_name_equal);
903                         }
904                 }
905         }
906                 
907         return attr;
908 }
909
910 /**
911  * sysfs_get_directory_link: retrieves link from one directory list
912  * @dir: directory to retrieve link from
913  * @linkname: name of link to look for
914  * returns reference to sysfs_link if found and NULL if not found
915  */
916 struct sysfs_link *sysfs_get_directory_link
917                         (struct sysfs_directory *dir, char *linkname)
918 {
919         if (dir == NULL || linkname == NULL) {
920                 errno = EINVAL;
921                 return NULL;
922         }
923         if (dir->links == NULL) {
924                 if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL))
925                         return NULL;
926         } else {
927                 if ((sysfs_refresh_dir_links(dir)) != 0) 
928                         return NULL;
929         }
930
931         return (struct sysfs_link *)dlist_find_custom(dir->links,
932                 linkname, dir_link_name_equal);
933 }
934
935 /**
936  * sysfs_get_subdirectory: retrieves subdirectory by name.
937  * @dir: directory to search for subdirectory.
938  * @subname: subdirectory name to get.
939  * returns reference to subdirectory or NULL if not found
940  */
941 struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir,
942                                                 char *subname)
943 {
944         struct sysfs_directory *sub = NULL, *cursub = NULL;
945
946         if (dir == NULL || subname == NULL) {
947                 errno = EINVAL;
948                 return NULL;
949         }
950
951         if (dir->subdirs == NULL)
952                 if (sysfs_read_dir_subdirs(dir) != 0)
953                         return NULL;
954
955         sub = (struct sysfs_directory *)dlist_find_custom(dir->subdirs,
956                 subname, dir_subdir_name_equal);
957         if (sub != NULL) 
958                 return sub;
959
960         if (dir->subdirs != NULL) {
961                 dlist_for_each_data(dir->subdirs, cursub, 
962                                         struct sysfs_directory) {
963                         if (cursub->subdirs == NULL) {
964                                 if (sysfs_read_dir_subdirs(cursub) != 0)
965                                         continue;
966                                 if (cursub->subdirs == NULL)
967                                         continue;
968                         }
969                         sub = sysfs_get_subdirectory(cursub, subname);
970                         if (sub != NULL)
971                                 return sub;
972                 }
973         }
974         return NULL;
975 }
976
977 /**
978  * sysfs_get_subdirectory_link: looks through all subdirs for specific link.
979  * @dir: directory and subdirectories to search for link.
980  * @linkname: link name to get.
981  * returns reference to link or NULL if not found
982  */
983 struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir,
984                                                 char *linkname)
985 {
986         struct sysfs_directory *cursub = NULL;
987         struct sysfs_link *ln = NULL;
988
989         if (dir == NULL || linkname == NULL) {
990                 errno = EINVAL;
991                 return NULL;
992         }
993
994         ln = sysfs_get_directory_link(dir, linkname);
995         if (ln != NULL)
996                 return ln;
997
998         if (dir->subdirs == NULL) 
999                 if (sysfs_read_dir_subdirs(dir) != 0)
1000                         return NULL;
1001
1002         if (dir->subdirs != NULL) {
1003                 dlist_for_each_data(dir->subdirs, cursub, 
1004                                                 struct sysfs_directory) {
1005                         ln = sysfs_get_subdirectory_link(cursub, linkname);
1006                         if (ln != NULL)
1007                                 return ln;
1008                 }
1009         }
1010         return NULL;
1011 }
1012
1013 /**
1014  * sysfs_get_dir_attributes: returns dlist of directory attributes
1015  * @dir: directory to retrieve attributes from
1016  * returns dlist of attributes or NULL
1017  */
1018 struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir)
1019 {
1020         if (dir == NULL) {
1021                 errno = EINVAL;
1022                 return NULL;
1023         }
1024
1025         if (dir->attributes == NULL) {
1026                 if (sysfs_read_dir_attributes(dir) != 0)
1027                         return NULL;
1028         }
1029
1030         return (dir->attributes);
1031 }
1032
1033 /**
1034  * sysfs_get_dir_links: returns dlist of directory links
1035  * @dir: directory to return links for
1036  * returns dlist of links or NULL
1037  */
1038 struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir)
1039 {
1040         if (dir == NULL) {
1041                 errno = EINVAL;
1042                 return NULL;
1043         }
1044
1045         if (dir->links == NULL) {
1046                 if (sysfs_read_dir_links(dir) != 0)
1047                         return NULL;
1048         }
1049
1050         return (dir->links);
1051 }
1052
1053 /**
1054  * sysfs_get_dir_subdirs: returns dlist of directory subdirectories
1055  * @dir: directory to return subdirs for
1056  * returns dlist of subdirs or NULL
1057  */
1058 struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir)
1059 {
1060         if (dir == NULL) {
1061                 errno = EINVAL;
1062                 return NULL;
1063         }
1064
1065         if (dir->subdirs == NULL) {
1066                 if (sysfs_read_dir_subdirs(dir) != 0)
1067                         return NULL;
1068         }
1069
1070         return (dir->subdirs);
1071 }