diff options
author | Simon Quigley <tsimonq2@ubuntu.com> | 2017-06-19 15:19:47 -0500 |
---|---|---|
committer | Simon Quigley <tsimonq2@ubuntu.com> | 2017-06-19 15:19:47 -0500 |
commit | 7aacc9f2510901c9e97b30fa9bcb550bb7f99c03 (patch) | |
tree | 16908948750c11da8332d80d8bb9b339399ee4d7 /hardinfo | |
parent | 7c47b5b9584f5011aeba18d7e1b26b3d3124825f (diff) |
New upstream version 0.5.1+git20170605
Diffstat (limited to 'hardinfo')
-rw-r--r-- | hardinfo/binreloc.c | 668 | ||||
-rw-r--r-- | hardinfo/expr.c | 250 | ||||
-rw-r--r-- | hardinfo/hardinfo.c | 158 | ||||
-rw-r--r-- | hardinfo/socket.c | 127 | ||||
-rw-r--r-- | hardinfo/util.c | 1404 | ||||
-rw-r--r-- | hardinfo/vendor.c | 195 |
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, ¶ms); + + /* 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; +} |