4 * Directory utility functions for libsysfs
6 * Copyright (C) IBM Corp. 2003-2005
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.
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.
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
26 static int sort_char(void *new, void *old)
28 return ((strncmp((char *)new, (char *)old,
29 strlen((char *)new))) < 0 ? 1 : 0);
33 * sysfs_del_name: free function for sysfs_open_subsystem_list
34 * @name: memory area to be freed
36 static void sysfs_del_name(void *name)
42 * sysfs_del_attribute: routine for dlist integration
44 static void sysfs_del_attribute(void *attr)
46 sysfs_close_attribute((struct sysfs_attribute *)attr);
50 * attr_name_equal: compares attributes by name
51 * @a: attribute name for comparison
52 * @b: sysfs_attribute to be compared.
53 * returns 1 if a==b->name or 0 if not equal
55 static int attr_name_equal(void *a, void *b)
60 if (strcmp(((char *)a), ((struct sysfs_attribute *)b)->name) == 0)
67 * sysfs_close_attribute: closes and cleans up attribute
68 * @sysattr: attribute to close.
70 void sysfs_close_attribute(struct sysfs_attribute *sysattr)
80 * alloc_attribute: allocates and initializes attribute structure
81 * returns struct sysfs_attribute with success and NULL with error.
83 static struct sysfs_attribute *alloc_attribute(void)
85 return (struct sysfs_attribute *)
86 calloc(1, sizeof(struct sysfs_attribute));
90 * sysfs_open_attribute: creates sysfs_attribute structure
91 * @path: path to attribute.
92 * returns sysfs_attribute struct with success and NULL with error.
94 struct sysfs_attribute *sysfs_open_attribute(const char *path)
96 struct sysfs_attribute *sysattr = NULL;
103 sysattr = alloc_attribute();
105 dprintf("Error allocating attribute at %s\n", path);
108 if (sysfs_get_name_from_path(path, sysattr->name,
109 SYSFS_NAME_LEN) != 0) {
110 dprintf("Error retrieving attrib name from path: %s\n", path);
111 sysfs_close_attribute(sysattr);
114 safestrcpy(sysattr->path, path);
115 if ((stat(sysattr->path, &fileinfo)) != 0) {
116 dprintf("Stat failed: No such attribute?\n");
121 if (fileinfo.st_mode & S_IRUSR)
122 sysattr->method |= SYSFS_METHOD_SHOW;
123 if (fileinfo.st_mode & S_IWUSR)
124 sysattr->method |= SYSFS_METHOD_STORE;
131 * sysfs_read_attribute: reads value from attribute
132 * @sysattr: attribute to read
133 * returns 0 with success and -1 with error.
135 int sysfs_read_attribute(struct sysfs_attribute *sysattr)
147 if (!(sysattr->method & SYSFS_METHOD_SHOW)) {
148 dprintf("Show method not supported for attribute %s\n",
153 pgsize = getpagesize();
154 fbuf = (char *)calloc(1, pgsize+1);
156 dprintf("calloc failed\n");
159 if ((fd = open(sysattr->path, O_RDONLY)) < 0) {
160 dprintf("Error reading attribute %s\n", sysattr->path);
164 length = read(fd, fbuf, pgsize);
166 dprintf("Error reading from attribute %s\n", sysattr->path);
171 if (sysattr->len > 0) {
172 if ((sysattr->len == length) &&
173 (!(strncmp(sysattr->value, fbuf, length)))) {
178 free(sysattr->value);
180 sysattr->len = length;
182 vbuf = (char *)realloc(fbuf, length+1);
184 dprintf("realloc failed\n");
188 sysattr->value = vbuf;
194 * sysfs_write_attribute: write value to the attribute
195 * @sysattr: attribute to write
196 * @new_value: value to write
197 * @len: length of "new_value"
198 * returns 0 with success and -1 with error.
200 int sysfs_write_attribute(struct sysfs_attribute *sysattr,
201 const char *new_value, size_t len)
206 if (!sysattr || !new_value || len == 0) {
211 if (!(sysattr->method & SYSFS_METHOD_STORE)) {
212 dprintf ("Store method not supported for attribute %s\n",
217 if (sysattr->method & SYSFS_METHOD_SHOW) {
219 * read attribute again to see if we can get an updated value
221 if ((sysfs_read_attribute(sysattr))) {
222 dprintf("Error reading attribute\n");
225 if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) {
226 dprintf("Attr %s already has the requested value %s\n",
227 sysattr->name, new_value);
232 * open O_WRONLY since some attributes have no "read" but only
235 if ((fd = open(sysattr->path, O_WRONLY)) < 0) {
236 dprintf("Error reading attribute %s\n", sysattr->path);
240 length = write(fd, new_value, len);
242 dprintf("Error writing to the attribute %s - invalid value?\n",
246 } else if ((unsigned int)length != len) {
247 dprintf("Could not write %zd bytes to attribute %s\n",
250 * since we could not write user supplied number of bytes,
251 * restore the old value if one available
253 if (sysattr->method & SYSFS_METHOD_SHOW) {
254 length = write(fd, sysattr->value, sysattr->len);
261 * Validate length that has been copied. Alloc appropriate area
262 * in sysfs_attribute. Verify first if the attribute supports reading
263 * (show method). If it does not, do not bother
265 if (sysattr->method & SYSFS_METHOD_SHOW) {
266 if (length != sysattr->len) {
267 sysattr->value = (char *)realloc
268 (sysattr->value, length);
269 sysattr->len = length;
270 safestrcpymax(sysattr->value, new_value, length);
272 /*"length" of the new value is same as old one */
273 safestrcpymax(sysattr->value, new_value, length);
282 * add_attribute: open and add attribute at path to given directory
283 * @dev: device whose attribute is to be added
284 * @path: path to attribute
285 * returns pointer to attr added with success and NULL with error.
287 static struct sysfs_attribute *add_attribute(void *dev, const char *path)
289 struct sysfs_attribute *attr;
291 attr = sysfs_open_attribute(path);
293 dprintf("Error opening attribute %s\n", path);
296 if (attr->method & SYSFS_METHOD_SHOW) {
297 if (sysfs_read_attribute(attr)) {
298 dprintf("Error reading attribute %s\n", path);
299 sysfs_close_attribute(attr);
304 if (!((struct sysfs_device *)dev)->attrlist) {
305 ((struct sysfs_device *)dev)->attrlist = dlist_new_with_delete
306 (sizeof(struct sysfs_attribute), sysfs_del_attribute);
308 dlist_unshift_sorted(((struct sysfs_device *)dev)->attrlist,
315 * get_attribute - given a sysfs_* struct and a name, return the
316 * sysfs_attribute corresponding to "name"
317 * returns sysfs_attribute on success and NULL on error
319 struct sysfs_attribute *get_attribute(void *dev, const char *name)
321 struct sysfs_attribute *cur = NULL;
322 char path[SYSFS_PATH_MAX];
329 if (((struct sysfs_device *)dev)->attrlist) {
330 /* check if attr is already in the list */
331 cur = (struct sysfs_attribute *)dlist_find_custom
332 ((((struct sysfs_device *)dev)->attrlist),
333 (void *)name, attr_name_equal);
337 safestrcpymax(path, ((struct sysfs_device *)dev)->path,
339 safestrcatmax(path, "/", SYSFS_PATH_MAX);
340 safestrcatmax(path, name, SYSFS_PATH_MAX);
341 if (!sysfs_path_is_file(path))
342 cur = add_attribute((void *)dev, path);
347 * read_dir_links: grabs links in a specific directory
348 * @sysdir: sysfs directory to read
349 * returns list of link names with success and NULL with error.
351 struct dlist *read_dir_links(const char *path)
354 struct dirent *dirent = NULL;
355 char file_path[SYSFS_PATH_MAX], *linkname;
356 struct dlist *linklist = NULL;
364 dprintf("Error opening directory %s\n", path);
367 while ((dirent = readdir(dir)) != NULL) {
368 if (0 == strcmp(dirent->d_name, "."))
370 if (0 == strcmp(dirent->d_name, ".."))
372 memset(file_path, 0, SYSFS_PATH_MAX);
373 safestrcpy(file_path, path);
374 safestrcat(file_path, "/");
375 safestrcat(file_path, dirent->d_name);
376 if (!sysfs_path_is_link(file_path)) {
378 linklist = dlist_new_with_delete
379 (SYSFS_NAME_LEN, sysfs_del_name);
381 dprintf("Error creating list\n");
385 linkname = (char *)calloc(1, SYSFS_NAME_LEN);
386 safestrcpymax(linkname, dirent->d_name, SYSFS_NAME_LEN);
387 dlist_unshift_sorted(linklist, linkname, sort_char);
395 * read_dir_subdirs: grabs subdirs in a specific directory
396 * @sysdir: sysfs directory to read
397 * returns list of directory names with success and NULL with error.
399 struct dlist *read_dir_subdirs(const char *path)
402 struct dirent *dirent = NULL;
403 char file_path[SYSFS_PATH_MAX], *dir_name;
404 struct dlist *dirlist = NULL;
412 dprintf("Error opening directory %s\n", path);
415 while ((dirent = readdir(dir)) != NULL) {
416 if (0 == strcmp(dirent->d_name, "."))
418 if (0 == strcmp(dirent->d_name, ".."))
420 memset(file_path, 0, SYSFS_PATH_MAX);
421 safestrcpy(file_path, path);
422 safestrcat(file_path, "/");
423 safestrcat(file_path, dirent->d_name);
424 if (!sysfs_path_is_dir(file_path)) {
426 dirlist = dlist_new_with_delete
427 (SYSFS_NAME_LEN, sysfs_del_name);
429 dprintf("Error creating list\n");
433 dir_name = (char *)calloc(1, SYSFS_NAME_LEN);
434 safestrcpymax(dir_name, dirent->d_name, SYSFS_NAME_LEN);
435 dlist_unshift_sorted(dirlist, dir_name, sort_char);
443 * get_attributes_list: build a list of attributes for the given device
444 * @dev: devices whose attributes list is required
445 * returns dlist of attributes on success and NULL on failure
447 struct dlist *get_attributes_list(void *dev)
450 struct dirent *dirent = NULL;
451 struct sysfs_attribute *attr = NULL;
452 char file_path[SYSFS_PATH_MAX], path[SYSFS_PATH_MAX];
458 memset(path, 0, SYSFS_PATH_MAX);
459 safestrcpy(path, ((struct sysfs_device *)dev)->path);
462 dprintf("Error opening directory %s\n", path);
465 while ((dirent = readdir(dir)) != NULL) {
466 if (0 == strcmp(dirent->d_name, "."))
468 if (0 == strcmp(dirent->d_name, ".."))
470 memset(file_path, 0, SYSFS_PATH_MAX);
471 safestrcpy(file_path, path);
472 safestrcat(file_path, "/");
473 safestrcat(file_path, dirent->d_name);
474 if (!sysfs_path_is_file(file_path)) {
475 if (((struct sysfs_device *)dev)->attrlist) {
476 /* check if attr is already in the list */
477 attr = (struct sysfs_attribute *)
479 ((((struct sysfs_device *)dev)->attrlist),
480 (void *)dirent->d_name, attr_name_equal);
484 add_attribute(dev, file_path);
486 attr = add_attribute(dev, file_path);
490 return ((struct sysfs_device *)dev)->attrlist;