/*
* 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;
}