/* * sysfs.c * Utility functions for reading and writing sysfs properties and otherwise * interacting with the /sys filesystem. * * Copyright (C) 2009 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author(s): David Cantrell */ #include #include #include #include #include "sysfs.h" /* * ARCH: all * Read the value of the specified property and return to the caller. The * variable arguments are joined in to the sysfs path to read. The caller * is responsible for freeing the returned value. */ gchar *read_sysfs_property(gchar *path, ...) { gchar *arg = NULL; va_list ap; gchar *value = NULL; gsize len = 0; GString *tmp = NULL; GError *e = NULL; if (path == NULL) { return NULL; } tmp = g_string_new(path); va_start(ap, path); /* join the variable arguments in to a path specification */ while ((arg = va_arg(ap, char *)) != NULL) { if (g_str_has_suffix(tmp->str, "/")) { if (g_str_has_prefix(arg, "/")) { while (*arg != '/' && arg != '\0') { arg++; } } else { g_string_append_printf(tmp, "/"); } g_string_append_printf(tmp, arg); } else if (g_str_has_prefix(arg, "/")) { g_string_append_printf(tmp, arg); } else { g_string_append_printf(tmp, "/%s", arg); } } va_end(ap); if (!g_file_get_contents(tmp->str, &value, &len, &e)) { g_string_free(tmp, TRUE); return NULL; } g_string_free(tmp, TRUE); return value; } /* * ARCH: all * Write specified value to the given sysfs path. The sysfs path is * constructed from all of the arguments following the first one. The * first argument is the value to write. All variadic arguments must be * strings. */ gboolean write_sysfs_property(gchar *value, ...) { gchar *arg = NULL; va_list ap; GString *tmp = g_string_new(NULL); GError *e = NULL; va_start(ap, value); while ((arg = va_arg(ap, char *)) != NULL) { if (tmp->len == 0) { g_string_append_printf(tmp, arg); } else if (g_str_has_suffix(tmp->str, "/")) { if (g_str_has_prefix(arg, "/")) { while (*arg != '/' && arg != '\0') { arg++; } } else { g_string_append_printf(tmp, "/"); } g_string_append_printf(tmp, arg); } else if (g_str_has_prefix(arg, "/")) { g_string_append_printf(tmp, arg); } else { g_string_append_printf(tmp, "/%s", arg); } } va_end(ap); if (!g_file_set_contents(tmp->str, value, -1, &e)) { g_string_free(tmp, TRUE); return FALSE; } g_string_free(tmp, TRUE); return TRUE; } /* * ARCH: all * Given a path and a bus component, look for that bus component in the * subdirectories of the specified path, return the fully composed bus * path. Caller is responsible for freeing the returned path. */ gchar *sysfs_find_bus_by_component(gchar *root, gchar *component) { gchar *ret = NULL; const gchar *dir = NULL; GDir *dirs = NULL; GError *e = NULL; GString *tmp = NULL; if (root == NULL || component == NULL || sysfs_path_is_dir(root)) { return NULL; } if ((dirs = g_dir_open(root, 0, &e)) == NULL) { fprintf(stderr, "*** error opening %s: %s\n", root, e->message); return NULL; } tmp = g_string_new(NULL); while ((dir = g_dir_read_name(dirs)) != NULL) { g_string_printf(tmp, "%s/%s/%s", root, dir, component); if (!sysfs_path_is_dir(tmp->str)) { ret = g_strdup(tmp->str); break; } } g_dir_close(dirs); g_string_free(tmp, TRUE); return ret; }