aboutsummaryrefslogtreecommitdiff
path: root/hardinfo
diff options
context:
space:
mode:
Diffstat (limited to 'hardinfo')
-rw-r--r--hardinfo/binreloc.c668
-rw-r--r--hardinfo/expr.c250
-rw-r--r--hardinfo/hardinfo.c158
-rw-r--r--hardinfo/socket.c127
-rw-r--r--hardinfo/util.c1404
-rw-r--r--hardinfo/vendor.c195
6 files changed, 2802 insertions, 0 deletions
diff --git a/hardinfo/binreloc.c b/hardinfo/binreloc.c
new file mode 100644
index 00000000..f47a3fae
--- /dev/null
+++ b/hardinfo/binreloc.c
@@ -0,0 +1,668 @@
+/*
+ * BinReloc - a library for creating relocatable executables
+ * Written by: Hongli Lai <h.lai@chello.nl>
+ * http://autopackage.org/
+ *
+ * This source code is public domain. You can relicense this code
+ * under whatever license you want.
+ *
+ * See http://autopackage.org/docs/binreloc/ for
+ * more information and how to use this.
+ */
+
+#ifndef __BINRELOC_C__
+#define __BINRELOC_C__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "binreloc.h"
+#include "config.h"
+
+G_BEGIN_DECLS
+/** @internal
+ * Find the canonical filename of the executable. Returns the filename
+ * (which must be freed) or NULL on error. If the parameter 'error' is
+ * not NULL, the error code will be stored there, if an error occured.
+ */
+static char *_br_find_exe(GbrInitError * error)
+{
+ char *path, *path2, *line, *result;
+ size_t buf_size;
+ ssize_t size;
+ struct stat stat_buf;
+ FILE *f;
+
+ /* Read from /proc/self/exe (symlink) */
+ if (sizeof(path) > SSIZE_MAX)
+ buf_size = SSIZE_MAX - 1;
+ else
+ buf_size = PATH_MAX - 1;
+ path = (char *) g_try_malloc(buf_size);
+ if (path == NULL) {
+ /* Cannot allocate memory. */
+ if (error)
+ *error = GBR_INIT_ERROR_NOMEM;
+ return NULL;
+ }
+ path2 = (char *) g_try_malloc(buf_size);
+ if (path2 == NULL) {
+ /* Cannot allocate memory. */
+ if (error)
+ *error = GBR_INIT_ERROR_NOMEM;
+ g_free(path);
+ return NULL;
+ }
+
+ strncpy(path2, "/proc/self/exe", buf_size - 1);
+
+ while (1) {
+ int i;
+
+ size = readlink(path2, path, buf_size - 1);
+ if (size == -1) {
+ /* Error. */
+ g_free(path2);
+ break;
+ }
+
+ /* readlink() success. */
+ path[size] = '\0';
+
+ /* Check whether the symlink's target is also a symlink.
+ * We want to get the final target. */
+ i = stat(path, &stat_buf);
+ if (i == -1) {
+ /* Error. */
+ g_free(path2);
+ break;
+ }
+
+ /* stat() success. */
+ if (!S_ISLNK(stat_buf.st_mode)) {
+ /* path is not a symlink. Done. */
+ g_free(path2);
+ return path;
+ }
+
+ /* path is a symlink. Continue loop and resolve this. */
+ strncpy(path, path2, buf_size - 1);
+ }
+
+
+ /* readlink() or stat() failed; this can happen when the program is
+ * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
+
+ buf_size = PATH_MAX + 128;
+ line = (char *) g_try_realloc(path, buf_size);
+ if (line == NULL) {
+ /* Cannot allocate memory. */
+ g_free(path);
+ if (error)
+ *error = GBR_INIT_ERROR_NOMEM;
+ return NULL;
+ }
+
+ f = fopen("/proc/self/maps", "r");
+ if (f == NULL) {
+ g_free(line);
+ if (error)
+ *error = GBR_INIT_ERROR_OPEN_MAPS;
+ return NULL;
+ }
+
+ /* The first entry should be the executable name. */
+ result = fgets(line, (int) buf_size, f);
+ if (result == NULL) {
+ fclose(f);
+ g_free(line);
+ if (error)
+ *error = GBR_INIT_ERROR_READ_MAPS;
+ return NULL;
+ }
+
+ /* Get rid of newline character. */
+ buf_size = strlen(line);
+ if (buf_size <= 0) {
+ /* Huh? An empty string? */
+ fclose(f);
+ g_free(line);
+ if (error)
+ *error = GBR_INIT_ERROR_INVALID_MAPS;
+ return NULL;
+ }
+ if (line[buf_size - 1] == 10)
+ line[buf_size - 1] = 0;
+
+ /* Extract the filename; it is always an absolute path. */
+ path = strchr(line, '/');
+
+ /* Sanity check. */
+ if (strstr(line, " r-xp ") == NULL || path == NULL) {
+ fclose(f);
+ g_free(line);
+ if (error)
+ *error = GBR_INIT_ERROR_INVALID_MAPS;
+ return NULL;
+ }
+
+ path = g_strdup(path);
+ g_free(line);
+ fclose(f);
+ return path;
+}
+
+
+/** @internal
+ * Find the canonical filename of the executable which owns symbol.
+ * Returns a filename which must be freed, or NULL on error.
+ */
+static char *_br_find_exe_for_symbol(const void *symbol,
+ GbrInitError * error)
+{
+#define SIZE PATH_MAX + 100
+ FILE *f;
+ size_t address_string_len;
+ char *address_string, line[SIZE], *found;
+
+ if (symbol == NULL)
+ return (char *) NULL;
+
+ f = fopen("/proc/self/maps", "r");
+ if (f == NULL)
+ return (char *) NULL;
+
+ address_string_len = 4;
+ address_string = (char *) g_try_malloc(address_string_len);
+ found = (char *) NULL;
+
+ while (!feof(f)) {
+ char *start_addr, *end_addr, *end_addr_end, *file;
+ void *start_addr_p, *end_addr_p;
+ size_t len;
+
+ if (fgets(line, SIZE, f) == NULL)
+ break;
+
+ /* Sanity check. */
+ if (strstr(line, " r-xp ") == NULL || strchr(line, '/') == NULL)
+ continue;
+
+ /* Parse line. */
+ start_addr = line;
+ end_addr = strchr(line, '-');
+ file = strchr(line, '/');
+
+ /* More sanity check. */
+ if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
+ continue;
+
+ end_addr[0] = '\0';
+ end_addr++;
+ end_addr_end = strchr(end_addr, ' ');
+ if (end_addr_end == NULL)
+ continue;
+
+ end_addr_end[0] = '\0';
+ len = strlen(file);
+ if (len == 0)
+ continue;
+ if (file[len - 1] == '\n')
+ file[len - 1] = '\0';
+
+ /* Get rid of "(deleted)" from the filename. */
+ len = strlen(file);
+ if (len > 10 && strcmp(file + len - 10, " (deleted)") == 0)
+ file[len - 10] = '\0';
+
+ /* I don't know whether this can happen but better safe than sorry. */
+ len = strlen(start_addr);
+ if (len != strlen(end_addr))
+ continue;
+
+
+ /* Transform the addresses into a string in the form of 0xdeadbeef,
+ * then transform that into a pointer. */
+ if (address_string_len < len + 3) {
+ address_string_len = len + 3;
+ address_string =
+ (char *) g_try_realloc(address_string, address_string_len);
+ }
+
+ memcpy(address_string, "0x", 2);
+ memcpy(address_string + 2, start_addr, len);
+ address_string[2 + len] = '\0';
+ sscanf(address_string, "%p", &start_addr_p);
+
+ memcpy(address_string, "0x", 2);
+ memcpy(address_string + 2, end_addr, len);
+ address_string[2 + len] = '\0';
+ sscanf(address_string, "%p", &end_addr_p);
+
+
+ if (symbol >= start_addr_p && symbol < end_addr_p) {
+ found = file;
+ break;
+ }
+ }
+
+ g_free(address_string);
+ fclose(f);
+
+ if (found == NULL)
+ return (char *) NULL;
+ else
+ return g_strdup(found);
+}
+
+
+static gchar *exe = NULL;
+
+static void set_gerror(GError ** error, GbrInitError errcode);
+
+
+/** Initialize the BinReloc library (for applications).
+ *
+ * This function must be called before using any other BinReloc functions.
+ * It attempts to locate the application's canonical filename.
+ *
+ * @note If you want to use BinReloc for a library, then you should call
+ * gbr_init_lib() instead.
+ *
+ * @param error If BinReloc failed to initialize, then the error report will
+ * be stored in this variable. Set to NULL if you don't want an
+ * error report. See the #GbrInitError for a list of error
+ * codes.
+ *
+ * @returns TRUE on success, FALSE if BinReloc failed to initialize.
+ */
+gboolean gbr_init(GError ** error)
+{
+ GbrInitError errcode = 0;
+
+ /* Locate the application's filename. */
+ exe = _br_find_exe(&errcode);
+ if (exe != NULL)
+ /* Success! */
+ return TRUE;
+ else {
+ /* Failed :-( */
+ set_gerror(error, errcode);
+ return FALSE;
+ }
+}
+
+
+/** Initialize the BinReloc library (for libraries).
+ *
+ * This function must be called before using any other BinReloc functions.
+ * It attempts to locate the calling library's canonical filename.
+ *
+ * @note The BinReloc source code MUST be included in your library, or this
+ * function won't work correctly.
+ *
+ * @returns TRUE on success, FALSE if a filename cannot be found.
+ */
+gboolean gbr_init_lib(GError ** error)
+{
+ GbrInitError errcode = 0;
+
+ exe = _br_find_exe_for_symbol((const void *) "", &errcode);
+ if (exe != NULL)
+ /* Success! */
+ return TRUE;
+ else {
+ /* Failed :-( */
+ set_gerror(error, errcode);
+ return exe != NULL;
+ }
+}
+
+
+static void set_gerror(GError ** error, GbrInitError errcode)
+{
+ gchar *error_message;
+
+ if (error == NULL)
+ return;
+
+ switch (errcode) {
+ case GBR_INIT_ERROR_NOMEM:
+ error_message = "Cannot allocate memory.";
+ break;
+ case GBR_INIT_ERROR_OPEN_MAPS:
+ error_message = "Unable to open /proc/self/maps for reading.";
+ break;
+ case GBR_INIT_ERROR_READ_MAPS:
+ error_message = "Unable to read from /proc/self/maps.";
+ break;
+ case GBR_INIT_ERROR_INVALID_MAPS:
+ error_message = "The file format of /proc/self/maps is invalid.";
+ break;
+ case GBR_INIT_ERROR_DISABLED:
+ error_message = "Binary relocation support is disabled.";
+ break;
+ default:
+ error_message = "Unknown error.";
+ break;
+ };
+ g_set_error(error, g_quark_from_static_string("GBinReloc"),
+ errcode, "%s", error_message);
+}
+
+
+/** Find the canonical filename of the current application.
+ *
+ * @param default_exe A default filename which will be used as fallback.
+ * @returns A string containing the application's canonical filename,
+ * which must be freed when no longer necessary. If BinReloc is
+ * not initialized, or if the initialization function failed,
+ * then a copy of default_exe will be returned. If default_exe
+ * is NULL, then NULL will be returned.
+ */
+gchar *gbr_find_exe(const gchar * default_exe)
+{
+ if (exe == NULL) {
+ /* BinReloc is not initialized. */
+ if (default_exe != NULL)
+ return g_strdup(default_exe);
+ else
+ return NULL;
+ }
+ return g_strdup(exe);
+}
+
+
+/** Locate the directory in which the current application is installed.
+ *
+ * The prefix is generated by the following pseudo-code evaluation:
+ * \code
+ * dirname(exename)
+ * \endcode
+ *
+ * @param default_dir A default directory which will used as fallback.
+ * @return A string containing the directory, which must be freed when no
+ * longer necessary. If BinReloc is not initialized, or if the
+ * initialization function failed, then a copy of default_dir
+ * will be returned. If default_dir is NULL, then NULL will be
+ * returned.
+ */
+gchar *gbr_find_exe_dir(const gchar * default_dir)
+{
+ if (exe == NULL) {
+ /* BinReloc not initialized. */
+ if (default_dir != NULL)
+ return g_strdup(default_dir);
+ else
+ return NULL;
+ }
+
+ return g_path_get_dirname(exe);
+}
+
+
+/** Locate the prefix in which the current application is installed.
+ *
+ * The prefix is generated by the following pseudo-code evaluation:
+ * \code
+ * dirname(dirname(exename))
+ * \endcode
+ *
+ * @param default_prefix A default prefix which will used as fallback.
+ * @return A string containing the prefix, which must be freed when no
+ * longer necessary. If BinReloc is not initialized, or if the
+ * initialization function failed, then a copy of default_prefix
+ * will be returned. If default_prefix is NULL, then NULL will be
+ * returned.
+ */
+gchar *gbr_find_prefix(const gchar * default_prefix)
+{
+ gchar *dir1, *dir2;
+
+ if (exe == NULL) {
+ /* BinReloc not initialized. */
+ if (default_prefix != NULL)
+ return g_strdup(default_prefix);
+ else
+ return NULL;
+ }
+
+ dir1 = g_path_get_dirname(exe);
+ dir2 = g_path_get_dirname(dir1);
+ g_free(dir1);
+ return dir2;
+}
+
+
+/** Locate the application's binary folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/bin"
+ * \endcode
+ *
+ * @param default_bin_dir A default path which will used as fallback.
+ * @return A string containing the bin folder's path, which must be freed when
+ * no longer necessary. If BinReloc is not initialized, or if the
+ * initialization function failed, then a copy of default_bin_dir will
+ * be returned. If default_bin_dir is NULL, then NULL will be returned.
+ */
+gchar *gbr_find_bin_dir(const gchar * default_bin_dir)
+{
+ gchar *prefix, *dir;
+
+ prefix = gbr_find_prefix(NULL);
+ if (prefix == NULL) {
+ /* BinReloc not initialized. */
+ if (default_bin_dir != NULL)
+ return g_strdup(default_bin_dir);
+ else
+ return NULL;
+ }
+
+ dir = g_build_filename(prefix, "bin", NULL);
+ g_free(prefix);
+ return dir;
+}
+
+
+/** Locate the application's superuser binary folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/sbin"
+ * \endcode
+ *
+ * @param default_sbin_dir A default path which will used as fallback.
+ * @return A string containing the sbin folder's path, which must be freed when
+ * no longer necessary. If BinReloc is not initialized, or if the
+ * initialization function failed, then a copy of default_sbin_dir will
+ * be returned. If default_bin_dir is NULL, then NULL will be returned.
+ */
+gchar *gbr_find_sbin_dir(const gchar * default_sbin_dir)
+{
+ gchar *prefix, *dir;
+
+ prefix = gbr_find_prefix(NULL);
+ if (prefix == NULL) {
+ /* BinReloc not initialized. */
+ if (default_sbin_dir != NULL)
+ return g_strdup(default_sbin_dir);
+ else
+ return NULL;
+ }
+
+ dir = g_build_filename(prefix, "sbin", NULL);
+ g_free(prefix);
+ return dir;
+}
+
+
+/** Locate the application's data folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/share"
+ * \endcode
+ *
+ * @param default_data_dir A default path which will used as fallback.
+ * @return A string containing the data folder's path, which must be freed when
+ * no longer necessary. If BinReloc is not initialized, or if the
+ * initialization function failed, then a copy of default_data_dir
+ * will be returned. If default_data_dir is NULL, then NULL will be
+ * returned.
+ */
+gchar *gbr_find_data_dir(const gchar * default_data_dir)
+{
+ gchar *prefix, *dir;
+
+ prefix = gbr_find_prefix(NULL);
+ if (prefix == NULL) {
+ /* BinReloc not initialized. */
+ if (default_data_dir != NULL)
+ return g_strdup(default_data_dir);
+ else
+ return NULL;
+ }
+
+ dir = g_build_filename(prefix, "share", NULL);
+ g_free(prefix);
+ return dir;
+}
+
+
+/** Locate the application's localization folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/share/locale"
+ * \endcode
+ *
+ * @param default_locale_dir A default path which will used as fallback.
+ * @return A string containing the localization folder's path, which must be freed when
+ * no longer necessary. If BinReloc is not initialized, or if the
+ * initialization function failed, then a copy of default_locale_dir will be returned.
+ * If default_locale_dir is NULL, then NULL will be returned.
+ */
+gchar *gbr_find_locale_dir(const gchar * default_locale_dir)
+{
+ gchar *data_dir, *dir;
+
+ data_dir = gbr_find_data_dir(NULL);
+ if (data_dir == NULL) {
+ /* BinReloc not initialized. */
+ if (default_locale_dir != NULL)
+ return g_strdup(default_locale_dir);
+ else
+ return NULL;
+ }
+
+ dir = g_build_filename(data_dir, "locale", NULL);
+ g_free(data_dir);
+ return dir;
+}
+
+
+/** Locate the application's library folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/lib"
+ * \endcode
+ *
+ * @param default_lib_dir A default path which will used as fallback.
+ * @return A string containing the library folder's path, which must be freed when
+ * no longer necessary. If BinReloc is not initialized, or if the
+ * initialization function failed, then a copy of default_lib_dir will be returned.
+ * If default_lib_dir is NULL, then NULL will be returned.
+ */
+gchar *gbr_find_lib_dir(const gchar * default_lib_dir)
+{
+ gchar *prefix, *dir;
+
+ prefix = gbr_find_prefix(NULL);
+ if (prefix == NULL) {
+ /* BinReloc not initialized. */
+ if (default_lib_dir != NULL)
+ return g_strdup(default_lib_dir);
+ else
+ return NULL;
+ }
+
+ dir = g_build_filename(prefix, LIBDIR, NULL);
+
+ g_free(prefix);
+ return dir;
+}
+
+
+/** Locate the application's libexec folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/libexec"
+ * \endcode
+ *
+ * @param default_libexec_dir A default path which will used as fallback.
+ * @return A string containing the libexec folder's path, which must be freed when
+ * no longer necessary. If BinReloc is not initialized, or if the initialization
+ * function failed, then a copy of default_libexec_dir will be returned.
+ * If default_libexec_dir is NULL, then NULL will be returned.
+ */
+gchar *gbr_find_libexec_dir(const gchar * default_libexec_dir)
+{
+ gchar *prefix, *dir;
+
+ prefix = gbr_find_prefix(NULL);
+ if (prefix == NULL) {
+ /* BinReloc not initialized. */
+ if (default_libexec_dir != NULL)
+ return g_strdup(default_libexec_dir);
+ else
+ return NULL;
+ }
+
+ dir = g_build_filename(prefix, "libexec", NULL);
+ g_free(prefix);
+ return dir;
+}
+
+
+/** Locate the application's configuration files folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/etc"
+ * \endcode
+ *
+ * @param default_etc_dir A default path which will used as fallback.
+ * @return A string containing the etc folder's path, which must be freed when
+ * no longer necessary. If BinReloc is not initialized, or if the initialization
+ * function failed, then a copy of default_etc_dir will be returned.
+ * If default_etc_dir is NULL, then NULL will be returned.
+ */
+gchar *gbr_find_etc_dir(const gchar * default_etc_dir)
+{
+ gchar *prefix, *dir;
+
+ prefix = gbr_find_prefix(NULL);
+ if (prefix == NULL) {
+ /* BinReloc not initialized. */
+ if (default_etc_dir != NULL)
+ return g_strdup(default_etc_dir);
+ else
+ return NULL;
+ }
+
+ dir = g_build_filename(prefix, "etc", NULL);
+ g_free(prefix);
+ return dir;
+}
+
+
+G_END_DECLS
+#endif /* __BINRELOC_C__ */
diff --git a/hardinfo/expr.c b/hardinfo/expr.c
new file mode 100644
index 00000000..32e303d7
--- /dev/null
+++ b/hardinfo/expr.c
@@ -0,0 +1,250 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * 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, version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * This is only used to compute sensor values, hence the only variable supported is '@'.
+ * The '`' operator (ln(x)) is not available, nor multi-line formulas.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "expr.h"
+#include "config.h"
+
+static MathToken *new_operator(gchar op)
+{
+ MathToken *t = g_new0(MathToken, 1);
+
+ t->val.op = op;
+ t->type = TOKEN_OPERATOR; /* operator */
+
+ return t;
+}
+
+static MathToken *new_variable(gchar var)
+{
+ MathToken *t = g_new0(MathToken, 1);
+
+ t->val.op = '@';
+ t->type = TOKEN_VARIABLE; /* variable */
+
+ return t;
+}
+
+static MathToken *new_value(gfloat value)
+{
+ MathToken *t = g_new0(MathToken, 1);
+
+ t->val.value = value;
+ t->type = TOKEN_VALUE; /* value */
+
+ return t;
+}
+
+static inline gint priority(char operation)
+{
+ switch (operation) {
+ case '^':
+ return 3;
+ case '*':
+ case '/':
+ return 2;
+ case '+':
+ case '-':
+ return 1;
+ case '(':
+ return 0;
+ }
+
+ return 0;
+}
+
+GSList *math_infix_to_postfix(GSList * infix)
+{
+ MathToken *stack[500];
+ gint t_sp = 0;
+
+ GSList *postfix = NULL, *p;
+ MathToken *top;
+
+ for (p = infix; p; p = p->next) {
+ MathToken *t = (MathToken *) p->data;
+
+ if (t->type == TOKEN_OPERATOR && t->val.op == '(') {
+ stack[++t_sp] = t;
+ } else if (t->type == TOKEN_OPERATOR && t->val.op == ')') {
+ for (top = stack[t_sp]; t_sp != 0 && top->val.op != '(';
+ top = stack[t_sp]) {
+ postfix = g_slist_append(postfix, stack[t_sp--]);
+ }
+ t_sp--;
+ } else if (t->type != TOKEN_OPERATOR) {
+ postfix = g_slist_append(postfix, t);
+ } else if (t_sp == 0) {
+ stack[++t_sp] = t;
+ } else {
+ while (t_sp != 0
+ && priority(t->val.op) <= priority(stack[t_sp]->val.op))
+ postfix = g_slist_append(postfix, stack[t_sp--]);
+ stack[++t_sp] = t;
+ }
+ }
+
+ while (t_sp)
+ postfix = g_slist_append(postfix, stack[t_sp--]);
+
+ return postfix;
+}
+
+static inline gfloat __result(gfloat op1, gfloat op2, gchar operation)
+{
+ switch (operation) {
+ case '^':
+ return powf(op1, op2);
+ case '+':
+ return op1 + op2;
+ case '-':
+ return op1 - op2;
+ case '/':
+ return op1 / op2;
+ case '*':
+ return op1 * op2;
+ }
+
+ return 0;
+}
+
+gfloat math_postfix_eval(GSList * postfix, gfloat at_value)
+{
+ GSList *p;
+ gfloat stack[500];
+ gint sp = 0;
+
+ memset(stack, 0, sizeof(gfloat) * 500);
+
+ for (p = postfix; p; p = p->next) {
+ MathToken *t = (MathToken *) p->data;
+
+ if (t->type == TOKEN_VARIABLE) {
+ stack[++sp] = at_value;
+ } else if (t->type == TOKEN_VALUE) {
+ stack[++sp] = t->val.value;
+ } else {
+ gfloat op1, op2;
+
+ op2 = stack[sp--];
+ op1 = stack[sp];
+
+ stack[sp] = __result(op1, op2, t->val.op);
+ }
+ }
+
+ return stack[sp];
+}
+
+GSList *math_string_to_infix(gchar * string)
+{
+ GSList *infix = NULL;
+ gchar *expr = string;
+
+ for (; *expr; expr++) {
+ if (strchr("+-/*^()", *expr)) {
+ infix = g_slist_append(infix, new_operator(*expr));
+ } else if (strchr("@", *expr)) {
+ infix = g_slist_append(infix, new_variable(*expr));
+ } else if (strchr("-.1234567890", *expr)) {
+ gchar value[32], *v = value;
+ gfloat floatval;
+
+ do {
+ *v++ = *expr++;
+ } while (*expr && strchr("-.1234567890", *expr));
+ expr--;
+ *v = '\0';
+
+ sscanf(value, "%f", &floatval);
+
+ infix = g_slist_append(infix, new_value(floatval));
+ } else if (!isspace(*expr)) {
+ g_print("Invalid token: [%c][%d]\n", *expr, *expr);
+ math_infix_free(infix, TRUE);
+ return NULL;
+ }
+ }
+
+ return infix;
+}
+
+void math_infix_free(GSList * infix, gboolean free_tokens)
+{
+ GSList *p;
+
+ if (!free_tokens)
+ for (p = infix; p; p = g_slist_delete_link(p, p));
+ else
+ for (p = infix; p; p = g_slist_delete_link(p, p)) {
+ MathToken *t = (MathToken *) p->data;
+ g_free(t);
+ }
+}
+
+GSList *math_string_to_postfix(gchar * string)
+{
+ GSList *infix;
+ GSList *postfix;
+
+ infix = math_string_to_infix(string);
+ if (!infix)
+ return NULL;
+
+ postfix = math_infix_to_postfix(infix);
+ math_infix_free(infix, FALSE);
+
+ return postfix;
+}
+
+gfloat math_string_eval(gchar * string, gfloat at_value)
+{
+ GSList *postfix;
+ gfloat val;
+
+ postfix = math_string_to_postfix(string);
+ val = math_postfix_eval(postfix, at_value);
+ math_postfix_free(postfix, TRUE);
+
+ return val;
+}
+
+#ifdef MATH_TEST
+int main(void)
+{
+ GSList *postfix;
+
+ gchar *expr = "0.9*(@+(5.2*0.923+3*(2.0)))";
+
+ postfix = math_string_to_postfix(expr);
+ g_print("%s = %f (must be 18.71964)\n", expr,
+ math_postfix_eval(postfix, 10));
+ math_postfix_free(postfix, TRUE);
+
+ return 0;
+}
+#endif
diff --git a/hardinfo/hardinfo.c b/hardinfo/hardinfo.c
new file mode 100644
index 00000000..4a38fe1a
--- /dev/null
+++ b/hardinfo/hardinfo.c
@@ -0,0 +1,158 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * 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, version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <shell.h>
+
+#include <report.h>
+#include <hardinfo.h>
+#include <iconcache.h>
+#include <stock.h>
+#include <vendor.h>
+
+#include <binreloc.h>
+
+ProgramParameters params = { 0 };
+
+int main(int argc, char **argv)
+{
+ GSList *modules;
+
+ bindtextdomain("hardinfo", "/usr/share/locale");
+ textdomain("hardinfo");
+
+ DEBUG("HardInfo version " VERSION ". Debug version.");
+
+ /* parse all command line parameters */
+ parameters_init(&argc, &argv, &params);
+
+ /* show version information and quit */
+ if (params.show_version) {
+ g_print("HardInfo version " VERSION "\n");
+ g_print
+ (_("Copyright (C) 2003-2009 Leandro A. F. Pereira. See COPYING for details.\n\n"));
+
+ g_print(_("Compile-time options:\n"
+ " Release version: %s (%s)\n"
+ " BinReloc enabled: %s\n"
+ " Data prefix: %s\n"
+ " Library prefix: %s\n"
+ " Compiled on: %s %s (%s)\n"),
+ RELEASE ? _("Yes") : "No (" VERSION ")", ARCH,
+ ENABLE_BINRELOC ? _("Yes") : _("No"),
+ PREFIX, LIBPREFIX, PLATFORM, KERNEL, HOSTNAME);
+
+ DEBUG(" Debugging is enabled.");
+
+ /* show also available modules */
+ params.list_modules = TRUE;
+ }
+
+ /* initialize the binreloc library, so we can load program data */
+ if (!binreloc_init(FALSE))
+ g_error(_("Failed to find runtime data.\n\n"
+ "\342\200\242 Is HardInfo correctly installed?\n"
+ "\342\200\242 See if %s and %s exists and you have read permision."),
+ PREFIX, LIBPREFIX);
+
+ /* list all module names */
+ if (params.list_modules) {
+ g_print(_("Modules:\n"
+ "%-20s%-15s%-12s\n"), _("File Name"), _("Name"), _("Version"));
+
+ for (modules = modules_load_all(); modules;
+ modules = modules->next) {
+ ShellModule *module = (ShellModule *) modules->data;
+ ModuleAbout *ma = module_get_about(module);
+ gchar *name = g_path_get_basename(g_module_name(module->dll));
+
+ g_print("%-20s%-15s%-12s\n", name, module->name, ma->version);
+
+ g_free(name);
+ }
+
+ return 0;
+ }
+
+ if (!params.create_report && !params.run_benchmark) {
+ /* we only try to open the UI if the user didn't ask for a report. */
+ params.gui_running = ui_init(&argc, &argv);
+
+ /* as a fallback, if GTK+ initialization failed, run in report
+ generation mode. */
+ if (!params.gui_running)
+ params.create_report = TRUE;
+ }
+
+ if (params.use_modules) {
+ /* load only selected modules */
+ DEBUG("loading user-selected modules");
+ modules = modules_load_selected();
+ } else {
+ /* load all modules */
+ DEBUG("loading all modules");
+ modules = modules_load_all();
+ }
+
+ /* initialize vendor database */
+ vendor_init();
+
+ /* initialize moreinfo */
+ moreinfo_init();
+
+ if (params.run_benchmark) {
+ gchar *result;
+
+ result = module_call_method_param("benchmark::runBenchmark", params.run_benchmark);
+ if (!result) {
+ g_error(_("Unknown benchmark ``%s'' or libbenchmark.so not loaded"), params.run_benchmark);
+ } else {
+ g_print("%s\n", result);
+ g_free(result);
+ }
+ } else if (params.gui_running) {
+ /* initialize gui and start gtk+ main loop */
+ icon_cache_init();
+ stock_icons_init();
+
+ shell_init(modules);
+
+ DEBUG("entering gtk+ main loop");
+
+ gtk_main();
+ } else if (params.create_report) {
+ /* generate report */
+ gchar *report;
+
+ DEBUG("generating report");
+
+ report = report_create_from_module_list_format(modules,
+ params.
+ report_format);
+ g_print("%s", report);
+
+ g_free(report);
+ } else {
+ g_error(_("Don't know what to do. Exiting."));
+ }
+
+ moreinfo_shutdown();
+
+ DEBUG("finished");
+ return 0;
+}
diff --git a/hardinfo/socket.c b/hardinfo/socket.c
new file mode 100644
index 00000000..40cb8e50
--- /dev/null
+++ b/hardinfo/socket.c
@@ -0,0 +1,127 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * 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, version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "socket.h"
+
+Socket *sock_connect(gchar * host, gint port)
+{
+ struct sockaddr_in server;
+ Socket *s;
+ int sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock > 0) {
+ memset(&server, 0, sizeof(server));
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = inet_addr(host);
+ server.sin_port = htons(port);
+
+ if (connect(sock, (struct sockaddr *) (void *) &server, sizeof(server)) < 0) {
+ goto cleanup;
+ }
+
+ s = g_new0(Socket, 1);
+ s->sock = sock;
+
+ return s;
+ }
+
+cleanup:
+ close(sock);
+
+ return NULL;
+}
+
+/* From: http://www.erlenstar.demon.co.uk/unix/faq_3.html#SEC26 */
+static inline int __sock_is_ready(Socket * s, int mode)
+{
+ int rc, fd = s->sock;
+ fd_set fds;
+ struct timeval tv;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = tv.tv_usec = 0;
+
+ if (mode == 0) {
+ /* read */
+ rc = select(fd + 1, &fds, NULL, NULL, &tv);
+ } else {
+ /* write */
+ rc = select(fd + 1, NULL, &fds, NULL, &tv);
+ }
+
+ if (rc < 0)
+ return -1;
+
+ return FD_ISSET(fd, &fds) ? 1 : 0;
+}
+
+int sock_ready_to_read(Socket * s)
+{
+ return __sock_is_ready(s, 0);
+}
+
+int sock_ready_to_write(Socket * s)
+{
+ return __sock_is_ready(s, 1);
+}
+
+int sock_read(Socket * s, gchar * buffer, gint size)
+{
+ if (size > 2 && sock_ready_to_read(s)) {
+ gint n;
+
+ n = read(s->sock, buffer, size - 1);
+ if (n > 0) {
+ buffer[n] = '\0';
+ } else {
+ return 0;
+ }
+
+ return n;
+ }
+
+ return 0;
+}
+
+int sock_write(Socket * s, gchar * str)
+{
+ while (!sock_ready_to_write(s));
+
+ return write(s->sock, str, strlen(str));
+}
+
+void sock_close(Socket * s)
+{
+ shutdown(s->sock, 2);
+ close(s->sock);
+ g_free(s);
+}
diff --git a/hardinfo/util.c b/hardinfo/util.c
new file mode 100644
index 00000000..40566eac
--- /dev/null
+++ b/hardinfo/util.c
@@ -0,0 +1,1404 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * 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, version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Functions h_strdup_cprintf and h_strconcat are based on GLib version 2.4.6
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <report.h>
+#include <string.h>
+#include <shell.h>
+#include <iconcache.h>
+#include <hardinfo.h>
+#include <gtk/gtk.h>
+
+#include <binreloc.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define KiB 1024
+#define MiB 1048576
+#define GiB 1073741824
+#define TiB 1099511627776
+#define PiB 1125899906842624
+
+static GSList *modules_list = NULL;
+
+void sync_manager_clear_entries(void);
+
+gchar *find_program(gchar *program_name)
+{
+ int i;
+ char *temp;
+ static GHashTable *cache = NULL;
+ const char *path[] = { "/usr/local/bin", "/usr/local/sbin",
+ "/usr/bin", "/usr/sbin",
+ "/bin", "/sbin",
+ NULL };
+
+ /* we don't need to call stat() every time: cache the results */
+ if (!cache) {
+ cache = g_hash_table_new(g_str_hash, g_str_equal);
+ } else if ((temp = g_hash_table_lookup(cache, program_name))) {
+ return g_strdup(temp);
+ }
+
+ for (i = 0; path[i]; i++) {
+ temp = g_build_filename(path[i], program_name, NULL);
+
+ if (g_file_test(temp, G_FILE_TEST_IS_EXECUTABLE)) {
+ g_hash_table_insert(cache, program_name, g_strdup(temp));
+ return temp;
+ }
+
+ g_free(temp);
+ }
+
+ /* our search has failed; use GLib's search (which uses $PATH env var) */
+ if ((temp = g_find_program_in_path(program_name))) {
+ g_hash_table_insert(cache, program_name, g_strdup(temp));
+ return temp;
+ }
+
+ return NULL;
+}
+
+gchar *seconds_to_string(unsigned int seconds)
+{
+ unsigned int hours, minutes, days;
+
+ minutes = seconds / 60;
+ hours = minutes / 60;
+ minutes %= 60;
+ days = hours / 24;
+ hours %= 24;
+
+ gchar *wminutes;
+ gchar *whours;
+ gchar *wdays;
+
+ wdays = ngettext("%d day, ", "%d days, ", days);
+ whours = ngettext("%d hour, ", "%d hours, ", hours);
+ wminutes = ngettext("%d minute", "%d minutes", minutes);
+ if (days < 1) {
+ if (hours < 1)
+ return g_strdup_printf(ngettext("%d minute", "%d minutes", minutes), minutes);
+ return g_strdup_printf(whours, wminutes);
+ }
+ return g_strdup_printf(wdays, whours, wminutes);
+}
+
+inline gchar *size_human_readable(gfloat size)
+{
+ if (size < KiB)
+ return g_strdup_printf(_("%.1f B"), size);
+ if (size < MiB)
+ return g_strdup_printf(_("%.1f KiB"), size / KiB);
+ if (size < GiB)
+ return g_strdup_printf(_("%.1f MiB"), size / MiB);
+ if (size < TiB)
+ return g_strdup_printf(_("%.1f GiB"), size / GiB);
+ if (size < PiB)
+ return g_strdup_printf(_("%.1f TiB"), size / TiB);
+
+ return g_strdup_printf(_("%.1f PiB"), size / PiB);
+}
+
+inline char *strend(gchar * str, gchar chr)
+{
+ if (!str)
+ return NULL;
+
+ char *p;
+ if ((p = g_utf8_strchr(str, -1, chr)))
+ *p = 0;
+
+ return str;
+}
+
+inline void remove_quotes(gchar * str)
+{
+ if (!str)
+ return;
+
+ while (*str == '"')
+ *(str++) = ' ';
+
+ strend(str, '"');
+}
+
+inline void remove_linefeed(gchar * str)
+{
+ strend(str, '\n');
+}
+
+void widget_set_cursor(GtkWidget * widget, GdkCursorType cursor_type)
+{
+ GdkCursor *cursor;
+
+ if ((cursor = gdk_cursor_new(cursor_type))) {
+ gdk_window_set_cursor(GDK_WINDOW(widget->window), cursor);
+ gdk_display_flush(gtk_widget_get_display(widget));
+ gdk_cursor_unref(cursor);
+ }
+
+ while (gtk_events_pending())
+ gtk_main_iteration();
+}
+
+static gboolean __nonblock_cb(gpointer data)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+void nonblock_sleep(guint msec)
+{
+ g_timeout_add(msec, (GSourceFunc) __nonblock_cb, NULL);
+ gtk_main();
+}
+
+static void __expand_cb(GtkWidget * widget, gpointer data)
+{
+ if (GTK_IS_EXPANDER(widget)) {
+ gtk_expander_set_expanded(GTK_EXPANDER(widget), TRUE);
+ } else if (GTK_IS_CONTAINER(widget)) {
+ gtk_container_foreach(GTK_CONTAINER(widget),
+ (GtkCallback) __expand_cb, NULL);
+ }
+}
+
+void file_chooser_open_expander(GtkWidget * chooser)
+{
+ gtk_container_foreach(GTK_CONTAINER(chooser),
+ (GtkCallback) __expand_cb, NULL);
+}
+
+void file_chooser_add_filters(GtkWidget * chooser, FileTypes * filters)
+{
+ GtkFileFilter *filter;
+ gint i;
+
+ for (i = 0; filters[i].name; i++) {
+ filter = gtk_file_filter_new();
+ gtk_file_filter_add_mime_type(filter, filters[i].mime_type);
+ gtk_file_filter_set_name(filter, filters[i].name);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
+ }
+}
+
+gchar *file_chooser_get_extension(GtkWidget * chooser, FileTypes * filters)
+{
+ GtkFileFilter *filter;
+ const gchar *filter_name;
+ gint i;
+
+ filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(chooser));
+ filter_name = gtk_file_filter_get_name(filter);
+ for (i = 0; filters[i].name; i++) {
+ if (g_str_equal(filter_name, filters[i].name)) {
+ return filters[i].extension;
+ }
+ }
+
+ return NULL;
+}
+
+gpointer file_types_get_data_by_name(FileTypes * filters, gchar * filename)
+{
+ gint i;
+
+ for (i = 0; filters[i].name; i++) {
+ if (g_str_has_suffix(filename, filters[i].extension)) {
+ return filters[i].data;
+ }
+ }
+
+ return NULL;
+}
+
+gchar *file_chooser_build_filename(GtkWidget * chooser, gchar * extension)
+{
+ gchar *filename =
+ gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
+ gchar *retval;
+
+ if (g_str_has_suffix(filename, extension)) {
+ return filename;
+ }
+
+ retval = g_strconcat(filename, extension, NULL);
+ g_free(filename);
+
+ return retval;
+}
+
+gboolean binreloc_init(gboolean try_hardcoded)
+{
+ GError *error = NULL;
+ gchar *tmp;
+
+ DEBUG("initializing binreloc (hardcoded = %d)", try_hardcoded);
+
+ /* If the runtime data directories we previously found, don't even try
+ to find them again. */
+ if (params.path_data && params.path_lib) {
+ DEBUG("data and lib path already found.");
+ return TRUE;
+ }
+
+ if (try_hardcoded || !gbr_init(&error)) {
+ /* We were asked to try hardcoded paths or BinReloc failed to initialize. */
+ params.path_data = g_strdup(PREFIX);
+ params.path_lib = g_strdup(LIBPREFIX);
+
+ if (error) {
+ g_error_free(error);
+ }
+
+ DEBUG("%strying hardcoded paths.",
+ try_hardcoded ? "" : "binreloc init failed. ");
+ } else {
+ /* If we were able to initialize BinReloc, build the default data
+ and library paths. */
+ DEBUG("done, trying to use binreloc paths.");
+
+ tmp = gbr_find_data_dir(PREFIX);
+ params.path_data = g_build_filename(tmp, "hardinfo", NULL);
+ g_free(tmp);
+
+ tmp = gbr_find_lib_dir(PREFIX);
+ params.path_lib = g_build_filename(tmp, "hardinfo", NULL);
+ g_free(tmp);
+ }
+
+ DEBUG("searching for runtime data on these locations:");
+ DEBUG(" lib: %s", params.path_lib);
+ DEBUG(" data: %s", params.path_data);
+
+ /* Try to see if the uidefs.xml file isn't missing. This isn't the
+ definitive test, but it should do okay for most situations. */
+ tmp = g_build_filename(params.path_data, "benchmark.data", NULL);
+ if (!g_file_test(tmp, G_FILE_TEST_EXISTS)) {
+ DEBUG("runtime data not found");
+
+ g_free(params.path_data);
+ g_free(params.path_lib);
+ g_free(tmp);
+
+ params.path_data = params.path_lib = NULL;
+
+ if (try_hardcoded) {
+ /* We tried the hardcoded paths, but still was unable to find the
+ runtime data. Give up. */
+ DEBUG("giving up");
+ return FALSE;
+ } else {
+ /* Even though BinReloc worked OK, the runtime data was not found.
+ Try the hardcoded paths. */
+ DEBUG("trying to find elsewhere");
+ return binreloc_init(TRUE);
+ }
+ }
+ g_free(tmp);
+
+ DEBUG("runtime data found!");
+ /* We found the runtime data; hope everything is fine */
+ return TRUE;
+}
+
+static void
+log_handler(const gchar * log_domain,
+ GLogLevelFlags log_level,
+ const gchar * message, gpointer user_data)
+{
+ if (!params.gui_running) {
+ /* No GUI running: spit the message to the terminal */
+ g_print("\n\n*** %s: %s\n\n",
+ (log_level & G_LOG_FLAG_FATAL) ? _("Error") : _("Warning"),
+ message);
+ } else {
+ /* Hooray! We have a GUI running! */
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new_with_markup(NULL, GTK_DIALOG_MODAL,
+ (log_level &
+ G_LOG_FLAG_FATAL) ?
+ GTK_MESSAGE_ERROR :
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE,
+ "<big><b>%s</b></big>\n\n%s",
+ (log_level &
+ G_LOG_FLAG_FATAL) ?
+ _("Fatal Error") :
+ _("Warning"), message);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ }
+}
+
+void parameters_init(int *argc, char ***argv, ProgramParameters * param)
+{
+ static gboolean create_report = FALSE;
+ static gboolean show_version = FALSE;
+ static gboolean list_modules = FALSE;
+ static gboolean autoload_deps = FALSE;
+ static gboolean run_xmlrpc_server = FALSE;
+ static gchar *report_format = NULL;
+ static gchar *run_benchmark = NULL;
+ static gchar **use_modules = NULL;
+
+ static GOptionEntry options[] = {
+ {
+ .long_name = "generate-report",
+ .short_name = 'r',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &create_report,
+ .description = N_("creates a report and prints to standard output")},
+ {
+ .long_name = "report-format",
+ .short_name = 'f',
+ .arg = G_OPTION_ARG_STRING,
+ .arg_data = &report_format,
+ .description = N_("chooses a report format (text, html)")},
+ {
+ .long_name = "run-benchmark",
+ .short_name = 'b',
+ .arg = G_OPTION_ARG_STRING,
+ .arg_data = &run_benchmark,
+ .description = N_("run benchmark; requires benchmark.so to be loaded")},
+ {
+ .long_name = "list-modules",
+ .short_name = 'l',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &list_modules,
+ .description = N_("lists modules")},
+ {
+ .long_name = "load-module",
+ .short_name = 'm',
+ .arg = G_OPTION_ARG_STRING_ARRAY,
+ .arg_data = &use_modules,
+ .description = N_("specify module to load")},
+ {
+ .long_name = "autoload-deps",
+ .short_name = 'a',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &autoload_deps,
+ .description = N_("automatically load module dependencies")},
+#ifdef HAS_LIBSOUP
+ {
+ .long_name = "xmlrpc-server",
+ .short_name = 'x',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &run_xmlrpc_server,
+ .description = N_("run in XML-RPC server mode")},
+#endif /* HAS_LIBSOUP */
+ {
+ .long_name = "version",
+ .short_name = 'v',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &show_version,
+ .description = N_("shows program version and quit")},
+ {NULL}
+ };
+ GOptionContext *ctx;
+
+ ctx = g_option_context_new(_("- System Profiler and Benchmark tool"));
+ g_option_context_set_ignore_unknown_options(ctx, FALSE);
+ g_option_context_set_help_enabled(ctx, TRUE);
+
+ g_option_context_add_main_entries(ctx, options, *(argv)[0]);
+ g_option_context_parse(ctx, argc, argv, NULL);
+
+ g_option_context_free(ctx);
+
+ if (*argc >= 2) {
+ g_print(_("Unrecognized arguments.\n"
+ "Try ``%s --help'' for more information.\n"), *(argv)[0]);
+ exit(1);
+ }
+
+ param->create_report = create_report;
+ param->report_format = REPORT_FORMAT_TEXT;
+ param->show_version = show_version;
+ param->list_modules = list_modules;
+ param->use_modules = use_modules;
+ param->run_benchmark = run_benchmark;
+ param->autoload_deps = autoload_deps;
+ param->run_xmlrpc_server = run_xmlrpc_server;
+ param->argv0 = *(argv)[0];
+
+ if (report_format && g_str_equal(report_format, "html"))
+ param->report_format = REPORT_FORMAT_HTML;
+
+ gchar *confdir = g_build_filename(g_get_home_dir(), ".hardinfo", NULL);
+ if (!g_file_test(confdir, G_FILE_TEST_EXISTS)) {
+ mkdir(confdir, 0744);
+ }
+ g_free(confdir);
+}
+
+gboolean ui_init(int *argc, char ***argv)
+{
+ DEBUG("initializing gtk+ UI");
+
+ g_set_application_name("HardInfo");
+ g_log_set_handler(NULL,
+ G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL |
+ G_LOG_LEVEL_ERROR, log_handler, NULL);
+
+ return gtk_init_check(argc, argv);
+}
+
+void open_url(gchar * url)
+{
+ const gchar *browsers[] = {
+ "xdg-open", "gnome-open", "kfmclient openURL",
+ "sensible-browser", "firefox", "epiphany",
+ "iceweasel", "seamonkey", "galeon", "mozilla",
+ "opera", "konqueror", "netscape", "links -g",
+ NULL
+ };
+ gint i = 0;
+ gchar *browser = (gchar *)g_getenv("BROWSER");
+
+ if (!browser || *browser == '\0') {
+ browser = (gchar *)browsers[i++];
+ }
+
+ do {
+ gchar *cmdline = g_strdup_printf("%s '%s'", browser, url);
+
+ if (g_spawn_command_line_async(cmdline, NULL)) {
+ g_free(cmdline);
+ return;
+ }
+
+ g_free(cmdline);
+
+ browser = (gchar *)browsers[i++];
+ } while (browser);
+
+ g_warning(_("Couldn't find a Web browser to open URL %s."), url);
+}
+
+/* Copyright: Jens Låås, SLU 2002 */
+gchar *strreplacechr(gchar * string, gchar * replace, gchar new_char)
+{
+ gchar *s;
+ for (s = string; *s; s++)
+ if (strchr(replace, *s))
+ *s = new_char;
+
+ return string;
+}
+
+gchar *strreplace(gchar *string, gchar *replace, gchar *replacement)
+{
+ gchar **tmp, *ret;
+
+ tmp = g_strsplit(string, replace, 0);
+ ret = g_strjoinv(replacement, tmp);
+ g_strfreev(tmp);
+
+ return ret;
+}
+
+static GHashTable *__module_methods = NULL;
+
+static void module_register_methods(ShellModule * module)
+{
+ ShellModuleMethod *(*get_methods) (void);
+ gchar *method_name;
+
+ if (__module_methods == NULL) {
+ __module_methods = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ if (g_module_symbol
+ (module->dll, "hi_exported_methods", (gpointer) & get_methods)) {
+ ShellModuleMethod *methods;
+
+ for (methods = get_methods(); methods->name; methods++) {
+ ShellModuleMethod method = *methods;
+ gchar *name = g_path_get_basename(g_module_name(module->dll));
+ gchar *simple_name = strreplace(name, "lib", "");
+
+ strend(simple_name, '.');
+
+ method_name = g_strdup_printf("%s::%s", simple_name, method.name);
+ g_hash_table_insert(__module_methods, method_name,
+ method.function);
+ g_free(name);
+ g_free(simple_name);
+ }
+ }
+
+}
+
+gchar *module_call_method(gchar * method)
+{
+ gchar *(*function) (void);
+
+ if (__module_methods == NULL) {
+ return NULL;
+ }
+
+ function = g_hash_table_lookup(__module_methods, method);
+ return function ? g_strdup(function()) : NULL;
+}
+
+/* FIXME: varargs? */
+gchar *module_call_method_param(gchar * method, gchar * parameter)
+{
+ gchar *(*function) (gchar *param);
+
+ if (__module_methods == NULL) {
+ return NULL;
+ }
+
+ function = g_hash_table_lookup(__module_methods, method);
+ return function ? g_strdup(function(parameter)) : NULL;
+}
+
+static gboolean remove_module_methods(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, data);
+}
+
+static void module_unload(ShellModule * module)
+{
+ GSList *entry;
+
+ if (module->dll) {
+ gchar *name;
+
+ if (module->deinit) {
+ DEBUG("cleaning up module \"%s\"", module->name);
+ module->deinit();
+ } else {
+ DEBUG("module \"%s\" does not need cleanup", module->name);
+ }
+
+ name = g_path_get_basename(g_module_name(module->dll));
+ g_hash_table_foreach_remove(__module_methods, remove_module_methods, name);
+
+ g_module_close(module->dll);
+ g_free(name);
+ }
+
+ g_free(module->name);
+ g_object_unref(module->icon);
+
+ for (entry = module->entries; entry; entry = entry->next) {
+ ShellModuleEntry *e = (ShellModuleEntry *)entry->data;
+
+ g_source_remove_by_user_data(e);
+ g_free(e);
+ }
+
+ g_slist_free(module->entries);
+ g_free(module);
+}
+
+
+void module_unload_all(void)
+{
+ Shell *shell;
+ GSList *module, *merge_id;
+
+ shell = shell_get_main_shell();
+
+ sync_manager_clear_entries();
+ shell_clear_timeouts(shell);
+ shell_clear_tree_models(shell);
+ shell_clear_field_updates();
+ shell_set_title(shell, NULL);
+
+ for (module = shell->tree->modules; module; module = module->next) {
+ module_unload((ShellModule *)module->data);
+ }
+
+ for (merge_id = shell->merge_ids; merge_id; merge_id = merge_id->next) {
+ gtk_ui_manager_remove_ui(shell->ui_manager,
+ GPOINTER_TO_INT(merge_id->data));
+ }
+ g_slist_free(shell->tree->modules);
+ g_slist_free(shell->merge_ids);
+
+ shell->merge_ids = NULL;
+ shell->tree->modules = NULL;
+ shell->selected = NULL;
+}
+
+static ShellModule *module_load(gchar * filename)
+{
+ ShellModule *module;
+ gchar *tmp;
+
+ module = g_new0(ShellModule, 1);
+
+ if (params.gui_running) {
+ gchar *tmpicon, *dot, *simple_name;
+
+ tmpicon = g_strdup(filename);
+ dot = g_strrstr(tmpicon, "." G_MODULE_SUFFIX);
+
+ *dot = '\0';
+
+ simple_name = strreplace(tmpicon, "lib", "");
+
+ tmp = g_strdup_printf("%s.png", simple_name);
+ module->icon = icon_cache_get_pixbuf(tmp);
+
+ g_free(tmp);
+ g_free(tmpicon);
+ g_free(simple_name);
+ }
+
+ tmp = g_build_filename(params.path_lib, "modules", filename, NULL);
+ module->dll = g_module_open(tmp, G_MODULE_BIND_LAZY);
+ DEBUG("gmodule resource for ``%s'' is %p", tmp, module->dll);
+ g_free(tmp);
+
+ if (module->dll) {
+ void (*init) (void);
+ ModuleEntry *(*get_module_entries) (void);
+ gint(*weight_func) (void);
+ gchar *(*name_func) (void);
+ ModuleEntry *entries;
+ gint i = 0;
+
+ if (!g_module_symbol(module->dll, "hi_module_get_entries", (gpointer) & get_module_entries) ||
+ !g_module_symbol(module->dll, "hi_module_get_name", (gpointer) & name_func)) {
+ DEBUG("cannot find needed symbols; is ``%s'' a real module?", filename);
+ goto failed;
+ }
+
+ if (g_module_symbol(module->dll, "hi_module_init", (gpointer) & init)) {
+ DEBUG("initializing module ``%s''", filename);
+ init();
+ }
+
+ g_module_symbol(module->dll, "hi_module_get_weight",
+ (gpointer) & weight_func);
+
+ module->weight = weight_func ? weight_func() : 0;
+ module->name = name_func();
+
+ g_module_symbol(module->dll, "hi_module_get_about",
+ (gpointer) & (module->aboutfunc));
+ g_module_symbol(module->dll, "hi_module_deinit",
+ (gpointer) & (module->deinit));
+ g_module_symbol(module->dll, "hi_module_get_summary",
+ (gpointer) & (module->summaryfunc));
+
+ entries = get_module_entries();
+ while (entries[i].name) {
+ ShellModuleEntry *entry = g_new0(ShellModuleEntry, 1);
+
+ if (params.gui_running) {
+ entry->icon = icon_cache_get_pixbuf(entries[i].icon);
+ }
+ entry->icon_file = entries[i].icon;
+
+ g_module_symbol(module->dll, "hi_more_info",
+ (gpointer) & (entry->morefunc));
+ g_module_symbol(module->dll, "hi_get_field",
+ (gpointer) & (entry->fieldfunc));
+ g_module_symbol(module->dll, "hi_note_func",
+ (gpointer) & (entry->notefunc));
+
+ entry->name = _(entries[i].name); //gettext unname N_() in computer.c line 67 etc...
+ entry->scan_func = entries[i].scan_callback;
+ entry->func = entries[i].callback;
+ entry->number = i;
+ entry->flags = entries[i].flags;
+
+ module->entries = g_slist_append(module->entries, entry);
+
+ i++;
+ }
+
+ DEBUG("registering methods for module ``%s''", filename);
+ module_register_methods(module);
+ } else {
+ DEBUG("cannot g_module_open(``%s''). permission problem?", filename);
+ failed:
+ DEBUG("loading module %s failed: %s", filename, g_module_error());
+
+ g_free(module->name);
+ g_free(module);
+ module = NULL;
+ }
+
+ return module;
+}
+
+static gboolean module_in_module_list(gchar * module, gchar ** module_list)
+{
+ int i = 0;
+
+ if (!module_list)
+ return TRUE;
+
+ for (; module_list[i]; i++) {
+ if (g_str_equal(module_list[i], module))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gint module_cmp(gconstpointer m1, gconstpointer m2)
+{
+ ShellModule *a = (ShellModule *) m1;
+ ShellModule *b = (ShellModule *) m2;
+
+ return a->weight - b->weight;
+}
+
+#if 0
+static void module_entry_free(gpointer data, gpointer user_data)
+{
+ ShellModuleEntry *entry = (ShellModuleEntry *) data;
+
+ if (entry) {
+ g_free(entry->name);
+ g_object_unref(entry->icon);
+
+ g_free(entry);
+ }
+}
+#endif
+
+ModuleAbout *module_get_about(ShellModule * module)
+{
+ if (module->aboutfunc) {
+ return module->aboutfunc();
+ }
+
+ return NULL;
+}
+
+static GSList *modules_check_deps(GSList * modules)
+{
+ GSList *mm;
+ ShellModule *module;
+
+ for (mm = modules; mm; mm = mm->next) {
+ gchar **(*get_deps) (void);
+ gchar **deps;
+ gint i;
+
+ module = (ShellModule *) mm->data;
+
+ if (g_module_symbol(module->dll, "hi_module_get_dependencies",
+ (gpointer) & get_deps)) {
+ for (i = 0, deps = get_deps(); deps[i]; i++) {
+ GSList *l;
+ ShellModule *m;
+ gboolean found = FALSE;
+
+ for (l = modules; l && !found; l = l->next) {
+ m = (ShellModule *) l->data;
+ gchar *name = g_path_get_basename(g_module_name(m->dll));
+
+ found = g_str_equal(name, deps[i]);
+ g_free(name);
+ }
+
+ if (!found) {
+ if (params.autoload_deps) {
+ ShellModule *mod = module_load(deps[i]);
+
+ if (mod)
+ modules = g_slist_append(modules, mod);
+ modules = modules_check_deps(modules); /* re-check dependencies */
+
+ break;
+ }
+
+ if (params.gui_running) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new(NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("Module \"%s\" depends on module \"%s\", load it?"),
+ module->name,
+ deps[i]);
+ gtk_dialog_add_buttons(GTK_DIALOG(dialog),
+ GTK_STOCK_NO,
+ GTK_RESPONSE_REJECT,
+ GTK_STOCK_OPEN,
+ GTK_RESPONSE_ACCEPT, NULL);
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) ==
+ GTK_RESPONSE_ACCEPT) {
+ ShellModule *mod = module_load(deps[i]);
+
+ if (mod)
+ modules = g_slist_prepend(modules, mod);
+ modules = modules_check_deps(modules); /* re-check dependencies */
+ } else {
+ g_error("HardInfo cannot run without loading the additional module.");
+ exit(1);
+ }
+
+ gtk_widget_destroy(dialog);
+ } else {
+ g_error(_("Module \"%s\" depends on module \"%s\"."),
+ module->name, deps[i]);
+ }
+ }
+ }
+ }
+ }
+
+ return modules;
+}
+
+
+GSList *modules_get_list()
+{
+ return modules_list;
+}
+
+static GSList *modules_load(gchar ** module_list)
+{
+ GDir *dir;
+ GSList *modules = NULL;
+ ShellModule *module;
+ gchar *filename;
+
+ filename = g_build_filename(params.path_lib, "modules", NULL);
+ dir = g_dir_open(filename, 0, NULL);
+ g_free(filename);
+
+ if (dir) {
+ while ((filename = (gchar *) g_dir_read_name(dir))) {
+ if (g_strrstr(filename, "." G_MODULE_SUFFIX) &&
+ module_in_module_list(filename, module_list) &&
+ ((module = module_load(filename)))) {
+ modules = g_slist_prepend(modules, module);
+ }
+ }
+
+ g_dir_close(dir);
+ }
+
+ modules = modules_check_deps(modules);
+
+ if (g_slist_length(modules) == 0) {
+ if (params.use_modules == NULL) {
+ g_error
+ (_("No module could be loaded. Check permissions on \"%s\" and try again."),
+ params.path_lib);
+ } else {
+ g_error
+ (_("No module could be loaded. Please use hardinfo -l to list all avai"
+ "lable modules and try again with a valid module list."));
+
+ }
+ }
+
+ modules_list = g_slist_sort(modules, module_cmp);
+ return modules_list;
+}
+
+GSList *modules_load_selected(void)
+{
+ return modules_load(params.use_modules);
+}
+
+GSList *modules_load_all(void)
+{
+ return modules_load(NULL);
+}
+
+gint tree_view_get_visible_height(GtkTreeView * tv)
+{
+ GtkTreePath *path;
+ GdkRectangle rect;
+ GtkTreeIter iter;
+ GtkTreeModel *model = gtk_tree_view_get_model(tv);
+ gint nrows = 1;
+
+ path = gtk_tree_path_new_first();
+ gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect);
+
+ /* FIXME: isn't there any easier way to tell the number of rows? */
+ gtk_tree_model_get_iter_first(model, &iter);
+ do {
+ nrows++;
+ } while (gtk_tree_model_iter_next(model, &iter));
+
+ gtk_tree_path_free(path);
+
+ return nrows * rect.height;
+}
+
+void tree_view_save_image(gchar * filename)
+{
+ /* this is ridiculously complicated :/ why in the hell gtk+ makes this kind of
+ thing so difficult? */
+
+ /* FIXME: this does not work if the window (or part of it) isn't visible. does
+ anyone know how to fix this? :/ */
+ Shell *shell = shell_get_main_shell();
+ GtkWidget *widget = shell->info->view;
+
+ PangoLayout *layout;
+ PangoContext *context;
+ PangoRectangle rect;
+
+ GdkPixmap *pm;
+ GdkPixbuf *pb;
+ GdkGC *gc;
+ GdkColor black = { 0, 0, 0, 0 };
+ GdkColor white = { 0, 65535, 65535, 65535 };
+
+ gint w, h, visible_height;
+ gchar *tmp;
+
+ gboolean tv_enabled;
+
+ /* present the window */
+ gtk_window_present(GTK_WINDOW(shell->window));
+
+ /* if the treeview is disabled, we need to enable it so we get the
+ correct colors when saving. we make it insensitive later on if it
+ was this way before entering this function */
+ tv_enabled = GTK_WIDGET_IS_SENSITIVE(widget);
+ gtk_widget_set_sensitive(widget, TRUE);
+
+ gtk_widget_queue_draw(widget);
+
+ /* unselect things in the information treeview */
+ gtk_range_set_value(GTK_RANGE
+ (GTK_SCROLLED_WINDOW(shell->info->scroll)->
+ vscrollbar), 0.0);
+ gtk_tree_selection_unselect_all(gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(widget)));
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ /* initialize stuff */
+ gc = gdk_gc_new(widget->window);
+ gdk_gc_set_background(gc, &black);
+ gdk_gc_set_foreground(gc, &white);
+
+ context = gtk_widget_get_pango_context(widget);
+ layout = pango_layout_new(context);
+
+ visible_height = tree_view_get_visible_height(GTK_TREE_VIEW(widget));
+
+ /* draw the title */
+ tmp = g_strdup_printf("<b><big>%s</big></b>\n<small>%s</small>",
+ shell->selected->name,
+ shell->selected->notefunc(shell->selected->
+ number));
+ pango_layout_set_markup(layout, tmp, -1);
+ pango_layout_set_width(layout, widget->allocation.width * PANGO_SCALE);
+ pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+ pango_layout_get_pixel_extents(layout, NULL, &rect);
+
+ w = widget->allocation.width;
+ h = visible_height + rect.height;
+
+ pm = gdk_pixmap_new(widget->window, w, rect.height, -1);
+ gdk_draw_rectangle(GDK_DRAWABLE(pm), gc, TRUE, 0, 0, w, rect.height);
+ gdk_draw_layout_with_colors(GDK_DRAWABLE(pm), gc, 0, 0, layout,
+ &white, &black);
+
+ /* copy the pixmap from the treeview and from the title */
+ pb = gdk_pixbuf_get_from_drawable(NULL,
+ widget->window,
+ NULL, 0, 0, 0, 0, w, h);
+ pb = gdk_pixbuf_get_from_drawable(pb,
+ pm,
+ NULL,
+ 0, 0,
+ 0, visible_height, w, rect.height);
+
+ /* save the pixbuf to a png file */
+ gdk_pixbuf_save(pb, filename, "png", NULL,
+ "compression", "9",
+ "tEXt::hardinfo::version", VERSION,
+ "tEXt::hardinfo::arch", ARCH, NULL);
+
+ /* unref */
+ g_object_unref(pb);
+ g_object_unref(layout);
+ g_object_unref(pm);
+ g_object_unref(gc);
+ g_free(tmp);
+
+ gtk_widget_set_sensitive(widget, tv_enabled);
+}
+
+static gboolean __idle_free_do(gpointer ptr)
+{
+ g_free(ptr);
+
+ return FALSE;
+}
+
+#if RELEASE == 1
+gpointer idle_free(gpointer ptr)
+#else
+gpointer __idle_free(gpointer ptr, gchar * f, gint l)
+#endif
+{
+ DEBUG("file: %s, line: %d, ptr %p", f, l, ptr);
+
+ if (ptr) {
+ g_timeout_add(10000, __idle_free_do, ptr);
+ }
+
+ return ptr;
+}
+
+void module_entry_scan_all_except(ModuleEntry * entries, gint except_entry)
+{
+ ModuleEntry entry;
+ gint i = 0;
+ void (*scan_callback) (gboolean reload);
+ gchar *text;
+
+ shell_view_set_enabled(FALSE);
+
+ for (entry = entries[0]; entry.name; entry = entries[++i]) {
+ if (i == except_entry)
+ continue;
+
+ text = g_strdup_printf(_("Scanning: %s..."), _(entry.name));
+ shell_status_update(text);
+ g_free(text);
+
+ if ((scan_callback = entry.scan_callback)) {
+ scan_callback(FALSE);
+ }
+ }
+
+ shell_view_set_enabled(TRUE);
+ shell_status_update(_("Done."));
+}
+
+void module_entry_scan_all(ModuleEntry * entries)
+{
+ module_entry_scan_all_except(entries, -1);
+}
+
+void module_entry_reload(ShellModuleEntry * module_entry)
+{
+
+ if (module_entry->scan_func) {
+ module_entry->scan_func(TRUE);
+ }
+}
+
+void module_entry_scan(ShellModuleEntry * module_entry)
+{
+ if (module_entry->scan_func) {
+ module_entry->scan_func(FALSE);
+ }
+}
+
+gchar *module_entry_get_field(ShellModuleEntry * module_entry, gchar * field)
+{
+ if (module_entry->fieldfunc) {
+ return module_entry->fieldfunc(field);
+ }
+
+ return NULL;
+}
+
+gchar *module_entry_function(ShellModuleEntry * module_entry)
+{
+ if (module_entry->func) {
+ return module_entry->func();
+ }
+
+ return NULL;
+}
+
+gchar *module_entry_get_moreinfo(ShellModuleEntry * module_entry, gchar * field)
+{
+ if (module_entry->morefunc) {
+ return module_entry->morefunc(field);
+ }
+
+ return NULL;
+}
+
+const gchar *module_entry_get_note(ShellModuleEntry * module_entry)
+{
+ if (module_entry->notefunc) {
+ return module_entry->notefunc(module_entry->number);
+ }
+
+ return NULL;
+}
+
+gchar *h_strdup_cprintf(const gchar * format, gchar * source, ...)
+{
+ gchar *buffer, *retn;
+ va_list args;
+
+ va_start(args, source);
+ buffer = g_strdup_vprintf(format, args);
+ va_end(args);
+
+ if (source) {
+ retn = g_strconcat(source, buffer, NULL);
+ g_free(buffer);
+ g_free(source);
+ } else {
+ retn = buffer;
+ }
+
+ return retn;
+}
+
+gchar *h_strconcat(gchar * string1, ...)
+{
+ gsize l;
+ va_list args;
+ gchar *s;
+ gchar *concat;
+ gchar *ptr;
+
+ if (!string1)
+ return NULL;
+
+ l = 1 + strlen(string1);
+ va_start(args, string1);
+ s = va_arg(args, gchar *);
+ while (s) {
+ l += strlen(s);
+ s = va_arg(args, gchar *);
+ }
+ va_end(args);
+
+ concat = g_new(gchar, l);
+ ptr = concat;
+
+ ptr = g_stpcpy(ptr, string1);
+ va_start(args, string1);
+ s = va_arg(args, gchar *);
+ while (s) {
+ ptr = g_stpcpy(ptr, s);
+ s = va_arg(args, gchar *);
+ }
+ va_end(args);
+
+ g_free(string1);
+
+ return concat;
+}
+
+static gboolean h_hash_table_remove_all_true(gpointer key, gpointer data, gpointer user_data)
+{
+ return TRUE;
+}
+
+void
+h_hash_table_remove_all(GHashTable *hash_table)
+{
+ g_hash_table_foreach_remove(hash_table,
+ h_hash_table_remove_all_true,
+ NULL);
+}
+
+gfloat
+h_sysfs_read_float(gchar *endpoint, gchar *entry)
+{
+ gchar *tmp, *buffer;
+ gfloat return_value = 0.0f;
+
+ tmp = g_build_filename(endpoint, entry, NULL);
+ if (g_file_get_contents(tmp, &buffer, NULL, NULL))
+ return_value = atof(buffer);
+
+ g_free(tmp);
+ g_free(buffer);
+
+ return return_value;
+}
+
+gint
+h_sysfs_read_int(gchar *endpoint, gchar *entry)
+{
+ gchar *tmp, *buffer;
+ gint return_value = 0;
+
+ tmp = g_build_filename(endpoint, entry, NULL);
+ if (g_file_get_contents(tmp, &buffer, NULL, NULL))
+ return_value = atoi(buffer);
+
+ g_free(tmp);
+ g_free(buffer);
+
+ return return_value;
+}
+
+gchar *
+h_sysfs_read_string(gchar *endpoint, gchar *entry)
+{
+ gchar *tmp, *return_value;
+
+ tmp = g_build_filename(endpoint, entry, NULL);
+ if (!g_file_get_contents(tmp, &return_value, NULL, NULL)) {
+ g_free(return_value);
+
+ return_value = NULL;
+ } else {
+ return_value = g_strstrip(return_value);
+ }
+
+ g_free(tmp);
+
+ return return_value;
+}
+
+static GHashTable *_moreinfo = NULL;
+
+void
+moreinfo_init(void)
+{
+ if (G_UNLIKELY(_moreinfo)) {
+ DEBUG("moreinfo already initialized");
+ return;
+ }
+ DEBUG("initializing moreinfo");
+ _moreinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+}
+
+void
+moreinfo_shutdown(void)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+ DEBUG("shutting down moreinfo");
+ g_hash_table_destroy(_moreinfo);
+ _moreinfo = NULL;
+}
+
+void
+moreinfo_add_with_prefix(gchar *prefix, gchar *key, gchar *value)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+
+ if (prefix) {
+ gchar *hashkey = g_strconcat(prefix, ":", key, NULL);
+ g_hash_table_insert(_moreinfo, hashkey, value);
+ return;
+ }
+
+ g_hash_table_insert(_moreinfo, g_strdup(key), value);
+}
+
+void
+moreinfo_add(gchar *key, gchar *value)
+{
+ moreinfo_add_with_prefix(NULL, key, value);
+}
+
+static gboolean
+_moreinfo_del_cb(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, data);
+}
+
+void
+moreinfo_del_with_prefix(gchar *prefix)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+
+ g_hash_table_foreach_remove(_moreinfo, _moreinfo_del_cb, prefix);
+}
+
+void
+moreinfo_clear(void)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+ h_hash_table_remove_all(_moreinfo);
+}
+
+gchar *
+moreinfo_lookup_with_prefix(gchar *prefix, gchar *key)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return 0;
+ }
+
+ if (prefix) {
+ gchar *lookup_key = g_strconcat(prefix, ":", key, NULL);
+ gchar *result = g_hash_table_lookup(_moreinfo, lookup_key);
+ g_free(lookup_key);
+ return result;
+ }
+
+ return g_hash_table_lookup(_moreinfo, key);
+}
+
+gchar *
+moreinfo_lookup(gchar *key)
+{
+ return moreinfo_lookup_with_prefix(NULL, key);
+}
+
+#if !GLIB_CHECK_VERSION(2,44,0)
+gboolean g_strv_contains(const gchar * const * strv, const gchar *str) {
+ /* g_strv_contains() requires glib>2.44
+ * fallback for older versions */
+ gint i = 0;
+ while(strv[i] != NULL) {
+ if (g_strcmp0(strv[i], str) == 0)
+ return 1;
+ i++;
+ }
+ return 0;
+}
+#endif
diff --git a/hardinfo/vendor.c b/hardinfo/vendor.c
new file mode 100644
index 00000000..86dba97a
--- /dev/null
+++ b/hardinfo/vendor.c
@@ -0,0 +1,195 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * List of vendors based on GtkSysInfo (c) Pissens Sebastien.
+ *
+ * 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, version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "vendor.h"
+#include "syncmanager.h"
+#include "config.h"
+#include "hardinfo.h"
+
+static const Vendor vendors[] = {
+ {"ATI", "ATI Technologies", "www.ati.com"},
+ {"nVidia", "NVIDIA", "www.nvidia.com"},
+ {"3Com", "3Com", "www.3com.com"},
+ {"Intel", "Intel", "www.intel.com"},
+ {"Cirrus Logic", "Cirrus Logic", "www.cirrus.com"},
+ {"VIA Technologies", "VIA Technologies", "www.via.com.tw"},
+ {"VIA", "VIA Technologies", "www.via.com.tw"},
+ {"hp", "Hewlett-Packard", "www.hp.com"},
+ {"NEC Corporation", "NEC Coporation", "www.nec.com"},
+ {"MAXTOR", "MAXTOR", "www.maxtor.com"},
+ {"SAMSUNG", "SAMSUNG", "www.samsung.com"},
+ {"PIONEER", "PIONEER", "www.pioneer-eur.com"},
+ {"PLEXTOR", "PLEXTOR", "www.plextor.be"},
+ {"Realtek Semiconductor", "Realtek", "www.realtek.com.tw"},
+ {"TOSHIBA", "TOSHIBA", "www.toshiba.com"},
+ {"LITE-ON", "LITE-ON", "www.liteonit.com"},
+ {"WDC", "Western Digital", "www.wdc.com"},
+ {"HL-DT-ST", "LG Electronics", "www.lge.com"},
+ {"ST", "SEAGATE", "www.seagate.com"},
+ {"Lexmark", "Lexmark", "www.lexmark.com"},
+ {"_NEC", "NEC Corporation", "www.nec.com"},
+ {"Creative Labs", "Creative Labs", "www.creative.com"},
+ {"Brooktree", "Conexant", "www.brooktree.com"},
+ {"Atheros", "Atheros Communications", "www.atheros.com"},
+ {"MATSHITA", "Panasonic", "www.panasonic.com"},
+ {"Silicon Image", "Silicon Image", "www.siliconimage.com"},
+ {"Silicon Integrated Image", "Silicon Image", "www.siliconimage.com"},
+ {"KYE", "KYE Systems", "www.genius-kye.com"},
+ {"Broadcom", "Broadcom", "www.broadcom.com"},
+ {"Apple", "Apple", "www.apple.com"},
+ {"IBM", "IBM", "www.ibm.com"},
+ {"Dell", "Dell Computer", "www.dell.com"},
+ {"Logitech", "Logitech International", "www.logitech.com"},
+ {"FUJITSU", "Fujitsu", "www.fujitsu.com"},
+ {"CDU", "Sony", "www.sony.com"},
+ {"SanDisk", "SanDisk", "www.sandisk.com"},
+ {"ExcelStor", "ExcelStor Technology", "www.excelstor.com"},
+ {"D-Link", "D-Link", "www.dlink.com.tw"},
+ {"Giga-byte", "Gigabyte Technology", "www.gigabyte.com.tw"},
+ {"Gigabyte", "Gigabyte Technology", "www.gigabyte.com.tw"},
+ {"C-Media", "C-Media Electronics", "www.cmedia.com.tw"},
+ {"Avermedia", "AVerMedia Technologies", "www.aver.com"},
+ {"Philips", "Philips", "www.philips.com"},
+ {"RaLink", "Ralink Technology", "www.ralinktech.com"},
+ {"Siemens", "Siemens AG", "www.siemens.com"},
+ {"HP", "Hewlett-Packard", "www.hp.com"},
+ {"Hewlett-Packard", "Hewlett-Packard", "www.hp.com"},
+ {"TEAC", "TEAC America", "www.teac.com"},
+ {"Microsoft", "Microsoft", "www.microsoft.com"},
+ {"Memorex", "Memorex Products", "www.memorex.com"},
+ {"eMPIA", "eMPIA Technology", "www.empiatech.com.tw"},
+ {"Canon", "Canon", "www.canon.com"},
+ {"A4Tech", "A4tech", "www.a4tech.com"},
+ {"ALCOR", "Alcor", "www.alcor.org"},
+ {"Vimicro", "Vimicro", "www.vimicro.com"},
+ {"OTi", "Ours Technology", "www.oti.com.tw"},
+ {"BENQ", "BenQ", "www.benq.com"},
+ {"Acer", "Acer", "www.acer.com"},
+ {"QUANTUM", "Quantum", "www.quantum.com"},
+ {"Kingston", "Kingston", "www.kingston.com"},
+ {"Chicony", "Chicony", "www.chicony.com.tw"},
+ {"Genius", "Genius", "www.genius.ru"},
+ /* BIOS manufacturers */
+ {"American Megatrends", "American Megatrends", "www.ami.com"},
+ {"Award", "Award Software International", "www.award-bios.com"},
+ {"Phoenix", "Phoenix Technologies", "www.phoenix.com"},
+};
+
+static GSList *vendor_list = NULL;
+
+void vendor_init(void)
+{
+ gint i;
+ gchar *path;
+ static SyncEntry se = {
+ .fancy_name = "Update vendor list",
+ .name = "RecvVendorList",
+ .save_to = "vendor.conf",
+ .get_data = NULL
+ };
+
+ DEBUG("initializing vendor list");
+ sync_manager_add_entry(&se);
+
+ path = g_build_filename(g_get_home_dir(), ".hardinfo", "vendor.conf", NULL);
+ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ DEBUG("local vendor.conf not found, trying system-wise");
+ g_free(path);
+ path = g_build_filename(params.path_data, "vendor.conf", NULL);
+ }
+
+ if (g_file_test(path, G_FILE_TEST_EXISTS)) {
+ GKeyFile *vendors;
+ gchar *tmp;
+ gint num_vendors;
+
+ DEBUG("loading %s", path);
+
+ vendors = g_key_file_new();
+ if (g_key_file_load_from_file(vendors, path, 0, NULL)) {
+ num_vendors = g_key_file_get_integer(vendors, "vendors", "number", NULL);
+
+ for (i = num_vendors - 1; i >= 0; i--) {
+ Vendor *v = g_new0(Vendor, 1);
+
+ tmp = g_strdup_printf("vendor%d", i);
+
+ v->id = g_key_file_get_string(vendors, tmp, "id", NULL);
+ v->name = g_key_file_get_string(vendors, tmp, "name", NULL);
+ v->url = g_key_file_get_string(vendors, tmp, "url", NULL);
+
+ vendor_list = g_slist_prepend(vendor_list, v);
+
+ g_free(tmp);
+ }
+ }
+
+ g_key_file_free(vendors);
+ } else {
+ DEBUG("system-wise vendor.conf not found, using internal database");
+
+ for (i = G_N_ELEMENTS(vendors) - 1; i >= 0; i--) {
+ vendor_list = g_slist_prepend(vendor_list, (gpointer) &vendors[i]);
+ }
+ }
+
+ g_free(path);
+}
+
+const gchar *vendor_get_name(const gchar * id)
+{
+ GSList *vendor;
+
+ if (!id) {
+ return NULL;
+ }
+
+ for (vendor = vendor_list; vendor; vendor = vendor->next) {
+ Vendor *v = (Vendor *)vendor->data;
+
+ if (v && v->id && strstr(id, v->id)) {
+ return g_strdup(v->name);
+ }
+ }
+
+ return id;
+}
+
+const gchar *vendor_get_url(const gchar * id)
+{
+ GSList *vendor;
+
+ if (!id) {
+ return NULL;
+ }
+
+ for (vendor = vendor_list; vendor; vendor = vendor->next) {
+ Vendor *v = (Vendor *)vendor->data;
+
+ if (v && v->id && strstr(id, v->id)) {
+ return g_strdup(v->url);
+ }
+ }
+
+ return NULL;
+}