4 * Generic device utility functions for libsysfs
6 * Copyright (C) IBM Corp. 2003
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
27 * get_dev_driver: fills in the dev->driver_name field, but searches by
28 * opening subsystem. Only to be used if no driver link exists in
31 * Returns 0 on SUCCESS and 1 on error
33 static int get_dev_driver(struct sysfs_device *dev)
35 struct dlist *drvlist = NULL;
36 char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX];
37 char *drv = NULL, *c = NULL;
43 if (dev->bus[0] == '\0')
45 memset(path, 0, SYSFS_PATH_MAX);
46 memset(devpath, 0, SYSFS_PATH_MAX);
47 safestrcpy(path, SYSFS_BUS_NAME);
48 safestrcat(path, "/");
49 safestrcat(path, dev->bus);
50 safestrcat(path, "/");
51 safestrcat(path, SYSFS_DRIVERS_NAME);
53 safestrcpy(devpath, dev->path);
54 c = strstr(devpath, SYSFS_DEVICES_NAME);
58 safestrcatmax(c, path, (sizeof(devpath) - strlen(devpath)));
60 drvlist = sysfs_open_subsystem_list(path);
61 if (drvlist != NULL) {
62 dlist_for_each_data(drvlist, drv, char) {
63 safestrcpy(path, devpath);
64 safestrcat(path, "/");
65 safestrcat(path, drv);
66 safestrcat(path, "/");
67 safestrcat(path, dev->bus_id);
68 if (sysfs_path_is_link(path) == 0) {
69 safestrcpy(dev->driver_name, drv);
70 sysfs_close_list(drvlist);
74 sysfs_close_list(drvlist);
80 * get_device_driver_name: gets device's driver name, searches for driver
81 * link first before going the brute force route.
82 * @dev: device to retrieve driver
83 * returns 0 with success and 1 with error
85 static int get_device_driver_name(struct sysfs_device *dev)
87 char devpath[SYSFS_PATH_MAX], drvpath[SYSFS_PATH_MAX];
93 memset(devpath, 0, SYSFS_PATH_MAX);
94 memset(drvpath, 0, SYSFS_PATH_MAX);
95 safestrcpy(devpath, dev->path);
96 safestrcat(devpath, "/driver");
98 if ((sysfs_get_link(devpath, drvpath, SYSFS_PATH_MAX)) != 0)
99 return(get_dev_driver(dev));
101 return (sysfs_get_name_from_path(drvpath, dev->driver_name,
106 * sysfs_get_device_bus: retrieves the bus name the device is on, checks path
107 * to bus' link to make sure it has correct device.
108 * @dev: device to get busname.
109 * returns 0 with success and -1 with error.
111 int sysfs_get_device_bus(struct sysfs_device *dev)
113 char subsys[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX];
114 char target[SYSFS_PATH_MAX], *bus = NULL, *c = NULL;
115 struct dlist *buslist = NULL;
122 memset(subsys, 0, SYSFS_NAME_LEN);
123 safestrcpy(subsys, SYSFS_BUS_NAME); /* subsys = bus */
124 buslist = sysfs_open_subsystem_list(subsys);
125 if (buslist != NULL) {
126 dlist_for_each_data(buslist, bus, char) {
127 memset(path, 0, SYSFS_PATH_MAX);
128 safestrcpy(path, dev->path);
129 c = strstr(path, "/devices");
131 dprintf("Invalid path to device %s\n", path);
132 sysfs_close_list(buslist);
136 safestrcat(path, "/");
137 safestrcat(path, SYSFS_BUS_NAME);
138 safestrcat(path, "/");
139 safestrcat(path, bus);
140 safestrcat(path, "/");
141 safestrcat(path, SYSFS_DEVICES_NAME);
142 safestrcat(path, "/");
143 safestrcat(path, dev->bus_id);
144 if ((sysfs_path_is_link(path)) == 0) {
145 memset(target, 0, SYSFS_PATH_MAX);
146 if ((sysfs_get_link(path, target,
147 SYSFS_PATH_MAX)) != 0) {
148 dprintf("Error getting link target\n");
149 sysfs_close_list(buslist);
152 if (!(strncmp(target, dev->path,
154 safestrcpy(dev->bus, bus);
155 sysfs_close_list(buslist);
160 sysfs_close_list(buslist);
166 * sysfs_close_device_tree: closes every device in the supplied tree,
167 * closing children only.
168 * @devroot: device root of tree.
170 void sysfs_close_device_tree(struct sysfs_device *devroot)
172 if (devroot != NULL) {
173 if (devroot->children != NULL) {
174 struct sysfs_device *child = NULL;
176 dlist_for_each_data(devroot->children, child,
177 struct sysfs_device) {
178 sysfs_close_device_tree(child);
181 sysfs_close_device(devroot);
186 * sysfs_close_dev_tree: routine for dlist integration
188 static void sysfs_close_dev_tree(void *dev)
190 sysfs_close_device_tree((struct sysfs_device *)dev);
194 * sysfs_close_device: closes and cleans up a device
195 * @dev = device to clean up
197 void sysfs_close_device(struct sysfs_device *dev)
200 if (dev->parent != NULL)
201 sysfs_close_device(dev->parent);
202 if (dev->directory != NULL)
203 sysfs_close_directory(dev->directory);
204 if (dev->children != NULL && dev->children->count == 0)
205 dlist_destroy(dev->children);
211 * alloc_device: allocates and initializes device structure
212 * returns struct sysfs_device
214 static struct sysfs_device *alloc_device(void)
216 return (struct sysfs_device *)calloc(1, sizeof(struct sysfs_device));
220 * open_device_dir: opens up sysfs_directory for specific root dev
221 * @name: name of root
222 * returns struct sysfs_directory with success and NULL with error
224 static struct sysfs_directory *open_device_dir(const char *path)
226 struct sysfs_directory *rdir = NULL;
233 rdir = sysfs_open_directory(path);
236 dprintf ("Device %s not supported on this system\n", path);
239 if ((sysfs_read_dir_subdirs(rdir)) != 0) {
240 dprintf ("Error reading device at dir %s\n", path);
241 sysfs_close_directory(rdir);
249 * sysfs_open_device_path: opens and populates device structure
250 * @path: path to device, this is the /sys/devices/ path
251 * returns sysfs_device structure with success or NULL with error
253 struct sysfs_device *sysfs_open_device_path(const char *path)
255 struct sysfs_device *dev = NULL;
261 if ((sysfs_path_is_dir(path)) != 0) {
262 dprintf("Incorrect path to device: %s\n", path);
265 dev = alloc_device();
267 dprintf("Error allocating device at %s\n", path);
270 if ((sysfs_get_name_from_path(path, dev->bus_id,
271 SYSFS_NAME_LEN)) != 0) {
273 dprintf("Error getting device bus_id\n");
274 sysfs_close_device(dev);
277 safestrcpy(dev->path, path);
278 if ((sysfs_remove_trailing_slash(dev->path)) != 0) {
279 dprintf("Invalid path to device %s\n", dev->path);
280 sysfs_close_device(dev);
284 * The "name" attribute no longer exists... return the device's
285 * sysfs representation instead, in the "dev->name" field, which
286 * implies that the dev->name and dev->bus_id contain same data.
288 safestrcpy(dev->name, dev->bus_id);
290 if (sysfs_get_device_bus(dev) != 0)
291 dprintf("Could not get device bus\n");
293 if (get_device_driver_name(dev) != 0) {
294 dprintf("Could not get device %s's driver\n", dev->bus_id);
295 safestrcpy(dev->driver_name, SYSFS_UNKNOWN);
302 * sysfs_open_device_tree: opens root device and all of its children,
303 * creating a tree of devices. Only opens children.
304 * @path: sysfs path to devices
305 * returns struct sysfs_device and its children with success or NULL with
308 struct sysfs_device *sysfs_open_device_tree(const char *path)
310 struct sysfs_device *rootdev = NULL, *new = NULL;
311 struct sysfs_directory *cur = NULL;
317 rootdev = sysfs_open_device_path(path);
318 if (rootdev == NULL) {
319 dprintf("Error opening root device at %s\n", path);
322 if (rootdev->directory == NULL) {
323 rootdev->directory = open_device_dir(rootdev->path);
324 if (rootdev->directory == NULL)
327 if (rootdev->directory->subdirs != NULL) {
328 dlist_for_each_data(rootdev->directory->subdirs, cur,
329 struct sysfs_directory) {
330 new = sysfs_open_device_tree(cur->path);
332 dprintf("Error opening device tree at %s\n",
334 sysfs_close_device_tree(rootdev);
337 if (rootdev->children == NULL)
338 rootdev->children = dlist_new_with_delete
339 (sizeof(struct sysfs_device),
340 sysfs_close_dev_tree);
341 dlist_unshift_sorted(rootdev->children,
350 * sysfs_close_root_device: closes root and all devices
351 * @root: root device to close
353 void sysfs_close_root_device(struct sysfs_root_device *root)
356 if (root->devices != NULL)
357 dlist_destroy(root->devices);
358 if (root->directory != NULL)
359 sysfs_close_directory(root->directory);
365 * sysfs_get_root_devices: opens up all the devices under this root device
366 * @root: root device to open devices for
367 * returns dlist of devices with success and NULL with error
369 struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root)
371 struct sysfs_device *dev = NULL;
372 struct sysfs_directory *cur = NULL;
378 if (root->directory == NULL) {
379 root->directory = open_device_dir(root->path);
380 if (root->directory == NULL)
384 if (root->directory->subdirs == NULL)
387 dlist_for_each_data(root->directory->subdirs, cur,
388 struct sysfs_directory) {
389 dev = sysfs_open_device_tree(cur->path);
391 dprintf ("Error opening device at %s\n", cur->path);
394 if (root->devices == NULL)
395 root->devices = dlist_new_with_delete
396 (sizeof(struct sysfs_device),
397 sysfs_close_dev_tree);
398 dlist_unshift_sorted(root->devices, dev, sort_list);
401 return root->devices;
405 * sysfs_open_root_device: opens sysfs devices root and all of its
407 * @name: name of /sys/devices/root to open
408 * returns struct sysfs_root_device if success and NULL with error
410 struct sysfs_root_device *sysfs_open_root_device(const char *name)
412 struct sysfs_root_device *root = NULL;
413 char rootpath[SYSFS_PATH_MAX];
420 memset(rootpath, 0, SYSFS_PATH_MAX);
421 if (sysfs_get_mnt_path(rootpath, SYSFS_PATH_MAX) != 0) {
422 dprintf ("Sysfs not supported on this system\n");
426 safestrcat(rootpath, "/");
427 safestrcat(rootpath, SYSFS_DEVICES_NAME);
428 safestrcat(rootpath, "/");
429 safestrcat(rootpath, name);
430 if ((sysfs_path_is_dir(rootpath)) != 0) {
432 dprintf("Invalid root device: %s\n", name);
435 root = (struct sysfs_root_device *)calloc
436 (1, sizeof(struct sysfs_root_device));
438 dprintf("calloc failure\n");
441 safestrcpy(root->name, name);
442 safestrcpy(root->path, rootpath);
443 if ((sysfs_remove_trailing_slash(root->path)) != 0) {
444 dprintf("Invalid path to root device %s\n", root->path);
445 sysfs_close_root_device(root);
452 * sysfs_get_device_attributes: returns a dlist of attributes corresponding to
453 * the specific device
454 * @device: struct sysfs_device * for which attributes are to be returned
456 struct dlist *sysfs_get_device_attributes(struct sysfs_device *device)
458 if (device == NULL) {
463 if (device->directory == NULL) {
464 device->directory = sysfs_open_directory(device->path);
465 if (device->directory == NULL)
468 if (device->directory->attributes == NULL) {
469 if ((sysfs_read_dir_attributes(device->directory)) != 0)
472 return (device->directory->attributes);
476 * sysfs_refresh_device_attributes: refreshes the device's list of attributes
477 * @device: sysfs_device whose attributes to refresh
479 * NOTE: Upon return, prior references to sysfs_attributes for this device
482 * Returns list of attributes on success and NULL on failure
484 struct dlist *sysfs_refresh_device_attributes(struct sysfs_device *device)
486 if (device == NULL) {
491 if (device->directory == NULL)
492 return (sysfs_get_device_attributes(device));
494 if ((sysfs_refresh_dir_attributes(device->directory)) != 0) {
495 dprintf("Error refreshing device attributes\n");
499 return (device->directory->attributes);
503 * sysfs_get_device_attr: searches dev's attributes by name
504 * @dev: device to look through
505 * @name: attribute name to get
506 * returns sysfs_attribute reference with success or NULL with error.
508 struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
511 struct dlist *attrlist = NULL;
513 if (dev == NULL || name == NULL) {
518 attrlist = sysfs_get_device_attributes(dev);
519 if (attrlist == NULL)
522 return sysfs_get_directory_attribute(dev->directory, (char *)name);
526 * get_device_absolute_path: looks up the bus the device is on, gets
527 * absolute path to the device
528 * @device: device for which path is needed
529 * @path: buffer to store absolute path
530 * @psize: size of "path"
531 * Returns 0 on success -1 on failure
533 static int get_device_absolute_path(const char *device, const char *bus,
534 char *path, size_t psize)
536 char bus_path[SYSFS_PATH_MAX];
538 if (device == NULL || path == NULL) {
543 memset(bus_path, 0, SYSFS_PATH_MAX);
544 if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX) != 0) {
545 dprintf ("Sysfs not supported on this system\n");
548 safestrcat(bus_path, "/");
549 safestrcat(bus_path, SYSFS_BUS_NAME);
550 safestrcat(bus_path, "/");
551 safestrcat(bus_path, bus);
552 safestrcat(bus_path, "/");
553 safestrcat(bus_path, SYSFS_DEVICES_NAME);
554 safestrcat(bus_path, "/");
555 safestrcat(bus_path, device);
557 * We now are at /sys/bus/"bus_name"/devices/"device" which is a link.
558 * Now read this link to reach to the device.
560 if ((sysfs_get_link(bus_path, path, psize)) != 0) {
561 dprintf("Error getting to device %s\n", device);
568 * sysfs_open_device: open a device by id (use the "bus" subsystem)
569 * @bus: bus the device belongs to
570 * @bus_id: bus_id of the device to open - has to be the "bus_id" in
571 * /sys/bus/xxx/devices
572 * returns struct sysfs_device if found, NULL otherwise
574 * 1. Use sysfs_close_device to close the device
575 * 2. Bus the device is on must be supplied
576 * Use sysfs_find_device_bus to get the bus name
578 struct sysfs_device *sysfs_open_device(const char *bus, const char *bus_id)
580 char sysfs_path[SYSFS_PATH_MAX];
581 struct sysfs_device *device = NULL;
583 if (bus_id == NULL || bus == NULL) {
587 memset(sysfs_path, 0, SYSFS_PATH_MAX);
588 if ((get_device_absolute_path(bus_id, bus, sysfs_path,
589 SYSFS_PATH_MAX)) != 0) {
590 dprintf("Error getting to device %s\n", bus_id);
594 device = sysfs_open_device_path(sysfs_path);
595 if (device == NULL) {
596 dprintf("Error opening device %s\n", bus_id);
604 * sysfs_get_device_parent: opens up given device's parent and returns a
605 * reference to its sysfs_device
606 * @dev: sysfs_device whose parent is requested
607 * Returns sysfs_device of the parent on success and NULL on failure
609 struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev)
611 char ppath[SYSFS_PATH_MAX], *tmp = NULL;
618 if (dev->parent != NULL)
619 return (dev->parent);
621 memset(ppath, 0, SYSFS_PATH_MAX);
622 safestrcpy(ppath, dev->path);
623 tmp = strrchr(ppath, '/');
625 dprintf("Invalid path to device %s\n", ppath);
628 if (*(tmp + 1) == '\0') {
630 tmp = strrchr(tmp, '/');
632 dprintf("Invalid path to device %s\n", ppath);
639 * All "devices" have the "detach_state" attribute - validate here
641 safestrcat(ppath, "/detach_state");
642 if ((sysfs_path_is_file(ppath)) != 0) {
643 dprintf("Device at %s does not have a parent\n", dev->path);
646 tmp = strrchr(ppath, '/');
648 dev->parent = sysfs_open_device_path(ppath);
649 if (dev->parent == NULL) {
650 dprintf("Error opening device %s's parent at %s\n",
654 return (dev->parent);
658 * sysfs_open_device_attr: open the given device's attribute
659 * @bus: Bus on which to look
660 * @dev_id: device for which attribute is required
661 * @attrname: name of the attribute to look for
662 * Returns struct sysfs_attribute on success and NULL on failure
665 * A call to sysfs_close_attribute() is required to close
666 * the attribute returned and free memory.
668 struct sysfs_attribute *sysfs_open_device_attr(const char *bus,
669 const char *bus_id, const char *attrib)
671 struct sysfs_attribute *attribute = NULL;
672 char devpath[SYSFS_PATH_MAX];
674 if (bus == NULL || bus_id == NULL || attrib == NULL) {
679 memset(devpath, 0, SYSFS_PATH_MAX);
680 if ((get_device_absolute_path(bus_id, bus, devpath,
681 SYSFS_PATH_MAX)) != 0) {
682 dprintf("Error getting to device %s\n", bus_id);
685 safestrcat(devpath, "/");
686 safestrcat(devpath, attrib);
687 attribute = sysfs_open_attribute(devpath);
688 if (attribute == NULL) {
689 dprintf("Error opening attribute %s for device %s\n",
693 if ((sysfs_read_attribute(attribute)) != 0) {
694 dprintf("Error reading attribute %s for device %s\n",
696 sysfs_close_attribute(attribute);