chiark / gitweb /
[PATCH] udevsend now almost compiles with klibc, struct sockaddr_un is only problem...
[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(((unsigned char *)a), ((struct sysfs_attribute *)b)->name) 
62             == 0)
63                 return 1;
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(((unsigned char *)a), ((struct sysfs_link *)b)->name) 
79             == 0)
80                 return 1;
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(((unsigned char *)a), ((struct sysfs_directory *)b)->name)
96             == 0)
97                 return 1;
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 unsigned 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, SYSFS_NAME_LEN) 
144             != 0) {
145                 dprintf("Error retrieving attribute name from path: %s\n", 
146                         path);
147                 sysfs_close_attribute(sysattr);
148                 return NULL;
149         }
150         strncpy(sysattr->path, path, SYSFS_PATH_MAX);
151         if ((stat(sysattr->path, &fileinfo)) != 0) {
152                 dprintf("Stat failed: No such attribute?\n");
153                 sysattr->method = 0;
154                 free(sysattr);
155                 sysattr = NULL;
156         } else {
157                 if (fileinfo.st_mode & S_IRUSR)
158                         sysattr->method |= SYSFS_METHOD_SHOW;
159                 if (fileinfo.st_mode & S_IWUSR)
160                         sysattr->method |= SYSFS_METHOD_STORE;
161         }
162
163         return sysattr;
164 }
165
166 /**
167  * sysfs_write_attribute: write value to the attribute
168  * @sysattr: attribute to write
169  * @new_value: value to write
170  * @len: length of "new_value"
171  * returns 0 with success and -1 with error.
172  */
173 int sysfs_write_attribute(struct sysfs_attribute *sysattr,
174                 const unsigned char *new_value, size_t len)
175 {
176         int fd;
177         int length;
178         
179         if (sysattr == NULL || new_value == NULL || len == 0) {
180                 errno = EINVAL;
181                 return -1;
182         }
183         
184         if (!(sysattr->method & SYSFS_METHOD_STORE)) {
185                 dprintf ("Store method not supported for attribute %s\n",
186                         sysattr->path);
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 (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(sysattr->value, 
240                                                                 length);
241                         sysattr->len = length;
242                         strncpy(sysattr->value, new_value, length);
243                 } else {
244                         /*"length" of the new value is same as old one */ 
245                         strncpy(sysattr->value, new_value, length);
246                 }
247         }
248                         
249         close(fd);      
250         return 0;
251 }
252
253
254 /**
255  * sysfs_read_attribute: reads value from attribute
256  * @sysattr: attribute to read
257  * returns 0 with success and -1 with error.
258  */
259 int sysfs_read_attribute(struct sysfs_attribute *sysattr)
260 {
261         unsigned char *fbuf = NULL;
262         unsigned char *vbuf = NULL;
263         ssize_t length = 0;
264         long pgsize = 0;
265         int fd;
266
267         if (sysattr == NULL) {
268                 errno = EINVAL;
269                 return -1;
270         }
271         if (!(sysattr->method & SYSFS_METHOD_SHOW)) {
272                 dprintf("Show method not supported for attribute %s\n",
273                         sysattr->path);
274                 return -1;
275         }
276
277         pgsize = getpagesize();
278         fbuf = (unsigned char *)calloc(1, pgsize+1);
279         if (fbuf == NULL) {
280                 dprintf("calloc failed\n");
281                 return -1;
282         }
283         if ((fd = open(sysattr->path, O_RDONLY)) < 0) {
284                 dprintf("Error reading attribute %s\n", sysattr->path);
285                 free(fbuf);
286                 return -1;
287         }
288         length = read(fd, fbuf, pgsize);
289         if (length < 0) {
290                 dprintf("Error reading from attribute %s\n", sysattr->path);
291                 close(fd);
292                 free(fbuf);
293                 return -1;
294         }
295         if (sysattr->len > 0) {
296                 if ((sysattr->len == length) && 
297                                 (!(strncmp(sysattr->value, fbuf, length)))) {
298                         close(fd);
299                         return 0;
300                 }
301                 free(sysattr->value);
302         }
303         sysattr->len = length;
304         close(fd);
305         vbuf = (unsigned 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 unsigned char *attrpath, 
326                                         unsigned char *value, size_t vsize)
327 {
328         struct sysfs_attribute *attr = NULL;
329         size_t length = 0;
330
331         if (attrpath == NULL || value == NULL) {
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         strncpy(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 unsigned char * value - could be NULL
363  */
364 unsigned char *sysfs_get_value_from_attributes(struct dlist *attr, 
365                                         const unsigned char *name)
366 {       
367         struct sysfs_attribute *cur = NULL;
368         
369         if (attr == NULL || name == NULL) {
370                 errno = EINVAL;
371                 return NULL;
372         }
373         dlist_for_each_data(attr, cur, struct sysfs_attribute) {
374                 if (strcmp(cur->name, name) == 0)
375                         return cur->value;
376         }
377         return NULL;
378 }
379
380 /**
381  * sysfs_close_link: closes and cleans up link.
382  * @ln: link to close.
383  */
384 void sysfs_close_link(struct sysfs_link *ln)
385 {
386         if (ln != NULL) 
387                 free(ln);
388 }
389
390 /**
391  * sysfs_close_directory: closes directory, cleans up attributes and links
392  * @sysdir: sysfs_directory to close
393  */
394 void sysfs_close_directory(struct sysfs_directory *sysdir)
395 {
396         if (sysdir != NULL) {
397                 if (sysdir->subdirs != NULL) 
398                         dlist_destroy(sysdir->subdirs);
399                 if (sysdir->links != NULL)
400                         dlist_destroy(sysdir->links);
401                 if (sysdir->attributes != NULL) 
402                         dlist_destroy(sysdir->attributes);
403                 free(sysdir);
404                 sysdir = NULL;
405         }
406 }
407
408 /**
409  * alloc_directory: allocates and initializes directory structure
410  * returns struct sysfs_directory with success or NULL with error.
411  */
412 static struct sysfs_directory *alloc_directory(void)
413 {
414         return (struct sysfs_directory *)
415                         calloc(1, sizeof(struct sysfs_directory));
416 }
417
418 /**
419  * alloc_link: allocates and initializes link structure
420  * returns struct sysfs_link with success or NULL with error.
421  */
422 static struct sysfs_link *alloc_link(void)
423 {
424         return (struct sysfs_link *)calloc(1, sizeof(struct sysfs_link));
425 }
426
427 /**
428  * sysfs_read_all_subdirs: calls sysfs_read_directory for all subdirs
429  * @sysdir: directory whose subdirs need reading.
430  * returns 0 with success and -1 with error.
431  */
432 int sysfs_read_all_subdirs(struct sysfs_directory *sysdir)
433 {
434         struct sysfs_directory *cursub = NULL;
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                 }
450         }
451         return 0;
452 }
453
454 /**
455  * sysfs_open_directory: opens a sysfs directory, creates dir struct, and
456  *              returns.
457  * @path: path of directory to open.
458  * returns: struct sysfs_directory * with success and NULL on error.
459  */
460 struct sysfs_directory *sysfs_open_directory(const unsigned char *path)
461 {
462         struct sysfs_directory *sdir = NULL;
463
464         if (path == NULL) {
465                 errno = EINVAL;
466                 return NULL;
467         }
468
469         if (sysfs_path_is_dir(path) != 0) {
470                 dprintf("Invalid path directory %s\n", path);
471                 errno = EINVAL;
472                 return NULL;
473         }
474
475         sdir = alloc_directory();
476         if (sdir == NULL) {
477                 dprintf("Error allocating directory %s\n", path);
478                 return NULL;
479         }
480         if (sysfs_get_name_from_path(path, sdir->name, SYSFS_NAME_LEN) != 0) {
481                 dprintf("Error getting directory name from path: %s\n", path);
482                 sysfs_close_directory(sdir);
483                 return NULL;
484         }
485         strncpy(sdir->path, path, SYSFS_PATH_MAX);
486
487         return sdir;
488 }
489
490 /**
491  * sysfs_open_link: opens a sysfs link, creates struct, and returns
492  * @path: path of link to open.
493  * returns: struct sysfs_link * with success and NULL on error.
494  */
495 struct sysfs_link *sysfs_open_link(const unsigned char *linkpath)
496 {
497         struct sysfs_link *ln = NULL;
498
499         if (linkpath == NULL || strlen(linkpath) > SYSFS_PATH_MAX) {
500                 errno = EINVAL;
501                 return NULL;
502         }
503
504         ln = alloc_link();
505         if (ln == NULL) {
506                 dprintf("Error allocating link %s\n", linkpath);
507                 return NULL;
508         }
509         strcpy(ln->path, linkpath);
510         if ((sysfs_get_name_from_path(linkpath, ln->name, SYSFS_NAME_LEN)) != 0
511             || (sysfs_get_link(linkpath, ln->target, SYSFS_PATH_MAX)) != 0) {
512                 errno = EINVAL;
513                 dprintf("Invalid link path %s\n", linkpath);
514                 return NULL;
515         }
516
517         return ln;
518 }
519
520 /**
521  * add_attribute: open and add attribute at path to given directory
522  * @sysdir: directory to add attribute to
523  * @path: path to attribute
524  * returns 0 with success and -1 with error.
525  */
526 static int add_attribute(struct sysfs_directory *sysdir, 
527                                         const unsigned char *path)
528 {
529         struct sysfs_attribute *attr = NULL;
530
531         attr = sysfs_open_attribute(path);
532         if (attr == NULL) {
533                 dprintf("Error opening attribute %s\n", path);
534                 return -1;
535         }
536         if (attr->method & SYSFS_METHOD_SHOW) {
537                 if ((sysfs_read_attribute(attr)) != 0) {
538                         dprintf("Error reading attribute %s\n", path);
539                         sysfs_close_attribute(attr);
540                         return 0;
541                 }
542         }
543                                                 
544         if (sysdir->attributes == NULL) {
545                 sysdir->attributes = dlist_new_with_delete
546                         (sizeof(struct sysfs_attribute), sysfs_del_attribute);
547         }
548         dlist_unshift(sysdir->attributes, attr);
549
550         return 0;
551 }
552
553 /**
554  * add_subdirectory: open and add subdirectory at path to given directory
555  * @sysdir: directory to add subdir to
556  * @path: path to subdirectory
557  * returns 0 with success and -1 with error.
558  */
559 static int add_subdirectory(struct sysfs_directory *sysdir, 
560                                         const unsigned char *path)
561 {
562         struct sysfs_directory *subdir = NULL;
563
564         subdir = sysfs_open_directory(path);
565         if (subdir == NULL) {
566                 dprintf("Error opening directory %s\n", path);
567                 return -1;
568         }
569         if (sysdir->subdirs == NULL)
570                 sysdir->subdirs = dlist_new_with_delete
571                         (sizeof(struct sysfs_directory), sysfs_del_directory);
572         dlist_unshift(sysdir->subdirs, subdir);
573         return 0;
574 }
575
576 /**
577  * add_link: open and add link at path to given directory
578  * @sysdir: directory to add link to
579  * @path: path to link
580  * returns 0 with success and -1 with error.
581  */
582 static int add_link(struct sysfs_directory *sysdir, const unsigned char *path)
583 {
584         struct sysfs_link *ln = NULL;
585
586         ln = sysfs_open_link(path);
587         if (ln == NULL) {
588                 dprintf("Error opening link %s\n", path);
589                 return -1;
590         }
591         if (sysdir->links == NULL)
592                 sysdir->links = dlist_new_with_delete
593                                 (sizeof(struct sysfs_link), sysfs_del_link);
594         dlist_unshift(sysdir->links, ln);
595         return 0;
596 }
597
598 /**
599  * sysfs_read_dir_attributes: grabs attributes for the given directory
600  * @sysdir: sysfs directory to open
601  * returns 0 with success and -1 with error.
602  */
603 int sysfs_read_dir_attributes(struct sysfs_directory *sysdir)
604 {
605         DIR *dir = NULL;
606         struct dirent *dirent = NULL;
607         unsigned char file_path[SYSFS_PATH_MAX];
608         int retval = 0;
609
610         if (sysdir == NULL) {
611                 errno = EINVAL;
612                 return -1;
613         }
614         dir = opendir(sysdir->path);
615         if (dir == NULL) {
616                 dprintf("Error opening directory %s\n", sysdir->path);
617                 return -1;
618         }
619         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
620                 if (0 == strcmp(dirent->d_name, "."))
621                          continue;
622                 if (0 == strcmp(dirent->d_name, ".."))
623                         continue;
624                 memset(file_path, 0, SYSFS_PATH_MAX);
625                 strncpy(file_path, sysdir->path, SYSFS_PATH_MAX);
626                 strcat(file_path, "/");
627                 strcat(file_path, dirent->d_name);
628                 if ((sysfs_path_is_file(file_path)) == 0)
629                         retval = add_attribute(sysdir, file_path);
630         }
631         closedir(dir);
632         return(retval);
633 }
634
635 /**
636  * sysfs_read_dir_links: grabs links in a specific directory
637  * @sysdir: sysfs directory to read links
638  * returns 0 with success and -1 with error.
639  */
640 int sysfs_read_dir_links(struct sysfs_directory *sysdir)
641 {
642         DIR *dir = NULL;
643         struct dirent *dirent = NULL;
644         unsigned char file_path[SYSFS_PATH_MAX];
645         int retval = 0;
646
647         if (sysdir == NULL) {
648                 errno = EINVAL;
649                 return -1;
650         }
651         dir = opendir(sysdir->path);
652         if (dir == NULL) {
653                 dprintf("Error opening directory %s\n", sysdir->path);
654                 return -1;
655         }
656         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
657                 if (0 == strcmp(dirent->d_name, "."))
658                          continue;
659                 if (0 == strcmp(dirent->d_name, ".."))
660                         continue;
661                 memset(file_path, 0, SYSFS_PATH_MAX);
662                 strncpy(file_path, sysdir->path, SYSFS_PATH_MAX);
663                 strcat(file_path, "/");
664                 strcat(file_path, dirent->d_name);
665                 if ((sysfs_path_is_link(file_path)) == 0) {
666                         retval = add_link(sysdir, file_path);
667                         if (retval != 0)
668                                 break;
669                 }
670         }
671         closedir(dir);
672         return(retval);
673 }
674
675 /**
676  * sysfs_read_dir_subdirs: grabs subdirs in a specific directory
677  * @sysdir: sysfs directory to read links
678  * returns 0 with success and -1 with error.
679  */
680 int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir)
681 {
682         DIR *dir = NULL;
683         struct dirent *dirent = NULL;
684         unsigned char file_path[SYSFS_PATH_MAX];
685         int retval = 0;
686
687         if (sysdir == NULL) {
688                 errno = EINVAL;
689                 return -1;
690         }
691         dir = opendir(sysdir->path);
692         if (dir == NULL) {
693                 dprintf("Error opening directory %s\n", sysdir->path);
694                 return -1;
695         }
696         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
697                 if (0 == strcmp(dirent->d_name, "."))
698                          continue;
699                 if (0 == strcmp(dirent->d_name, ".."))
700                         continue;
701                 memset(file_path, 0, SYSFS_PATH_MAX);
702                 strncpy(file_path, sysdir->path, SYSFS_PATH_MAX);
703                 strcat(file_path, "/");
704                 strcat(file_path, dirent->d_name);
705                 if ((sysfs_path_is_dir(file_path)) == 0)
706                         retval = add_subdirectory(sysdir, file_path);
707         }
708         closedir(dir);
709         return(retval);
710 }
711
712 /**
713  * sysfs_read_directory: grabs attributes, links, and subdirectories
714  * @sysdir: sysfs directory to open
715  * returns 0 with success and -1 with error.
716  */
717 int sysfs_read_directory(struct sysfs_directory *sysdir)
718 {
719         DIR *dir = NULL;
720         struct dirent *dirent = NULL;
721         struct stat astats;
722         unsigned char file_path[SYSFS_PATH_MAX];
723         int retval = 0;
724
725         if (sysdir == NULL) {
726                 errno = EINVAL;
727                 return -1;
728         }
729         dir = opendir(sysdir->path);
730         if (dir == NULL) {
731                 dprintf("Error opening directory %s\n", sysdir->path);
732                 return -1;
733         }
734         while(((dirent = readdir(dir)) != NULL) && retval == 0) {
735                 if (0 == strcmp(dirent->d_name, "."))
736                          continue;
737                 if (0 == strcmp(dirent->d_name, ".."))
738                         continue;
739                 memset(file_path, 0, SYSFS_PATH_MAX);
740                 strncpy(file_path, sysdir->path, SYSFS_PATH_MAX);
741                 strcat(file_path, "/");
742                 strcat(file_path, dirent->d_name);
743                 if ((lstat(file_path, &astats)) != 0) {
744                         dprintf("stat failed\n");
745                         continue;
746                 }
747                 if (S_ISDIR(astats.st_mode)) 
748                         retval = add_subdirectory(sysdir, file_path);
749
750                 else if (S_ISLNK(astats.st_mode))
751                         retval = add_link(sysdir, file_path);
752
753                 else if (S_ISREG(astats.st_mode))
754                         retval = add_attribute(sysdir, file_path);
755         }
756         closedir(dir);
757         return(retval);
758 }
759
760 /**
761  * sysfs_refresh_dir_attributes: Refresh attributes list
762  * @sysdir: directory whose list of attributes to refresh
763  * Returns 0 on success, 1 on failure
764  */
765 int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir)
766 {
767         if (sysdir == NULL) {
768                 errno = EINVAL;
769                 return 1;
770         }
771         if ((sysfs_path_is_dir(sysdir->path)) != 0) {
772                 dprintf("Invalid path to directory %s\n", sysdir->path);
773                 errno = EINVAL;
774                 return 1;
775         }
776         if (sysdir->attributes != NULL) {
777                 dlist_destroy(sysdir->attributes);
778                 sysdir->attributes = NULL;
779         }
780         if ((sysfs_read_dir_attributes(sysdir)) != 0) {
781                 dprintf("Error refreshing attributes for directory %s\n", 
782                                                         sysdir->path);
783                 return 1;
784         }
785         return 0;
786 }
787
788 /**
789  * sysfs_refresh_dir_links: Refresh links list
790  * @sysdir: directory whose list of links to refresh
791  * Returns 0 on success, 1 on failure
792  */
793 int sysfs_refresh_dir_links(struct sysfs_directory *sysdir)
794 {
795         if (sysdir == NULL) {
796                 errno = EINVAL;
797                 return 1;
798         }
799         if ((sysfs_path_is_dir(sysdir->path)) != 0) {
800                 dprintf("Invalid path to directory %s\n", sysdir->path);
801                 errno = EINVAL;
802                 return 1;
803         }
804         if (sysdir->links != NULL) {
805                 dlist_destroy(sysdir->links);
806                 sysdir->links = NULL;
807         }
808         if ((sysfs_read_dir_links(sysdir)) != 0) {
809                 dprintf("Error refreshing links for directory %s\n", 
810                                                         sysdir->path);
811                 return 1;
812         }
813         return 0;
814 }
815
816 /**
817  * sysfs_refresh_dir_subdirs: Refresh subdirs list
818  * @sysdir: directory whose list of subdirs to refresh
819  * Returns 0 on success, 1 on failure
820  */
821 int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir)
822 {
823         if (sysdir == NULL) {
824                 errno = EINVAL;
825                 return 1;
826         }
827         if ((sysfs_path_is_dir(sysdir->path)) != 0) {
828                 dprintf("Invalid path to directory %s\n", sysdir->path);
829                 errno = EINVAL;
830                 return 1;
831         }
832         if (sysdir->subdirs != NULL) {
833                 dlist_destroy(sysdir->subdirs);
834                 sysdir->subdirs = NULL;
835         }
836         if ((sysfs_read_dir_subdirs(sysdir)) != 0) {
837                 dprintf("Error refreshing subdirs for directory %s\n", 
838                                                         sysdir->path);
839                 return 1;
840         }
841         return 0;
842 }
843
844 /**
845  * sysfs_get_directory_attribute: retrieves attribute attrname from current
846  *      directory only
847  * @dir: directory to retrieve attribute from
848  * @attrname: name of attribute to look for
849  * returns sysfs_attribute if found and NULL if not found
850  */
851 struct sysfs_attribute *sysfs_get_directory_attribute
852                         (struct sysfs_directory *dir, unsigned char *attrname)
853 {
854         struct sysfs_attribute *attr = NULL;
855         unsigned char new_path[SYSFS_PATH_MAX];
856         
857         if (dir == NULL || attrname == NULL) {
858                 errno = EINVAL;
859                 return NULL;
860         }
861
862         if (dir->attributes == NULL) 
863                 if ((sysfs_read_dir_attributes(dir) != 0) 
864                     || (dir->attributes == NULL))
865                         return NULL;
866
867         attr = (struct sysfs_attribute *)dlist_find_custom
868                         (dir->attributes, attrname, dir_attribute_name_equal);
869         if (attr != NULL) {
870                 if ((sysfs_read_attribute(attr)) != 0) {
871                         dprintf("Error reading attribute %s\n", attr->name);
872                         return NULL;
873                 }
874         } else {
875                 memset(new_path, 0, SYSFS_PATH_MAX);
876                 strcpy(new_path, dir->path);
877                 strcat(new_path, "/");
878                 strcat(new_path, attrname);
879                 if ((sysfs_path_is_file(new_path)) == 0) {
880                         if ((add_attribute(dir, new_path)) == 0) {
881                                 attr = (struct sysfs_attribute *)
882                                         dlist_find_custom(dir->attributes,
883                                         attrname, dir_attribute_name_equal);
884                         }
885                 }
886         }
887                 
888         return attr;
889 }
890
891 /**
892  * sysfs_get_directory_link: retrieves link from one directory list
893  * @dir: directory to retrieve link from
894  * @linkname: name of link to look for
895  * returns reference to sysfs_link if found and NULL if not found
896  */
897 struct sysfs_link *sysfs_get_directory_link
898                         (struct sysfs_directory *dir, unsigned char *linkname)
899 {
900         if (dir == NULL || linkname == NULL) {
901                 errno = EINVAL;
902                 return NULL;
903         }
904         if (dir->links == NULL) {
905                 if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL))
906                         return NULL;
907         } else {
908                 if ((sysfs_refresh_dir_links(dir)) != 0) 
909                         return NULL;
910         }
911
912         return (struct sysfs_link *)dlist_find_custom(dir->links,
913                 linkname, dir_link_name_equal);
914 }
915
916 /**
917  * sysfs_get_subdirectory: retrieves subdirectory by name.
918  * @dir: directory to search for subdirectory.
919  * @subname: subdirectory name to get.
920  * returns reference to subdirectory or NULL if not found
921  */
922 struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir,
923                                                 unsigned char *subname)
924 {
925         struct sysfs_directory *sub = NULL, *cursub = NULL;
926
927         if (dir == NULL || subname == NULL) {
928                 errno = EINVAL;
929                 return NULL;
930         }
931
932         if (dir->subdirs == NULL)
933                 if (sysfs_read_dir_subdirs(dir) != 0)
934                         return NULL;
935
936         sub = (struct sysfs_directory *)dlist_find_custom(dir->subdirs,
937                 subname, dir_subdir_name_equal);
938         if (sub != NULL) 
939                 return sub;
940
941         if (dir->subdirs != NULL) {
942                 dlist_for_each_data(dir->subdirs, cursub, 
943                                         struct sysfs_directory) {
944                         if (cursub->subdirs == NULL) {
945                                 if (sysfs_read_dir_subdirs(cursub) != 0)
946                                         continue;
947                                 if (cursub->subdirs == NULL)
948                                         continue;
949                         }
950                         sub = sysfs_get_subdirectory(cursub, subname);
951                         if (sub != NULL)
952                                 return sub;
953                 }
954         }
955         return NULL;
956 }
957
958 /**
959  * sysfs_get_subdirectory_link: looks through all subdirs for specific link.
960  * @dir: directory and subdirectories to search for link.
961  * @linkname: link name to get.
962  * returns reference to link or NULL if not found
963  */
964 struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir,
965                                                 unsigned char *linkname)
966 {
967         struct sysfs_directory *cursub = NULL;
968         struct sysfs_link *ln = NULL;
969
970         if (dir == NULL || linkname == NULL) {
971                 errno = EINVAL;
972                 return NULL;
973         }
974
975         ln = sysfs_get_directory_link(dir, linkname);
976         if (ln != NULL)
977                 return ln;
978
979         if (dir->subdirs == NULL) 
980                 if (sysfs_read_dir_subdirs(dir) != 0)
981                         return NULL;
982
983         if (dir->subdirs != NULL) {
984                 dlist_for_each_data(dir->subdirs, cursub, 
985                                                 struct sysfs_directory) {
986                         ln = sysfs_get_subdirectory_link(cursub, linkname);
987                         if (ln != NULL)
988                                 return ln;
989                 }
990         }
991         return NULL;
992 }
993
994 /**
995  * sysfs_get_dir_attributes: returns dlist of directory attributes
996  * @dir: directory to retrieve attributes from
997  * returns dlist of attributes or NULL
998  */
999 struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir)
1000 {
1001         if (dir == NULL) {
1002                 errno = EINVAL;
1003                 return NULL;
1004         }
1005
1006         if (dir->attributes == NULL) {
1007                 if (sysfs_read_dir_attributes(dir) != 0)
1008                         return NULL;
1009         }
1010
1011         return (dir->attributes);
1012 }
1013
1014 /**
1015  * sysfs_get_dir_links: returns dlist of directory links
1016  * @dir: directory to return links for
1017  * returns dlist of links or NULL
1018  */
1019 struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir)
1020 {
1021         if (dir == NULL) {
1022                 errno = EINVAL;
1023                 return NULL;
1024         }
1025
1026         if (dir->links == NULL) {
1027                 if (sysfs_read_dir_links(dir) != 0)
1028                         return NULL;
1029         }
1030
1031         return (dir->links);
1032 }
1033
1034 /**
1035  * sysfs_get_dir_subdirs: returns dlist of directory subdirectories
1036  * @dir: directory to return subdirs for
1037  * returns dlist of subdirs or NULL
1038  */
1039 struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir)
1040 {
1041         if (dir == NULL) {
1042                 errno = EINVAL;
1043                 return NULL;
1044         }
1045
1046         if (dir->subdirs == NULL) {
1047                 if (sysfs_read_dir_subdirs(dir) != 0)
1048                         return NULL;
1049         }
1050
1051         return (dir->subdirs);
1052 }