/** * sysfs_open_class: opens specific class and all its devices on system * returns sysfs_class structure with success or NULL with error. */ struct sysfs_class *sysfs_open_class(const char *name) { struct sysfs_class *cls = NULL; char *c, classpath[SYSFS_PATH_MAX]; if (!name) { errno = EINVAL; return NULL; } memset(classpath, 0, SYSFS_PATH_MAX); if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) { dprintf("Sysfs not supported on this system\n"); return NULL; } safestrcat(classpath, "/"); if (strcmp(name, SYSFS_BLOCK_NAME) == 0) { safestrcat(classpath, SYSFS_BLOCK_NAME); if (!sysfs_path_is_dir(classpath)) goto done; c = strrchr(classpath, '/'); *(c+1) = '\0'; } safestrcat(classpath, SYSFS_CLASS_NAME); safestrcat(classpath, "/"); safestrcat(classpath, name); done: if (sysfs_path_is_dir(classpath)) { dprintf("Class %s not found on the system\n", name); return NULL; } cls = alloc_class(); if (cls == NULL) { dprintf("calloc failed\n"); return NULL; } safestrcpy(cls->name, name); safestrcpy(cls->path, classpath); if ((sysfs_remove_trailing_slash(cls->path)) != 0) { dprintf("Invalid path to class device %s\n", cls->path); sysfs_close_class(cls); return NULL; } return cls; }
/** * get_classdev_path: given the class and a device in the class, return the * absolute path to the device * @classname: name of the class * @clsdev: the class device * @path: buffer to return path * @psize: size of "path" * Returns 0 on SUCCESS or -1 on error */ static int get_classdev_path(const char *classname, const char *clsdev, char *path, size_t len) { char *c; if (!classname || !clsdev || !path) { errno = EINVAL; return -1; } if (sysfs_get_mnt_path(path, len) != 0) { dprintf("Error getting sysfs mount path\n"); return -1; } safestrcatmax(path, "/", len); if (strncmp(classname, SYSFS_BLOCK_NAME, sizeof(SYSFS_BLOCK_NAME)) == 0) { safestrcatmax(path, SYSFS_BLOCK_NAME, len); if (!sysfs_path_is_dir(path)) goto done; c = strrchr(path, '/'); *(c+1) = '\0'; } safestrcatmax(path, SYSFS_CLASS_NAME, len); safestrcatmax(path, "/", len); safestrcatmax(path, classname, len); done: safestrcatmax(path, "/", len); safestrcatmax(path, clsdev, len); return 0; }
/* If /sys/class/net/XXX/bridge exists then it must be a bridge */ static int isbridge(const struct sysfs_class_device *dev) { char path[SYSFS_PATH_MAX]; snprintf(path, sizeof(path), "%s/bridge", dev->path); return !sysfs_path_is_dir(path); }
/** * read_dir_subdirs: grabs subdirs in a specific directory * @sysdir: sysfs directory to read * returns list of directory names with success and NULL with error. */ struct sysfs_device *sysfs_read_dir_subdirs(const char *path) { DIR *dir = NULL; struct dirent *dirent = NULL; char file_path[SYSFS_PATH_MAX]; struct sysfs_device *dev = NULL; if (!path) { errno = EINVAL; return NULL; } dev = sysfs_open_device_path(path); dir = opendir(path); if (!dir) { dprintf("Error opening directory %s\n", path); return NULL; } while ((dirent = readdir(dir)) != NULL) { if (0 == strcmp(dirent->d_name, ".")) continue; if (0 == strcmp(dirent->d_name, "..")) continue; memset(file_path, 0, SYSFS_PATH_MAX); safestrcpy(file_path, path); safestrcat(file_path, "/"); safestrcat(file_path, dirent->d_name); if (!sysfs_path_is_dir(file_path)) add_subdirectory(dev, file_path); } closedir(dir); return dev; }
/* * Get bridge parameters using either sysfs or old * ioctl. */ static int br_get_bridge_info(const char *bridge, struct bridge_info *info) { #ifdef HAVE_LIBSYSFS struct sysfs_class_device *dev; char path[SYSFS_PATH_MAX]; if (!br_class_net) goto fallback; dev = sysfs_get_class_device(br_class_net, bridge); if (!dev) { dprintf("get_class_device '%s' failed\n", bridge); goto fallback; } snprintf(path, SYSFS_PATH_MAX, "%s/bridge", dev->path); if (sysfs_path_is_dir(path)) { dprintf("path '%s' is not a directory\n", path); sysfs_close_class_device(dev); goto fallback; } memset(info, 0, sizeof(*info)); fetch_id(dev, BRIDGEATTR("root_id"), &info->designated_root); fetch_id(dev, BRIDGEATTR("bridge_id"), &info->bridge_id); info->root_path_cost = fetch_int(dev, BRIDGEATTR("root_path_cost")); fetch_tv(dev, BRIDGEATTR("max_age"), &info->max_age); fetch_tv(dev, BRIDGEATTR("hello_time"), &info->hello_time); fetch_tv(dev, BRIDGEATTR("forward_delay"), &info->forward_delay); fetch_tv(dev, BRIDGEATTR("max_age"), &info->bridge_max_age); fetch_tv(dev, BRIDGEATTR("hello_time"), &info->bridge_hello_time); fetch_tv(dev, BRIDGEATTR("forward_delay"), &info->bridge_forward_delay); fetch_tv(dev, BRIDGEATTR("ageing_time"), &info->ageing_time); fetch_tv(dev, BRIDGEATTR("hello_timer"), &info->hello_timer_value); fetch_tv(dev, BRIDGEATTR("tcn_timer"), &info->tcn_timer_value); fetch_tv(dev, BRIDGEATTR("topology_change_timer"), &info->topology_change_timer_value);; fetch_tv(dev, BRIDGEATTR("gc_timer"), &info->gc_timer_value); info->root_port = fetch_int(dev, BRIDGEATTR("root_port")); info->stp_enabled = fetch_int(dev, BRIDGEATTR("stp_state")); info->topology_change = fetch_int(dev, BRIDGEATTR("topology_change")); info->topology_change_detected = fetch_int(dev, BRIDGEATTR ("topology_change_detected")); sysfs_close_class_device(dev); return 0; fallback: #endif return old_get_bridge_info(bridge, info); }
/** * sysfs_open_class_device_path: Opens and populates class device * @path: path to class device. * returns struct sysfs_class_device with success and NULL with error. */ struct sysfs_class_device *sysfs_open_class_device_path(const char *path) { struct sysfs_class_device *cdev; char temp_path[SYSFS_PATH_MAX]; if (!path) { errno = EINVAL; return NULL; } /* * Post linux-2.6.14 driver model supports nested classes with * links to the nested hierarchy at /sys/class/xxx/. Check for * a link to the actual class device if a directory isn't found */ if (sysfs_path_is_dir(path)) { dprintf("%s: Directory not found, checking for a link\n", path); if (!sysfs_path_is_link(path)) { if (sysfs_get_link(path, temp_path, SYSFS_PATH_MAX)) { dprintf("Error retrieving link at %s\n", path); return NULL; } } else { dprintf("%s is not a valid class device path\n", path); return NULL; } } else safestrcpy(temp_path, path); cdev = alloc_class_device(); if (!cdev) { dprintf("calloc failed\n"); return NULL; } if (sysfs_get_name_from_path(temp_path, cdev->name, SYSFS_NAME_LEN)) { errno = EINVAL; dprintf("Error getting class device name\n"); sysfs_close_class_device(cdev); return NULL; } safestrcpy(cdev->path, temp_path); if (sysfs_remove_trailing_slash(cdev->path)) { dprintf("Invalid path to class device %s\n", cdev->path); sysfs_close_class_device(cdev); return NULL; } set_classdev_classname(cdev); return cdev; }
/** * read_dir_subdirs: grabs subdirs in a specific directory * @sysdir: sysfs directory to read * returns list of directory names with success and NULL with error. */ struct dlist *read_dir_subdirs(const char *path) { DIR *dir = NULL; struct dirent *dirent = NULL; char file_path[SYSFS_PATH_MAX], *dir_name; struct dlist *dirlist = NULL; if (!path) { errno = EINVAL; return NULL; } dir = opendir(path); if (!dir) { dprintf("Error opening directory %s\n", path); return NULL; } while ((dirent = readdir(dir)) != NULL) { if (0 == strcmp(dirent->d_name, ".")) continue; if (0 == strcmp(dirent->d_name, "..")) continue; memset(file_path, 0, SYSFS_PATH_MAX); safestrcpy(file_path, path); safestrcat(file_path, "/"); safestrcat(file_path, dirent->d_name); if (!sysfs_path_is_dir(file_path)) { if (!dirlist) { dirlist = dlist_new_with_delete (SYSFS_NAME_LEN, sysfs_del_name); if (!dirlist) { dprintf("Error creating list\n"); return NULL; } } dir_name = (char *)calloc(1, SYSFS_NAME_LEN); safestrcpymax(dir_name, dirent->d_name, SYSFS_NAME_LEN); dlist_unshift_sorted(dirlist, dir_name, sort_char); } } closedir(dir); return dirlist; }
/** * sysfs_open_bus: opens specific bus and all its devices on system * returns sysfs_bus structure with success or NULL with error. */ struct sysfs_bus *sysfs_open_bus(const char *name) { struct sysfs_bus *bus; char buspath[SYSFS_PATH_MAX]; if (!name) { errno = EINVAL; return NULL; } memset(buspath, 0, SYSFS_PATH_MAX); if (sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX)) { dprintf("Sysfs not supported on this system\n"); return NULL; } safestrcat(buspath, "/"); safestrcat(buspath, SYSFS_BUS_NAME); safestrcat(buspath, "/"); safestrcat(buspath, name); if (sysfs_path_is_dir(buspath)) { dprintf("Invalid path to bus: %s\n", buspath); return NULL; } bus = alloc_bus(); if (!bus) { dprintf("calloc failed\n"); return NULL; } safestrcpy(bus->name, name); safestrcpy(bus->path, buspath); if (sysfs_remove_trailing_slash(bus->path)) { dprintf("Incorrect path to bus %s\n", bus->path); sysfs_close_bus(bus); return NULL; } return bus; }
/** * sysfs_open_driver_path: opens and initializes driver structure * @path: path to driver directory * returns struct sysfs_driver with success and NULL with error */ struct sysfs_driver *sysfs_open_driver_path(const char *path) { struct sysfs_driver *driver = NULL; if (!path) { errno = EINVAL; return NULL; } if (sysfs_path_is_dir(path)) { dprintf("Invalid path to driver: %s\n", path); return NULL; } driver = alloc_driver(); if (!driver) { dprintf("Error allocating driver at %s\n", path); return NULL; } if (sysfs_get_name_from_path(path, driver->name, SYSFS_NAME_LEN)) { dprintf("Error getting driver name from path\n"); free(driver); return NULL; } safestrcpy(driver->path, path); if (sysfs_remove_trailing_slash(driver->path)) { dprintf("Invalid path to driver %s\n", driver->path); sysfs_close_driver(driver); return NULL; } if (get_driver_bus(driver)) { dprintf("Could not get the bus driver is on\n"); sysfs_close_driver(driver); return NULL; } return driver; }