summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorSimon Quigley <tsimonq2@ubuntu.com>2017-06-19 15:19:47 -0500
committerSimon Quigley <tsimonq2@ubuntu.com>2017-06-19 15:19:47 -0500
commit7aacc9f2510901c9e97b30fa9bcb550bb7f99c03 (patch)
tree16908948750c11da8332d80d8bb9b339399ee4d7 /modules
parent7c47b5b9584f5011aeba18d7e1b26b3d3124825f (diff)
New upstream version 0.5.1+git20170605
Diffstat (limited to 'modules')
-rw-r--r--modules/benchmark.c663
-rw-r--r--modules/benchmark/blowfish.c533
-rw-r--r--modules/benchmark/cryptohash.c79
-rw-r--r--modules/benchmark/drawing.c29
-rw-r--r--modules/benchmark/fbench.c745
-rw-r--r--modules/benchmark/fft.c67
-rw-r--r--modules/benchmark/fftbench.c212
-rw-r--r--modules/benchmark/fib.c50
-rw-r--r--modules/benchmark/guibench.c353
-rw-r--r--modules/benchmark/md5.c317
-rw-r--r--modules/benchmark/nqueens.c66
-rw-r--r--modules/benchmark/raytrace.c47
-rw-r--r--modules/benchmark/sha1.c329
-rw-r--r--modules/computer.c716
-rw-r--r--modules/computer/alsa.c71
-rw-r--r--modules/computer/boots.c65
-rw-r--r--modules/computer/display.c148
-rw-r--r--modules/computer/environment.c45
-rw-r--r--modules/computer/filesystem.c103
-rw-r--r--modules/computer/groups.c45
-rw-r--r--modules/computer/languages.c112
-rw-r--r--modules/computer/loadavg.c68
-rw-r--r--modules/computer/memory.c59
-rw-r--r--modules/computer/modules.c169
-rw-r--r--modules/computer/os.c258
-rw-r--r--modules/computer/uptime.c76
-rw-r--r--modules/computer/users.c60
-rw-r--r--modules/devices.c613
-rw-r--r--modules/devices/alpha/processor.c78
-rw-r--r--modules/devices/arm/arm_data.c215
-rw-r--r--modules/devices/arm/arm_data.h38
-rw-r--r--modules/devices/arm/processor.c340
-rw-r--r--modules/devices/battery.c388
-rw-r--r--modules/devices/devmemory.c108
-rw-r--r--modules/devices/dmi.c209
-rw-r--r--modules/devices/ia64/processor.c78
-rw-r--r--modules/devices/inputdevices.c140
-rw-r--r--modules/devices/m68k/processor.c79
-rw-r--r--modules/devices/mips/processor.c75
-rw-r--r--modules/devices/parisc/processor.c87
-rw-r--r--modules/devices/pci.c247
-rw-r--r--modules/devices/ppc/processor.c85
-rw-r--r--modules/devices/printers.c266
-rw-r--r--modules/devices/resources.c119
-rw-r--r--modules/devices/s390/processor.c78
-rw-r--r--modules/devices/sensors.c444
-rw-r--r--modules/devices/sh/processor.c75
-rw-r--r--modules/devices/sparc/processor.c64
-rw-r--r--modules/devices/spd-decode.c1509
-rw-r--r--modules/devices/storage.c371
-rw-r--r--modules/devices/usb.c381
-rw-r--r--modules/devices/x86/processor.c727
l---------modules/devices/x86_641
-rw-r--r--modules/network.c438
-rw-r--r--modules/network/net.c452
-rw-r--r--modules/network/nfs.c59
-rw-r--r--modules/network/samba.c124
-rw-r--r--modules/placeholder0
58 files changed, 13373 insertions, 0 deletions
diff --git a/modules/benchmark.c b/modules/benchmark.c
new file mode 100644
index 00000000..94997df8
--- /dev/null
+++ b/modules/benchmark.c
@@ -0,0 +1,663 @@
+/*
+ * 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 <hardinfo.h>
+#include <iconcache.h>
+#include <shell.h>
+#include <config.h>
+#include <syncmanager.h>
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <sys/types.h>
+#include <signal.h>
+
+#include "benchmark.h"
+
+void scan_fft(gboolean reload);
+void scan_raytr(gboolean reload);
+void scan_bfsh(gboolean reload);
+void scan_cryptohash(gboolean reload);
+void scan_fib(gboolean reload);
+void scan_nqueens(gboolean reload);
+void scan_gui(gboolean reload);
+
+gchar *callback_fft();
+gchar *callback_raytr();
+gchar *callback_bfsh();
+gchar *callback_fib();
+gchar *callback_cryptohash();
+gchar *callback_nqueens();
+gchar *callback_gui();
+
+static ModuleEntry entries[] = {
+ {N_("CPU Blowfish"), "blowfish.png", callback_bfsh, scan_bfsh, MODULE_FLAG_NONE},
+ {N_("CPU CryptoHash"), "cryptohash.png", callback_cryptohash, scan_cryptohash, MODULE_FLAG_NONE},
+ {N_("CPU Fibonacci"), "nautilus.png", callback_fib, scan_fib, MODULE_FLAG_NONE},
+ {N_("CPU N-Queens"), "nqueens.png", callback_nqueens, scan_nqueens, MODULE_FLAG_NONE},
+ {N_("FPU FFT"), "fft.png", callback_fft, scan_fft, MODULE_FLAG_NONE},
+ {N_("FPU Raytracing"), "raytrace.png", callback_raytr, scan_raytr, MODULE_FLAG_NONE},
+ {N_("GPU Drawing"), "module.png", callback_gui, scan_gui, MODULE_FLAG_NO_REMOTE},
+ {NULL}
+};
+
+static gboolean sending_benchmark_results = FALSE;
+
+typedef struct _ParallelBenchTask ParallelBenchTask;
+
+struct _ParallelBenchTask {
+ gint thread_number;
+ guint start, end;
+ gpointer data, callback;
+};
+
+static gpointer benchmark_parallel_for_dispatcher(gpointer data)
+{
+ ParallelBenchTask *pbt = (ParallelBenchTask *)data;
+ gpointer (*callback)(unsigned int start, unsigned int end, void *data, gint thread_number);
+ gpointer return_value = NULL;
+
+ if ((callback = pbt->callback)) {
+ DEBUG("this is thread %p; items %d -> %d, data %p", g_thread_self(),
+ pbt->start, pbt->end, pbt->data);
+ return_value = callback(pbt->start, pbt->end, pbt->data, pbt->thread_number);
+ DEBUG("this is thread %p; return value is %p", g_thread_self(), return_value);
+ } else {
+ DEBUG("this is thread %p; callback is NULL and it should't be!", g_thread_self());
+ }
+
+ g_free(pbt);
+
+ return return_value;
+}
+
+gdouble benchmark_parallel_for(guint start, guint end,
+ gpointer callback, gpointer callback_data) {
+ gchar *temp;
+ guint n_cores, iter_per_core, iter, thread_number = 0;
+ gdouble elapsed_time;
+ GSList *threads = NULL, *t;
+ GTimer *timer;
+
+ timer = g_timer_new();
+
+ temp = module_call_method("devices::getProcessorCount");
+ n_cores = temp ? atoi(temp) : 1;
+ g_free(temp);
+
+ while (n_cores > 0) {
+ iter_per_core = (end - start) / n_cores;
+
+ if (iter_per_core == 0) {
+ DEBUG("not enough items per core; disabling one");
+ n_cores--;
+ } else {
+ break;
+ }
+ }
+
+ DEBUG("processor has %d cores; processing %d elements (%d per core)",
+ n_cores, (end - start), iter_per_core);
+
+ g_timer_start(timer);
+ for (iter = start; iter < end; iter += iter_per_core) {
+ ParallelBenchTask *pbt = g_new0(ParallelBenchTask, 1);
+ GThread *thread;
+
+ DEBUG("launching thread %d", 1 + (iter / iter_per_core));
+
+ pbt->thread_number = thread_number++;
+ pbt->start = iter == 0 ? 0 : iter;
+ pbt->end = iter + iter_per_core - 1;
+ pbt->data = callback_data;
+ pbt->callback = callback;
+
+ if (pbt->end > end)
+ pbt->end = end;
+
+ thread = g_thread_new("dispatcher",
+ (GThreadFunc)benchmark_parallel_for_dispatcher, pbt);
+ threads = g_slist_prepend(threads, thread);
+
+ DEBUG("thread %d launched as context %p", thread_number, thread);
+ }
+
+ DEBUG("waiting for all threads to finish");
+ for (t = threads; t; t = t->next) {
+ DEBUG("waiting for thread with context %p", t->data);
+ g_thread_join((GThread *)t->data);
+ }
+
+ g_timer_stop(timer);
+ elapsed_time = g_timer_elapsed(timer, NULL);
+
+ g_slist_free(threads);
+ g_timer_destroy(timer);
+
+ DEBUG("finishing; all threads took %f seconds to finish", elapsed_time);
+
+ return elapsed_time;
+}
+
+static gchar *clean_cpuname(gchar *cpuname)
+{
+ gchar *ret = NULL, *tmp;
+ gchar *remove[] = {
+ "(R)", "(r)", "(TM)", "(tm)", "Processor",
+ "Technology", "processor", "CPU",
+ "cpu", "Genuine", "Authentic", NULL
+ };
+ gint i;
+
+ ret = g_strdup(cpuname);
+ for (i = 0; remove[i]; i++) {
+ tmp = strreplace(ret, remove[i], "");
+ g_free(ret);
+ ret = tmp;
+ }
+
+ ret = strend(ret, '@');
+ ret = g_strstrip(ret);
+
+ tmp = g_strdup(ret);
+ g_free(ret);
+
+ return tmp;
+}
+
+static gchar *__benchmark_include_results(gdouble result,
+ const gchar * benchmark,
+ ShellOrderType order_type)
+{
+ GKeyFile *conf;
+ gchar **machines;
+ gchar *path, *results = g_strdup(""), *return_value, *processor_frequency;
+ int i;
+
+ conf = g_key_file_new();
+
+ path = g_build_filename(g_get_home_dir(), ".hardinfo", "benchmark.conf", NULL);
+ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ DEBUG("local benchmark.conf not found, trying system-wide");
+ g_free(path);
+ path = g_build_filename(params.path_data, "benchmark.conf", NULL);
+ }
+
+ g_key_file_load_from_file(conf, path, 0, NULL);
+
+ machines = g_key_file_get_keys(conf, benchmark, NULL, NULL);
+ for (i = 0; machines && machines[i]; i++) {
+ gchar *value, *cleaned_machine;
+
+ value = g_key_file_get_value(conf, benchmark, machines[i], NULL);
+ cleaned_machine = clean_cpuname(machines[i]);
+ results = h_strconcat(results, cleaned_machine, "=", value, "\n", NULL);
+
+ g_free(value);
+ g_free(cleaned_machine);
+ }
+
+ g_strfreev(machines);
+ g_free(path);
+ g_key_file_free(conf);
+
+ if (result > 0.0f) {
+ processor_frequency = module_call_method("devices::getProcessorFrequency");
+ return_value = g_strdup_printf(_("[$ShellParam$]\n"
+ "Zebra=1\n"
+ "OrderType=%d\n"
+ "ViewType=3\n"
+ "ColumnTitle$Extra1=CPU Clock\n"
+ "ColumnTitle$Progress=Results\n"
+ "ColumnTitle$TextValue=CPU\n"
+ "ShowColumnHeaders=true\n"
+ "[%s]\n"
+ "<big><b>This Machine</b></big>=%.3f|%s MHz\n"
+ "%s"), order_type, benchmark, result, processor_frequency, results);
+ g_free(processor_frequency);
+ } else {
+ return_value = g_strdup_printf(_("[$ShellParam$]\n"
+ "Zebra=1\n"
+ "OrderType=%d\n"
+ "ViewType=3\n"
+ "ColumnTitle$Extra1=CPU Clock\n"
+ "ColumnTitle$Progress=Results\n"
+ "ColumnTitle$TextValue=CPU\n"
+ "ShowColumnHeaders=true\n"
+ "[%s]\n"
+ "%s"), order_type, benchmark, results);
+ }
+ return return_value;
+}
+
+
+
+static gchar *benchmark_include_results_reverse(gdouble result,
+ const gchar * benchmark)
+{
+ return __benchmark_include_results(result, benchmark,
+ SHELL_ORDER_DESCENDING);
+}
+
+static gchar *benchmark_include_results(gdouble result,
+ const gchar * benchmark)
+{
+ return __benchmark_include_results(result, benchmark,
+ SHELL_ORDER_ASCENDING);
+}
+
+gdouble bench_results[BENCHMARK_N_ENTRIES];
+
+gchar *callback_gui()
+{
+ return benchmark_include_results_reverse(bench_results[BENCHMARK_GUI],
+ "GPU Drawing");
+}
+
+gchar *callback_fft()
+{
+ return benchmark_include_results(bench_results[BENCHMARK_FFT],
+ "FPU FFT");
+}
+
+gchar *callback_nqueens()
+{
+ return benchmark_include_results(bench_results[BENCHMARK_NQUEENS],
+ "CPU N-Queens");
+}
+
+gchar *callback_raytr()
+{
+ return benchmark_include_results(bench_results[BENCHMARK_RAYTRACE],
+ "FPU Raytracing");
+}
+
+gchar *callback_bfsh()
+{
+ return benchmark_include_results(bench_results[BENCHMARK_BLOWFISH],
+ "CPU Blowfish");
+}
+
+gchar *callback_cryptohash()
+{
+ return benchmark_include_results_reverse(bench_results[BENCHMARK_CRYPTOHASH],
+ "CPU CryptoHash");
+}
+
+gchar *callback_fib()
+{
+ return benchmark_include_results(bench_results[BENCHMARK_FIB],
+ "CPU Fibonacci");
+}
+
+typedef struct _BenchmarkDialog BenchmarkDialog;
+struct _BenchmarkDialog {
+ GtkWidget *dialog;
+ double result;
+};
+
+static gboolean do_benchmark_handler(GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ BenchmarkDialog *bench_dialog = (BenchmarkDialog*)data;
+ GIOStatus status;
+ gchar *result;
+ gchar *buffer;
+ float float_result;
+
+ status = g_io_channel_read_line(source, &result, NULL, NULL, NULL);
+ if (status != G_IO_STATUS_NORMAL) {
+ DEBUG("error while reading benchmark result");
+
+ bench_dialog->result = -1.0f;
+ gtk_widget_destroy(bench_dialog->dialog);
+ return FALSE;
+ }
+
+ float_result = strtof(result, &buffer);
+ if (buffer == result) {
+ DEBUG("error while converting floating point value");
+ bench_dialog->result = -1.0f;
+ } else {
+ bench_dialog->result = float_result;
+ }
+
+ gtk_widget_destroy(bench_dialog->dialog);
+ g_free(result);
+
+ return FALSE;
+}
+
+static void do_benchmark(void (*benchmark_function)(void), int entry)
+{
+ int old_priority = 0;
+
+ if (params.gui_running && !sending_benchmark_results) {
+ gchar *argv[] = { params.argv0, "-b", entries[entry].name,
+ "-m", "benchmark.so", "-a", NULL };
+ GPid bench_pid;
+ gint bench_stdout;
+ GtkWidget *bench_dialog;
+ GtkWidget *bench_image;
+ BenchmarkDialog *benchmark_dialog;
+ GSpawnFlags spawn_flags = G_SPAWN_STDERR_TO_DEV_NULL;
+ gchar *bench_status;
+
+ bench_status = g_strdup_printf(_("Benchmarking: <b>%s</b>."), entries[entry].name);
+
+ shell_view_set_enabled(FALSE);
+ shell_status_update(bench_status);
+
+ g_free(bench_status);
+
+ bench_image = icon_cache_get_image("benchmark.png");
+ gtk_widget_show(bench_image);
+
+ bench_dialog = gtk_message_dialog_new(GTK_WINDOW(shell_get_main_shell()->window),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_NONE,
+ _("Benchmarking. Please do not move your mouse " \
+ "or press any keys."));
+ g_object_set_data(G_OBJECT(bench_dialog), "result", "0.0");
+ gtk_dialog_add_buttons(GTK_DIALOG(bench_dialog),
+ _("Cancel"), GTK_RESPONSE_ACCEPT, NULL);
+ gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(bench_dialog), bench_image);
+
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+
+ benchmark_dialog = g_new0(BenchmarkDialog, 1);
+ benchmark_dialog->dialog = bench_dialog;
+ benchmark_dialog->result = -1.0f;
+
+ if (!g_path_is_absolute(params.argv0)) {
+ spawn_flags |= G_SPAWN_SEARCH_PATH;
+ }
+
+ if (g_spawn_async_with_pipes(NULL,
+ argv, NULL,
+ spawn_flags,
+ NULL, NULL,
+ &bench_pid,
+ NULL, &bench_stdout, NULL,
+ NULL)) {
+ GIOChannel *channel;
+ guint watch_id;
+
+ DEBUG("spawning benchmark; pid=%d", bench_pid);
+
+ channel = g_io_channel_unix_new(bench_stdout);
+ watch_id = g_io_add_watch(channel, G_IO_IN, do_benchmark_handler,
+ benchmark_dialog);
+
+ switch (gtk_dialog_run(GTK_DIALOG(bench_dialog))) {
+ case GTK_RESPONSE_NONE:
+ DEBUG("benchmark finished");
+ break;
+ case GTK_RESPONSE_ACCEPT:
+ DEBUG("cancelling benchmark");
+
+ gtk_widget_destroy(bench_dialog);
+ g_source_remove(watch_id);
+ kill(bench_pid, SIGINT);
+ }
+
+ bench_results[entry] = benchmark_dialog->result;
+
+ g_io_channel_unref(channel);
+ shell_view_set_enabled(TRUE);
+ shell_status_set_enabled(TRUE);
+ g_free(benchmark_dialog);
+
+ shell_status_update(_("Done."));
+
+ return;
+ }
+
+ gtk_widget_destroy(bench_dialog);
+ g_free(benchmark_dialog);
+ shell_status_set_enabled(TRUE);
+ shell_status_update(_("Done."));
+ }
+
+ setpriority(PRIO_PROCESS, 0, -20);
+ benchmark_function();
+ setpriority(PRIO_PROCESS, 0, old_priority);
+}
+
+void scan_gui(gboolean reload)
+{
+ SCAN_START();
+
+ if (params.run_benchmark) {
+ int argc = 0;
+
+ ui_init(&argc, NULL);
+ }
+
+ if (params.gui_running || params.run_benchmark) {
+ do_benchmark(benchmark_gui, BENCHMARK_GUI);
+ } else {
+ bench_results[BENCHMARK_GUI] = 0.0f;
+ }
+ SCAN_END();
+}
+
+void scan_fft(gboolean reload)
+{
+ SCAN_START();
+ do_benchmark(benchmark_fft, BENCHMARK_FFT);
+ SCAN_END();
+}
+
+void scan_nqueens(gboolean reload)
+{
+ SCAN_START();
+ do_benchmark(benchmark_nqueens, BENCHMARK_NQUEENS);
+ SCAN_END();
+}
+
+void scan_raytr(gboolean reload)
+{
+ SCAN_START();
+ do_benchmark(benchmark_raytrace, BENCHMARK_RAYTRACE);
+ SCAN_END();
+}
+
+void scan_bfsh(gboolean reload)
+{
+ SCAN_START();
+ do_benchmark(benchmark_fish, BENCHMARK_BLOWFISH);
+ SCAN_END();
+}
+
+void scan_cryptohash(gboolean reload)
+{
+ SCAN_START();
+ do_benchmark(benchmark_cryptohash, BENCHMARK_CRYPTOHASH);
+ SCAN_END();
+}
+
+void scan_fib(gboolean reload)
+{
+ SCAN_START();
+ do_benchmark(benchmark_fib, BENCHMARK_FIB);
+ SCAN_END();
+}
+
+const gchar *hi_note_func(gint entry)
+{
+ switch (entry) {
+ case BENCHMARK_CRYPTOHASH:
+ return _("Results in MiB/second. Higher is better.");
+
+ case BENCHMARK_GUI:
+ return _("Results in HIMarks. Higher is better.");
+
+ case BENCHMARK_FFT:
+ case BENCHMARK_RAYTRACE:
+ case BENCHMARK_BLOWFISH:
+ case BENCHMARK_FIB:
+ case BENCHMARK_NQUEENS:
+ return _("Results in seconds. Lower is better.");
+ }
+
+ return NULL;
+}
+
+gchar *hi_module_get_name(void)
+{
+ return g_strdup(_("Benchmarks"));
+}
+
+guchar hi_module_get_weight(void)
+{
+ return 240;
+}
+
+ModuleEntry *hi_module_get_entries(void)
+{
+ return entries;
+}
+
+ModuleAbout *hi_module_get_about(void)
+{
+ static ModuleAbout ma[] = {
+ {
+ .author = "Leandro A. F. Pereira",
+ .description = N_("Perform tasks and compare with other systems"),
+ .version = VERSION,
+ .license = "GNU GPL version 2"}
+ };
+
+ return ma;
+}
+
+static gchar *get_benchmark_results()
+{
+ gint i;
+ void (*scan_callback) (gboolean rescan);
+
+ sending_benchmark_results = TRUE;
+
+ gchar *machine = module_call_method("devices::getProcessorName");
+ gchar *machineclock = module_call_method("devices::getProcessorFrequency");
+ gchar *machineram = module_call_method("devices::getMemoryTotal");
+ gchar *result = g_strdup_printf("[param]\n"
+ "machine=%s\n"
+ "machineclock=%s\n"
+ "machineram=%s\n"
+ "nbenchmarks=%zu\n",
+ machine,
+ machineclock,
+ machineram,
+ G_N_ELEMENTS(entries) - 1);
+ for (i = 0; i < G_N_ELEMENTS(entries); i++) {
+ scan_callback = entries[i].scan_callback;
+ if (!scan_callback)
+ continue;
+
+ if (bench_results[i] < 0.0) {
+ /* benchmark was cancelled */
+ scan_callback(TRUE);
+ } else {
+ scan_callback(FALSE);
+ }
+
+ result = h_strdup_cprintf("[bench%d]\n"
+ "name=%s\n"
+ "value=%f\n",
+ result,
+ i, entries[i].name, bench_results[i]);
+ }
+
+ g_free(machine);
+ g_free(machineclock);
+ g_free(machineram);
+
+ sending_benchmark_results = FALSE;
+
+ return result;
+}
+
+static gchar *run_benchmark(gchar *name)
+{
+ int i;
+
+ DEBUG("name = %s", name);
+
+ for (i = 0; entries[i].name; i++) {
+ if (g_str_equal(entries[i].name, name)) {
+ void (*scan_callback)(gboolean rescan);
+
+ if ((scan_callback = entries[i].scan_callback)) {
+ scan_callback(FALSE);
+
+ return g_strdup_printf("%f", bench_results[i]);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+ShellModuleMethod *hi_exported_methods(void)
+{
+ static ShellModuleMethod m[] = {
+ {"runBenchmark", run_benchmark},
+ {NULL}
+ };
+
+ return m;
+}
+
+void hi_module_init(void)
+{
+ static SyncEntry se[] = {
+ {
+ .fancy_name = N_("Send benchmark results"),
+ .name = "SendBenchmarkResults",
+ .save_to = NULL,
+ .get_data = get_benchmark_results},
+ {
+ .fancy_name = N_("Receive benchmark results"),
+ .name = "RecvBenchmarkResults",
+ .save_to = "benchmark.conf",
+ .get_data = NULL}
+ };
+
+ sync_manager_add_entry(&se[0]);
+ sync_manager_add_entry(&se[1]);
+
+ int i;
+ for (i = 0; i < G_N_ELEMENTS(entries) - 1; i++) {
+ bench_results[i] = -1.0f;
+ }
+}
+
+gchar **hi_module_get_dependencies(void)
+{
+ static gchar *deps[] = { "devices.so", NULL };
+
+ return deps;
+}
+
diff --git a/modules/benchmark/blowfish.c b/modules/benchmark/blowfish.c
new file mode 100644
index 00000000..feadc430
--- /dev/null
+++ b/modules/benchmark/blowfish.c
@@ -0,0 +1,533 @@
+/*
+blowfish.c: C implementation of the Blowfish algorithm.
+
+Copyright (C) 1997 by Paul Kocher
+
+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.1 of the License, or (at your option) any later version.
+This library 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
+Lesser General Public License for more details.
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+COMMENTS ON USING THIS CODE:
+
+Normal usage is as follows:
+ [1] Allocate a BLOWFISH_CTX. (It may be too big for the stack.)
+ [2] Call Blowfish_Init with a pointer to your BLOWFISH_CTX, a pointer to
+ the key, and the number of bytes in the key.
+ [3] To encrypt a 64-bit block, call Blowfish_Encrypt with a pointer to
+ BLOWFISH_CTX, a pointer to the 32-bit left half of the plaintext
+ and a pointer to the 32-bit right half. The plaintext will be
+ overwritten with the ciphertext.
+ [4] Decryption is the same as encryption except that the plaintext and
+ ciphertext are reversed.
+
+Warning #1: The code does not check key lengths. (Caveat encryptor.)
+Warning #2: Beware that Blowfish keys repeat such that "ab" = "abab".
+Warning #3: It is normally a good idea to zeroize the BLOWFISH_CTX before
+ freeing it.
+Warning #4: Endianness conversions are the responsibility of the caller.
+ (To encrypt bytes on a little-endian platforms, you'll probably want
+ to swap bytes around instead of just casting.)
+Warning #5: Make sure to use a reasonable mode of operation for your
+ application. (If you don't know what CBC mode is, see Warning #7.)
+Warning #6: This code is susceptible to timing attacks.
+Warning #7: Security engineering is risky and non-intuitive. Have someone
+ check your work. If you don't know what you are doing, get help.
+
+
+This is code is fast enough for most applications, but is not optimized for
+speed.
+
+If you require this code under a license other than LGPL, please ask. (I
+can be located using your favorite search engine.) Unfortunately, I do not
+have time to provide unpaid support for everyone who uses this code.
+
+ -- Paul Kocher
+*/
+
+#include "hardinfo.h"
+#include "benchmark.h"
+#include "blowfish.h"
+
+#define N 16
+static const unsigned long ORIG_P[16 + 2] =
+ { 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, 0xA4093822L,
+ 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, 0x452821E6L, 0x38D01377L,
+ 0xBE5466CFL, 0x34E90C6CL, 0xC0AC29B7L,
+ 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, 0x9216D5D9L, 0x8979FB1BL
+};
+
+static const unsigned long ORIG_S[4][256] = {
+ {0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, 0xB8E1AFEDL,
+ 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, 0x24A19947L, 0xB3916CF7L,
+ 0x0801F2E2L, 0x858EFC16L, 0x636920D8L, 0x71574E69L, 0xA458FEA3L,
+ 0xF4933D7EL, 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL,
+ 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, 0xC5D1B023L,
+ 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, 0x8E79DCB0L, 0x603A180EL,
+ 0x6C9E0E8BL, 0xB01E8A3EL, 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL,
+ 0x55605C60L, 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L,
+ 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, 0xA15486AFL,
+ 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, 0x2BA9C55DL, 0x741831F6L,
+ 0xCE5C3E16L, 0x9B87931EL, 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L,
+ 0x28958677L, 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L,
+ 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, 0xEF845D5DL,
+ 0xE98575B1L, 0xDC262302L, 0xEB651B88L, 0x23893E81L, 0xD396ACC5L,
+ 0x0F6D6FF3L, 0x83F44239L, 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL,
+ 0x9E1F9B5EL, 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L,
+ 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, 0x6EEF0B6CL,
+ 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, 0xA1F1651DL, 0x39AF0176L,
+ 0x66CA593EL, 0x82430E88L, 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L,
+ 0x3B8B5EBEL, 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L,
+ 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, 0x37D0D724L,
+ 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, 0x075372C9L, 0x80991B7BL,
+ 0x25D479D8L, 0xF6E8DEF7L, 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL,
+ 0x04C006BAL, 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L,
+ 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, 0x6DFC511FL,
+ 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, 0xBEE3D004L, 0xDE334AFDL,
+ 0x660F2807L, 0x192E4BB3L, 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L,
+ 0xB9D3FBDBL, 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L,
+ 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, 0x3C7516DFL,
+ 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, 0x323DB5FAL, 0xFD238760L,
+ 0x53317B48L, 0x3E00DF82L, 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL,
+ 0xDF1769DBL, 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L,
+ 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, 0x10FA3D98L,
+ 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, 0x9A53E479L, 0xB6F84565L,
+ 0xD28E49BCL, 0x4BFB9790L, 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L,
+ 0xCEE4C6E8L, 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L,
+ 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, 0xD08ED1D0L,
+ 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, 0x8FF6E2FBL, 0xF2122B64L,
+ 0x8888B812L, 0x900DF01CL, 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L,
+ 0xB3A8C1ADL, 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L,
+ 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, 0xB4A84FE0L,
+ 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, 0x165FA266L, 0x80957705L,
+ 0x93CC7314L, 0x211A1477L, 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L,
+ 0xFB9D35CFL, 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L,
+ 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, 0x2464369BL,
+ 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, 0x78C14389L, 0xD95A537FL,
+ 0x207D5BA2L, 0x02E5B9C5L, 0x83260376L, 0x6295CFA9L, 0x11C81968L,
+ 0x4E734A41L, 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L,
+ 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, 0x08BA6FB5L,
+ 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, 0xB6636521L, 0xE7B9F9B6L,
+ 0xFF34052EL, 0xC5855664L, 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L,
+ 0x6E85076AL}, {0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL,
+ 0xC4192623L, 0xAD6EA6B0L, 0x49A7DF7DL,
+ 0x9CEE60B8L, 0x8FEDB266L, 0xECAA8C71L,
+ 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L,
+ 0x193602A5L, 0x75094C29L, 0xA0591340L,
+ 0xE4183A3EL, 0x3F54989AL, 0x5B429D65L,
+ 0x6B8FE4D6L, 0x99F73FD6L, 0xA1D29C07L,
+ 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L,
+ 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L,
+ 0x021ECC5EL, 0x09686B3FL, 0x3EBAEFC9L,
+ 0x3C971814L, 0x6B6A70A1L, 0x687F3584L,
+ 0x52A0E286L, 0xB79C5305L, 0xAA500737L,
+ 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL,
+ 0x5716F2B8L, 0xB03ADA37L, 0xF0500C0DL,
+ 0xF01C1F04L, 0x0200B3FFL, 0xAE0CF51AL,
+ 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL,
+ 0xD19113F9L, 0x7CA92FF6L, 0x94324773L,
+ 0x22F54701L, 0x3AE5E581L, 0x37C2DADCL,
+ 0xC8B57634L, 0x9AF3DDA7L, 0xA9446146L,
+ 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L,
+ 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L,
+ 0x183EB331L, 0x4E548B38L, 0x4F6DB908L,
+ 0x6F420D03L, 0xF60A04BFL, 0x2CB81290L,
+ 0x24977C79L, 0x5679B072L, 0xBCAF89AFL,
+ 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L,
+ 0xDCCF3F2EL, 0x5512721FL, 0x2E6B7124L,
+ 0x501ADDE6L, 0x9F84CD87L, 0x7A584718L,
+ 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL,
+ 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L,
+ 0xC464C3D2L, 0xEF1C1847L, 0x3215D908L,
+ 0xDD433B37L, 0x24C2BA16L, 0x12A14D43L,
+ 0x2A65C451L, 0x50940002L, 0x133AE4DDL,
+ 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L,
+ 0x5F11199BL, 0x043556F1L, 0xD7A3C76BL,
+ 0x3C11183BL, 0x5924A509L, 0xF28FE6EDL,
+ 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL,
+ 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL,
+ 0x5A3E2AB3L, 0x771FE71CL, 0x4E3D06FAL,
+ 0x2965DCB9L, 0x99E71D0FL, 0x803E89D6L,
+ 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL,
+ 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L,
+ 0x1E0A2DF4L, 0xF2F74EA7L, 0x361D2B3DL,
+ 0x1939260FL, 0x19C27960L, 0x5223A708L,
+ 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L,
+ 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L,
+ 0x018CFF28L, 0xC332DDEFL, 0xBE6C5AA5L,
+ 0x65582185L, 0x68AB9802L, 0xEECEA50FL,
+ 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L,
+ 0x1521B628L, 0x29076170L, 0xECDD4775L,
+ 0x619F1510L, 0x13CCA830L, 0xEB61BD96L,
+ 0x0334FE1EL, 0xAA0363CFL, 0xB5735C90L,
+ 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L,
+ 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL,
+ 0xB2F3846EL, 0x648B1EAFL, 0x19BDF0CAL,
+ 0xA02369B9L, 0x655ABB50L, 0x40685A32L,
+ 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L,
+ 0x9B540B19L, 0x875FA099L, 0x95F7997EL,
+ 0x623D7DA8L, 0xF837889AL, 0x97E32D77L,
+ 0x11ED935FL, 0x16681281L, 0x0E358829L,
+ 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L,
+ 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL,
+ 0x1AC24696L, 0xCDB30AEBL, 0x532E3054L,
+ 0x8FD948E4L, 0x6DBC3128L, 0x58EBF2EFL,
+ 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L,
+ 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L,
+ 0x203E13E0L, 0x45EEE2B6L, 0xA3AAABEAL,
+ 0xDB6C4F15L, 0xFACB4FD0L, 0xC742F442L,
+ 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L,
+ 0xD81E799EL, 0x86854DC7L, 0xE44B476AL,
+ 0x3D816250L, 0xCF62A1F2L, 0x5B8D2646L,
+ 0xFC8883A0L, 0xC1C7B6A3L, 0x7F1524C3L,
+ 0x69CB7492L, 0x47848A0BL, 0x5692B285L,
+ 0x095BBF00L, 0xAD19489DL, 0x1462B174L,
+ 0x23820E00L, 0x58428D2AL, 0x0C55F5EAL,
+ 0x1DADF43EL, 0x233F7061L, 0x3372F092L,
+ 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL,
+ 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L,
+ 0xCE77326EL, 0xA6078084L, 0x19F8509EL,
+ 0xE8EFD855L, 0x61D99735L, 0xA969A7AAL,
+ 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL,
+ 0x9E447A2EL, 0xC3453484L, 0xFDD56705L,
+ 0x0E1E9EC9L, 0xDB73DBD3L, 0x105588CDL,
+ 0x675FDA79L, 0xE3674340L, 0xC5C43465L,
+ 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L,
+ 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL,
+ 0xDB83ADF7L}, {0xE93D5A68L, 0x948140F7L,
+ 0xF64C261CL, 0x94692934L,
+ 0x411520F7L, 0x7602D4F7L,
+ 0xBCF46B2EL, 0xD4A20068L,
+ 0xD4082471L, 0x3320F46AL,
+ 0x43B7D4B7L, 0x500061AFL,
+ 0x1E39F62EL, 0x97244546L,
+ 0x14214F74L, 0xBF8B8840L,
+ 0x4D95FC1DL, 0x96B591AFL,
+ 0x70F4DDD3L, 0x66A02F45L,
+ 0xBFBC09ECL, 0x03BD9785L,
+ 0x7FAC6DD0L, 0x31CB8504L,
+ 0x96EB27B3L, 0x55FD3941L,
+ 0xDA2547E6L, 0xABCA0A9AL,
+ 0x28507825L, 0x530429F4L,
+ 0x0A2C86DAL, 0xE9B66DFBL,
+ 0x68DC1462L, 0xD7486900L,
+ 0x680EC0A4L, 0x27A18DEEL,
+ 0x4F3FFEA2L, 0xE887AD8CL,
+ 0xB58CE006L, 0x7AF4D6B6L,
+ 0xAACE1E7CL, 0xD3375FECL,
+ 0xCE78A399L, 0x406B2A42L,
+ 0x20FE9E35L, 0xD9F385B9L,
+ 0xEE39D7ABL, 0x3B124E8BL,
+ 0x1DC9FAF7L, 0x4B6D1856L,
+ 0x26A36631L, 0xEAE397B2L,
+ 0x3A6EFA74L, 0xDD5B4332L,
+ 0x6841E7F7L, 0xCA7820FBL,
+ 0xFB0AF54EL, 0xD8FEB397L,
+ 0x454056ACL, 0xBA489527L,
+ 0x55533A3AL, 0x20838D87L,
+ 0xFE6BA9B7L, 0xD096954BL,
+ 0x55A867BCL, 0xA1159A58L,
+ 0xCCA92963L, 0x99E1DB33L,
+ 0xA62A4A56L, 0x3F3125F9L,
+ 0x5EF47E1CL, 0x9029317CL,
+ 0xFDF8E802L, 0x04272F70L,
+ 0x80BB155CL, 0x05282CE3L,
+ 0x95C11548L, 0xE4C66D22L,
+ 0x48C1133FL, 0xC70F86DCL,
+ 0x07F9C9EEL, 0x41041F0FL,
+ 0x404779A4L, 0x5D886E17L,
+ 0x325F51EBL, 0xD59BC0D1L,
+ 0xF2BCC18FL, 0x41113564L,
+ 0x257B7834L, 0x602A9C60L,
+ 0xDFF8E8A3L, 0x1F636C1BL,
+ 0x0E12B4C2L, 0x02E1329EL,
+ 0xAF664FD1L, 0xCAD18115L,
+ 0x6B2395E0L, 0x333E92E1L,
+ 0x3B240B62L, 0xEEBEB922L,
+ 0x85B2A20EL, 0xE6BA0D99L,
+ 0xDE720C8CL, 0x2DA2F728L,
+ 0xD0127845L, 0x95B794FDL,
+ 0x647D0862L, 0xE7CCF5F0L,
+ 0x5449A36FL, 0x877D48FAL,
+ 0xC39DFD27L, 0xF33E8D1EL,
+ 0x0A476341L, 0x992EFF74L,
+ 0x3A6F6EABL, 0xF4F8FD37L,
+ 0xA812DC60L, 0xA1EBDDF8L,
+ 0x991BE14CL, 0xDB6E6B0DL,
+ 0xC67B5510L, 0x6D672C37L,
+ 0x2765D43BL, 0xDCD0E804L,
+ 0xF1290DC7L, 0xCC00FFA3L,
+ 0xB5390F92L, 0x690FED0BL,
+ 0x667B9FFBL, 0xCEDB7D9CL,
+ 0xA091CF0BL, 0xD9155EA3L,
+ 0xBB132F88L, 0x515BAD24L,
+ 0x7B9479BFL, 0x763BD6EBL,
+ 0x37392EB3L, 0xCC115979L,
+ 0x8026E297L, 0xF42E312DL,
+ 0x6842ADA7L, 0xC66A2B3BL,
+ 0x12754CCCL, 0x782EF11CL,
+ 0x6A124237L, 0xB79251E7L,
+ 0x06A1BBE6L, 0x4BFB6350L,
+ 0x1A6B1018L, 0x11CAEDFAL,
+ 0x3D25BDD8L, 0xE2E1C3C9L,
+ 0x44421659L, 0x0A121386L,
+ 0xD90CEC6EL, 0xD5ABEA2AL,
+ 0x64AF674EL, 0xDA86A85FL,
+ 0xBEBFE988L, 0x64E4C3FEL,
+ 0x9DBC8057L, 0xF0F7C086L,
+ 0x60787BF8L, 0x6003604DL,
+ 0xD1FD8346L, 0xF6381FB0L,
+ 0x7745AE04L, 0xD736FCCCL,
+ 0x83426B33L, 0xF01EAB71L,
+ 0xB0804187L, 0x3C005E5FL,
+ 0x77A057BEL, 0xBDE8AE24L,
+ 0x55464299L, 0xBF582E61L,
+ 0x4E58F48FL, 0xF2DDFDA2L,
+ 0xF474EF38L, 0x8789BDC2L,
+ 0x5366F9C3L, 0xC8B38E74L,
+ 0xB475F255L, 0x46FCD9B9L,
+ 0x7AEB2661L, 0x8B1DDF84L,
+ 0x846A0E79L, 0x915F95E2L,
+ 0x466E598EL, 0x20B45770L,
+ 0x8CD55591L, 0xC902DE4CL,
+ 0xB90BACE1L, 0xBB8205D0L,
+ 0x11A86248L, 0x7574A99EL,
+ 0xB77F19B6L, 0xE0A9DC09L,
+ 0x662D09A1L, 0xC4324633L,
+ 0xE85A1F02L, 0x09F0BE8CL,
+ 0x4A99A025L, 0x1D6EFE10L,
+ 0x1AB93D1DL, 0x0BA5A4DFL,
+ 0xA186F20FL, 0x2868F169L,
+ 0xDCB7DA83L, 0x573906FEL,
+ 0xA1E2CE9BL, 0x4FCD7F52L,
+ 0x50115E01L, 0xA70683FAL,
+ 0xA002B5C4L, 0x0DE6D027L,
+ 0x9AF88C27L, 0x773F8641L,
+ 0xC3604C06L, 0x61A806B5L,
+ 0xF0177A28L, 0xC0F586E0L,
+ 0x006058AAL, 0x30DC7D62L,
+ 0x11E69ED7L, 0x2338EA63L,
+ 0x53C2DD94L, 0xC2C21634L,
+ 0xBBCBEE56L, 0x90BCB6DEL,
+ 0xEBFC7DA1L, 0xCE591D76L,
+ 0x6F05E409L, 0x4B7C0188L,
+ 0x39720A3DL, 0x7C927C24L,
+ 0x86E3725FL, 0x724D9DB9L,
+ 0x1AC15BB4L, 0xD39EB8FCL,
+ 0xED545578L, 0x08FCA5B5L,
+ 0xD83D7CD3L, 0x4DAD0FC4L,
+ 0x1E50EF5EL, 0xB161E6F8L,
+ 0xA28514D9L, 0x6C51133CL,
+ 0x6FD5C7E7L, 0x56E14EC4L,
+ 0x362ABFCEL, 0xDDC6C837L,
+ 0xD79A3234L, 0x92638212L,
+ 0x670EFA8EL, 0x406000E0L},
+{0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, 0x5CB0679EL,
+ 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, 0xD5118E9DL, 0xBF0F7315L,
+ 0xD62D1C7EL, 0xC700C47BL, 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL,
+ 0x6A366EB4L, 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L,
+ 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, 0x2939BBDBL,
+ 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, 0xA1FAD5F0L, 0x6A2D519AL,
+ 0x63EF8CE2L, 0x9A86EE22L, 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL,
+ 0x9CF2D0A4L, 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L,
+ 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, 0xC72FEFD3L,
+ 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, 0x80E4A915L, 0x87B08601L,
+ 0x9B09E6ADL, 0x3B3EE593L, 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L,
+ 0x022B8B51L, 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L,
+ 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, 0xE029AC71L,
+ 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, 0xE8D3C48DL, 0x283B57CCL,
+ 0xF8D56629L, 0x79132E28L, 0x785F0191L, 0xED756055L, 0xF7960E44L,
+ 0xE3D35E8CL, 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL,
+ 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, 0x1B3F6D9BL,
+ 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, 0x7533D928L, 0xB155FDF5L,
+ 0x03563482L, 0x8ABA3CBBL, 0x28517711L, 0xC20AD9F8L, 0xABCC5167L,
+ 0xCCAD925FL, 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L,
+ 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, 0xA8B6E37EL,
+ 0xC3293D46L, 0x48DE5369L, 0x6413E680L, 0xA2AE0810L, 0xDD6DB224L,
+ 0x69852DFDL, 0x09072166L, 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL,
+ 0x1C20C8AEL, 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL,
+ 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, 0x72EACEA8L,
+ 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, 0xD29BE463L, 0x542F5D9EL,
+ 0xAEC2771BL, 0xF64E6370L, 0x740E0D8DL, 0xE75B1357L, 0xF8721671L,
+ 0xAF537D5DL, 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L,
+ 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, 0x6F3F3B82L,
+ 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, 0x611560B1L, 0xE7933FDCL,
+ 0xBB3A792BL, 0x344525BDL, 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L,
+ 0xA01FBAC9L, 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L,
+ 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, 0x0339C32AL,
+ 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, 0xF79E59B7L, 0x43F5BB3AL,
+ 0xF2D519FFL, 0x27D9459CL, 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L,
+ 0x9B941525L, 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L,
+ 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, 0xE0EC6E0EL,
+ 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, 0x9F1F9532L, 0xE0D392DFL,
+ 0xD3A0342BL, 0x8971F21EL, 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L,
+ 0xC37632D8L, 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL,
+ 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, 0x1618B166L,
+ 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, 0xF523F357L, 0xA6327623L,
+ 0x93A83531L, 0x56CCCD02L, 0xACF08162L, 0x5A75EBB5L, 0x6E163697L,
+ 0x88D273CCL, 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L,
+ 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, 0xC9AA53FDL,
+ 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, 0x71126905L, 0xB2040222L,
+ 0xB6CBCF7CL, 0xCD769C2BL, 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L,
+ 0x2547ADF0L, 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L,
+ 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, 0x1948C25CL,
+ 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, 0x90D4F869L, 0xA65CDEA0L,
+ 0x3F09252DL, 0xC208E69FL, 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L,
+ 0x3AC372E6L}
+};
+
+static unsigned long F(BLOWFISH_CTX * ctx, unsigned long x)
+{
+ unsigned short a, b, c, d;
+ unsigned long y;
+ d = (unsigned short) (x & 0xFF);
+ x >>= 8;
+ c = (unsigned short) (x & 0xFF);
+ x >>= 8;
+ b = (unsigned short) (x & 0xFF);
+ x >>= 8;
+ a = (unsigned short) (x & 0xFF);
+ y = ctx->S[0][a] + ctx->S[1][b];
+ y = y ^ ctx->S[2][c];
+ y = y + ctx->S[3][d];
+ return y;
+}
+
+void Blowfish_Encrypt(BLOWFISH_CTX * ctx, unsigned long *xl,
+ unsigned long *xr)
+{
+ unsigned long Xl;
+ unsigned long Xr;
+ unsigned long temp;
+ short i;
+ Xl = *xl;
+ Xr = *xr;
+ for (i = 0; i < N; ++i) {
+ Xl = Xl ^ ctx->P[i];
+ Xr = F(ctx, Xl) ^ Xr;
+ temp = Xl;
+ Xl = Xr;
+ Xr = temp;
+ }
+ temp = Xl;
+ Xl = Xr;
+ Xr = temp;
+ Xr = Xr ^ ctx->P[N];
+ Xl = Xl ^ ctx->P[N + 1];
+ *xl = Xl;
+ *xr = Xr;
+}
+
+void Blowfish_Decrypt(BLOWFISH_CTX * ctx, unsigned long *xl,
+ unsigned long *xr)
+{
+ unsigned long Xl;
+ unsigned long Xr;
+ unsigned long temp;
+ short i;
+ Xl = *xl;
+ Xr = *xr;
+ for (i = N + 1; i > 1; --i) {
+ Xl = Xl ^ ctx->P[i];
+ Xr = F(ctx, Xl) ^ Xr;
+
+ /* Exchange Xl and Xr */
+ temp = Xl;
+ Xl = Xr;
+ Xr = temp;
+ }
+
+ /* Exchange Xl and Xr */
+ temp = Xl;
+ Xl = Xr;
+ Xr = temp;
+ Xr = Xr ^ ctx->P[1];
+ Xl = Xl ^ ctx->P[0];
+ *xl = Xl;
+ *xr = Xr;
+}
+
+void Blowfish_Init(BLOWFISH_CTX * ctx, unsigned char *key, int keyLen)
+{
+ int i, j, k;
+ unsigned long data, datal, datar;
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 256; j++)
+ ctx->S[i][j] = ORIG_S[i][j];
+ }
+ j = 0;
+ for (i = 0; i < N + 2; ++i) {
+ data = 0x00000000;
+ for (k = 0; k < 4; ++k) {
+ data = (data << 8) | key[j];
+ j = j + 1;
+ if (j >= keyLen)
+ j = 0;
+ }
+ ctx->P[i] = ORIG_P[i] ^ data;
+ }
+ datal = 0x00000000;
+ datar = 0x00000000;
+ for (i = 0; i < N + 2; i += 2) {
+ Blowfish_Encrypt(ctx, &datal, &datar);
+ ctx->P[i] = datal;
+ ctx->P[i + 1] = datar;
+ }
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 256; j += 2) {
+ Blowfish_Encrypt(ctx, &datal, &datar);
+ ctx->S[i][j] = datal;
+ ctx->S[i][j + 1] = datar;
+ }
+ }
+}
+
+static gpointer
+parallel_blowfish(unsigned int start, unsigned int end, void *data, gint thread_number)
+{
+ BLOWFISH_CTX ctx;
+ unsigned int i;
+ unsigned long L, R;
+
+ L = 0xBEBACAFE;
+ R = 0xDEADBEEF;
+
+ for (i = start; i <= end; i++) {
+ Blowfish_Init(&ctx, (unsigned char*)data, 65536);
+ Blowfish_Encrypt(&ctx, &L, &R);
+ Blowfish_Decrypt(&ctx, &L, &R);
+ }
+
+ return NULL;
+}
+
+void
+benchmark_fish(void)
+{
+ gchar *tmpsrc;
+ gchar *bdata_path;
+
+ bdata_path = g_build_filename(params.path_data, "benchmark.data", NULL);
+ if (!g_file_get_contents(bdata_path, &tmpsrc, NULL, NULL)) {
+ bench_results[BENCHMARK_BLOWFISH] = -1.0f;
+ g_free(bdata_path);
+ return;
+ }
+
+ shell_view_set_enabled(FALSE);
+ shell_status_update("Performing Blowfish benchmark...");
+
+ bench_results[BENCHMARK_BLOWFISH] = benchmark_parallel_for(0, 50000, parallel_blowfish, tmpsrc);
+ g_free(bdata_path);
+ g_free(tmpsrc);
+}
diff --git a/modules/benchmark/cryptohash.c b/modules/benchmark/cryptohash.c
new file mode 100644
index 00000000..d97e85c7
--- /dev/null
+++ b/modules/benchmark/cryptohash.c
@@ -0,0 +1,79 @@
+/*
+ * 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 "md5.h"
+#include "sha1.h"
+#include "benchmark.h"
+
+static void inline md5_step(char *data, glong srclen)
+{
+ struct MD5Context ctx;
+ guchar checksum[16];
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (guchar *)data, srclen);
+ MD5Final(checksum, &ctx);
+}
+
+static void inline sha1_step(char *data, glong srclen)
+{
+ SHA1_CTX ctx;
+ guchar checksum[20];
+
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, (guchar*)data, srclen);
+ SHA1Final(checksum, &ctx);
+}
+
+static gpointer cryptohash_for(unsigned int start, unsigned int end, void *data, gint thread_number)
+{
+ unsigned int i;
+
+ for (i = start; i <= end; i++) {
+ if (i & 1) {
+ md5_step(data, 65536);
+ } else {
+ sha1_step(data, 65536);
+ }
+ }
+
+ return NULL;
+}
+
+void
+benchmark_cryptohash(void)
+{
+ gdouble elapsed = 0;
+ gchar *tmpsrc, *bdata_path;
+
+ bdata_path = g_build_filename(params.path_data, "benchmark.data", NULL);
+ if (!g_file_get_contents(bdata_path, &tmpsrc, NULL, NULL)) {
+ g_free(bdata_path);
+ return;
+ }
+
+ shell_view_set_enabled(FALSE);
+ shell_status_update("Running CryptoHash benchmark...");
+
+ elapsed = benchmark_parallel_for(0, 5000, cryptohash_for, tmpsrc);
+
+ g_free(bdata_path);
+ g_free(tmpsrc);
+
+ bench_results[BENCHMARK_CRYPTOHASH] = 312.0 / elapsed;
+}
diff --git a/modules/benchmark/drawing.c b/modules/benchmark/drawing.c
new file mode 100644
index 00000000..67a2c264
--- /dev/null
+++ b/modules/benchmark/drawing.c
@@ -0,0 +1,29 @@
+/*
+ * 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 "benchmark.h"
+#include "guibench.h"
+
+void
+benchmark_gui(void)
+{
+ shell_view_set_enabled(FALSE);
+ shell_status_update("Running drawing benchmark...");
+
+ bench_results[BENCHMARK_GUI] = guibench();
+}
diff --git a/modules/benchmark/fbench.c b/modules/benchmark/fbench.c
new file mode 100644
index 00000000..b5afc1bc
--- /dev/null
+++ b/modules/benchmark/fbench.c
@@ -0,0 +1,745 @@
+/*
+
+ John Walker's Floating Point Benchmark, derived from...
+
+ Marinchip Interactive Lens Design System
+
+ John Walker December 1980
+
+ By John Walker
+ https://www.fourmilab.ch/
+
+ This program may be used, distributed, and modified freely as
+ long as the origin information is preserved.
+
+ This is a complete optical design raytracing algorithm,
+ stripped of its user interface and recast into portable C. It
+ not only determines execution speed on an extremely floating
+ point (including trig function) intensive real-world
+ application, it checks accuracy on an algorithm that is
+ exquisitely sensitive to errors. The performance of this
+ program is typically far more sensitive to changes in the
+ efficiency of the trigonometric library routines than the
+ average floating point program.
+
+ The benchmark may be compiled in two modes. If the symbol
+ INTRIG is defined, built-in trigonometric and square root
+ routines will be used for all calculations. Timings made with
+ INTRIG defined reflect the machine's basic floating point
+ performance for the arithmetic operators. If INTRIG is not
+ defined, the system library <math.h> functions are used.
+ Results with INTRIG not defined reflect the system's library
+ performance and/or floating point hardware support for trig
+ functions and square root. Results with INTRIG defined are a
+ good guide to general floating point performance, while
+ results with INTRIG undefined indicate the performance of an
+ application which is math function intensive.
+
+ Special note regarding errors in accuracy: this program has
+ generated numbers identical to the last digit it formats and
+ checks on the following machines, floating point
+ architectures, and languages:
+
+ Marinchip 9900 QBASIC IBM 370 double-precision (REAL * 8) format
+
+ IBM PC / XT / AT Lattice C IEEE 64 bit, 80 bit temporaries
+ High C same, in line 80x87 code
+ BASICA "Double precision"
+ Quick BASIC IEEE double precision, software routines
+
+ Sun 3 C IEEE 64 bit, 80 bit temporaries,
+ in-line 68881 code, in-line FPA code.
+
+ MicroVAX II C Vax "G" format floating point
+
+ Macintosh Plus MPW C SANE floating point, IEEE 64 bit format
+ implemented in ROM.
+
+ Inaccuracies reported by this program should be taken VERY
+ SERIOUSLY INDEED, as the program has been demonstrated to be
+ invariant under changes in floating point format, as long as
+ the format is a recognised double precision format. If you
+ encounter errors, please remember that they are just as likely
+ to be in the floating point editing library or the
+ trigonometric libraries as in the low level operator code.
+
+ The benchmark assumes that results are basically reliable, and
+ only tests the last result computed against the reference. If
+ you're running on a suspect system you can compile this
+ program with ACCURACY defined. This will generate a version
+ which executes as an infinite loop, performing the ray trace
+ and checking the results on every pass. All incorrect results
+ will be reported.
+
+ Representative timings are given below. All have been
+ normalised as if run for 1000 iterations.
+
+ Time in seconds Computer, Compiler, and notes
+ Normal INTRIG
+
+ 3466.00 4031.00 Commodore 128, 2 Mhz 8510 with software floating
+ point. Abacus Software/Data-Becker Super-C 128,
+ version 3.00, run in fast (2 Mhz) mode. Note:
+ the results generated by this system differed
+ from the reference results in the 8th to 10th
+ decimal place.
+
+ 3290.00 IBM PC/AT 6 Mhz, Microsoft/IBM BASICA version A3.00.
+ Run with the "/d" switch, software floating point.
+
+ 2131.50 IBM PC/AT 6 Mhz, Lattice C version 2.14, small model.
+ This version of Lattice compiles subroutine
+ calls which either do software floating point
+ or use the 80x87. The machine on which I ran
+ this had an 80287, but the results were so bad
+ I wonder if it was being used.
+
+ 1598.00 Macintosh Plus, MPW C, SANE Software floating point.
+
+ 1582.13 Marinchip 9900 2 Mhz, QBASIC compiler with software
+ floating point. This was a QBASIC version of the
+ program which contained the identical algorithm.
+
+ 404.00 IBM PC/AT 6 Mhz, Microsoft QuickBASIC version 2.0.
+ Software floating point.
+
+ 165.15 IBM PC/AT 6 Mhz, Metaware High C version 1.3, small
+ model. This was compiled to call subroutines for
+ floating point, and the machine contained an 80287
+ which was used by the subroutines.
+
+ 143.20 Macintosh II, MPW C, SANE calls. I was unable to
+ determine whether SANE was using the 68881 chip or
+ not.
+
+ 121.80 Sun 3/160 16 Mhz, Sun C. Compiled with -fsoft switch
+ which executes floating point in software.
+
+ 78.78 110.11 IBM RT PC (Model 6150). IBM AIX 1.0 C compiler
+ with -O switch.
+
+ 75.2 254.0 Microsoft Quick C 1.0, in-line 8087 instructions,
+ compiled with 80286 optimisation on. (Switches
+ were -Ol -FPi87-G2 -AS). Small memory model.
+
+ 69.50 IBM PC/AT 6Mhz, Borland Turbo BASIC 1.0. Compiled
+ in "8087 required" mode to generate in-line
+ code for the math coprocessor.
+
+ 66.96 IBM PC/AT 6Mhz, Microsoft QuickBASIC 4.0. This
+ release of QuickBASIC compiles code for the
+ 80287 math coprocessor.
+
+ 66.36 206.35 IBM PC/AT 6Mhz, Metaware High C version 1.3, small
+ model. This was compiled with in-line code for the
+ 80287 math coprocessor. Trig functions still call
+ library routines.
+
+ 63.07 220.43 IBM PC/AT, 6Mhz, Borland Turbo C, in-line 8087 code,
+ small model, word alignment, no stack checking,
+ 8086 code mode.
+
+ 17.18 Apollo DN-3000, 12 Mhz 68020 with 68881, compiled
+ with in-line code for the 68881 coprocessor.
+ According to Apollo, the library routines are chosen
+ at runtime based on coprocessor presence. Since the
+ coprocessor was present, the library is supposed to
+ use in-line floating point code.
+
+ 15.55 27.56 VAXstation II GPX. Compiled and executed under
+ VAX/VMS C.
+
+ 15.14 37.93 Macintosh II, Unix system V. Green Hills 68020
+ Unix compiler with in-line code for the 68881
+ coprocessor (-O -ZI switches).
+
+ 12.69 Sun 3/160 16 Mhz, Sun C. Compiled with -fswitch,
+ which calls a subroutine to select the fastest
+ floating point processor. This was using the 68881.
+
+ 11.74 26.73 Compaq Deskpro 386, 16 Mhz 80386 with 16 Mhz 80387.
+ Metaware High C version 1.3, compiled with in-line
+ for the math coprocessor (but not optimised for the
+ 80386/80387). Trig functions still call library
+ routines.
+
+ 8.43 30.49 Sun 3/160 16 Mhz, Sun C. Compiled with -f68881,
+ generating in-line MC68881 instructions. Trig
+ functions still call library routines.
+
+ 6.29 25.17 Sun 3/260 25 Mhz, Sun C. Compiled with -f68881,
+ generating in-line MC68881 instructions. Trig
+ functions still call library routines.
+
+ 4.57 Sun 3/260 25 Mhz, Sun FORTRAN 77. Compiled with
+ -O -f68881, generating in-line MC68881 instructions.
+ Trig functions are compiled in-line. This used
+ the FORTRAN 77 version of the program, FBFORT77.F.
+
+ 4.00 14.20 Sun386i/25 Mhz model 250, Sun C compiler.
+
+ 4.00 14.00 Sun386i/25 Mhz model 250, Metaware C.
+
+ 3.10 12.00 Compaq 386/387 25 Mhz running SCO Xenix 2.
+ Compiled with Metaware HighC 386, optimized
+ for 386.
+
+ 3.00 12.00 Compaq 386/387 25MHZ optimized for 386/387.
+
+ 2.96 5.17 Sun 4/260, Sparc RISC processor. Sun C,
+ compiled with the -O2 switch for global
+ optimisation.
+
+ 2.47 COMPAQ 486/25, secondary cache disabled, High C,
+ 486/387, inline f.p., small memory model.
+
+ 2.20 3.40 Data General Motorola 88000, 16 Mhz, Gnu C.
+
+ 1.56 COMPAQ 486/25, 128K secondary cache, High C, 486/387,
+ inline f.p., small memory model.
+
+ 0.66 1.50 DEC Pmax, Mips processor.
+
+ 0.63 0.91 Sun SparcStation 2, Sun C (SunOS 4.1.1) with
+ -O4 optimisation and "/usr/lib/libm.il" inline
+ floating point.
+
+ 0.60 1.07 Intel 860 RISC processor, 33 Mhz, Greenhills
+ C compiler.
+
+ 0.40 0.90 Dec 3MAX, MIPS 3000 processor, -O4.
+
+ 0.31 0.90 IBM RS/6000, -O.
+
+ 0.1129 0.2119 Dell Dimension XPS P133c, Pentium 133 MHz,
+ Windows 95, Microsoft Visual C 5.0.
+
+ 0.0883 0.2166 Silicon Graphics Indigo², MIPS R4400,
+ 175 Mhz, "-O3".
+
+ 0.0351 0.0561 Dell Dimension XPS R100, Pentium II 400 MHz,
+ Windows 98, Microsoft Visual C 5.0.
+
+ 0.0312 0.0542 Sun Ultra 2, UltraSPARC V9, 300 MHz, Solaris
+ 2.5.1.
+
+ 0.00862 0.01074 Dell Inspiron 9100, Pentium 4, 3.4 GHz, gcc -O3.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef INTRIG
+#include <math.h>
+#endif
+
+#define cot(x) (1.0 / tan(x))
+
+#define TRUE 1
+#define FALSE 0
+
+#define max_surfaces 10
+
+/* Local variables */
+
+/*static char tbfr[132];*/
+
+static short current_surfaces;
+static short paraxial;
+
+static double clear_aperture;
+
+static double aberr_lspher;
+static double aberr_osc;
+static double aberr_lchrom;
+
+static double max_lspher;
+static double max_osc;
+static double max_lchrom;
+
+static double radius_of_curvature;
+static double object_distance;
+static double ray_height;
+static double axis_slope_angle;
+static double from_index;
+static double to_index;
+
+static double spectral_line[9];
+static double s[max_surfaces][5];
+static double od_sa[2][2];
+
+ /*static char outarr[8][80];*//* Computed output of program goes here */
+
+static int itercount; /* The iteration counter for the main loop
+ in the program is made global so that
+ the compiler should not be allowed to
+ optimise out the loop over the ray
+ tracing code. */
+
+#ifndef ITERATIONS
+#define ITERATIONS 1000
+#endif
+static int niter = ITERATIONS; /* Iteration counter */
+
+#if 0
+static char *refarr[] = { /* Reference results. These happen to
+ be derived from a run on Microsoft
+ Quick BASIC on the IBM PC/AT. */
+
+ " Marginal ray 47.09479120920 0.04178472683",
+ " Paraxial ray 47.08372160249 0.04177864821",
+ "Longitudinal spherical aberration: -0.01106960671",
+ " (Maximum permissible): 0.05306749907",
+ "Offense against sine condition (coma): 0.00008954761",
+ " (Maximum permissible): 0.00250000000",
+ "Axial chromatic aberration: 0.00448229032",
+ " (Maximum permissible): 0.05306749907"
+};
+#endif
+
+/* The test case used in this program is the design for a 4 inch
+ achromatic telescope objective used as the example in Wyld's
+ classic work on ray tracing by hand, given in Amateur Telescope
+ Making, Volume 3. */
+
+static double testcase[4][4] = {
+ {27.05, 1.5137, 63.6, 0.52},
+ {-16.68, 1, 0, 0.138},
+ {-16.68, 1.6164, 36.7, 0.38},
+ {-78.1, 1, 0, 0}
+};
+
+/* Internal trig functions (used only if INTRIG is defined). These
+ standard functions may be enabled to obtain timings that reflect
+ the machine's floating point performance rather than the speed of
+ its trig function evaluation. */
+
+#ifdef INTRIG
+
+/* The following definitions should keep you from getting intro trouble
+ with compilers which don't let you redefine intrinsic functions. */
+
+#define sin I_sin
+#define cos I_cos
+#define tan I_tan
+#define sqrt I_sqrt
+#define atan I_atan
+#define atan2 I_atan2
+#define asin I_asin
+
+#define fabs(x) ((x < 0.0) ? -x : x)
+
+#define pic 3.1415926535897932
+
+/* Commonly used constants */
+
+static double pi = pic,
+ twopi = pic * 2.0,
+ piover4 = pic / 4.0, fouroverpi = 4.0 / pic, piover2 = pic / 2.0;
+
+/* Coefficients for ATAN evaluation */
+
+static double atanc[] = {
+ 0.0,
+ 0.4636476090008061165,
+ 0.7853981633974483094,
+ 0.98279372324732906714,
+ 1.1071487177940905022,
+ 1.1902899496825317322,
+ 1.2490457723982544262,
+ 1.2924966677897852673,
+ 1.3258176636680324644
+};
+
+/* aint(x) Return integer part of number. Truncates towards 0 */
+
+double aint(x)
+double x;
+{
+ long l;
+
+ /* Note that this routine cannot handle the full floating point
+ number range. This function should be in the machine-dependent
+ floating point library! */
+
+ l = x;
+ if ((int) (-0.5) != 0 && l < 0)
+ l++;
+ x = l;
+ return x;
+}
+
+/* sin(x) Return sine, x in radians */
+
+static double sin(x)
+double x;
+{
+ int sign;
+ double y, r, z;
+
+ x = (((sign = (x < 0.0)) != 0) ? -x : x);
+
+ if (x > twopi)
+ x -= (aint(x / twopi) * twopi);
+
+ if (x > pi) {
+ x -= pi;
+ sign = !sign;
+ }
+
+ if (x > piover2)
+ x = pi - x;
+
+ if (x < piover4) {
+ y = x * fouroverpi;
+ z = y * y;
+ r = y *
+ (((((((-0.202253129293E-13 * z + 0.69481520350522E-11) * z -
+ 0.17572474176170806E-8) * z +
+ 0.313361688917325348E-6) * z -
+ 0.365762041821464001E-4) * z +
+ 0.249039457019271628E-2) * z - 0.0807455121882807815) * z +
+ 0.785398163397448310);
+ } else {
+ y = (piover2 - x) * fouroverpi;
+ z = y * y;
+ r = ((((((-0.38577620372E-12 * z + 0.11500497024263E-9) * z -
+ 0.2461136382637005E-7) * z +
+ 0.359086044588581953E-5) * z -
+ 0.325991886926687550E-3) * z + 0.0158543442438154109) * z -
+ 0.308425137534042452) * z + 1.0;
+ }
+ return sign ? -r : r;
+}
+
+/* cos(x) Return cosine, x in radians, by identity */
+
+static double cos(x)
+double x;
+{
+ x = (x < 0.0) ? -x : x;
+ if (x > twopi) /* Do range reduction here to limit */
+ x = x - (aint(x / twopi) * twopi); /* roundoff on add of PI/2 */
+ return sin(x + piover2);
+}
+
+/* tan(x) Return tangent, x in radians, by identity */
+
+static double tan(x)
+double x;
+{
+ return sin(x) / cos(x);
+}
+
+/* sqrt(x) Return square root. Initial guess, then Newton-
+ Raphson refinement */
+
+double sqrt(x)
+double x;
+{
+ double c, cl, y;
+ int n;
+
+ if (x == 0.0)
+ return 0.0;
+
+ if (x < 0.0) {
+ fprintf(stderr,
+ "\nGood work! You tried to take the square root of %g",
+ x);
+ fprintf(stderr,
+ "\nunfortunately, that is too complex for me to handle.\n");
+ exit(1);
+ }
+
+ y = (0.154116 + 1.893872 * x) / (1.0 + 1.047988 * x);
+
+ c = (y - x / y) / 2.0;
+ cl = 0.0;
+ for (n = 50; c != cl && n--;) {
+ y = y - c;
+ cl = c;
+ c = (y - x / y) / 2.0;
+ }
+ return y;
+}
+
+/* atan(x) Return arctangent in radians,
+ range -pi/2 to pi/2 */
+
+static double atan(x)
+double x;
+{
+ int sign, l, y;
+ double a, b, z;
+
+ x = (((sign = (x < 0.0)) != 0) ? -x : x);
+ l = 0;
+
+ if (x >= 4.0) {
+ l = -1;
+ x = 1.0 / x;
+ y = 0;
+ goto atl;
+ } else {
+ if (x < 0.25) {
+ y = 0;
+ goto atl;
+ }
+ }
+
+ y = aint(x / 0.5);
+ z = y * 0.5;
+ x = (x - z) / (x * z + 1);
+
+ atl:
+ z = x * x;
+ b = ((((893025.0 * z + 49116375.0) * z + 425675250.0) * z +
+ 1277025750.0) * z + 1550674125.0) * z + 654729075.0;
+ a = (((13852575.0 * z + 216602100.0) * z + 891080190.0) * z +
+ 1332431100.0) * z + 654729075.0;
+ a = (a / b) * x + atanc[y];
+ if (l)
+ a = piover2 - a;
+ return sign ? -a : a;
+}
+
+/* atan2(y,x) Return arctangent in radians of y/x,
+ range -pi to pi */
+
+static double atan2(y, x)
+double y, x;
+{
+ double temp;
+
+ if (x == 0.0) {
+ if (y == 0.0) /* Special case: atan2(0,0) = 0 */
+ return 0.0;
+ else if (y > 0)
+ return piover2;
+ else
+ return -piover2;
+ }
+ temp = atan(y / x);
+ if (x < 0.0) {
+ if (y >= 0.0)
+ temp += pic;
+ else
+ temp -= pic;
+ }
+ return temp;
+}
+
+/* asin(x) Return arcsine in radians of x */
+
+static double asin(x)
+double x;
+{
+ if (fabs(x) > 1.0) {
+ fprintf(stderr,
+ "\nInverse trig functions lose much of their gloss when");
+ fprintf(stderr,
+ "\ntheir arguments are greater than 1, such as the");
+ fprintf(stderr, "\nvalue %g you passed.\n", x);
+ exit(1);
+ }
+ return atan2(x, sqrt(1 - x * x));
+}
+#endif
+
+/* Calculate passage through surface
+
+ If the variable PARAXIAL is true, the trace through the
+ surface will be done using the paraxial approximations.
+ Otherwise, the normal trigonometric trace will be done.
+
+ This routine takes the following inputs:
+
+ RADIUS_OF_CURVATURE Radius of curvature of surface
+ being crossed. If 0, surface is
+ plane.
+
+ OBJECT_DISTANCE Distance of object focus from
+ lens vertex. If 0, incoming
+ rays are parallel and
+ the following must be specified:
+
+ RAY_HEIGHT Height of ray from axis. Only
+ relevant if OBJECT.DISTANCE == 0
+
+ AXIS_SLOPE_ANGLE Angle incoming ray makes with axis
+ at intercept
+
+ FROM_INDEX Refractive index of medium being left
+
+ TO_INDEX Refractive index of medium being
+ entered.
+
+ The outputs are the following variables:
+
+ OBJECT_DISTANCE Distance from vertex to object focus
+ after refraction.
+
+ AXIS_SLOPE_ANGLE Angle incoming ray makes with axis
+ at intercept after refraction.
+
+*/
+
+static void transit_surface()
+{
+ double iang, /* Incidence angle */
+ rang, /* Refraction angle */
+ iang_sin, /* Incidence angle sin */
+ rang_sin, /* Refraction angle sin */
+ old_axis_slope_angle, sagitta;
+
+ if (paraxial) {
+ if (radius_of_curvature != 0.0) {
+ if (object_distance == 0.0) {
+ axis_slope_angle = 0.0;
+ iang_sin = ray_height / radius_of_curvature;
+ } else
+ iang_sin = ((object_distance -
+ radius_of_curvature) / radius_of_curvature) *
+ axis_slope_angle;
+
+ rang_sin = (from_index / to_index) * iang_sin;
+ old_axis_slope_angle = axis_slope_angle;
+ axis_slope_angle = axis_slope_angle + iang_sin - rang_sin;
+ if (object_distance != 0.0)
+ ray_height = object_distance * old_axis_slope_angle;
+ object_distance = ray_height / axis_slope_angle;
+ return;
+ }
+ object_distance = object_distance * (to_index / from_index);
+ axis_slope_angle = axis_slope_angle * (from_index / to_index);
+ return;
+ }
+
+ if (radius_of_curvature != 0.0) {
+ if (object_distance == 0.0) {
+ axis_slope_angle = 0.0;
+ iang_sin = ray_height / radius_of_curvature;
+ } else {
+ iang_sin = ((object_distance -
+ radius_of_curvature) / radius_of_curvature) *
+ sin(axis_slope_angle);
+ }
+ iang = asin(iang_sin);
+ rang_sin = (from_index / to_index) * iang_sin;
+ old_axis_slope_angle = axis_slope_angle;
+ axis_slope_angle = axis_slope_angle + iang - asin(rang_sin);
+ sagitta = sin((old_axis_slope_angle + iang) / 2.0);
+ sagitta = 2.0 * radius_of_curvature * sagitta * sagitta;
+ object_distance =
+ ((radius_of_curvature * sin(old_axis_slope_angle + iang)) *
+ cot(axis_slope_angle)) + sagitta;
+ return;
+ }
+
+ rang = -asin((from_index / to_index) * sin(axis_slope_angle));
+ object_distance = object_distance * ((to_index *
+ cos(-rang)) / (from_index *
+ cos
+ (axis_slope_angle)));
+ axis_slope_angle = -rang;
+}
+
+/* Perform ray trace in specific spectral line */
+
+static void trace_line(line, ray_h)
+int line;
+double ray_h;
+{
+ int i;
+
+ object_distance = 0.0;
+ ray_height = ray_h;
+ from_index = 1.0;
+
+ for (i = 1; i <= current_surfaces; i++) {
+ radius_of_curvature = s[i][1];
+ to_index = s[i][2];
+ if (to_index > 1.0)
+ to_index = to_index + ((spectral_line[4] -
+ spectral_line[line]) /
+ (spectral_line[3] -
+ spectral_line[6])) * ((s[i][2] -
+ 1.0) / s[i][3]);
+ transit_surface();
+ from_index = to_index;
+ if (i < current_surfaces)
+ object_distance = object_distance - s[i][4];
+ }
+}
+
+/* Initialise when called the first time */
+
+void fbench()
+{
+ int i, j;
+ double od_fline, od_cline;
+
+ spectral_line[1] = 7621.0; /* A */
+ spectral_line[2] = 6869.955; /* B */
+ spectral_line[3] = 6562.816; /* C */
+ spectral_line[4] = 5895.944; /* D */
+ spectral_line[5] = 5269.557; /* E */
+ spectral_line[6] = 4861.344; /* F */
+ spectral_line[7] = 4340.477; /* G' */
+ spectral_line[8] = 3968.494; /* H */
+
+ niter = 3000;
+
+ /* Load test case into working array */
+
+ clear_aperture = 4.0;
+ current_surfaces = 4;
+ for (i = 0; i < current_surfaces; i++)
+ for (j = 0; j < 4; j++)
+ s[i + 1][j + 1] = testcase[i][j];
+
+ for (itercount = 0; itercount < niter; itercount++) {
+ for (paraxial = 0; paraxial <= 1; paraxial++) {
+
+ /* Do main trace in D light */
+
+ trace_line(4, clear_aperture / 2.0);
+ od_sa[paraxial][0] = object_distance;
+ od_sa[paraxial][1] = axis_slope_angle;
+ }
+ paraxial = FALSE;
+
+ /* Trace marginal ray in C */
+
+ trace_line(3, clear_aperture / 2.0);
+ od_cline = object_distance;
+
+ /* Trace marginal ray in F */
+
+ trace_line(6, clear_aperture / 2.0);
+ od_fline = object_distance;
+
+ aberr_lspher = od_sa[1][0] - od_sa[0][0];
+ aberr_osc = 1.0 - (od_sa[1][0] * od_sa[1][1]) /
+ (sin(od_sa[0][1]) * od_sa[0][0]);
+ aberr_lchrom = od_fline - od_cline;
+ max_lspher = sin(od_sa[0][1]);
+
+ /* D light */
+
+ max_lspher = 0.0000926 / (max_lspher * max_lspher);
+ max_osc = 0.0025;
+ max_lchrom = max_lspher;
+ }
+}
+
+#ifdef __FBENCH_TEST__
+int main(void)
+{
+ fbench();
+
+ return 0;
+}
+#endif
diff --git a/modules/benchmark/fft.c b/modules/benchmark/fft.c
new file mode 100644
index 00000000..7c5889c8
--- /dev/null
+++ b/modules/benchmark/fft.c
@@ -0,0 +1,67 @@
+/*
+ * 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 "hardinfo.h"
+#include "benchmark.h"
+#include "fftbench.h"
+
+static gpointer fft_for(unsigned int start, unsigned int end, void *data, gint thread_number)
+{
+ unsigned int i;
+ FFTBench **benches = (FFTBench **)data;
+ FFTBench *fftbench = (FFTBench *)(benches[thread_number]);
+
+ for (i = start; i <= end; i++) {
+ fft_bench_run(fftbench);
+ }
+
+ return NULL;
+}
+
+void
+benchmark_fft(void)
+{
+ gdouble elapsed = 0;
+ int n_cores, i;
+ gchar *temp;
+ FFTBench **benches;
+
+ shell_view_set_enabled(FALSE);
+ shell_status_update("Running FFT benchmark...");
+
+ /* Pre-allocate all benchmarks */
+ temp = module_call_method("devices::getProcessorCount");
+ n_cores = temp ? atoi(temp) : 1;
+ g_free(temp);
+
+ benches = g_new0(FFTBench *, n_cores);
+ for (i = 0; i < n_cores; i++) {
+ benches[i] = fft_bench_new();
+ }
+
+ /* Run the benchmark */
+ elapsed = benchmark_parallel_for(0, 4, fft_for, benches);
+
+ /* Free up the memory */
+ for (i = 0; i < n_cores; i++) {
+ fft_bench_free(benches[i]);
+ }
+ g_free(benches);
+
+ bench_results[BENCHMARK_FFT] = elapsed;
+}
diff --git a/modules/benchmark/fftbench.c b/modules/benchmark/fftbench.c
new file mode 100644
index 00000000..89fd5a73
--- /dev/null
+++ b/modules/benchmark/fftbench.c
@@ -0,0 +1,212 @@
+/*
+ fftbench.c
+
+ Written by Scott Robert Ladd (scott@coyotegulch.com)
+ No rights reserved. This is public domain software, for use by anyone.
+
+ A number-crunching benchmark using LUP-decomposition to solve a large
+ linear equation.
+
+ The code herein is design for the purpose of testing computational
+ performance; error handling is minimal.
+
+ In fact, this is a weak implementation of the FFT; unfortunately, all
+ of my really nifty FFTs are in commercial code, and I haven't had time
+ to write a new FFT routine for this benchmark. I may add a Hartley
+ transform to the seat, too.
+
+ Actual benchmark results can be found at:
+ http://scottrobertladd.net/coyotegulch/
+
+ Please do not use this information or algorithm in any way that might
+ upset the balance of the universe or otherwise cause a disturbance in
+ the space-time continuum.
+*/
+
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "fftbench.h"
+
+// embedded random number generator; ala Park and Miller
+static long seed = 1325;
+static const long IA = 16807;
+static const long IM = 2147483647;
+static const double AM = 4.65661287525E-10;
+static const long IQ = 127773;
+static const long IR = 2836;
+static const long MASK = 123459876;
+
+static double random_double()
+{
+ long k;
+ double result;
+
+ seed ^= MASK;
+ k = seed / IQ;
+ seed = IA * (seed - k * IQ) - IR * k;
+
+ if (seed < 0)
+ seed += IM;
+
+ result = AM * seed;
+ seed ^= MASK;
+
+ return result;
+}
+
+static const int N = 800;
+static const int NM1 = 799; // N - 1
+static const int NP1 = 801; // N + 1
+
+static void lup_decompose(FFTBench *fftbench)
+{
+ int i, j, k, k2, t;
+ double p, temp, **a;
+
+ int *perm = (int *) malloc(sizeof(double) * N);
+
+ fftbench->p = perm;
+ a = fftbench->a;
+
+ for (i = 0; i < N; ++i)
+ perm[i] = i;
+
+ for (k = 0; k < NM1; ++k) {
+ p = 0.0;
+
+ for (i = k; i < N; ++i) {
+ temp = fabs(a[i][k]);
+
+ if (temp > p) {
+ p = temp;
+ k2 = i;
+ }
+ }
+
+ // check for invalid a
+ if (p == 0.0)
+ return;
+
+ // exchange rows
+ t = perm[k];
+ perm[k] = perm[k2];
+ perm[k2] = t;
+
+ for (i = 0; i < N; ++i) {
+ temp = a[k][i];
+ a[k][i] = a[k2][i];
+ a[k2][i] = temp;
+ }
+
+ for (i = k + 1; i < N; ++i) {
+ a[i][k] /= a[k][k];
+
+ for (j = k + 1; j < N; ++j)
+ a[i][j] -= a[i][k] * a[k][j];
+ }
+ }
+}
+
+static double *lup_solve(FFTBench *fftbench)
+{
+ int i, j, j2;
+ double sum, u;
+
+ double *y = (double *) malloc(sizeof(double) * N);
+ double *x = (double *) malloc(sizeof(double) * N);
+
+ double **a = fftbench->a;
+ double *b = fftbench->b;
+ int *perm = fftbench->p;
+
+ for (i = 0; i < N; ++i) {
+ y[i] = 0.0;
+ x[i] = 0.0;
+ }
+
+ for (i = 0; i < N; ++i) {
+ sum = 0.0;
+ j2 = 0;
+
+ for (j = 1; j <= i; ++j) {
+ sum += a[i][j2] * y[j2];
+ ++j2;
+ }
+
+ y[i] = b[perm[i]] - sum;
+ }
+
+ i = NM1;
+
+ while (1) {
+ sum = 0.0;
+ u = a[i][i];
+
+ for (j = i + 1; j < N; ++j)
+ sum += a[i][j] * x[j];
+
+ x[i] = (y[i] - sum) / u;
+
+ if (i == 0)
+ break;
+
+ --i;
+ }
+
+ free(y);
+
+ return x;
+}
+
+FFTBench *fft_bench_new(void)
+{
+ FFTBench *fftbench;
+ int i, j;
+
+ fftbench = g_new0(FFTBench, 1);
+
+ // generate test data
+ fftbench->a = (double **) malloc(sizeof(double *) * N);
+
+ for (i = 0; i < N; ++i) {
+ fftbench->a[i] = (double *) malloc(sizeof(double) * N);
+
+ for (j = 0; j < N; ++j)
+ fftbench->a[i][j] = random_double();
+ }
+
+ fftbench->b = (double *) malloc(sizeof(double) * N);
+
+ for (i = 0; i < N; ++i)
+ fftbench->b[i] = random_double();
+
+ return fftbench;
+}
+
+void fft_bench_run(FFTBench *fftbench)
+{
+ lup_decompose(fftbench);
+ double *x = lup_solve(fftbench);
+ free(x);
+}
+
+void fft_bench_free(FFTBench *fftbench)
+{
+ int i;
+
+ // clean up
+ for (i = 0; i < N; ++i)
+ free(fftbench->a[i]);
+
+ free(fftbench->a);
+ free(fftbench->b);
+ free(fftbench->p);
+ free(fftbench->r);
+
+ g_free(fftbench);
+}
diff --git a/modules/benchmark/fib.c b/modules/benchmark/fib.c
new file mode 100644
index 00000000..0f88be59
--- /dev/null
+++ b/modules/benchmark/fib.c
@@ -0,0 +1,50 @@
+/*
+ * 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 "benchmark.h"
+
+static gulong
+fib(gulong n)
+{
+ if (n == 0)
+ return 0;
+ else if (n <= 2)
+ return 1;
+ return fib(n - 1) + fib(n - 2);
+}
+
+void
+benchmark_fib(void)
+{
+ GTimer *timer = g_timer_new();
+ gdouble elapsed;
+
+ shell_view_set_enabled(FALSE);
+ shell_status_update("Calculating the 42nd Fibonacci number...");
+
+ g_timer_reset(timer);
+ g_timer_start(timer);
+
+ fib(42);
+
+ g_timer_stop(timer);
+ elapsed = g_timer_elapsed(timer, NULL);
+ g_timer_destroy(timer);
+
+ bench_results[BENCHMARK_FIB] = elapsed;
+}
diff --git a/modules/benchmark/guibench.c b/modules/benchmark/guibench.c
new file mode 100644
index 00000000..b9573278
--- /dev/null
+++ b/modules/benchmark/guibench.c
@@ -0,0 +1,353 @@
+/*
+ * 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 <gtk/gtk.h>
+
+#include "iconcache.h"
+#include "config.h"
+
+#define N_ITERATIONS 100000
+#define PHRASE "I \342\231\245 HardInfo"
+
+typedef double (*BenchCallback)(GtkWindow *window);
+
+static double test_lines(GtkWindow *window);
+static double test_shapes(GtkWindow *window);
+static double test_filled_shapes(GtkWindow *window);
+static double test_text(GtkWindow *window);
+static double test_icons(GtkWindow *window);
+
+/*
+Results on a AMD Athlon 3200+ (Barton), 1GB RAM,
+nVidia Geforce 6200 with nvidia Xorg driver,
+running Linux 2.6.28, Xorg 1.6.0, Ubuntu 9.04
+desktop, GNOME 2.26.1, composite enabled.
+
+Test Time Iter/Sec
+Line Drawing 3.9570 25271.7663
+Shape Drawing 22.2499 4494.4065
+Filled Shape Drawing 4.0377 24766.2806
+Text Drawing 59.1565 1690.4309
+Icon Blitting 51.720941 1933.4528
+
+Results are normalized according to these values.
+A guibench() result of 1000.0 is roughly equivalent
+to this same setup.
+*/
+
+static struct {
+ BenchCallback callback;
+ gchar *title;
+ gdouble weight;
+} tests[] = {
+ { test_lines, "Line Drawing", 25271.77 },
+ { test_shapes, "Shape Drawing", 4494.49 },
+ { test_filled_shapes, "Filled Shape Drawing", 24766.28 },
+ { test_text, "Text Drawing", 1690.43 },
+ { test_icons, "Icon Blitting", 1933.45 },
+ { NULL, NULL }
+};
+
+static gchar *phrase = NULL;
+
+static gboolean keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+{
+ const int magic[] = { 0x1b, 0x33, 0x3a, 0x35, 0x51 };
+ const int states[] = { 0xff52, 0xff52, 0xff54, 0xff54,
+ 0xff51, 0xff53, 0xff51, 0xff53,
+ 0x62, 0x61 };
+ static int state = 0;
+
+ if (event->keyval == states[state]) {
+ state++;
+ } else {
+ state = 0;
+ }
+
+ if (state == G_N_ELEMENTS(states)) {
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS(magic); i++) {
+ phrase[i + 6] = magic[i] ^ (states[i] & (states[i] >> 8));
+ }
+
+ state = 0;
+ }
+
+ return FALSE;
+}
+
+static double test_icons(GtkWindow *window)
+{
+ GdkPixbuf *pixbufs[3];
+ GdkGC *gc;
+ GRand *rand;
+ GTimer *timer;
+ double time;
+ GdkWindow *gdk_window = GTK_WIDGET(window)->window;
+ int icons;
+
+ gdk_window_clear(gdk_window);
+
+ rand = g_rand_new();
+ gc = gdk_gc_new(GDK_DRAWABLE(gdk_window));
+ timer = g_timer_new();
+
+ pixbufs[0] = icon_cache_get_pixbuf("logo.png");
+ pixbufs[1] = icon_cache_get_pixbuf("syncmanager.png");
+ pixbufs[2] = icon_cache_get_pixbuf("report-large.png");
+
+ g_timer_start(timer);
+ for (icons = N_ITERATIONS; icons >= 0; icons--) {
+ int x, y;
+
+ x = g_rand_int_range(rand, 0, 800);
+ y = g_rand_int_range(rand, 0, 600);
+
+ gdk_draw_pixbuf(GDK_DRAWABLE(gdk_window), gc,
+ pixbufs[icons % G_N_ELEMENTS(pixbufs)],
+ 0, 0, x, y, 48, 48,
+ GDK_RGB_DITHER_NONE, 0, 0);
+
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+ }
+ g_timer_stop(timer);
+
+ time = g_timer_elapsed(timer, NULL);
+
+ g_rand_free(rand);
+ gdk_gc_destroy(gc);
+ g_timer_destroy(timer);
+
+ return time;
+}
+
+static double test_text(GtkWindow *window)
+{
+ GRand *rand;
+ GTimer *timer;
+ GdkGC *gc;
+ double time;
+ PangoLayout *layout;
+ PangoFontDescription *font;
+ GdkWindow *gdk_window = GTK_WIDGET(window)->window;
+ int strings;
+
+ gdk_window_clear(gdk_window);
+
+ rand = g_rand_new();
+ gc = gdk_gc_new(GDK_DRAWABLE(gdk_window));
+ timer = g_timer_new();
+
+ font = pango_font_description_new();
+ layout = pango_layout_new(gtk_widget_get_pango_context(GTK_WIDGET(window)));
+ pango_layout_set_text(layout, phrase, -1);
+
+ g_timer_start(timer);
+ for (strings = N_ITERATIONS; strings >= 0; strings--) {
+ int x, y, size;
+
+ x = g_rand_int_range(rand, 0, 800);
+ y = g_rand_int_range(rand, 0, 600);
+ size = g_rand_int_range(rand, 1, 96) * PANGO_SCALE;
+
+ pango_font_description_set_size(font, size);
+ pango_layout_set_font_description(layout, font);
+ gdk_draw_layout(GDK_DRAWABLE(gdk_window), gc, x, y, layout);
+
+ gdk_rgb_gc_set_foreground(gc, strings << 8);
+
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+
+ }
+ g_timer_stop(timer);
+
+ time = g_timer_elapsed(timer, NULL);
+
+ g_rand_free(rand);
+ gdk_gc_destroy(gc);
+ g_timer_destroy(timer);
+ g_object_unref(layout);
+ pango_font_description_free(font);
+
+ return time;
+}
+
+static double test_filled_shapes(GtkWindow *window)
+{
+ GRand *rand;
+ GTimer *timer;
+ GdkGC *gc;
+ double time;
+ GdkWindow *gdk_window = GTK_WIDGET(window)->window;
+ int lines;
+
+ gdk_window_clear(gdk_window);
+
+ rand = g_rand_new();
+ gc = gdk_gc_new(GDK_DRAWABLE(gdk_window));
+ timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (lines = N_ITERATIONS; lines >= 0; lines--) {
+ int x1, y1;
+
+ x1 = g_rand_int_range(rand, 0, 800);
+ y1 = g_rand_int_range(rand, 0, 600);
+
+ gdk_rgb_gc_set_foreground(gc, lines << 8);
+
+ gdk_draw_rectangle(GDK_DRAWABLE(gdk_window), gc, TRUE,
+ x1, y1,
+ g_rand_int_range(rand, 0, 400),
+ g_rand_int_range(rand, 0, 300));
+
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+ }
+ g_timer_stop(timer);
+
+ time = g_timer_elapsed(timer, NULL);
+
+ g_rand_free(rand);
+ gdk_gc_destroy(gc);
+ g_timer_destroy(timer);
+
+ return time;
+}
+
+static double test_shapes(GtkWindow *window)
+{
+ GRand *rand;
+ GTimer *timer;
+ GdkGC *gc;
+ double time;
+ GdkWindow *gdk_window = GTK_WIDGET(window)->window;
+ int lines;
+
+ gdk_window_clear(gdk_window);
+
+ rand = g_rand_new();
+ gc = gdk_gc_new(GDK_DRAWABLE(gdk_window));
+ timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (lines = N_ITERATIONS; lines >= 0; lines--) {
+ int x1, y1;
+
+ x1 = g_rand_int_range(rand, 0, 800);
+ y1 = g_rand_int_range(rand, 0, 600);
+
+ gdk_rgb_gc_set_foreground(gc, lines << 8);
+
+ gdk_draw_rectangle(GDK_DRAWABLE(gdk_window), gc, FALSE,
+ x1, y1,
+ g_rand_int_range(rand, 0, 400),
+ g_rand_int_range(rand, 0, 300));
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+ }
+ g_timer_stop(timer);
+
+ time = g_timer_elapsed(timer, NULL);
+
+ g_rand_free(rand);
+ gdk_gc_destroy(gc);
+ g_timer_destroy(timer);
+
+ return time;
+}
+
+static double test_lines(GtkWindow *window)
+{
+ GRand *rand;
+ GTimer *timer;
+ GdkGC *gc;
+ double time;
+ GdkWindow *gdk_window = GTK_WIDGET(window)->window;
+ int lines;
+
+ gdk_window_clear(gdk_window);
+
+ rand = g_rand_new();
+ gc = gdk_gc_new(GDK_DRAWABLE(gdk_window));
+ timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (lines = N_ITERATIONS; lines >= 0; lines--) {
+ int x1, y1, x2, y2;
+
+ x1 = g_rand_int_range(rand, 0, 800);
+ y1 = g_rand_int_range(rand, 0, 600);
+ x2 = g_rand_int_range(rand, 0, 800);
+ y2 = g_rand_int_range(rand, 0, 600);
+
+ gdk_draw_line(GDK_DRAWABLE(gdk_window), gc, x1, y1, x2, y2);
+ gdk_rgb_gc_set_foreground(gc, lines << 8);
+
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+ }
+ g_timer_stop(timer);
+
+ time = g_timer_elapsed(timer, NULL);
+
+ g_rand_free(rand);
+ gdk_gc_destroy(gc);
+ g_timer_destroy(timer);
+
+ return time;
+}
+
+double guibench(void)
+{
+ GtkWidget *window;
+ gdouble score = 0.0f;
+ gint i;
+
+ phrase = g_strdup(PHRASE);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_size_request(window, 800, 600);
+ gtk_window_set_title(GTK_WINDOW(window), "guibench");
+
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
+ gtk_widget_show(window);
+
+ g_signal_connect(window, "key-press-event", G_CALLBACK(keypress_event), NULL);
+
+ for (i = 0; tests[i].title; i++) {
+ double time;
+
+ gtk_window_set_title(GTK_WINDOW(window), tests[i].title);
+ time = tests[i].callback(GTK_WINDOW(window));
+ score += (N_ITERATIONS / time) / tests[i].weight;
+ }
+
+ gtk_widget_destroy(window);
+ g_free(phrase);
+
+ return (score / i) * 1000.0f;
+}
diff --git a/modules/benchmark/md5.c b/modules/benchmark/md5.c
new file mode 100644
index 00000000..f4032ddd
--- /dev/null
+++ b/modules/benchmark/md5.c
@@ -0,0 +1,317 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
+ not require an integer type which is exactly 32 bits. This work
+ draws on the changes for the same purpose by Tatu Ylonen
+ <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
+ that code, there is no copyright issue. I hereby disclaim
+ copyright in any changes I have made; this code remains in the
+ public domain. */
+
+#include <string.h> /* for memcpy() and memset() */
+
+/* Add prototype support. */
+#ifndef PROTO
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define PROTO(ARGS) ARGS
+#else
+#define PROTO(ARGS) ()
+#endif
+#endif
+
+#include "md5.h"
+
+#if defined(__OPTIMIZE__)
+#error You must compile this program without "-O". (Or else the benchmark results may be different!)
+#endif
+
+/* Little-endian byte-swapping routines. Note that these do not
+ depend on the size of datatypes such as uint32, nor do they require
+ us to detect the endianness of the machine we are running on. It
+ is possible they should be macros for speed, but I would be
+ surprised if they were a performance bottleneck for MD5. */
+
+static uint32 getu32(addr)
+const unsigned char *addr;
+{
+ return (((((unsigned long) addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0];
+}
+
+static void putu32(data, addr)
+uint32 data;
+unsigned char *addr;
+{
+ addr[0] = (unsigned char) data;
+ addr[1] = (unsigned char) (data >> 8);
+ addr[2] = (unsigned char) (data >> 16);
+ addr[3] = (unsigned char) (data >> 24);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(ctx)
+struct MD5Context *ctx;
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(ctx, buf, len)
+struct MD5Context *ctx;
+unsigned char const *buf;
+unsigned len;
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = (t + ((uint32) len << 3)) & 0xffffffff) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(digest, ctx)
+unsigned char digest[16];
+struct MD5Context *ctx;
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ MD5Transform(ctx->buf, ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+
+ /* Append length in bits and transform */
+ putu32(ctx->bits[0], ctx->in + 56);
+ putu32(ctx->bits[1], ctx->in + 60);
+
+ MD5Transform(ctx->buf, ctx->in);
+ putu32(ctx->buf[0], digest);
+ putu32(ctx->buf[1], digest + 4);
+ putu32(ctx->buf[2], digest + 8);
+ putu32(ctx->buf[3], digest + 12);
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(buf, inraw)
+uint32 buf[4];
+const unsigned char inraw[64];
+{
+ register uint32 a, b, c, d;
+ uint32 in[16];
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ in[i] = getu32(inraw + 4 * i);
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+#endif
+
+#ifdef TEST
+/* Simple test program. Can use it to manually run the tests from
+ RFC1321 for example. */
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ struct MD5Context context;
+ unsigned char checksum[16];
+ int i;
+ int j;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s string-to-hash\n", argv[0]);
+ exit(1);
+ }
+ for (j = 1; j < argc; ++j) {
+ printf("MD5 (\"%s\") = ", argv[j]);
+ MD5Init(&context);
+ MD5Update(&context, argv[j], strlen(argv[j]));
+ MD5Final(checksum, &context);
+ for (i = 0; i < 16; i++) {
+ printf("%02x", (unsigned int) checksum[i]);
+ }
+ printf("\n");
+ }
+ return 0;
+}
+#endif /* TEST */
diff --git a/modules/benchmark/nqueens.c b/modules/benchmark/nqueens.c
new file mode 100644
index 00000000..a32ed8c1
--- /dev/null
+++ b/modules/benchmark/nqueens.c
@@ -0,0 +1,66 @@
+/*
+ * N-Queens Problem Solver
+ * Found somewhere on the Internet; can't remember where. Possibly Wikipedia.
+ */
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "hardinfo.h"
+#include "benchmark.h"
+
+#define QUEENS 11
+
+int row[QUEENS];
+
+bool safe(int x, int y)
+{
+ int i;
+ for (i = 1; i <= y; i++)
+ if (row[y - i] == x || row[y - i] == x - i || row[y - i] == x + i)
+ return false;
+ return true;
+}
+
+int nqueens(int y)
+{
+ int x;
+
+ for (x = 0; x < QUEENS; x++) {
+ if (safe((row[y - 1] = x), y - 1)) {
+ if (y < QUEENS) {
+ nqueens(y + 1);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static gpointer nqueens_for(unsigned int start, unsigned int end, void *data, gint thread_number)
+{
+ unsigned int i;
+
+ for (i = start; i <= end; i++) {
+ nqueens(0);
+ }
+
+ return NULL;
+}
+
+void
+benchmark_nqueens(void)
+{
+ gdouble elapsed = 0;
+
+ shell_view_set_enabled(FALSE);
+ shell_status_update("Running N-Queens benchmark...");
+
+ elapsed = benchmark_parallel_for(0, 10, nqueens_for, NULL);
+
+ bench_results[BENCHMARK_NQUEENS] = elapsed;
+}
+
+
diff --git a/modules/benchmark/raytrace.c b/modules/benchmark/raytrace.c
new file mode 100644
index 00000000..2ee36a93
--- /dev/null
+++ b/modules/benchmark/raytrace.c
@@ -0,0 +1,47 @@
+/*
+ * 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 "benchmark.h"
+
+void fbench(); /* fbench.c */
+
+static gpointer
+parallel_raytrace(unsigned int start, unsigned int end, gpointer data, gint thread_number)
+{
+ unsigned int i;
+
+ for (i = start; i <= end; i++) {
+ fbench();
+ }
+
+ return NULL;
+}
+
+void
+benchmark_raytrace(void)
+{
+ gdouble elapsed = 0;
+
+ shell_view_set_enabled(FALSE);
+ shell_status_update("Performing John Walker's FBENCH...");
+
+ elapsed = benchmark_parallel_for(0, 1000, parallel_raytrace, NULL);
+
+ bench_results[BENCHMARK_RAYTRACE] = elapsed;
+}
+
diff --git a/modules/benchmark/sha1.c b/modules/benchmark/sha1.c
new file mode 100644
index 00000000..b94ce254
--- /dev/null
+++ b/modules/benchmark/sha1.c
@@ -0,0 +1,329 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#include <stdio.h>
+#include <string.h>
+#include <sha1.h>
+
+#if defined(__OPTIMIZE__)
+#error You must compile this program without "-O".
+#endif
+
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(guint32 state[5], guchar buffer[64])
+{
+ guint32 a, b, c, d, e;
+ typedef union {
+ guchar c[64];
+ guint32 l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16 *block;
+#ifdef SHA1HANDSOFF
+ static guchar workspace[64];
+ block = (CHAR64LONG16 *) workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16 *) buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a, b, c, d, e, 0);
+ R0(e, a, b, c, d, 1);
+ R0(d, e, a, b, c, 2);
+ R0(c, d, e, a, b, 3);
+ R0(b, c, d, e, a, 4);
+ R0(a, b, c, d, e, 5);
+ R0(e, a, b, c, d, 6);
+ R0(d, e, a, b, c, 7);
+ R0(c, d, e, a, b, 8);
+ R0(b, c, d, e, a, 9);
+ R0(a, b, c, d, e, 10);
+ R0(e, a, b, c, d, 11);
+ R0(d, e, a, b, c, 12);
+ R0(c, d, e, a, b, 13);
+ R0(b, c, d, e, a, 14);
+ R0(a, b, c, d, e, 15);
+ R1(e, a, b, c, d, 16);
+ R1(d, e, a, b, c, 17);
+ R1(c, d, e, a, b, 18);
+ R1(b, c, d, e, a, 19);
+ R2(a, b, c, d, e, 20);
+ R2(e, a, b, c, d, 21);
+ R2(d, e, a, b, c, 22);
+ R2(c, d, e, a, b, 23);
+ R2(b, c, d, e, a, 24);
+ R2(a, b, c, d, e, 25);
+ R2(e, a, b, c, d, 26);
+ R2(d, e, a, b, c, 27);
+ R2(c, d, e, a, b, 28);
+ R2(b, c, d, e, a, 29);
+ R2(a, b, c, d, e, 30);
+ R2(e, a, b, c, d, 31);
+ R2(d, e, a, b, c, 32);
+ R2(c, d, e, a, b, 33);
+ R2(b, c, d, e, a, 34);
+ R2(a, b, c, d, e, 35);
+ R2(e, a, b, c, d, 36);
+ R2(d, e, a, b, c, 37);
+ R2(c, d, e, a, b, 38);
+ R2(b, c, d, e, a, 39);
+ R3(a, b, c, d, e, 40);
+ R3(e, a, b, c, d, 41);
+ R3(d, e, a, b, c, 42);
+ R3(c, d, e, a, b, 43);
+ R3(b, c, d, e, a, 44);
+ R3(a, b, c, d, e, 45);
+ R3(e, a, b, c, d, 46);
+ R3(d, e, a, b, c, 47);
+ R3(c, d, e, a, b, 48);
+ R3(b, c, d, e, a, 49);
+ R3(a, b, c, d, e, 50);
+ R3(e, a, b, c, d, 51);
+ R3(d, e, a, b, c, 52);
+ R3(c, d, e, a, b, 53);
+ R3(b, c, d, e, a, 54);
+ R3(a, b, c, d, e, 55);
+ R3(e, a, b, c, d, 56);
+ R3(d, e, a, b, c, 57);
+ R3(c, d, e, a, b, 58);
+ R3(b, c, d, e, a, 59);
+ R4(a, b, c, d, e, 60);
+ R4(e, a, b, c, d, 61);
+ R4(d, e, a, b, c, 62);
+ R4(c, d, e, a, b, 63);
+ R4(b, c, d, e, a, 64);
+ R4(a, b, c, d, e, 65);
+ R4(e, a, b, c, d, 66);
+ R4(d, e, a, b, c, 67);
+ R4(c, d, e, a, b, 68);
+ R4(b, c, d, e, a, 69);
+ R4(a, b, c, d, e, 70);
+ R4(e, a, b, c, d, 71);
+ R4(d, e, a, b, c, 72);
+ R4(c, d, e, a, b, 73);
+ R4(b, c, d, e, a, 74);
+ R4(a, b, c, d, e, 75);
+ R4(e, a, b, c, d, 76);
+ R4(d, e, a, b, c, 77);
+ R4(c, d, e, a, b, 78);
+ R4(b, c, d, e, a, 79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX * context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX * context, guchar * data, guint32 len)
+{
+ guint32 i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3))
+ context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64 - j));
+ SHA1Transform(context->state, context->buffer);
+ for (; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ } else
+ i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(guchar digest[20], SHA1_CTX * context)
+{
+ guint32 i, j;
+ guchar finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (guchar) ((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (guchar *) "\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (guchar *) "\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (guchar)
+ ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+#ifdef SHA1_TEST
+static char *b32_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+static void base32_encode_exactly(guchar * buf, gint len,
+ guchar * encbuf, gint enclen)
+{
+ gint i = 0;
+ guchar *ip = buf + len;
+ guchar *op = encbuf + enclen;
+
+ switch (len % 5) {
+ case 0:
+ do {
+ g_assert(op - encbuf >= 8);
+ i = *--ip; /* Input #4 */
+ *--op = b32_alphabet[i & 0x1f]; /* Ouput #7 */
+ i >>= 5; /* upper <234>, input #4 */
+ /* FALLTHROUGH */
+ case 4:
+ i |= ((guint32) * --ip) << 3; /* had 3 bits in `i' */
+ *--op = b32_alphabet[i & 0x1f]; /* Output #6 */
+ i >>= 5; /* upper <401234>, input #3 */
+ *--op = b32_alphabet[i & 0x1f]; /* Output #5 */
+ i >>= 5; /* upper <4>, input #3 */
+ /* FALLTHROUGH */
+ case 3:
+ i |= ((guint32) * --ip) << 1; /* had 1 bits in `i' */
+ *--op = b32_alphabet[i & 0x1f]; /* Output #4 */
+ i >>= 5; /* upper <1234>, input #2 */
+ /* FALLTHROUGH */
+ case 2:
+ i |= ((guint32) * --ip) << 4; /* had 4 bits in `i' */
+ *--op = b32_alphabet[i & 0x1f]; /* Output #3 */
+ i >>= 5; /* upper <3401234>, input #1 */
+ *--op = b32_alphabet[i & 0x1f]; /* Output #2 */
+ i >>= 5; /* upper <34>, input #1 */
+ /* FALLTHROUGH */
+ case 1:
+ i |= ((guint32) * --ip) << 2; /* had 2 bits in `i' */
+ *--op = b32_alphabet[i & 0x1f]; /* Output #1 */
+ i >>= 5; /* upper <01234>, input #0 */
+ *--op = b32_alphabet[i & 0x1f]; /* Output #0 */
+ i >>= 5; /* Holds nothing, MBZ */
+ g_assert(i == 0);
+ g_assert(op >= encbuf);
+ } while (op > encbuf);
+ }
+}
+
+
+
+/*************************************************************/
+
+int main(int argc, char **argv)
+{
+ gint i, j;
+ SHA1_CTX context;
+ guchar digest[20], buffer[16384];
+ FILE *file;
+
+ if (argc > 2) {
+ puts("Public domain SHA-1 implementation - by Steve Reid <steve@edmweb.com>");
+ puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
+ exit(0);
+ }
+ if (argc < 2) {
+ file = stdin;
+ } else {
+ if (!(file = fopen(argv[1], "rb"))) {
+ fputs("Unable to open file.", stderr);
+ exit(-1);
+ }
+ }
+ SHA1Init(&context);
+ while (!feof(file)) { /* note: what if ferror(file) */
+ i = fread(buffer, 1, 16384, file);
+ SHA1Update(&context, buffer, i);
+ }
+ SHA1Final(digest, &context);
+ fclose(file);
+
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 4; j++) {
+ printf("%02X", digest[i*4+j]);
+ }
+ putchar(' ');
+ }
+ putchar('\n');
+
+ {
+ guchar tmp[33];
+ tmp[32] = '\0';
+ base32_encode_exactly(digest, 20, tmp, 32);
+ printf("%s\n", tmp);
+ }
+
+ exit(0);
+}
+#endif /* SHA1_TEST */
diff --git a/modules/computer.c b/modules/computer.c
new file mode 100644
index 00000000..eda405e8
--- /dev/null
+++ b/modules/computer.c
@@ -0,0 +1,716 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 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 <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <config.h>
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <hardinfo.h>
+#include <iconcache.h>
+#include <shell.h>
+
+#include <vendor.h>
+
+#include "computer.h"
+
+/* Callbacks */
+gchar *callback_summary();
+gchar *callback_os();
+gchar *callback_modules();
+gchar *callback_boots();
+gchar *callback_locales();
+gchar *callback_fs();
+gchar *callback_display();
+gchar *callback_network();
+gchar *callback_users();
+gchar *callback_groups();
+gchar *callback_env_var();
+#if GLIB_CHECK_VERSION(2,14,0)
+gchar *callback_dev();
+#endif /* GLIB_CHECK_VERSION(2,14,0) */
+
+/* Scan callbacks */
+void scan_summary(gboolean reload);
+void scan_os(gboolean reload);
+void scan_modules(gboolean reload);
+void scan_boots(gboolean reload);
+void scan_locales(gboolean reload);
+void scan_fs(gboolean reload);
+void scan_display(gboolean reload);
+void scan_network(gboolean reload);
+void scan_users(gboolean reload);
+void scan_groups(gboolean reload);
+void scan_env_var(gboolean reload);
+#if GLIB_CHECK_VERSION(2,14,0)
+void scan_dev(gboolean reload);
+#endif /* GLIB_CHECK_VERSION(2,14,0) */
+
+static ModuleEntry entries[] = {
+ {N_("Summary"), "summary.png", callback_summary, scan_summary, MODULE_FLAG_NONE},
+ {N_("Operating System"), "os.png", callback_os, scan_os, MODULE_FLAG_NONE},
+ {N_("Kernel Modules"), "module.png", callback_modules, scan_modules, MODULE_FLAG_NONE},
+ {N_("Boots"), "boot.png", callback_boots, scan_boots, MODULE_FLAG_NONE},
+ {N_("Languages"), "language.png", callback_locales, scan_locales, MODULE_FLAG_NONE},
+ {N_("Filesystems"), "dev_removable.png", callback_fs, scan_fs, MODULE_FLAG_NONE},
+ {N_("Display"), "monitor.png", callback_display, scan_display, MODULE_FLAG_NONE},
+ {N_("Environment Variables"), "environment.png", callback_env_var, scan_env_var, MODULE_FLAG_NONE},
+#if GLIB_CHECK_VERSION(2,14,0)
+ {N_("Development"), "devel.png", callback_dev, scan_dev, MODULE_FLAG_NONE},
+#endif /* GLIB_CHECK_VERSION(2,14,0) */
+ {N_("Users"), "users.png", callback_users, scan_users, MODULE_FLAG_NONE},
+ {N_("Groups"), "users.png", callback_groups, scan_groups, MODULE_FLAG_NONE},
+ {NULL},
+};
+
+gchar *module_list = NULL;
+Computer *computer = NULL;
+
+gchar *hi_more_info(gchar * entry)
+{
+ gchar *info = moreinfo_lookup_with_prefix("COMP", entry);
+
+ if (info)
+ return g_strdup(info);
+
+ return g_strdup_printf("[%s]", entry);
+}
+
+gchar *hi_get_field(gchar * field)
+{
+ gchar *tmp;
+
+ if (g_str_equal(field, _("Memory"))) {
+ MemoryInfo *mi = computer_get_memory();
+ tmp = g_strdup_printf(_("%dMB (%dMB used)"), mi->total, mi->used);
+ g_free(mi);
+ } else if (g_str_equal(field, _("Uptime"))) {
+ tmp = computer_get_formatted_uptime();
+ } else if (g_str_equal(field, _("Date/Time"))) {
+ time_t t = time(NULL);
+
+ tmp = g_new0(gchar, 64);
+ strftime(tmp, 64, "%c", localtime(&t));
+ } else if (g_str_equal(field, _("Load Average"))) {
+ tmp = computer_get_formatted_loadavg();
+ } else if (g_str_equal(field, _("Available entropy in /dev/random"))) {
+ tmp = computer_get_entropy_avail();
+ } else {
+ tmp = g_strdup_printf("Unknown field: %s", field);
+ }
+ return tmp;
+}
+
+void scan_summary(gboolean reload)
+{
+ SCAN_START();
+ module_entry_scan_all_except(entries, 0);
+ computer->alsa = computer_get_alsainfo();
+ SCAN_END();
+}
+
+void scan_os(gboolean reload)
+{
+ SCAN_START();
+ computer->os = computer_get_os();
+ SCAN_END();
+}
+
+void scan_modules(gboolean reload)
+{
+ SCAN_START();
+ scan_modules_do();
+ SCAN_END();
+}
+
+void scan_boots(gboolean reload)
+{
+ SCAN_START();
+ scan_boots_real();
+ SCAN_END();
+}
+
+void scan_locales(gboolean reload)
+{
+ SCAN_START();
+ scan_os(FALSE);
+ scan_languages(computer->os);
+ SCAN_END();
+}
+
+void scan_fs(gboolean reload)
+{
+ SCAN_START();
+ scan_filesystems();
+ SCAN_END();
+}
+
+void scan_display(gboolean reload)
+{
+ SCAN_START();
+ computer->display = computer_get_display();
+ SCAN_END();
+}
+
+void scan_users(gboolean reload)
+{
+ SCAN_START();
+ scan_users_do();
+ SCAN_END();
+}
+
+void scan_groups(gboolean reload)
+{
+ SCAN_START();
+ scan_groups_do();
+ SCAN_END();
+}
+
+#if GLIB_CHECK_VERSION(2,14,0)
+static gchar *dev_list = NULL;
+void scan_dev(gboolean reload)
+{
+ SCAN_START();
+
+ int i;
+ struct {
+ gchar *compiler_name;
+ gchar *version_command;
+ gchar *regex;
+ gboolean stdout;
+ } detect_lang[] = {
+ { N_("Scripting Languages"), NULL, FALSE },
+ { N_("CPython"), "python -V", "\\d+\\.\\d+\\.\\d+", TRUE },
+ { N_("Perl"), "perl -v", "\\d+\\.\\d+\\.\\d+", TRUE },
+ { N_("PHP"), "php --version", "\\d+\\.\\d+\\.\\S+", TRUE},
+ { N_("Ruby"), "ruby --version", "\\d+\\.\\d+\\.\\d+", TRUE },
+ { N_("Bash"), "bash --version", "\\d+\\.\\d+\\.\\S+", TRUE},
+ { N_("Compilers"), NULL, FALSE },
+ { N_("C (GCC)"), "gcc -v", "\\d+\\.\\d+\\.\\d+", FALSE },
+ { N_("C (Clang)"), "clang -v", "\\d+\\.\\d+", FALSE },
+ { N_("D (dmd)"), "dmd --help", "\\d+\\.\\d+", TRUE },
+ { N_("Java"), "javac -version", "\\d+\\.\\d+\\.\\d+", FALSE },
+ { N_("CSharp (Mono, old)"), "mcs --version", "\\d+\\.\\d+\\.\\d+\\.\\d+", TRUE },
+ { N_("CSharp (Mono)"), "gmcs --version", "\\d+\\.\\d+\\.\\d+\\.\\d+", TRUE },
+ { N_("Vala"), "valac --version", "\\d+\\.\\d+\\.\\d+", TRUE },
+ { N_("Haskell (GHC)"), "ghc -v", "\\d+\\.\\d+\\.\\d+", FALSE },
+ { N_("FreePascal"), "fpc -iV", "\\d+\\.\\d+\\.?\\d*", TRUE },
+ { N_("Go"), "go version", "\\d+\\.\\d+\\.?\\d* ", TRUE },
+ { N_("Tools"), NULL, FALSE },
+ { N_("make"), "make --version", "\\d+\\.\\d+", TRUE },
+ { N_("GDB"), "gdb --version", "\\d+\\.\\S+", TRUE },
+ { N_("strace"), "strace -V", "\\d+\\.\\d+\\.?\\d*", TRUE },
+ { N_("valgrind"), "valgrind --version", "\\d+\\.\\d+\\.\\S+", TRUE },
+ { N_("QMake"), "qmake --version", "\\d+\\.\\S+", TRUE},
+ { N_("CMake"), "cmake --version", "\\d+\\.\\d+\\.?\\d*", TRUE},
+ };
+
+ g_free(dev_list);
+
+ dev_list = g_strdup("");
+
+ for (i = 0; i < G_N_ELEMENTS(detect_lang); i++) {
+ gchar *version = NULL;
+ gchar *output;
+ gchar *temp;
+ GRegex *regex;
+ GMatchInfo *match_info;
+ gboolean found;
+
+ if (!detect_lang[i].regex) {
+ dev_list = h_strdup_cprintf("[%s]\n", dev_list, detect_lang[i].compiler_name);
+ continue;
+ }
+
+ if (detect_lang[i].stdout) {
+ found = g_spawn_command_line_sync(detect_lang[i].version_command, &output, NULL, NULL, NULL);
+ } else {
+ found = g_spawn_command_line_sync(detect_lang[i].version_command, NULL, &output, NULL, NULL);
+ }
+
+ if (found) {
+ regex = g_regex_new(detect_lang[i].regex, 0, 0, NULL);
+
+ g_regex_match(regex, output, 0, &match_info);
+ if (g_match_info_matches(match_info)) {
+ version = g_match_info_fetch(match_info, 0);
+ }
+
+ g_match_info_free(match_info);
+ g_regex_unref(regex);
+ g_free(output);
+ }
+
+ if (version) {
+ dev_list = h_strdup_cprintf("%s=%s\n", dev_list, detect_lang[i].compiler_name, version);
+ g_free(version);
+ } else {
+ dev_list = h_strdup_cprintf(_("%s=Not found\n"), dev_list, detect_lang[i].compiler_name);
+ }
+
+ temp = g_strdup_printf(_("Detecting version: %s"),
+ detect_lang[i].compiler_name);
+ shell_status_update(temp);
+ g_free(temp);
+ }
+
+ SCAN_END();
+}
+
+gchar *callback_dev()
+{
+ return g_strdup_printf(_("[$ShellParam$]\n"
+ "ColumnTitle$TextValue=Program\n"
+ "ColumnTitle$Value=Version\n"
+ "ShowColumnHeaders=true\n"
+ "%s"), dev_list);
+}
+#endif /* GLIB_CHECK_VERSION(2,14,0) */
+
+/* Table based off imvirt by Thomas Liske <liske@ibh.de>
+ Copyright (c) 2008 IBH IT-Service GmbH under GPLv2. */
+gchar *computer_get_virtualization()
+{
+ gboolean found = FALSE;
+ gint i, j;
+ gchar *files[] = {
+ "/proc/scsi/scsi",
+ "/proc/cpuinfo",
+ "/var/log/dmesg",
+ NULL
+ };
+ const static struct {
+ gchar *str;
+ gchar *vmtype;
+ } vm_types[] = {
+ /* VMware */
+ { "VMware", "Virtual (VMware)" },
+ { ": VMware Virtual IDE CDROM Drive", "Virtual (VMware)" },
+ /* QEMU */
+ { "QEMU", "Virtual (QEMU)" },
+ { "QEMU Virtual CPU", "Virtual (QEMU)" },
+ { ": QEMU HARDDISK", "Virtual (QEMU)" },
+ { ": QEMU CD-ROM", "Virtual (QEMU)" },
+ /* Generic Virtual Machine */
+ { ": Virtual HD,", "Virtual (Unknown)" },
+ { ": Virtual CD,", "Virtual (Unknown)" },
+ /* Virtual Box */
+ { "VBOX", "Virtual (VirtualBox)" },
+ { ": VBOX HARDDISK", "Virtual (VirtualBox)" },
+ { ": VBOX CD-ROM", "Virtual (VirtualBox)" },
+ /* Xen */
+ { "Xen virtual console", "Virtual (Xen)" },
+ { "Xen reported: ", "Virtual (Xen)" },
+ { "xen-vbd: registered block device", "Virtual (Xen)" },
+ /* Generic */
+ { " hypervisor", "Virtual (hypervisor present)"} ,
+ { NULL }
+ };
+
+ DEBUG("Detecting virtual machine");
+
+ if (g_file_test("/proc/xen", G_FILE_TEST_EXISTS)) {
+ DEBUG("/proc/xen found; assuming Xen");
+ return g_strdup("Xen");
+ }
+
+ for (i = 0; files[i+1]; i++) {
+ gchar buffer[512];
+ FILE *file;
+
+ if ((file = fopen(files[i], "r"))) {
+ while (!found && fgets(buffer, 512, file)) {
+ for (j = 0; vm_types[j+1].str; j++) {
+ if (strstr(buffer, vm_types[j].str)) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ fclose(file);
+
+ if (found) {
+ DEBUG("%s found (by reading file %s)",
+ vm_types[j].vmtype, files[i]);
+ return g_strdup(vm_types[j].vmtype);
+ }
+ }
+
+ }
+
+ DEBUG("no virtual machine detected; assuming physical machine");
+
+ return g_strdup(_("Physical machine"));
+}
+
+gchar *callback_summary()
+{
+ gchar *processor_name, *alsa_cards;
+ gchar *input_devices, *printers;
+ gchar *storage_devices, *summary;
+ gchar *virt;
+
+ processor_name = module_call_method("devices::getProcessorName");
+ alsa_cards = computer_get_alsacards(computer);
+ input_devices = module_call_method("devices::getInputDevices");
+ printers = module_call_method("devices::getPrinters");
+ storage_devices = module_call_method("devices::getStorageDevices");
+ virt = computer_get_virtualization();
+
+ summary = g_strdup_printf(_("[$ShellParam$]\n"
+ "UpdateInterval$Memory=1000\n"
+ "UpdateInterval$Date/Time=1000\n"
+ "#ReloadInterval=5000\n"
+ "[Computer]\n"
+ "Processor=%s\n"
+ "Memory=...\n"
+ "Machine Type=%s\n"
+ "Operating System=%s\n"
+ "User Name=%s\n"
+ "Date/Time=...\n"
+ "[Display]\n"
+ "Resolution=%dx%d pixels\n"
+ "OpenGL Renderer=%s\n"
+ "X11 Vendor=%s\n"
+ "\n%s\n"
+ "[Input Devices]\n%s\n"
+ "\n%s\n"
+ "\n%s\n"),
+ processor_name,
+ virt,
+ computer->os->distro,
+ computer->os->username,
+ computer->display->width,
+ computer->display->height,
+ computer->display->ogl_renderer,
+ computer->display->vendor,
+ alsa_cards,
+ input_devices, printers, storage_devices);
+
+ g_free(processor_name);
+ g_free(alsa_cards);
+ g_free(input_devices);
+ g_free(printers);
+ g_free(storage_devices);
+ g_free(virt);
+
+ return summary;
+}
+
+gchar *callback_os()
+{
+ return g_strdup_printf(_("[$ShellParam$]\n"
+ "UpdateInterval$Uptime=10000\n"
+ "UpdateInterval$Load Average=1000\n"
+ "UpdateInterval$Available entropy in /dev/random=1000\n"
+ "[Version]\n"
+ "Kernel=%s\n"
+ "Version=%s\n"
+ "C Library=%s\n"
+ "Distribution=%s\n"
+ "[Current Session]\n"
+ "Computer Name=%s\n"
+ "User Name=%s\n"
+ "#Language=%s\n"
+ "Home Directory=%s\n"
+ "Desktop Environment=%s\n"
+ "[Misc]\n"
+ "Uptime=...\n"
+ "Load Average=...\n"
+ "Available entropy in /dev/random=..."),
+ computer->os->kernel,
+ computer->os->kernel_version,
+ computer->os->libc,
+ computer->os->distro,
+ computer->os->hostname,
+ computer->os->username,
+ computer->os->language,
+ computer->os->homedir,
+ computer->os->desktop);
+}
+
+gchar *callback_modules()
+{
+ return g_strdup_printf(_("[Loaded Modules]\n"
+ "%s"
+ "[$ShellParam$]\n"
+ "ViewType=1\n"
+ "ColumnTitle$TextValue=Name\n"
+ "ColumnTitle$Value=Description\n"
+ "ShowColumnHeaders=true\n"), module_list);
+}
+
+gchar *callback_boots()
+{
+ return g_strdup_printf(_("[$ShellParam$]\n"
+ "ColumnTitle$TextValue=Date & Time\n"
+ "ColumnTitle$Value=Kernel Version\n"
+ "ShowColumnHeaders=true\n"
+ "\n"
+ "%s"), computer->os->boots);
+}
+
+gchar *callback_locales()
+{
+ return g_strdup_printf(_("[$ShellParam$]\n"
+ "ViewType=1\n"
+ "ColumnTitle$TextValue=Language Code\n"
+ "ColumnTitle$Value=Name\n"
+ "ShowColumnHeaders=true\n"
+ "[Available Languages]\n"
+ "%s"), computer->os->languages);
+}
+
+gchar *callback_fs()
+{
+ return g_strdup_printf(_("[$ShellParam$]\n"
+ "ViewType=4\n"
+ "ReloadInterval=5000\n"
+ "Zebra=1\n"
+ "NormalizePercentage=false\n"
+ "ColumnTitle$Extra1=Mount Point\n"
+ "ColumnTitle$Progress=Usage\n"
+ "ColumnTitle$TextValue=Device\n"
+ "ShowColumnHeaders=true\n"
+ "[Mounted File Systems]\n%s\n"), fs_list);
+}
+
+gchar *callback_display()
+{
+ return g_strdup_printf(_("[Display]\n"
+ "Resolution=%dx%d pixels\n"
+ "Vendor=%s\n"
+ "Version=%s\n"
+ "[Monitors]\n"
+ "%s"
+ "[Extensions]\n"
+ "%s"
+ "[OpenGL]\n"
+ "Vendor=%s\n"
+ "Renderer=%s\n"
+ "Version=%s\n"
+ "Direct Rendering=%s\n"),
+ computer->display->width,
+ computer->display->height,
+ computer->display->vendor,
+ computer->display->version,
+ computer->display->monitors,
+ computer->display->extensions,
+ computer->display->ogl_vendor,
+ computer->display->ogl_renderer,
+ computer->display->ogl_version,
+ computer->display->dri ? _("Y_es") : _("No"));
+}
+
+gchar *callback_users()
+{
+ return g_strdup_printf("[$ShellParam$]\n"
+ "ReloadInterval=10000\n"
+ "ViewType=1\n"
+ "[Users]\n"
+ "%s\n", users);
+}
+
+gchar *callback_groups()
+{
+ return g_strdup_printf(_("[$ShellParam$]\n"
+ "ReloadInterval=10000\n"
+ "ColumnTitle$TextValue=Name\n"
+ "ColumnTitle$Value=Group ID\n"
+ "ShowColumnHeaders=true\n"
+ "[Groups]\n"
+ "%s\n"), groups);
+}
+
+gchar *get_os_kernel(void)
+{
+ scan_os(FALSE);
+ return g_strdup(computer->os->kernel);
+}
+
+gchar *get_os(void)
+{
+ scan_os(FALSE);
+ return g_strdup(computer->os->distro);
+}
+
+gchar *get_display_summary(void)
+{
+ scan_display(FALSE);
+
+ return g_strdup_printf("%dx%d\n"
+ "%s\n"
+ "%s",
+ computer->display->width,
+ computer->display->height,
+ computer->display->ogl_renderer,
+ computer->display->vendor);
+}
+
+gchar *get_kernel_module_description(gchar *module)
+{
+ gchar *description;
+
+ if (!_module_hash_table) {
+ scan_modules(FALSE);
+ }
+
+ description = g_hash_table_lookup(_module_hash_table, module);
+ if (!description) {
+ return NULL;
+ }
+
+ return g_strdup(description);
+}
+
+gchar *get_audio_cards(void)
+{
+ if (!computer->alsa) {
+ computer->alsa = computer_get_alsainfo();
+ }
+
+ return computer_get_alsacards(computer);
+}
+
+ShellModuleMethod *hi_exported_methods(void)
+{
+ static ShellModuleMethod m[] = {
+ {"getOSKernel", get_os_kernel},
+ {"getOS", get_os},
+ {"getDisplaySummary", get_display_summary},
+ {"getAudioCards", get_audio_cards},
+ {"getKernelModuleDescription", get_kernel_module_description},
+ {NULL}
+ };
+
+ return m;
+}
+
+ModuleEntry *hi_module_get_entries(void)
+{
+ return entries;
+}
+
+gchar *hi_module_get_name(void)
+{
+ return g_strdup(_("Computer"));
+}
+
+guchar hi_module_get_weight(void)
+{
+ return 80;
+}
+
+gchar **hi_module_get_dependencies(void)
+{
+ static gchar *deps[] = { "devices.so", NULL };
+
+ return deps;
+}
+
+gchar *hi_module_get_summary(void)
+{
+ return g_strdup("[Operating System]\n"
+ "Icon=os.png\n"
+ "Method=computer::getOS\n"
+ "[CPU]\n"
+ "Icon=processor.png\n"
+ "Method=devices::getProcessorName\n"
+ "[RAM]\n"
+ "Icon=memory.png\n"
+ "Method=devices::getMemoryTotal\n"
+ "[Motherboard]\n"
+ "Icon=module.png\n"
+ "Method=devices::getMotherboard\n"
+ "[Graphics]\n"
+ "Icon=monitor.png\n"
+ "Method=computer::getDisplaySummary\n"
+ "[Storage]\n"
+ "Icon=hdd.png\n"
+ "Method=devices::getStorageDevices\n"
+ "[Printers]\n"
+ "Icon=printer.png\n"
+ "Method=devices::getPrinters\n"
+ "[Audio]\n"
+ "Icon=audio.png\n"
+ "Method=computer::getAudioCards\n");
+}
+
+void hi_module_deinit(void)
+{
+ if (computer->os) {
+ g_free(computer->os->kernel);
+ g_free(computer->os->libc);
+ g_free(computer->os->distrocode);
+ g_free(computer->os->distro);
+ g_free(computer->os->hostname);
+ g_free(computer->os->language);
+ g_free(computer->os->homedir);
+ g_free(computer->os->kernel_version);
+ g_free(computer->os->languages);
+ g_free(computer->os->desktop);
+ g_free(computer->os->username);
+ g_free(computer->os->boots);
+ g_free(computer->os);
+ }
+
+ if (computer->display) {
+ g_free(computer->display->ogl_vendor);
+ g_free(computer->display->ogl_renderer);
+ g_free(computer->display->ogl_version);
+ g_free(computer->display->display_name);
+ g_free(computer->display->vendor);
+ g_free(computer->display->version);
+ g_free(computer->display->extensions);
+ g_free(computer->display->monitors);
+ g_free(computer->display);
+ }
+
+ if (computer->alsa) {
+ g_slist_free(computer->alsa->cards);
+ g_free(computer->alsa);
+ }
+
+ g_free(computer->date_time);
+ g_free(computer);
+
+ moreinfo_del_with_prefix("COMP");
+}
+
+void hi_module_init(void)
+{
+ computer = g_new0(Computer, 1);
+}
+
+ModuleAbout *hi_module_get_about(void)
+{
+ static ModuleAbout ma[] = {
+ {
+ .author = "Leandro A. F. Pereira",
+ .description = N_("Gathers high-level computer information"),
+ .version = VERSION,
+ .license = "GNU GPL version 2"}
+ };
+
+ return ma;
+}
+
diff --git a/modules/computer/alsa.c b/modules/computer/alsa.c
new file mode 100644
index 00000000..e1e7b946
--- /dev/null
+++ b/modules/computer/alsa.c
@@ -0,0 +1,71 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "computer.h"
+
+gchar *
+computer_get_alsacards(Computer * computer)
+{
+ GSList *p;
+ gchar *tmp = g_strdup(_("[Audio Devices]\n"));
+ gint n = 0;
+
+ if (computer->alsa) {
+ for (p = computer->alsa->cards; p; p = p->next) {
+ AlsaCard *ac = (AlsaCard *) p->data;
+
+ tmp = h_strdup_cprintf(_("Audio Adapter#%d=%s\n"),
+ tmp, ++n, ac->friendly_name);
+ }
+ }
+
+ return tmp;
+}
+
+AlsaInfo *
+computer_get_alsainfo(void)
+{
+ AlsaInfo *ai;
+ AlsaCard *ac;
+ FILE *cards;
+ gchar buffer[128];
+
+ cards = fopen("/proc/asound/cards", "r");
+ if (!cards)
+ return NULL;
+
+ ai = g_new0(AlsaInfo, 1);
+
+ while (fgets(buffer, 128, cards)) {
+ gchar **tmp;
+
+ ac = g_new0(AlsaCard, 1);
+
+ tmp = g_strsplit(buffer, ":", 0);
+
+ ac->friendly_name = g_strdup(tmp[1]);
+ ai->cards = g_slist_append(ai->cards, ac);
+
+ g_strfreev(tmp);
+ (void)fgets(buffer, 128, cards); /* skip next line */
+ }
+ fclose(cards);
+
+ return ai;
+}
diff --git a/modules/computer/boots.c b/modules/computer/boots.c
new file mode 100644
index 00000000..478e89ac
--- /dev/null
+++ b/modules/computer/boots.c
@@ -0,0 +1,65 @@
+/*
+ * 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 "hardinfo.h"
+#include "computer.h"
+
+void
+scan_boots_real(void)
+{
+ FILE *last;
+ char buffer[256];
+
+ scan_os(FALSE);
+
+ if (!computer->os->boots)
+ computer->os->boots = g_strdup(_("[Boots]\n"));
+ else
+ return;
+
+ last = popen("last", "r");
+ if (last) {
+ while (fgets(buffer, 256, last)) {
+ if (strstr(buffer, "system boot")) {
+ gchar **tmp, *buf = buffer;
+
+ strend(buffer, '\n');
+
+ while (*buf) {
+ if (*buf == ' ' && *(buf + 1) == ' ') {
+ memmove(buf, buf + 1, strlen(buf) + 1);
+
+ buf--;
+ } else {
+ buf++;
+ }
+ }
+
+ tmp = g_strsplit(buffer, " ", 0);
+ computer->os->boots = h_strdup_cprintf("\n%s %s %s %s=%s|%s",
+ computer->os->boots,
+ tmp[4], tmp[5], tmp[6], tmp[7], tmp[3], tmp[8]);
+ g_strfreev(tmp);
+ }
+ }
+
+ pclose(last);
+ }
+}
diff --git a/modules/computer/display.c b/modules/computer/display.c
new file mode 100644
index 00000000..2c98b144
--- /dev/null
+++ b/modules/computer/display.c
@@ -0,0 +1,148 @@
+/*
+ * 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 <string.h>
+
+#include "hardinfo.h"
+#include "computer.h"
+
+static void
+get_glx_info(DisplayInfo *di)
+{
+ gchar *output;
+ if (g_spawn_command_line_sync("glxinfo", &output, NULL, NULL, NULL)) {
+ gchar **output_lines;
+ gint i = 0;
+
+ for (output_lines = g_strsplit(output, "\n", 0);
+ output_lines && output_lines[i];
+ i++) {
+ if (strstr(output_lines[i], "OpenGL")) {
+ gchar **tmp = g_strsplit(output_lines[i], ":", 0);
+
+ tmp[1] = g_strchug(tmp[1]);
+
+ get_str("OpenGL vendor str", di->ogl_vendor);
+ get_str("OpenGL renderer str", di->ogl_renderer);
+ get_str("OpenGL version str", di->ogl_version);
+
+ g_strfreev(tmp);
+ } else if (strstr(output_lines[i], "direct rendering: Yes")) {
+ di->dri = TRUE;
+ }
+ }
+
+ g_free(output);
+ g_strfreev(output_lines);
+
+ if (!di->ogl_vendor)
+ di->ogl_vendor = "Unknown";
+ if (!di->ogl_renderer)
+ di->ogl_renderer = "Unknown";
+ if (!di->ogl_version)
+ di->ogl_version = "Unknown";
+ } else {
+ di->ogl_vendor = di->ogl_renderer = di->ogl_version = "Unknown";
+ }
+
+}
+
+static void
+get_x11_info(DisplayInfo *di)
+{
+ gchar *output;
+
+ if (g_spawn_command_line_sync("xdpyinfo", &output, NULL, NULL, NULL)) {
+ gchar **output_lines, **old;
+
+ output_lines = g_strsplit(output, "\n", 0);
+ g_free(output);
+
+ old = output_lines;
+ while (*(output_lines++)) {
+ gchar **tmp = g_strsplit(*output_lines, ":", 0);
+
+ if (tmp[1] && tmp[0]) {
+ tmp[1] = g_strchug(tmp[1]);
+
+ get_str("vendor string", di->vendor);
+ get_str("X.Org version", di->version);
+ get_str("XFree86 version", di->version);
+
+ if (g_str_has_prefix(tmp[0], "number of extensions")) {
+ int n;
+
+ di->extensions = g_strdup("");
+
+ for (n = atoi(tmp[1]); n; n--) {
+ di->extensions = h_strconcat(di->extensions,
+ g_strstrip(*(++output_lines)),
+ "=\n",
+ NULL);
+ }
+ g_strfreev(tmp);
+
+ break;
+ }
+ }
+
+ g_strfreev(tmp);
+ }
+
+ g_strfreev(old);
+ }
+
+ GdkScreen *screen = gdk_screen_get_default();
+
+ if (screen && GDK_IS_SCREEN(screen)) {
+ gint n_monitors = gdk_screen_get_n_monitors(screen);
+ gint i;
+
+ di->monitors = NULL;
+ for (i = 0; i < n_monitors; i++) {
+ GdkRectangle rect;
+
+ gdk_screen_get_monitor_geometry(screen, i, &rect);
+
+ di->monitors = h_strdup_cprintf(_("Monitor %d=%dx%d pixels\n"),
+ di->monitors, i, rect.width, rect.height);
+ }
+ } else {
+ di->monitors = "";
+ }
+}
+
+DisplayInfo *
+computer_get_display(void)
+{
+ DisplayInfo *di = g_new0(DisplayInfo, 1);
+
+ GdkScreen *screen = gdk_screen_get_default();
+
+ if (screen && GDK_IS_SCREEN(screen)) {
+ di->width = gdk_screen_get_width(screen);
+ di->height = gdk_screen_get_height(screen);
+ } else {
+ di->width = di->height = 0;
+ }
+
+ get_glx_info(di);
+ get_x11_info(di);
+
+ return di;
+}
diff --git a/modules/computer/environment.c b/modules/computer/environment.c
new file mode 100644
index 00000000..2a8d235c
--- /dev/null
+++ b/modules/computer/environment.c
@@ -0,0 +1,45 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 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 "hardinfo.h"
+#include "computer.h"
+
+static gchar *_env = NULL;
+void scan_env_var(gboolean reload)
+{
+ SCAN_START();
+
+ gchar **envlist;
+ gint i;
+
+ g_free(_env);
+
+ _env = g_strdup(_("[Environment Variables]\n"));
+ for (i = 0, envlist = g_listenv(); envlist[i]; i++) {
+ _env = h_strdup_cprintf("%s=%s\n", _env,
+ envlist[i], g_getenv(envlist[i]));
+ }
+ g_strfreev(envlist);
+
+ SCAN_END();
+}
+
+gchar *callback_env_var(void)
+{
+ return g_strdup(_env);
+}
diff --git a/modules/computer/filesystem.c b/modules/computer/filesystem.c
new file mode 100644
index 00000000..a7162777
--- /dev/null
+++ b/modules/computer/filesystem.c
@@ -0,0 +1,103 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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
+ *
+ * Some code from xfce4-mount-plugin, version 0.4.3
+ * Copyright (C) 2005 Jean-Baptiste jb_dul@yahoo.com
+ * Distributed under the terms of GNU GPL 2.
+ */
+
+#include <string.h>
+#include <sys/vfs.h>
+#include "hardinfo.h"
+#include "computer.h"
+
+gchar *fs_list = NULL;
+
+void
+scan_filesystems(void)
+{
+ FILE *mtab;
+ gchar buf[1024];
+ struct statfs sfs;
+ int count = 0;
+
+ g_free(fs_list);
+ fs_list = g_strdup("");
+ moreinfo_del_with_prefix("COMP:FS");
+
+ mtab = fopen("/etc/mtab", "r");
+ if (!mtab)
+ return;
+
+ while (fgets(buf, 1024, mtab)) {
+ gfloat size, used, avail;
+ gchar **tmp;
+
+ tmp = g_strsplit(buf, " ", 0);
+ if (!statfs(tmp[1], &sfs)) {
+ gfloat use_ratio;
+
+ size = (float) sfs.f_bsize * (float) sfs.f_blocks;
+ avail = (float) sfs.f_bsize * (float) sfs.f_bavail;
+ used = size - avail;
+
+ if (size == 0.0f) {
+ continue;
+ }
+
+ if (avail == 0.0f) {
+ use_ratio = 100.0f;
+ } else {
+ use_ratio = 100.0f * (used / size);
+ }
+
+ gchar *strsize = size_human_readable(size),
+ *stravail = size_human_readable(avail),
+ *strused = size_human_readable(used);
+
+ gchar *strhash;
+
+ strreplacechr(tmp[0], "#", '_');
+ strhash = g_strdup_printf("[%s]\n"
+ "Filesystem=%s\n"
+ "Mounted As=%s\n"
+ "Mount Point=%s\n"
+ "Size=%s\n"
+ "Used=%s\n"
+ "Available=%s\n",
+ tmp[0],
+ tmp[2],
+ strstr(tmp[3], "rw") ? "Read-Write" :
+ "Read-Only", tmp[1], strsize, strused,
+ stravail);
+ gchar *key = g_strdup_printf("FS%d", ++count);
+ moreinfo_add_with_prefix("COMP", key, strhash);
+ g_free(key);
+
+ fs_list = h_strdup_cprintf("$FS%d$%s=%.2f %% (%s of %s)|%s\n",
+ fs_list,
+ count, tmp[0], use_ratio, stravail, strsize, tmp[1]);
+
+ g_free(strsize);
+ g_free(stravail);
+ g_free(strused);
+ }
+ g_strfreev(tmp);
+ }
+
+ fclose(mtab);
+}
diff --git a/modules/computer/groups.c b/modules/computer/groups.c
new file mode 100644
index 00000000..244b8000
--- /dev/null
+++ b/modules/computer/groups.c
@@ -0,0 +1,45 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2012 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 <sys/types.h>
+#include <grp.h>
+#include "hardinfo.h"
+#include "computer.h"
+
+gchar *groups = NULL;
+
+void
+scan_groups_do(void)
+{
+ struct group *group_;
+
+ setgrent();
+ group_ = getgrent();
+ if (!group_)
+ return;
+
+ g_free(groups);
+ groups = g_strdup("");
+
+ while (group_) {
+ groups = h_strdup_cprintf("%s=%d\n", groups, group_->gr_name, group_->gr_gid);
+ group_ = getgrent();
+ }
+
+ endgrent();
+}
diff --git a/modules/computer/languages.c b/modules/computer/languages.c
new file mode 100644
index 00000000..5877c41c
--- /dev/null
+++ b/modules/computer/languages.c
@@ -0,0 +1,112 @@
+/*
+ * 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 <string.h>
+
+#include "hardinfo.h"
+#include "computer.h"
+
+void
+scan_languages(OperatingSystem * os)
+{
+ FILE *locale;
+ gchar buf[512], *retval = NULL;
+
+ locale = popen("locale -va && echo", "r");
+ if (!locale)
+ return;
+
+ gchar name[32];
+ gchar *title = NULL,
+ *source = NULL,
+ *address = NULL,
+ *email = NULL,
+ *language = NULL,
+ *territory = NULL,
+ *revision = NULL,
+ *date = NULL,
+ *codeset = NULL;
+
+ while (fgets(buf, 512, locale)) {
+ if (!strncmp(buf, "locale:", 7)) {
+ sscanf(buf, "locale: %s", name);
+ (void)fgets(buf, 128, locale);
+ } else if (strchr(buf, '|')) {
+ gchar **tmp = g_strsplit(buf, "|", 2);
+
+ tmp[0] = g_strstrip(tmp[0]);
+
+ if (tmp[1]) {
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("title", title);
+ get_str("source", source);
+ get_str("address", address);
+ get_str("email", email);
+ get_str("language", language);
+ get_str("territory", territory);
+ get_str("revision", revision);
+ get_str("date", date);
+ get_str("codeset", codeset);
+ }
+
+ g_strfreev(tmp);
+ } else {
+ gchar *currlocale;
+
+ retval = h_strdup_cprintf("$%s$%s=%s\n", retval, name, name, title);
+
+#define FIELD(f) f ? f : "(Unknown)"
+ currlocale = g_strdup_printf("[Locale Information]\n"
+ "Name=%s (%s)\n"
+ "Source=%s\n"
+ "Address=%s\n"
+ "Email=%s\n"
+ "Language=%s\n"
+ "Territory=%s\n"
+ "Revision=%s\n"
+ "Date=%s\n"
+ "Codeset=%s\n",
+ name, FIELD(title),
+ FIELD(source), FIELD(address),
+ FIELD(email), FIELD(language),
+ FIELD(territory), FIELD(revision),
+ FIELD(date), FIELD(codeset));
+#undef FIELD
+
+ moreinfo_add_with_prefix("COMP", name, currlocale);
+
+ g_free(title);
+ g_free(source);
+ g_free(address);
+ g_free(email);
+ g_free(language);
+ g_free(territory);
+ g_free(revision);
+ g_free(date);
+ g_free(codeset);
+
+ title = source = address = email = language = territory = \
+ revision = date = codeset = NULL;
+ }
+ }
+
+ fclose(locale);
+
+ os->languages = retval;
+}
diff --git a/modules/computer/loadavg.c b/modules/computer/loadavg.c
new file mode 100644
index 00000000..7311dbf0
--- /dev/null
+++ b/modules/computer/loadavg.c
@@ -0,0 +1,68 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 <string.h>
+
+#include "hardinfo.h"
+#include "computer.h"
+
+static gboolean
+computer_get_loadinfo(LoadInfo *li)
+{
+ FILE *procloadavg;
+ char buf[64];
+ int ret;
+
+ procloadavg = fopen("/proc/loadavg", "r");
+ if (!procloadavg)
+ return FALSE;
+
+ if (!fgets(buf, sizeof(buf), procloadavg)) {
+ fclose(procloadavg);
+ return FALSE;
+ }
+
+ ret = sscanf(buf, "%f %f %f", &li->load1, &li->load5, &li->load15);
+ if (ret != 3) {
+ size_t len = strlen(buf);
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '.')
+ buf[i] = ',';
+ }
+
+ ret = sscanf(buf, "%f %f %f", &li->load1, &li->load5, &li->load15);
+ }
+
+ fclose(procloadavg);
+
+ return ret == 3;
+}
+
+gchar *
+computer_get_formatted_loadavg()
+{
+ LoadInfo li;
+
+ if (!computer_get_loadinfo(&li))
+ return g_strdup(_("Couldn't obtain load average"));
+
+ return g_strdup_printf("%.2f, %.2f, %.2f", li.load1, li.load5,
+ li.load15);
+}
diff --git a/modules/computer/memory.c b/modules/computer/memory.c
new file mode 100644
index 00000000..3d320e8a
--- /dev/null
+++ b/modules/computer/memory.c
@@ -0,0 +1,59 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "computer.h"
+
+MemoryInfo *
+computer_get_memory(void)
+{
+ MemoryInfo *mi;
+ FILE *procmem;
+ gchar buffer[128];
+
+ procmem = fopen("/proc/meminfo", "r");
+ if (!procmem)
+ return NULL;
+ mi = g_new0(MemoryInfo, 1);
+
+ while (fgets(buffer, 128, procmem)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_int("MemTotal", mi->total);
+ get_int("MemFree", mi->free);
+ get_int("Cached", mi->cached);
+
+ g_strfreev(tmp);
+ }
+ fclose(procmem);
+
+ mi->used = mi->total - mi->free;
+
+ mi->total /= 1000;
+ mi->cached /= 1000;
+ mi->used /= 1000;
+ mi->free /= 1000;
+
+ mi->used -= mi->cached;
+ mi->ratio = 1 - (gdouble) mi->used / mi->total;
+
+ return mi;
+}
diff --git a/modules/computer/modules.c b/modules/computer/modules.c
new file mode 100644
index 00000000..bbc05f42
--- /dev/null
+++ b/modules/computer/modules.c
@@ -0,0 +1,169 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 <string.h>
+
+#include "hardinfo.h"
+#include "computer.h"
+
+#define GET_STR(field_name,ptr) \
+ if (!ptr && strstr(tmp[0], field_name)) { \
+ ptr = g_markup_escape_text(g_strstrip(tmp[1]), strlen(tmp[1])); \
+ g_strfreev(tmp); \
+ continue; \
+ }
+
+GHashTable *_module_hash_table = NULL;
+
+void
+scan_modules_do(void)
+{
+ FILE *lsmod;
+ gchar buffer[1024];
+ gchar *lsmod_path;
+
+ if (!_module_hash_table) {
+ _module_hash_table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ g_free(module_list);
+
+ module_list = NULL;
+ moreinfo_del_with_prefix("COMP:MOD");
+
+ lsmod_path = find_program("lsmod");
+ if (!lsmod_path)
+ return;
+ lsmod = popen(lsmod_path, "r");
+ if (!lsmod) {
+ g_free(lsmod_path);
+ return;
+ }
+
+ (void)fgets(buffer, 1024, lsmod); /* Discards the first line */
+
+ while (fgets(buffer, 1024, lsmod)) {
+ gchar *buf, *strmodule, *hashkey;
+ gchar *author = NULL,
+ *description = NULL,
+ *license = NULL,
+ *deps = NULL, *vermagic = NULL, *filename = NULL, modname[64];
+ FILE *modi;
+ glong memory;
+
+ shell_status_pulse();
+
+ buf = buffer;
+
+ sscanf(buf, "%s %ld", modname, &memory);
+
+ hashkey = g_strdup_printf("MOD%s", modname);
+ buf = g_strdup_printf("/sbin/modinfo %s 2>/dev/null", modname);
+
+ modi = popen(buf, "r");
+ while (fgets(buffer, 1024, modi)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ GET_STR("author", author);
+ GET_STR("description", description);
+ GET_STR("license", license);
+ GET_STR("depends", deps);
+ GET_STR("vermagic", vermagic);
+ GET_STR("filename", filename);
+
+ g_strfreev(tmp);
+ }
+ pclose(modi);
+ g_free(buf);
+
+ /* old modutils includes quotes in some strings; strip them */
+ /*remove_quotes(modname);
+ remove_quotes(description);
+ remove_quotes(vermagic);
+ remove_quotes(author);
+ remove_quotes(license); */
+
+ /* old modutils displays <none> when there's no value for a
+ given field; this is not desirable in the module name
+ display, so change it to an empty string */
+ if (description && g_str_equal(description, "&lt;none&gt;")) {
+ g_free(description);
+ description = g_strdup("");
+
+ g_hash_table_insert(_module_hash_table,
+ g_strdup(modname),
+ g_strdup_printf("Kernel module (%s)", modname));
+ } else {
+ g_hash_table_insert(_module_hash_table,
+ g_strdup(modname),
+ g_strdup(description));
+ }
+
+ /* append this module to the list of modules */
+ module_list = h_strdup_cprintf("$%s$%s=%s\n",
+ module_list,
+ hashkey,
+ modname,
+ description ? description : "");
+
+#define NONE_IF_NULL(var) (var) ? (var) : "N/A"
+
+ /* create the module information string */
+ strmodule = g_strdup_printf("[Module Information]\n"
+ "Path=%s\n"
+ "Used Memory=%.2fKiB\n"
+ "[Description]\n"
+ "Name=%s\n"
+ "Description=%s\n"
+ "Version Magic=%s\n"
+ "[Copyright]\n"
+ "Author=%s\n"
+ "License=%s\n",
+ NONE_IF_NULL(filename),
+ memory / 1024.0,
+ modname,
+ NONE_IF_NULL(description),
+ NONE_IF_NULL(vermagic),
+ NONE_IF_NULL(author),
+ NONE_IF_NULL(license));
+
+ /* if there are dependencies, append them to that string */
+ if (deps && strlen(deps)) {
+ gchar **tmp = g_strsplit(deps, ",", 0);
+
+ strmodule = h_strconcat(strmodule,
+ "\n[Dependencies]\n",
+ g_strjoinv("=\n", tmp),
+ "=\n", NULL);
+ g_strfreev(tmp);
+ g_free(deps);
+ }
+
+ moreinfo_add_with_prefix("COMP", hashkey, strmodule);
+ g_free(hashkey);
+
+ g_free(license);
+ g_free(description);
+ g_free(author);
+ g_free(vermagic);
+ g_free(filename);
+ }
+ pclose(lsmod);
+
+ g_free(lsmod_path);
+}
diff --git a/modules/computer/os.c b/modules/computer/os.c
new file mode 100644
index 00000000..3caf6c26
--- /dev/null
+++ b/modules/computer/os.c
@@ -0,0 +1,258 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 <string.h>
+#include <sys/utsname.h>
+#include "hardinfo.h"
+#include "computer.h"
+
+static gchar *
+get_libc_version(void)
+{
+ FILE *libc;
+ gchar buf[256], *tmp, *p;
+ char *libc_paths[] = {
+ "/lib/ld-uClibc.so.0", "/lib64/ld-uClibc.so.0",
+ "/lib/libc.so.6", "/lib64/libc.so.6"
+ };
+ int i;
+
+ for (i=0; i < 4; i++) {
+ if (g_file_test(libc_paths[i], G_FILE_TEST_EXISTS)) break;
+ }
+ switch (i) {
+ case 0: case 1: return g_strdup("uClibc Library");
+ case 2: case 3: break; // gnu libc, continue processing
+ default: goto err;
+ }
+
+ libc = popen(libc_paths[i], "r");
+ if (!libc) goto err;
+
+ (void)fgets(buf, 256, libc);
+ if (pclose(libc)) goto err;
+
+ tmp = strstr(buf, "version ");
+ if (!tmp) goto err;
+
+ p = strchr(tmp, ',');
+ if (p) *p = '\0';
+ else goto err;
+
+ return g_strdup_printf(_("GNU C Library version %s (%sstable)"),
+ strchr(tmp, ' ') + 1,
+ strstr(buf, " stable ") ? "" : _("un"));
+ err:
+ return g_strdup(_("Unknown"));
+}
+
+#include <gdk/gdkx.h>
+
+void
+detect_desktop_environment(OperatingSystem * os)
+{
+ const gchar *tmp = g_getenv("GNOME_DESKTOP_SESSION_ID");
+ FILE *version;
+ char vers[16];
+
+ if (tmp) {
+ /* FIXME: this might not be true, as the gnome-panel in path
+ may not be the one that's running.
+ see where the user's running panel is and run *that* to
+ obtain the version. */
+ version = popen("gnome-about --gnome-version", "r");
+ if (version) {
+ (void)fscanf(version, _("Version: %s"), vers);
+ if (pclose(version))
+ goto unknown;
+ } else {
+ goto unknown;
+ }
+
+ os->desktop = g_strdup_printf("GNOME %s", vers);
+ } else if (g_getenv("KDE_FULL_SESSION")) {
+
+ if (g_getenv("KDE_SESSION_VERSION") && strstr(g_getenv("KDE_SESSION_VERSION"),(gchar *)"4")) {
+ version = popen("kwin --version", "r");
+ } else {
+ version = popen("kcontrol --version", "r");
+ }
+
+ if (version) {
+ char buf[32];
+
+ (void)fgets(buf, 32, version);
+
+ (void)fscanf(version, "KDE: %s", vers);
+ if (pclose(version))
+ goto unknown;
+ } else {
+ goto unknown;
+ }
+
+ os->desktop = g_strdup_printf("KDE %s", vers);
+ } else {
+ unknown:
+ os->desktop = NULL;
+
+ if (!g_getenv("DISPLAY")) {
+ os->desktop = g_strdup(_("Terminal"));
+ } else {
+ GdkScreen *screen = gdk_screen_get_default();
+
+ if (screen && GDK_IS_SCREEN(screen)) {
+ const gchar *windowman;
+
+ windowman = gdk_x11_screen_get_window_manager_name(screen);
+ if (g_str_equal(windowman, "Xfwm4")) {
+ /* FIXME: check if xprop -root | grep XFCE_DESKTOP_WINDOW is defined */
+ os->desktop = g_strdup("XFCE 4");
+ } else if ((tmp = g_getenv("XDG_CURRENT_DESKTOP"))) {
+ os->desktop = g_strdup(tmp);
+ if ((tmp = g_getenv("DESKTOP_SESSION")) && !g_str_equal(os->desktop, tmp)) {
+ g_free(os->desktop);
+ os->desktop = g_strdup(tmp);
+ }
+ }
+
+ if (!os->desktop) {
+ os->desktop = g_strdup_printf(_("Unknown (Window Manager: %s)"),
+ windowman);
+ }
+ } else {
+ os->desktop = g_strdup(_("Unknown"));
+ }
+ }
+ }
+}
+
+gchar *
+computer_get_entropy_avail(void)
+{
+ gint bits = h_sysfs_read_int("/proc/sys/kernel/random", "entropy_avail");
+ if (bits < 200)
+ return g_strdup_printf("%d bits (low)", bits);
+ if (bits < 3000)
+ return g_strdup_printf("%d bits (medium)", bits);
+ return g_strdup_printf("%d bits (healthy)", bits);
+}
+
+OperatingSystem *
+computer_get_os(void)
+{
+ struct utsname utsbuf;
+ OperatingSystem *os;
+ int i;
+
+ os = g_new0(OperatingSystem, 1);
+
+ /* Attempt to get the Distribution name; try using /etc/lsb-release first,
+ then doing the legacy method (checking for /etc/$DISTRO-release files) */
+ if (g_file_test("/etc/lsb-release", G_FILE_TEST_EXISTS)) {
+ FILE *release;
+ gchar buffer[128];
+
+ release = popen("lsb_release -d", "r");
+ if (release) {
+ (void)fgets(buffer, 128, release);
+ pclose(release);
+
+ os->distro = buffer;
+ os->distro = g_strdup(os->distro + strlen("Description:\t"));
+ }
+ } else if (g_file_test("/etc/arch-release", G_FILE_TEST_EXISTS)) {
+ os->distrocode = g_strdup("arch");
+ os->distro = g_strdup("Arch Linux");
+ } else {
+ for (i = 0;; i++) {
+ if (distro_db[i].file == NULL) {
+ os->distrocode = g_strdup("unk");
+ os->distro = g_strdup(_("Unknown distribution"));
+ break;
+ }
+
+ if (g_file_test(distro_db[i].file, G_FILE_TEST_EXISTS)) {
+ FILE *distro_ver;
+ char buf[128];
+
+ distro_ver = fopen(distro_db[i].file, "r");
+ if (distro_ver) {
+ (void)fgets(buf, 128, distro_ver);
+ fclose(distro_ver);
+ } else {
+ continue;
+ }
+
+ buf[strlen(buf) - 1] = 0;
+
+ if (!os->distro) {
+ /*
+ * HACK: Some Debian systems doesn't include
+ * the distribuition name in /etc/debian_release,
+ * so add them here.
+ */
+ if (!strncmp(distro_db[i].codename, "deb", 3) &&
+ ((buf[0] >= '0' && buf[0] <= '9') || buf[0] != 'D')) {
+ os->distro = g_strdup_printf
+ ("Debian GNU/Linux %s", buf);
+ } else {
+ os->distro = g_strdup(buf);
+ }
+ }
+
+ if (g_str_equal(distro_db[i].codename, "ppy")) {
+ gchar *tmp;
+ tmp = g_strdup_printf("Puppy Linux");
+ g_free(os->distro);
+ os->distro = tmp;
+ }
+
+ if (g_str_equal(distro_db[i].codename, "fatdog")) {
+ gchar *tmp;
+ tmp = g_strdup_printf("Fatdog64 [%.10s]", os->distro);
+ g_free(os->distro);
+ os->distro = tmp;
+ }
+
+ os->distrocode = g_strdup(distro_db[i].codename);
+
+ break;
+ }
+ }
+ }
+
+ os->distro = g_strstrip(os->distro);
+
+ /* Kernel and hostname info */
+ uname(&utsbuf);
+ os->kernel_version = g_strdup(utsbuf.version);
+ os->kernel = g_strdup_printf("%s %s (%s)", utsbuf.sysname,
+ utsbuf.release, utsbuf.machine);
+ os->hostname = g_strdup(utsbuf.nodename);
+ os->language = g_strdup(g_getenv("LC_MESSAGES"));
+ os->homedir = g_strdup(g_get_home_dir());
+ os->username = g_strdup_printf("%s (%s)",
+ g_get_user_name(), g_get_real_name());
+ os->libc = get_libc_version();
+ scan_languages(os);
+ detect_desktop_environment(os);
+
+ os->entropy_avail = computer_get_entropy_avail();
+
+ return os;
+}
diff --git a/modules/computer/uptime.c b/modules/computer/uptime.c
new file mode 100644
index 00000000..8eb563fa
--- /dev/null
+++ b/modules/computer/uptime.c
@@ -0,0 +1,76 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "computer.h"
+
+UptimeInfo *
+computer_get_uptime(void)
+{
+ UptimeInfo *ui = g_new0(UptimeInfo, 1);
+ FILE *procuptime;
+ gulong minutes;
+
+ if ((procuptime = fopen("/proc/uptime", "r")) != NULL) {
+ (void)fscanf(procuptime, "%lu", &minutes);
+ ui->minutes = minutes / 60;
+ fclose(procuptime);
+ } else {
+ return NULL;
+ }
+
+ ui->hours = ui->minutes / 60;
+ ui->minutes %= 60;
+ ui->days = ui->hours / 24;
+ ui->hours %= 24;
+
+ return ui;
+}
+
+gchar *
+computer_get_formatted_uptime()
+{
+ UptimeInfo *ui;
+ gchar *tmp;
+
+ ui = computer_get_uptime();
+
+ /* FIXME: Use ngettext */
+#define plural(x) ((x > 1) ? "s" : "")
+
+ if (ui->days < 1) {
+ if (ui->hours < 1) {
+ tmp =
+ g_strdup_printf("%d minute%s", ui->minutes,
+ plural(ui->minutes));
+ } else {
+ tmp =
+ g_strdup_printf("%d hour%s, %d minute%s", ui->hours,
+ plural(ui->hours), ui->minutes,
+ plural(ui->minutes));
+ }
+ } else {
+ tmp =
+ g_strdup_printf("%d day%s, %d hour%s and %d minute%s",
+ ui->days, plural(ui->days), ui->hours,
+ plural(ui->hours), ui->minutes,
+ plural(ui->minutes));
+ }
+
+ g_free(ui);
+ return tmp;
+}
diff --git a/modules/computer/users.c b/modules/computer/users.c
new file mode 100644
index 00000000..e8f891ac
--- /dev/null
+++ b/modules/computer/users.c
@@ -0,0 +1,60 @@
+/*
+ * 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 <pwd.h>
+#include "hardinfo.h"
+#include "computer.h"
+
+gchar *users = NULL;
+
+void
+scan_users_do(void)
+{
+ struct passwd *passwd_;
+ passwd_ = getpwent();
+ if (!passwd_)
+ return;
+
+ if (users) {
+ g_free(users);
+ moreinfo_del_with_prefix("COMP:USER");
+ }
+
+ users = g_strdup("");
+
+ while (passwd_) {
+ gchar *key = g_strdup_printf("USER%s", passwd_->pw_name);
+ gchar *val = g_strdup_printf("[User Information]\n"
+ "User ID=%d\n"
+ "Group ID=%d\n"
+ "Home directory=%s\n"
+ "Default shell=%s\n",
+ (gint) passwd_->pw_uid,
+ (gint) passwd_->pw_gid,
+ passwd_->pw_dir,
+ passwd_->pw_shell);
+ moreinfo_add_with_prefix("COMP", key, val);
+
+ strend(passwd_->pw_gecos, ',');
+ users = h_strdup_cprintf("$%s$%s=%s\n", users, key, passwd_->pw_name, passwd_->pw_gecos);
+ passwd_ = getpwent();
+ g_free(key);
+ }
+
+ endpwent();
+}
diff --git a/modules/devices.c b/modules/devices.c
new file mode 100644
index 00000000..87bb8a80
--- /dev/null
+++ b/modules/devices.c
@@ -0,0 +1,613 @@
+/*
+ * 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
+ */
+
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif /* __USE_XOPEN */
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE
+#endif /* _XOPEN_SOURCE */
+
+#include <gtk/gtk.h>
+#include <config.h>
+#include <string.h>
+
+#include <hardinfo.h>
+#include <shell.h>
+#include <iconcache.h>
+#include <syncmanager.h>
+
+#include <expr.h>
+#include <socket.h>
+
+#include "devices.h"
+
+gchar *callback_processors();
+gchar *callback_memory();
+gchar *callback_battery();
+gchar *callback_pci();
+gchar *callback_sensors();
+gchar *callback_printers();
+gchar *callback_storage();
+gchar *callback_input();
+gchar *callback_usb();
+#if defined(ARCH_x86) || defined(ARCH_x86_64)
+gchar *callback_dmi();
+gchar *callback_spd();
+#endif
+gchar *callback_device_resources();
+
+void scan_processors(gboolean reload);
+void scan_memory(gboolean reload);
+void scan_battery(gboolean reload);
+void scan_pci(gboolean reload);
+void scan_sensors(gboolean reload);
+void scan_printers(gboolean reload);
+void scan_storage(gboolean reload);
+void scan_input(gboolean reload);
+void scan_usb(gboolean reload);
+#if defined(ARCH_x86) || defined(ARCH_x86_64)
+void scan_dmi(gboolean reload);
+void scan_spd(gboolean reload);
+#endif
+void scan_device_resources(gboolean reload);
+
+gboolean root_required_for_resources(void);
+
+gchar *hi_more_info(gchar *entry);
+
+enum {
+ ENTRY_PROCESSOR,
+ ENTRY_MEMORY,
+ ENTRY_PCI,
+ ENTRY_USB,
+ ENTRY_PRINTERS,
+ ENTRY_BATTERY,
+ ENTRY_SENSORS,
+ ENTRY_INPUT,
+ ENTRY_STORAGE,
+ ENTRY_DMI,
+ ENTRY_SPD,
+ ENTRY_RESOURCES
+};
+
+static ModuleEntry entries[] = {
+ [ENTRY_PROCESSOR] = {N_("Processor"), "processor.png", callback_processors, scan_processors, MODULE_FLAG_NONE},
+ [ENTRY_MEMORY] = {N_("Memory"), "memory.png", callback_memory, scan_memory, MODULE_FLAG_NONE},
+ [ENTRY_PCI] = {N_("PCI Devices"), "devices.png", callback_pci, scan_pci, MODULE_FLAG_NONE},
+ [ENTRY_USB] = {N_("USB Devices"), "usb.png", callback_usb, scan_usb, MODULE_FLAG_NONE},
+ [ENTRY_PRINTERS] = {N_("Printers"), "printer.png", callback_printers, scan_printers, MODULE_FLAG_NONE},
+ [ENTRY_BATTERY] = {N_("Battery"), "battery.png", callback_battery, scan_battery, MODULE_FLAG_NONE},
+ [ENTRY_SENSORS] = {N_("Sensors"), "therm.png", callback_sensors, scan_sensors, MODULE_FLAG_NONE},
+ [ENTRY_INPUT] = {N_("Input Devices"), "inputdevices.png", callback_input, scan_input, MODULE_FLAG_NONE},
+ [ENTRY_STORAGE] = {N_("Storage"), "hdd.png", callback_storage, scan_storage, MODULE_FLAG_NONE},
+#if defined(ARCH_x86) || defined(ARCH_x86_64)
+ [ENTRY_DMI] = {N_("DMI"), "computer.png", callback_dmi, scan_dmi, MODULE_FLAG_NONE},
+ [ENTRY_SPD] = {N_("Memory SPD"), "memory.png", callback_spd, scan_spd, MODULE_FLAG_NONE},
+#endif /* x86 or x86_64 */
+ [ENTRY_RESOURCES] = {N_("Resources"), "resources.png", callback_device_resources, scan_device_resources, MODULE_FLAG_NONE},
+ {NULL}
+};
+
+static GSList *processors = NULL;
+gchar *printer_list = NULL;
+gchar *printer_icons = NULL;
+gchar *pci_list = NULL;
+gchar *input_list = NULL;
+gchar *storage_list = NULL;
+gchar *battery_list = NULL;
+gchar *meminfo = NULL;
+gchar *lginterval = NULL;
+
+#include <vendor.h>
+
+gchar *get_processor_name(void)
+{
+ scan_processors(FALSE);
+
+ Processor *p = (Processor *) processors->data;
+
+ if (g_slist_length(processors) > 1) {
+ return idle_free(g_strdup_printf("%dx %s",
+ g_slist_length(processors),
+ p->model_name));
+ } else {
+ return p->model_name;
+ }
+}
+
+gchar *get_storage_devices(void)
+{
+ scan_storage(FALSE);
+
+ return storage_list;
+}
+
+gchar *get_printers(void)
+{
+ scan_printers(FALSE);
+
+ return printer_list;
+}
+
+gchar *get_input_devices(void)
+{
+ scan_input(FALSE);
+
+ return input_list;
+}
+
+gchar *get_processor_count(void)
+{
+ scan_processors(FALSE);
+
+ return g_strdup_printf("%d", g_slist_length(processors));
+}
+
+gchar *get_processor_frequency(void)
+{
+ Processor *p;
+
+ scan_processors(FALSE);
+
+ p = (Processor *)processors->data;
+ if (p->cpu_mhz == 0.0f) {
+ return g_strdup(N_("Unknown"));
+ } else {
+ return g_strdup_printf("%.0f", p->cpu_mhz);
+ }
+}
+
+gchar *get_pci_device_description(gchar *pci_id)
+{
+ gchar *description;
+
+ if (!_pci_devices) {
+ scan_pci(FALSE);
+ }
+
+ if ((description = g_hash_table_lookup(_pci_devices, pci_id))) {
+ return g_strdup(description);
+ }
+
+ return NULL;
+}
+
+gchar *get_memory_total(void)
+{
+ scan_memory(FALSE);
+ return moreinfo_lookup ("DEV:Total Memory"); //hi_more_info(N_("Total Memory"));
+}
+
+/* information table from: http://elinux.org/RPi_HardwareHistory */
+static struct {
+ char *value, *intro, *model, *pcb, *mem, *mfg;
+} rpi_boardinfo[] = {
+/* Value Introduction Model Name PCB rev. Memory Manufacturer *
+ * Raspberry Pi %s */
+ { "Beta", "Q1 2012", "B (Beta)", "?", "256MB", "(Beta board)" },
+ { "0002", "Q1 2012", "B", "1.0", "256MB", "?" },
+ { "0003", "Q3 2012", "B (ECN0001)", "1.0", "256MB", "(Fuses mod and D14 removed)" },
+ { "0004", "Q3 2012", "B", "2.0", "256MB", "Sony" },
+ { "0005", "Q4 2012", "B", "2.0", "256MB", "Qisda" },
+ { "0006", "Q4 2012", "B", "2.0", "256MB", "Egoman" },
+ { "0007", "Q1 2013", "A", "2.0", "256MB", "Egoman" },
+ { "0008", "Q1 2013", "A", "2.0", "256MB", "Sony" },
+ { "0009", "Q1 2013", "A", "2.0", "256MB", "Qisda" },
+ { "000d", "Q4 2012", "B", "2.0", "512MB", "Egoman" },
+ { "000e", "Q4 2012", "B", "2.0", "512MB", "Sony" },
+ { "000f", "Q4 2012", "B", "2.0", "512MB", "Qisda" },
+ { "0010", "Q3 2014", "B+", "1.0", "512MB", "Sony" },
+ { "0011", "Q2 2014", "Compute Module 1", "1.0", "512MB", "Sony" },
+ { "0012", "Q4 2014", "A+", "1.1", "256MB", "Sony" },
+ { "0013", "Q1 2015", "B+", "1.2", "512MB", "?" },
+ { "0014", "Q2 2014", "Compute Module 1", "1.0", "512MB", "Embest" },
+ { "0015", "?", "A+", "1.1", "256MB/512MB", "Embest" },
+ { "a01040", "Unknown", "2 Model B", "1.0", "1GB", "Sony" },
+ { "a01041", "Q1 2015", "2 Model B", "1.1", "1GB", "Sony" },
+ { "a21041", "Q1 2015", "2 Model B", "1.1", "1GB", "Embest" },
+ { "a22042", "Q3 2016", "2 Model B", "1.2", "1GB", "Embest" }, /* (with BCM2837) */
+ { "900021", "Q3 2016", "A+", "1.1", "512MB", "Sony" },
+ { "900032", "Q2 2016?", "B+", "1.2", "512MB", "Sony" },
+ { "900092", "Q4 2015", "Zero", "1.2", "512MB", "Sony" },
+ { "900093", "Q2 2016", "Zero", "1.3", "512MB", "Sony" },
+ { "920093", "Q4 2016?", "Zero", "1.3", "512MB", "Embest" },
+ { "9000c1", "Q1 2017", "Zero W", "1.1", "512MB", "Sony" },
+ { "a02082", "Q1 2016", "3 Model B", "1.2", "1GB", "Sony" },
+ { "a020a0", "Q1 2017", "Compute Module 3 or CM3 Lite", "1.0", "1GB", "Sony" },
+ { "a22082", "Q1 2016", "3 Model B", "1.2", "1GB", "Embest" },
+ { "a32082", "Q4 2016", "3 Model B", "1.2", "1GB", "Sony Japan" },
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+static gchar *rpi_get_boardname(void) {
+ int i = 0, c = 0;
+ gchar *ret = NULL;
+ gchar *soc = NULL;
+ gchar *revision = NULL;
+ int overvolt = 0;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+ get_str("Revision", revision);
+ get_str("Hardware", soc);
+ }
+ fclose(cpuinfo);
+
+ if (revision == NULL || soc == NULL) {
+ g_free(soc);
+ g_free(revision);
+ return NULL;
+ }
+
+ if (g_str_has_prefix(revision, "1000"))
+ overvolt = 1;
+
+ while (rpi_boardinfo[i].value != NULL) {
+ if (overvolt)
+ /* +4 to ignore the 1000 prefix */
+ c = g_strcmp0(revision+4, rpi_boardinfo[i].value);
+ else
+ c = g_strcmp0(revision, rpi_boardinfo[i].value);
+
+ if (c == 0) {
+ ret = g_strdup_printf("Raspberry Pi %s (%s) pcb-rev:%s soc:%s mem:%s mfg-by:%s%s",
+ rpi_boardinfo[i].model, rpi_boardinfo[i].intro,
+ rpi_boardinfo[i].pcb, soc,
+ rpi_boardinfo[i].mem, rpi_boardinfo[i].mfg,
+ (overvolt) ? " (over-volted)" : "" );
+ break;
+ }
+ i++;
+ }
+ g_free(soc);
+ g_free(revision);
+ return ret;
+}
+
+gchar *get_motherboard(void)
+{
+ char *board_name, *board_vendor;
+#if defined(ARCH_x86) || defined(ARCH_x86_64)
+ scan_dmi(FALSE);
+
+ board_name = moreinfo_lookup("DEV:DMI:Board:Name");
+ board_vendor = moreinfo_lookup("DEV:DMI:Board:Vendor");
+
+ if (board_name && board_vendor && *board_name && *board_vendor)
+ return g_strconcat(board_vendor, " ", board_name, NULL);
+ else if (board_name && *board_name)
+ return g_strconcat(board_name, _(" (vendor unknown)"), NULL);
+ else if (board_vendor && *board_vendor)
+ return g_strconcat(board_vendor, _(" (model unknown)"), NULL);
+#else
+ /* use device tree "model" */
+ if (g_file_get_contents("/proc/device-tree/model", &board_vendor, NULL, NULL)) {
+
+ /* if a raspberry pi, try and get a more detailed name */
+ if (g_str_has_prefix(board_vendor, "Raspberry Pi")) {
+ board_name = rpi_get_boardname();
+ if (board_name != NULL) {
+ g_free(board_vendor);
+ return board_name;
+ }
+ }
+
+ return board_vendor;
+ }
+#endif
+
+ return g_strdup(_("Unknown"));
+}
+
+ShellModuleMethod *hi_exported_methods(void)
+{
+ static ShellModuleMethod m[] = {
+ {"getProcessorCount", get_processor_count},
+ {"getProcessorName", get_processor_name},
+ {"getProcessorFrequency", get_processor_frequency},
+ {"getMemoryTotal", get_memory_total},
+ {"getStorageDevices", get_storage_devices},
+ {"getPrinters", get_printers},
+ {"getInputDevices", get_input_devices},
+ {"getPCIDeviceDescription", get_pci_device_description},
+ {"getMotherboard", get_motherboard},
+ {NULL}
+ };
+
+ return m;
+}
+
+gchar *hi_more_info(gchar * entry)
+{
+ gchar *info = moreinfo_lookup_with_prefix("DEV", entry);
+
+ if (info)
+ return g_strdup(info);
+
+ return g_strdup("?");
+}
+
+gchar *hi_get_field(gchar * field)
+{
+ gchar *info = moreinfo_lookup_with_prefix("DEV", field);
+
+ if (info)
+ return g_strdup(info);
+
+ return g_strdup(field);
+}
+
+#if defined(ARCH_x86) || defined(ARCH_x86_64)
+void scan_dmi(gboolean reload)
+{
+ SCAN_START();
+ __scan_dmi();
+ SCAN_END();
+}
+
+void scan_spd(gboolean reload)
+{
+ SCAN_START();
+ scan_spd_do();
+ SCAN_END();
+}
+#endif
+
+void scan_processors(gboolean reload)
+{
+ SCAN_START();
+ if (!processors)
+ processors = processor_scan();
+ SCAN_END();
+}
+
+void scan_memory(gboolean reload)
+{
+ SCAN_START();
+ scan_memory_do();
+ SCAN_END();
+}
+
+void scan_battery(gboolean reload)
+{
+ SCAN_START();
+ scan_battery_do();
+ SCAN_END();
+}
+
+void scan_pci(gboolean reload)
+{
+ SCAN_START();
+ scan_pci_do();
+ SCAN_END();
+}
+
+void scan_sensors(gboolean reload)
+{
+ SCAN_START();
+ scan_sensors_do();
+ SCAN_END();
+}
+
+void scan_printers(gboolean reload)
+{
+ SCAN_START();
+ scan_printers_do();
+ SCAN_END();
+}
+
+void scan_storage(gboolean reload)
+{
+ SCAN_START();
+ g_free(storage_list);
+ storage_list = g_strdup("");
+
+ __scan_ide_devices();
+ __scan_scsi_devices();
+ SCAN_END();
+}
+
+void scan_input(gboolean reload)
+{
+ SCAN_START();
+ __scan_input_devices();
+ SCAN_END();
+}
+
+void scan_usb(gboolean reload)
+{
+ SCAN_START();
+ __scan_usb();
+ SCAN_END();
+}
+
+gchar *callback_processors()
+{
+ return processor_get_info(processors);
+}
+
+#if defined(ARCH_x86) || defined(ARCH_x86_64)
+gchar *callback_dmi()
+{
+ return g_strdup(dmi_info);
+}
+
+gchar *callback_spd()
+{
+ return g_strdup(spd_info);
+}
+#endif
+
+gchar *callback_memory()
+{
+ return g_strdup_printf("[Memory]\n"
+ "%s\n"
+ "[$ShellParam$]\n"
+ "ViewType=2\n"
+ "LoadGraphSuffix= kB\n"
+ "RescanInterval=2000\n"
+ "%s\n", meminfo, lginterval);
+}
+
+gchar *callback_battery()
+{
+ return g_strdup_printf("%s\n"
+ "[$ShellParam$]\n"
+ "ReloadInterval=4000\n", battery_list);
+}
+
+gchar *callback_pci()
+{
+ return g_strdup_printf("[PCI Devices]\n"
+ "%s"
+ "[$ShellParam$]\n" "ViewType=1\n", pci_list);
+}
+
+gchar *callback_sensors()
+{
+ return g_strdup_printf("[$ShellParam$]\n"
+ "ReloadInterval=5000\n" "%s", sensors);
+}
+
+gchar *callback_printers()
+{
+ return g_strdup_printf("%s\n"
+ "[$ShellParam$]\n"
+ "ViewType=1\n"
+ "ReloadInterval=5000\n"
+ "%s", printer_list, printer_icons);
+}
+
+gchar *callback_storage()
+{
+ return g_strdup_printf("%s\n"
+ "[$ShellParam$]\n"
+ "ReloadInterval=5000\n"
+ "ViewType=1\n%s", storage_list, storage_icons);
+}
+
+gchar *callback_input()
+{
+ return g_strdup_printf("[Input Devices]\n"
+ "%s"
+ "[$ShellParam$]\n"
+ "ViewType=1\n"
+ "ReloadInterval=5000\n%s", input_list,
+ input_icons);
+}
+
+gchar *callback_usb()
+{
+ return g_strdup_printf("%s"
+ "[$ShellParam$]\n"
+ "ViewType=1\n"
+ "ReloadInterval=5000\n", usb_list);
+}
+
+ModuleEntry *hi_module_get_entries(void)
+{
+ return entries;
+}
+
+gchar *hi_module_get_name(void)
+{
+ return g_strdup(_("Devices"));
+}
+
+guchar hi_module_get_weight(void)
+{
+ return 85;
+}
+
+void hi_module_init(void)
+{
+ if (!g_file_test("/usr/share/misc/pci.ids", G_FILE_TEST_EXISTS)) {
+ static SyncEntry se = {
+ .fancy_name = N_("Update PCI ID listing"),
+ .name = "GetPCIIds",
+ .save_to = "pci.ids",
+ .get_data = NULL
+ };
+
+ sync_manager_add_entry(&se);
+ }
+
+#if defined(ARCH_x86) || defined(ARCH_x86_64)
+ {
+ static SyncEntry se = {
+ .fancy_name = N_("Update CPU feature database"),
+ .name = "RecvCPUFlags",
+ .save_to = "cpuflags.conf",
+ .get_data = NULL
+ };
+
+ sync_manager_add_entry(&se);
+ }
+#endif /* defined(ARCH_x86) */
+
+ init_memory_labels();
+ init_cups();
+ sensors_init();
+}
+
+void hi_module_deinit(void)
+{
+ moreinfo_del_with_prefix("DEV");
+ sensors_shutdown();
+ g_hash_table_destroy(memlabels);
+ g_module_close(cups);
+}
+
+ModuleAbout *hi_module_get_about(void)
+{
+ static ModuleAbout ma[] = {
+ {
+ .author = "Leandro A. F. Pereira",
+ .description = N_("Gathers information about hardware devices"),
+ .version = VERSION,
+ .license = "GNU GPL version 2"}
+ };
+
+ return ma;
+}
+
+gchar **hi_module_get_dependencies(void)
+{
+ static gchar *deps[] = { "computer.so", NULL };
+
+ return deps;
+}
+
+const gchar *hi_note_func(gint entry)
+{
+ if (entry == ENTRY_RESOURCES) {
+ if (root_required_for_resources()) {
+ return g_strdup_printf(_("Resource information requires superuser privileges"));
+ }
+ }
+ return NULL;
+}
diff --git a/modules/devices/alpha/processor.c b/modules/devices/alpha/processor.c
new file mode 100644
index 00000000..f55526f7
--- /dev/null
+++ b/modules/devices/alpha/processor.c
@@ -0,0 +1,78 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("cpu model", processor->model_name);
+ get_float("BogoMIPS", processor->bogomips);
+ get_str("platform string", processor->strmodel);
+
+ }
+ g_strfreev(tmp);
+ }
+
+ gchar *tmp = g_strconcat("Alpha ", processor->model_name, NULL);
+ g_free(processor->model_name);
+ processor->model_name = tmp;
+ processor->cpu_mhz = 0.0f;
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "Model=%s\n"
+ "Platform String=%s\n"
+ "BogoMIPS=%.2f"
+ "Byte Order=%s\n",
+ processor->model_name,
+ processor->strmodel,
+ processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ );
+}
diff --git a/modules/devices/arm/arm_data.c b/modules/devices/arm/arm_data.c
new file mode 100644
index 00000000..246cb643
--- /dev/null
+++ b/modules/devices/arm/arm_data.c
@@ -0,0 +1,215 @@
+/*
+ * rpiz - https://github.com/bp0/rpiz
+ * Copyright (C) 2017 Burt P. <pburt0@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "arm_data.h"
+
+/* sources:
+ * https://unix.stackexchange.com/a/43563
+ * git:linux/arch/arm/kernel/setup.c
+ * git:linux/arch/arm64/kernel/cpuinfo.c
+ */
+static struct {
+ char *name, *meaning;
+} tab_flag_meaning[] = {
+ /* arm/hw_cap */
+ { "swp", "SWP instruction (atomic read-modify-write)" },
+ { "half", "Half-word loads and stores" },
+ { "thumb", "Thumb (16-bit instruction set)" },
+ { "26bit", "26-Bit Model (Processor status register folded into program counter)" },
+ { "fastmult", "32x32->64-bit multiplication" },
+ { "fpa", "Floating point accelerator" },
+ { "vfp", "VFP (early SIMD vector floating point instructions)" },
+ { "edsp", "DSP extensions (the 'e' variant of the ARM9 CPUs, and all others above)" },
+ { "java", "Jazelle (Java bytecode accelerator)" },
+ { "iwmmxt", "SIMD instructions similar to Intel MMX" },
+ { "crunch", "MaverickCrunch coprocessor (if kernel support enabled)" },
+ { "thumbee", "ThumbEE" },
+ { "neon", "Advanced SIMD/NEON on AArch32" },
+ { "evtstrm", "kernel event stream using generic architected timer" },
+ { "vfpv3", "VFP version 3" },
+ { "vfpv3d16", "VFP version 3 with 16 D-registers" },
+ { "vfpv4", "VFP version 4 with fast context switching" },
+ { "vfpd32", "VFP with 32 D-registers" },
+ { "tls", "TLS register" },
+ { "idiva", "SDIV and UDIV hardware division in ARM mode" },
+ { "idivt", "SDIV and UDIV hardware division in Thumb mode" },
+ { "lpae", "40-bit Large Physical Address Extension" },
+ /* arm/hw_cap2 */
+ { "pmull", "64x64->128-bit F2m multiplication (arch>8)" },
+ { "aes", "Crypto:AES (arch>8)" },
+ { "sha1", "Crypto:SHA1 (arch>8)" },
+ { "sha2", "Crypto:SHA2 (arch>8)" },
+ { "crc32", "CRC32 checksum instructions (arch>8)" },
+ /* arm64/hw_cap */
+ { "fp", "" },
+ { "asimd", "Advanced SIMD/NEON on AArch64 (arch>8)" },
+ { "atomics", "" },
+ { "fphp", "" },
+ { "asimdhp", "" },
+ { "cpuid", "" },
+ { "asimdrdm", "" },
+ { "jscvt", "" },
+ { "fcma", "" },
+ { "lrcpc", "" },
+
+ { NULL, NULL},
+};
+
+static struct {
+ int code; char *name;
+} tab_arm_implementer[] = {
+ { 0x41, "ARM" },
+ { 0x44, "Intel (formerly DEC) StrongARM" },
+ { 0x4e, "nVidia" },
+ { 0x54, "Texas Instruments" },
+ { 0x56, "Marvell" },
+ { 0x69, "Intel XScale" },
+ { 0, NULL},
+};
+
+static struct {
+ /* source: t = tested, d = official docs, f = web */
+ int code; char *part_desc;
+} tab_arm_arm_part[] = { /* only valid for implementer 0x41 ARM */
+ /*d */ { 0x920, "ARM920" },
+ /*d */ { 0x926, "ARM926" },
+ /*d */ { 0x946, "ARM946" },
+ /*d */ { 0x966, "ARM966" },
+ /*d */ { 0xb02, "ARM11 MPCore" },
+ /*d */ { 0xb36, "ARM1136" },
+ /*d */ { 0xb56, "ARM1156" },
+ /*dt*/ { 0xb76, "ARM1176" },
+ /*dt*/ { 0xc05, "Cortex-A5" },
+ /*d */ { 0xc07, "Cortex-A7 MPCore" },
+ /*dt*/ { 0xc08, "Cortex-A8" },
+ /*dt*/ { 0xc09, "Cortex-A9" },
+ /*d */ { 0xc0e, "Cortex-A17 MPCore" },
+ /*d */ { 0xc0f, "Cortex-A15" },
+ /*d */ { 0xd01, "Cortex-A32" },
+ /*dt*/ { 0xd03, "Cortex-A53" },
+ /*d */ { 0xd04, "Cortex-A35" },
+ /*d */ { 0xd07, "Cortex-A57 MPCore" },
+ /*d */ { 0xd08, "Cortex-A72" },
+ /*d */ { 0xd09, "Cortex-A73" },
+ { 0, NULL},
+};
+
+static char all_flags[1024] = "";
+
+#define APPEND_FLAG(f) strcat(all_flags, f); strcat(all_flags, " ");
+const char *arm_flag_list() {
+ int i = 0, built = 0;
+ built = strlen(all_flags);
+ if (!built) {
+ while(tab_flag_meaning[i].name != NULL) {
+ APPEND_FLAG(tab_flag_meaning[i].name);
+ i++;
+ }
+ }
+ return all_flags;
+}
+
+const char *arm_flag_meaning(const char *flag) {
+ int i = 0;
+ if (flag)
+ while(tab_flag_meaning[i].name != NULL) {
+ if (strcmp(tab_flag_meaning[i].name, flag) == 0)
+ return tab_flag_meaning[i].meaning;
+ i++;
+ }
+ return NULL;
+}
+
+static int code_match(int c0, const char* code1) {
+ int c1;
+ if (code1 == NULL) return 0;
+ c1 = strtol(code1, NULL, 0);
+ return (c0 == c1) ? 1 : 0;
+}
+
+const char *arm_implementer(const char *code) {
+ int i = 0;
+ if (code)
+ while(tab_arm_implementer[i].code) {
+ if (code_match(tab_arm_implementer[i].code, code))
+ return tab_arm_implementer[i].name;
+ i++;
+ }
+ return NULL;
+}
+
+const char *arm_part(const char *imp_code, const char *part_code) {
+ int i = 0;
+ if (imp_code && part_code) {
+ if (code_match(0x41, imp_code)) {
+ /* 0x41=ARM parts */
+ while(tab_arm_arm_part[i].code) {
+ if (code_match(tab_arm_arm_part[i].code, part_code))
+ return tab_arm_arm_part[i].part_desc;
+ i++;
+ }
+ }
+ }
+ return NULL;
+}
+
+char *arm_decoded_name(const char *imp, const char *part, const char *var, const char *rev, const char *arch, const char *model_name) {
+ char *dnbuff;
+ char *imp_name = NULL, *part_desc = NULL;
+ int r = 0, p = 0;
+ dnbuff = malloc(256);
+ if (dnbuff) {
+ memset(dnbuff, 0, 256);
+
+ if (imp && arch && part && rev) {
+ /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0395b/CIHCAGHH.html
+ * variant and revision can be rendered r{variant}p{revision} */
+ r = strtol(var, NULL, 0);
+ p = strtol(rev, NULL, 0);
+ imp_name = (char*) arm_implementer(imp);
+ part_desc = (char*) arm_part(imp, part);
+ if (imp_name || part_desc) {
+ sprintf(dnbuff, "%s %s r%dp%d (arch:%s)",
+ (imp_name) ? imp_name : imp,
+ (part_desc) ? part_desc : part,
+ r, p, arch);
+ } else {
+ /* fallback for now */
+ sprintf(dnbuff, "%s [imp:%s part:%s r%dp%d arch:%s]",
+ model_name,
+ (imp_name) ? imp_name : imp,
+ (part_desc) ? part_desc : part,
+ r, p, arch);
+ }
+ } else {
+ /* prolly not ARM arch at all */
+ if (model_name)
+ sprintf(dnbuff, "%s", model_name);
+ else {
+ free(dnbuff);
+ return NULL;
+ }
+ }
+ }
+ return dnbuff;
+}
diff --git a/modules/devices/arm/arm_data.h b/modules/devices/arm/arm_data.h
new file mode 100644
index 00000000..4d1d4cf9
--- /dev/null
+++ b/modules/devices/arm/arm_data.h
@@ -0,0 +1,38 @@
+/*
+ * rpiz - https://github.com/bp0/rpiz
+ * Copyright (C) 2017 Burt P. <pburt0@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _ARMDATA_H_
+#define _ARMDATA_H_
+
+/* table lookups */
+const char *arm_implementer(const char *code);
+const char *arm_part(const char *imp_code, const char *part_code);
+
+/* cpu_implementer, cpu_part, cpu_variant, cpu_revision, cpu_architecture from /proc/cpuinfo
+ * model_name is returned as a fallback if not enough data is known */
+char *arm_decoded_name(
+ const char *imp, const char *part, const char *var, const char *rev,
+ const char *arch, const char *model_name);
+
+/* cpu flags from /proc/cpuinfo */
+const char *arm_flag_list(void); /* list of all known flags */
+const char *arm_flag_meaning(const char *flag); /* lookup flag meaning */
+
+#endif
diff --git a/modules/devices/arm/processor.c b/modules/devices/arm/processor.c
new file mode 100644
index 00000000..c94f41e5
--- /dev/null
+++ b/modules/devices/arm/processor.c
@@ -0,0 +1,340 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+#include "arm_data.h"
+#include "arm_data.c"
+
+enum {
+ ARM_A32 = 0,
+ ARM_A64 = 1,
+ ARM_A32_ON_A64 = 2,
+};
+
+static const gchar *arm_mode_str[] = {
+ "A32",
+ "A64",
+ "A32 on A64",
+};
+
+GHashTable *cpu_flags = NULL; /* FIXME: when is it freed? */
+
+static void
+populate_cpu_flags_list_internal()
+{
+ int i;
+ gchar **afl, *fm;
+
+ cpu_flags = g_hash_table_new(g_str_hash, g_str_equal);
+ afl = g_strsplit(arm_flag_list(), " ", 0);
+ while(afl[i] != NULL) {
+ fm = (char *)arm_flag_meaning(afl[i]);
+ if (g_strcmp0(afl[i], "") != 0)
+ g_hash_table_insert(cpu_flags, afl[i], (fm) ? fm : "");
+ i++;
+ }
+}
+
+static gint get_cpu_int(const gchar* file, gint cpuid) {
+ gchar *tmp0 = NULL;
+ gchar *tmp1 = NULL;
+ gint ret = 0;
+
+ tmp0 = g_strdup_printf("/sys/devices/system/cpu/cpu%d/%s", cpuid, file);
+ g_file_get_contents(tmp0, &tmp1, NULL, NULL);
+ if (tmp1)
+ ret = atol(tmp1);
+ g_free(tmp0);
+ g_free(tmp1);
+ return ret;
+}
+
+int processor_has_flag(gchar * strflags, gchar * strflag)
+{
+ gchar **flags;
+ gint ret = 0;
+ if (strflags == NULL || strflag == NULL)
+ return 0;
+ flags = g_strsplit(strflags, " ", 0);
+ ret = g_strv_contains((const gchar * const *)flags, strflag);
+ g_strfreev(flags);
+ return ret;
+}
+
+#define PROC_CPUINFO "/proc/cpuinfo"
+
+GSList *
+processor_scan(void)
+{
+ GSList *procs = NULL;
+ Processor *processor = NULL;
+ FILE *cpuinfo;
+ gchar buffer[128];
+ gchar *rep_pname = NULL;
+ gchar *tmpfreq_str = NULL;
+ GSList *pi = NULL;
+
+ cpuinfo = fopen(PROC_CPUINFO, "r");
+ if (!cpuinfo)
+ return NULL;
+
+#define CHECK_FOR(k) (g_str_has_prefix(tmp[0], k))
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+ } else {
+ g_strfreev(tmp);
+ continue;
+ }
+
+ get_str("Processor", rep_pname);
+
+ if ( CHECK_FOR("processor") ) {
+ /* finish previous */
+ if (processor) {
+ procs = g_slist_append(procs, processor);
+ }
+
+ /* start next */
+ processor = g_new0(Processor, 1);
+ processor->id = atol(tmp[1]);
+
+ if (rep_pname)
+ processor->model_name = g_strdup(rep_pname);
+
+ g_strfreev(tmp);
+ continue;
+ }
+
+ if (!processor &&
+ ( CHECK_FOR("model name")
+ || CHECK_FOR("Features")
+ || CHECK_FOR("BogoMIPS") ) ) {
+
+ /* single proc/core may not have "processor : n" */
+ processor = g_new0(Processor, 1);
+ processor->id = 0;
+
+ if (rep_pname)
+ processor->model_name = g_strdup(rep_pname);
+ }
+
+ if (processor) {
+ get_str("model name", processor->model_name);
+ get_str("Features", processor->flags);
+ get_float("BogoMIPS", processor->bogomips);
+
+ get_str("CPU implementer", processor->cpu_implementer);
+ get_str("CPU architecture", processor->cpu_architecture);
+ get_str("CPU variant", processor->cpu_variant);
+ get_str("CPU part", processor->cpu_part);
+ get_str("CPU revision", processor->cpu_revision);
+ }
+ g_strfreev(tmp);
+ }
+
+ if (processor)
+ procs = g_slist_append(procs, processor);
+
+ g_free(rep_pname);
+ fclose(cpuinfo);
+
+ /* re-duplicate missing data for /proc/cpuinfo variant that de-duplicated it */
+#define REDUP(f) if (dproc->f && !processor->f) processor->f = g_strdup(dproc->f);
+ Processor *dproc;
+ GSList *l;
+ l = procs = g_slist_reverse(procs);
+ while (l) {
+ processor = l->data;
+ if (processor->flags) {
+ dproc = processor;
+ } else if (dproc) {
+ REDUP(flags);
+ REDUP(cpu_implementer);
+ REDUP(cpu_architecture);
+ REDUP(cpu_variant);
+ REDUP(cpu_part);
+ REDUP(cpu_revision);
+ }
+ l = g_slist_next(l);
+ }
+ procs = g_slist_reverse(procs);
+
+ /* data not from /proc/cpuinfo */
+ for (pi = procs; pi; pi = pi->next) {
+ processor = (Processor *) pi->data;
+
+ /* strings can't be null or segfault later */
+#define UNKIFNULL(f) if (processor->f == NULL) processor->f = g_strdup("(Unknown)");
+#define EMPIFNULL(f) if (processor->f == NULL) processor->f = g_strdup("");
+ UNKIFNULL(model_name);
+ EMPIFNULL(flags);
+ UNKIFNULL(cpu_implementer);
+ UNKIFNULL(cpu_architecture);
+ UNKIFNULL(cpu_variant);
+ UNKIFNULL(cpu_part);
+ UNKIFNULL(cpu_revision);
+
+ processor->decoded_name = arm_decoded_name(
+ processor->cpu_implementer, processor->cpu_part,
+ processor->cpu_variant, processor->cpu_revision,
+ processor->cpu_architecture, processor->model_name);
+
+ /* freq */
+ processor->cpukhz_cur = get_cpu_int("cpufreq/scaling_cur_freq", processor->id);
+ processor->cpukhz_min = get_cpu_int("cpufreq/scaling_min_freq", processor->id);
+ processor->cpukhz_max = get_cpu_int("cpufreq/scaling_max_freq", processor->id);
+ if (processor->cpukhz_max)
+ processor->cpu_mhz = processor->cpukhz_max / 1000;
+ else
+ processor->cpu_mhz = 0.0f;
+
+ /* mode */
+ processor->mode = ARM_A32;
+ if ( processor_has_flag(processor->flags, "pmull")
+ || processor_has_flag(processor->flags, "crc32") ) {
+#ifdef __aarch64__
+ processor->mode = ARM_A64;
+#else
+ processor->mode = ARM_A32_ON_A64;
+#endif
+ }
+ }
+
+ return procs;
+}
+
+gchar *processor_get_capabilities_from_flags(gchar * strflags)
+{
+ gchar **flags, **old;
+ gchar *tmp = NULL;
+ gint j = 0;
+
+ if (!cpu_flags)
+ populate_cpu_flags_list_internal();
+
+ flags = g_strsplit(strflags, " ", 0);
+ old = flags;
+
+ while (flags[j]) {
+ gchar *meaning = g_hash_table_lookup(cpu_flags, flags[j]);
+
+ if (meaning) {
+ tmp = h_strdup_cprintf("%s=%s\n", tmp, flags[j], meaning);
+ } else {
+ tmp = h_strdup_cprintf("%s=\n", tmp, flags[j]);
+ }
+ j++;
+ }
+ if (tmp == NULL || g_strcmp0(tmp, "") == 0)
+ tmp = g_strdup_printf("%s=%s\n", "empty", _("Empty List"));
+
+ g_strfreev(old);
+ return tmp;
+}
+
+gchar *
+processor_get_detailed_info(Processor *processor)
+{
+ gchar *tmp_flags, *tmp_imp, *tmp_part, *ret;
+ tmp_flags = processor_get_capabilities_from_flags(processor->flags);
+ tmp_imp = (char*)arm_implementer(processor->cpu_implementer);
+ tmp_part = (char *)arm_part(processor->cpu_implementer, processor->cpu_part);
+ ret = g_strdup_printf("[Processor]\n"
+ "Linux Name=%s\n"
+ "Decoded Name=%s\n"
+ "Mode=%s\n"
+ "BogoMips=%.2f\n"
+ "Endianesss="
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ "\n"
+ "[Frequency Scaling]\n"
+ "Minimum=%d kHz\n"
+ "Maximum=%d kHz\n"
+ "Current=%d kHz\n"
+ "[ARM]\n"
+ "Implementer=[%s] %s\n"
+ "Part=[%s] %s\n"
+ "Architecture=%s\n"
+ "Variant=%s\n"
+ "Revision=%s\n"
+ "[Capabilities]\n"
+ "%s"
+ "%s",
+ processor->model_name,
+ processor->decoded_name,
+ arm_mode_str[processor->mode],
+ processor->bogomips,
+ processor->cpukhz_min,
+ processor->cpukhz_max,
+ processor->cpukhz_cur,
+ processor->cpu_implementer, (tmp_imp) ? tmp_imp : "",
+ processor->cpu_part, (tmp_part) ? tmp_part : "",
+ processor->cpu_architecture,
+ processor->cpu_variant,
+ processor->cpu_revision,
+ tmp_flags,
+ "");
+ g_free(tmp_flags);
+ return ret;
+}
+
+gchar *processor_get_info(GSList * processors)
+{
+ Processor *processor;
+
+ if (g_slist_length(processors) > 1) {
+ gchar *ret, *tmp, *hashkey;
+ GSList *l;
+
+ tmp = g_strdup("");
+
+ for (l = processors; l; l = l->next) {
+ processor = (Processor *) l->data;
+
+ tmp = g_strdup_printf(_("%s$CPU%d$%s=%.2fMHz\n"),
+ tmp, processor->id,
+ processor->model_name,
+ processor->cpu_mhz);
+
+ hashkey = g_strdup_printf("CPU%d", processor->id);
+ moreinfo_add_with_prefix("DEV", hashkey,
+ processor_get_detailed_info(processor));
+ g_free(hashkey);
+ }
+
+ ret = g_strdup_printf("[$ShellParam$]\n"
+ "ViewType=1\n"
+ "[Processors]\n"
+ "%s", tmp);
+ g_free(tmp);
+
+ return ret;
+ }
+
+ processor = (Processor *) processors->data;
+ return processor_get_detailed_info(processor);
+}
diff --git a/modules/devices/battery.c b/modules/devices/battery.c
new file mode 100644
index 00000000..cbcebb12
--- /dev/null
+++ b/modules/devices/battery.c
@@ -0,0 +1,388 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 <string.h>
+#include <time.h>
+
+#include "hardinfo.h"
+#include "devices.h"
+
+const struct {
+ gchar *key, *name;
+} ups_fields[] = {
+ { "UPS Status", NULL },
+ { "STATUS", "Status" },
+ { "TIMELEFT", "Time Left" },
+ { "LINEV", "Line Voltage" },
+ { "LOADPCT", "Load Percent" },
+
+ { "UPS Battery Information", NULL },
+ { "BATTV", "Battery Voltage" },
+ { "BCHARGE", "Battery Charge" },
+ { "BATTDATE", "Battery Date" },
+
+ { "UPS Information", NULL },
+ { "APCMODEL", "Model" },
+ { "FIRMWARE", "Firmware Version" },
+ { "SERIALNO", "Serial Number" },
+ { "UPSMODE", "UPS Mode" },
+ { "CABLE", "Cable" },
+ { "UPSNAME", "UPS Name" },
+
+ { "UPS Nominal Values", NULL },
+ { "NOMINV", "Voltage" },
+ { "NOMBATTV", "Battery Voltage" },
+ { "NOMPOWER", "Power" }
+};
+
+
+static void
+__scan_battery_apcupsd(void)
+{
+ GHashTable *ups_data;
+ FILE *apcaccess;
+ char buffer[512], *apcaccess_path;
+ int i;
+
+ apcaccess_path = find_program("apcaccess");
+ if (apcaccess_path && (apcaccess = popen(apcaccess_path, "r"))) {
+ /* first line isn't important */
+ if (fgets(buffer, 512, apcaccess)) {
+ /* allocate the key, value hash table */
+ ups_data = g_hash_table_new(g_str_hash, g_str_equal);
+
+ /* read up all the apcaccess' output, saving it in the key, value hash table */
+ while (fgets(buffer, 512, apcaccess)) {
+ buffer[9] = '\0';
+
+ g_hash_table_insert(ups_data,
+ g_strdup(g_strstrip(buffer)),
+ g_strdup(g_strstrip(buffer + 10)));
+ }
+
+ /* builds the ups info string, respecting the field order as found in ups_fields */
+ for (i = 0; i < G_N_ELEMENTS(ups_fields); i++) {
+ if (!ups_fields[i].name) {
+ /* there's no name: make a group with the key as its name */
+ battery_list = h_strdup_cprintf("[%s]\n", battery_list, ups_fields[i].key);
+ } else {
+ /* there's a name: adds a line */
+ battery_list = h_strdup_cprintf("%s=%s\n", battery_list,
+ ups_fields[i].name,
+ g_hash_table_lookup(ups_data, ups_fields[i].key));
+ }
+ }
+
+ g_hash_table_destroy(ups_data);
+ }
+
+ pclose(apcaccess);
+ }
+
+ g_free(apcaccess_path);
+}
+
+static void
+__scan_battery_acpi(void)
+{
+ gchar *acpi_path;
+
+ gchar *present = NULL;
+ gchar *capacity = NULL;
+ gchar *technology = NULL;
+ gchar *voltage = NULL;
+ gchar *model = NULL, *serial = NULL, *type = NULL;
+ gchar *state = NULL, *rate = NULL;
+ gchar *remaining = NULL;
+ gchar *manufacturer = NULL;
+
+ acpi_path = g_strdup("/proc/acpi/battery");
+ if (g_file_test(acpi_path, G_FILE_TEST_EXISTS)) {
+ GDir *acpi;
+
+ if ((acpi = g_dir_open(acpi_path, 0, NULL))) {
+ const gchar *entry;
+
+ while ((entry = g_dir_read_name(acpi))) {
+ gchar *path = g_strdup_printf("%s/%s/info", acpi_path, entry);
+ FILE *f;
+ gchar buffer[256];
+ gdouble charge_rate = 1.0;
+
+ f = fopen(path, "r");
+ g_free(path);
+
+ if (!f)
+ goto cleanup;
+
+ while (fgets(buffer, 256, f)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ GET_STR("present", present);
+ GET_STR("design capacity", capacity);
+ GET_STR("battery technology", technology);
+ GET_STR("design voltage", voltage);
+ GET_STR("model number", model);
+ GET_STR("serial number", serial);
+ GET_STR("battery type", type);
+ GET_STR("OEM info", manufacturer);
+
+ g_strfreev(tmp);
+ }
+ fclose(f);
+
+ path = g_strdup_printf("%s/%s/state", acpi_path, entry);
+ f = fopen(path, "r");
+ g_free(path);
+
+ if (!f)
+ goto cleanup;
+
+ while (fgets(buffer, 256, f)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ GET_STR("charging state", state);
+ GET_STR("present rate", rate);
+ GET_STR("remaining capacity", remaining);
+
+ g_strfreev(tmp);
+ }
+
+ fclose(f);
+
+ const gchar *url = vendor_get_url(manufacturer);
+ if (url) {
+ char *tmp = g_strdup_printf("%s (%s)", vendor_get_name(manufacturer), url);
+ g_free(manufacturer);
+ manufacturer = tmp;
+ }
+
+ if (g_str_equal(present, "yes")) {
+ if (remaining && capacity)
+ charge_rate = atof(remaining) / atof(capacity);
+ else
+ charge_rate = 0;
+
+ battery_list = h_strdup_cprintf(_("\n[Battery: %s]\n"
+ "State=%s (load: %s)\n"
+ "Capacity=%s / %s (%.2f%%)\n"
+ "Battery Technology=%s (%s)\n"
+ "Manufacturer=%s\n"
+ "Model Number=%s\n"
+ "Serial Number=%s\n"),
+ battery_list,
+ entry,
+ state, rate,
+ remaining, capacity, charge_rate * 100.0,
+ technology, type,
+ manufacturer,
+ model,
+ serial);
+ }
+
+ cleanup:
+ g_free(present);
+ g_free(capacity);
+ g_free(technology);
+ g_free(type);
+ g_free(model);
+ g_free(serial);
+ g_free(state);
+ g_free(remaining);
+ g_free(rate);
+ g_free(manufacturer);
+
+ present = capacity = technology = type = \
+ model = serial = state = remaining = rate = manufacturer = NULL;
+ }
+
+ g_dir_close(acpi);
+ }
+ }
+
+ g_free(acpi_path);
+}
+
+static gchar *
+read_contents(const gchar *base, const gchar *key)
+{
+ gchar *value;
+ gchar *path;
+
+ path = g_strdup_printf("%s/%s", base, key);
+ if (!path)
+ return NULL;
+
+ if (!g_file_get_contents(path, &value, NULL, NULL)) {
+ free(path);
+ return NULL;
+ }
+
+ free(path);
+ return g_strchomp(value);
+}
+
+static void
+__scan_battery_sysfs_add_battery(const gchar *name)
+{
+ gchar *path = g_strdup_printf("/sys/class/power_supply/%s", name);
+ gchar *status, *capacity, *capacity_level, *technology, *manufacturer,
+ *model_name, *serial_number;
+
+ if (!path)
+ return;
+
+ status = read_contents(path, "status");
+ capacity = read_contents(path, "capacity");
+ capacity_level = read_contents(path, "capacity_level");
+ technology = read_contents(path, "technology");
+ manufacturer = read_contents(path, "manufacturer");
+ model_name = read_contents(path, "model_name");
+ serial_number = read_contents(path, "serial_number");
+
+ battery_list = h_strdup_cprintf(_("\n[Battery: %s]\n"
+ "State=%s\n"
+ "Capacity=%s / %s\n"
+ "Battery Technology=%s\n"
+ "Manufacturer=%s\n"
+ "Model Number=%s\n"
+ "Serial Number=%s\n"),
+ battery_list,
+ name,
+ status,
+ capacity, capacity_level,
+ technology,
+ manufacturer,
+ model_name,
+ serial_number);
+
+ free(status);
+ free(capacity);
+ free(capacity_level);
+ free(technology);
+ free(manufacturer);
+ free(model_name);
+ free(serial_number);
+}
+
+static void
+__scan_battery_sysfs(void)
+{
+ GDir *dir;
+ const gchar *entry;
+
+ dir = g_dir_open("/sys/class/power_supply", 0, NULL);
+ if (!dir)
+ return;
+
+ while ((entry = g_dir_read_name(dir))) {
+ if (g_str_has_prefix(entry, "BAT"))
+ __scan_battery_sysfs_add_battery(entry);
+ }
+
+ g_dir_close(dir);
+}
+
+static void
+__scan_battery_apm(void)
+{
+ FILE *procapm;
+ static char *sremaining = NULL, *stotal = NULL;
+ static unsigned int last_time = 0;
+ static int percentage = 0;
+ const char *ac_status[] = { "Battery",
+ "AC Power",
+ "Charging" };
+ int ac_bat;
+ char apm_bios_ver[16], apm_drv_ver[16];
+ char trash[10];
+
+ if ((procapm = fopen("/proc/apm", "r"))) {
+ int old_percentage = percentage;
+
+ (void)fscanf(procapm, "%s %s %s 0x%x %s %s %d%%",
+ apm_drv_ver, apm_bios_ver, trash,
+ &ac_bat, trash, trash, &percentage);
+ fclose(procapm);
+
+ if (last_time == 0) {
+ last_time = time(NULL);
+ sremaining = stotal = NULL;
+ }
+
+ if (old_percentage - percentage > 0) {
+ if (sremaining && stotal) {
+ g_free(sremaining);
+ g_free(stotal);
+ }
+
+ int secs_remaining = (time(NULL) - last_time) * percentage /
+ (old_percentage - percentage);
+ sremaining = seconds_to_string(secs_remaining);
+ stotal = seconds_to_string((secs_remaining * 100) / percentage);
+
+ last_time = time(NULL);
+ }
+ } else {
+ return;
+ }
+
+ if (stotal && sremaining) {
+ battery_list = h_strdup_cprintf(_("\n[Battery (APM)]\n"
+ "Charge=%d%%\n"
+ "Remaining Charge=%s of %s\n"
+ "Using=%s\n"
+ "APM driver version=%s\n"
+ "APM BIOS version=%s\n"),
+ battery_list,
+ percentage,
+ sremaining, stotal,
+ ac_status[ac_bat],
+ apm_drv_ver, apm_bios_ver);
+ } else {
+ battery_list = h_strdup_cprintf(_("\n[Battery (APM)]\n"
+ "Charge=%d%%\n"
+ "Using=%s\n"
+ "APM driver version=%s\n"
+ "APM BIOS version=%s\n"),
+ battery_list,
+ percentage,
+ ac_status[ac_bat],
+ apm_drv_ver, apm_bios_ver);
+
+ }
+}
+
+void
+scan_battery_do(void)
+{
+ g_free(battery_list);
+ battery_list = g_strdup("");
+
+ __scan_battery_sysfs();
+ __scan_battery_acpi();
+ __scan_battery_apm();
+ __scan_battery_apcupsd();
+
+ if (*battery_list == '\0') {
+ g_free(battery_list);
+
+ battery_list = g_strdup(_("[No batteries]\n"
+ "No batteries found on this system=\n"));
+ }
+}
diff --git a/modules/devices/devmemory.c b/modules/devices/devmemory.c
new file mode 100644
index 00000000..7131536c
--- /dev/null
+++ b/modules/devices/devmemory.c
@@ -0,0 +1,108 @@
+/*
+ * 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 <string.h>
+#include "devices.h"
+
+GHashTable *memlabels = NULL;
+
+void scan_memory_do(void)
+{
+ gchar **keys, *tmp;
+ static gint offset = -1;
+ gint i;
+
+ if (offset == -1) {
+ /* gah. linux 2.4 adds three lines of data we don't need in
+ /proc/meminfo */
+ gchar *os_kernel = module_call_method("computer::getOSKernel");
+ if (os_kernel) {
+ offset = strstr(os_kernel, "Linux 2.4") ? 3 : 0;
+ g_free(os_kernel);
+ } else {
+ offset = 0;
+ }
+ }
+
+ g_file_get_contents("/proc/meminfo", &meminfo, NULL, NULL);
+
+ keys = g_strsplit(meminfo, "\n", 0);
+
+ g_free(meminfo);
+ g_free(lginterval);
+
+ meminfo = g_strdup("");
+ lginterval = g_strdup("");
+
+ for (i = offset; keys[i]; i++) {
+ gchar **newkeys = g_strsplit(keys[i], ":", 0);
+
+ if (!newkeys[0]) {
+ g_strfreev(newkeys);
+ break;
+ }
+
+ g_strstrip(newkeys[1]);
+
+ if ((tmp = g_hash_table_lookup(memlabels, newkeys[0]))) {
+ g_free(newkeys[0]);
+ newkeys[0] = g_strdup(tmp);
+ }
+
+ moreinfo_add_with_prefix("DEV", newkeys[0], g_strdup(newkeys[1]));
+
+ tmp = g_strconcat(meminfo, newkeys[0], "=", newkeys[1], "\n", NULL);
+ g_free(meminfo);
+ meminfo = tmp;
+
+ tmp = g_strconcat(lginterval,
+ "UpdateInterval$", newkeys[0], "=1000\n", NULL);
+ g_free(lginterval);
+ lginterval = tmp;
+
+ g_strfreev(newkeys);
+ }
+ g_strfreev(keys);
+}
+
+void init_memory_labels(void)
+{
+ static const struct {
+ char *proc_label;
+ char *real_label;
+ } proc2real[] = {
+ { "MemTotal", N_("Total Memory") },
+ { "MemFree", N_("Free Memory") },
+ { "SwapCached", N_("Cached Swap") },
+ { "HighTotal", N_("High Memory") },
+ { "HighFree", N_("Free High Memory") },
+ { "LowTotal", N_("Low Memory") },
+ { "LowFree", N_("Free Low Memory") },
+ { "SwapTotal", N_("Virtual Memory") },
+ { "SwapFree", N_("Free Virtual Memory") },
+ { NULL },
+ };
+ gint i;
+
+ memlabels = g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (i = 0; proc2real[i].proc_label; i++) {
+ g_hash_table_insert(memlabels, proc2real[i].proc_label,
+ _(proc2real[i].real_label));
+ }
+}
diff --git a/modules/devices/dmi.c b/modules/devices/dmi.c
new file mode 100644
index 00000000..61cea65d
--- /dev/null
+++ b/modules/devices/dmi.c
@@ -0,0 +1,209 @@
+/*
+ * 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
+ */
+/*
+ * DMI support based on patch by Stewart Adam <s.adam@diffingo.com>
+ */
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "devices.h"
+
+typedef struct _DMIInfo DMIInfo;
+
+struct _DMIInfo {
+ const gchar *name;
+ const gchar *file; /* for sysfs */
+ const gchar *param; /* for dmidecode */
+};
+
+DMIInfo dmi_info_table[] = {
+ { "$BIOS", NULL, NULL },
+ { "Date", "/sys/class/dmi/id/bios_date", "bios-release-date" },
+ { "Vendor", "/sys/class/dmi/id/bios_vendor", "bios-vendor" },
+ { "Version", "/sys/class/dmi/id/bios_version", "bios-version" },
+ { "$Board", NULL, NULL },
+ { "Name", "/sys/class/dmi/id/board_name", "baseboard-product-name" },
+ { "Vendor", "/sys/class/dmi/id/board_vendor", "baseboard-manufacturer" },
+};
+
+gchar *dmi_info = NULL;
+
+static void add_to_moreinfo(const char *group, const char *key, char *value)
+{
+ char *new_key = g_strconcat("DMI:", group, ":", key, NULL);
+ moreinfo_add_with_prefix("DEV", new_key, g_strdup(g_strstrip(value)));
+}
+
+gboolean dmi_get_info_dmidecode()
+{
+ FILE *dmi_pipe;
+ gchar buffer[256];
+ const gchar *group;
+ DMIInfo *info;
+ gboolean dmi_failed = FALSE;
+ gint i;
+
+ if (dmi_info) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) {
+ info = &dmi_info_table[i];
+
+ if (*(info->name) == '$') {
+ group = info->name + 1;
+ dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, group);
+ } else {
+ gchar *temp;
+
+ if (!info->param)
+ continue;
+
+ temp = g_strconcat("dmidecode -s ", info->param, NULL);
+ if ((dmi_pipe = popen(temp, "r"))) {
+ g_free(temp);
+
+ (void)fgets(buffer, 256, dmi_pipe);
+ if (pclose(dmi_pipe)) {
+ dmi_failed = TRUE;
+ break;
+ }
+
+ add_to_moreinfo(group, info->name, buffer);
+
+ const gchar *url = vendor_get_url(buffer);
+ if (url) {
+ const gchar *vendor = vendor_get_name(buffer);
+ if (g_strstr_len(vendor, -1, g_strstrip(buffer)) ||
+ g_strstr_len(g_strstrip(buffer), -1, vendor)) {
+ dmi_info = h_strdup_cprintf("%s=%s (%s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ url);
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s (%s, %s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ vendor, url);
+ }
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s\n",
+ dmi_info,
+ info->name,
+ buffer);
+ }
+ } else {
+ g_free(temp);
+ dmi_failed = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (dmi_failed) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ return !dmi_failed;
+}
+
+gboolean dmi_get_info_sys()
+{
+ FILE *dmi_file;
+ gchar buffer[256];
+ const gchar *group = NULL;
+ DMIInfo *info;
+ gboolean dmi_failed = FALSE;
+ gint i;
+
+ if (dmi_info) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) {
+ info = &dmi_info_table[i];
+
+ if (*(info->name) == '$') {
+ group = info->name + 1;
+ dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, group);
+ } else if (group && info->file) {
+ if ((dmi_file = fopen(info->file, "r"))) {
+ (void)fgets(buffer, 256, dmi_file);
+ fclose(dmi_file);
+
+ add_to_moreinfo(group, info->name, buffer);
+
+ const gchar *url = vendor_get_url(buffer);
+ if (url) {
+ const gchar *vendor = vendor_get_name(buffer);
+ if (g_strstr_len(vendor, -1, g_strstrip(buffer)) ||
+ g_strstr_len(g_strstrip(buffer), -1, vendor)) {
+ dmi_info = h_strdup_cprintf("%s=%s (%s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ url);
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s (%s, %s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ vendor, url);
+ }
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer));
+ }
+ } else {
+ dmi_failed = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (dmi_failed) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ return !dmi_failed;
+}
+
+void __scan_dmi()
+{
+ gboolean dmi_ok;
+
+ dmi_ok = dmi_get_info_sys();
+
+ if (!dmi_ok) {
+ dmi_ok = dmi_get_info_dmidecode();
+ }
+
+ if (!dmi_ok) {
+ dmi_info = g_strdup("[No DMI information]\n"
+ "There was an error retrieving the information.=\n"
+ "Please try running HardInfo as root.=\n");
+ }
+}
diff --git a/modules/devices/ia64/processor.c b/modules/devices/ia64/processor.c
new file mode 100644
index 00000000..55e5e3a8
--- /dev/null
+++ b/modules/devices/ia64/processor.c
@@ -0,0 +1,78 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("vendor", processor->model_name);
+ get_str("arch", processor->vendor_id);
+ get_str("family", processor->strmodel);
+ get_float("BogoMIPS", processor->bogomips);
+
+ }
+ g_strfreev(tmp);
+ }
+
+ processor->cpu_mhz = 0.0f;
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "Model=%s\n"
+ "Architecture=%s\n"
+ "Family=%sMHz\n"
+ "BogoMIPS=%s\n"
+ "Byte Order=%s\n",
+ processor->model_name,
+ processor->vendor_id,
+ processor->strmodel,
+ processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ );
+}
diff --git a/modules/devices/inputdevices.c b/modules/devices/inputdevices.c
new file mode 100644
index 00000000..d3f8847f
--- /dev/null
+++ b/modules/devices/inputdevices.c
@@ -0,0 +1,140 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 <string.h>
+
+#include "hardinfo.h"
+#include "devices.h"
+
+gchar *input_icons = NULL;
+
+static struct {
+ char *name;
+ char *icon;
+} input_devices[] = {
+ { "Keyboard", "keyboard.png" },
+ { "Joystick", "joystick.png" },
+ { "Mouse", "mouse.png" },
+ { "Speaker", "audio.png" },
+ { "Unknown", "module.png" },
+};
+
+void
+__scan_input_devices(void)
+{
+ FILE *dev;
+ gchar buffer[1024];
+ gchar *tmp, *name = NULL, *phys = NULL;
+ gint bus = 0, vendor = 0, product = 0, version = 0;
+ int d = 0, n = 0;
+
+ dev = fopen("/proc/bus/input/devices", "r");
+ if (!dev)
+ return;
+
+ if (input_list) {
+ moreinfo_del_with_prefix("DEV:INP");
+ g_free(input_list);
+ g_free(input_icons);
+ }
+ input_list = g_strdup("");
+ input_icons = g_strdup("");
+
+ while (fgets(buffer, sizeof(buffer), dev)) {
+ tmp = buffer;
+
+ switch (*tmp) {
+ case 'N':
+ tmp = strreplacechr(tmp + strlen("N: Name="), "=", ':');
+ name = g_strdup(tmp);
+ remove_quotes(name);
+ break;
+ case 'P':
+ phys = g_strdup(tmp + strlen("P: Phys="));
+ break;
+ case 'I':
+ sscanf(tmp, "I: Bus=%x Vendor=%x Product=%x Version=%x",
+ &bus, &vendor, &product, &version);
+ break;
+ case 'H':
+ if (strstr(tmp, "kbd"))
+ d = 0; //INPUT_KEYBOARD;
+ else if (strstr(tmp, "js"))
+ d = 1; //INPUT_JOYSTICK;
+ else if (strstr(tmp, "mouse"))
+ d = 2; //INPUT_MOUSE;
+ else
+ d = 4; //INPUT_UNKNOWN;
+ break;
+ case '\n':
+ if (name && strstr(name, "PC Speaker")) {
+ d = 3; // INPUT_PCSPKR
+ }
+
+ tmp = g_strdup_printf("INP%d", ++n);
+ input_list = h_strdup_cprintf("$%s$%s=\n",
+ input_list,
+ tmp, name);
+ input_icons = h_strdup_cprintf("Icon$%s$%s=%s\n",
+ input_icons,
+ tmp, name,
+ input_devices[d].icon);
+ gchar *strhash = g_strdup_printf("[Device Information]\n"
+ "Name=%s\n"
+ "Type=%s\n"
+ "Bus=0x%x\n",
+ name,
+ input_devices[d].name,
+ bus);
+
+ const gchar *url = vendor_get_url(name);
+ if (url) {
+ strhash = h_strdup_cprintf("Vendor=%s (%s)\n",
+ strhash,
+ vendor_get_name(name),
+ url);
+ } else {
+ strhash = h_strdup_cprintf("Vendor=%x\n",
+ strhash,
+ vendor);
+ }
+
+ strhash = h_strdup_cprintf("Product=0x%x\n"
+ "Version=0x%x\n",
+ strhash, product, version);
+
+ if (phys && phys[1] != 0) {
+ strhash = h_strdup_cprintf("Connected to=%s\n",
+ strhash, phys);
+ }
+
+ if (phys && strstr(phys, "ir")) {
+ strhash = h_strdup_cprintf("InfraRed port=yes\n",
+ strhash);
+ }
+
+ moreinfo_add_with_prefix("DEV", tmp, strhash);
+ g_free(tmp);
+
+ g_free(phys);
+ g_free(name);
+ }
+ }
+
+ fclose(dev);
+}
diff --git a/modules/devices/m68k/processor.c b/modules/devices/m68k/processor.c
new file mode 100644
index 00000000..d9902428
--- /dev/null
+++ b/modules/devices/m68k/processor.c
@@ -0,0 +1,79 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("CPU", processor->model_name);
+ get_float("Clocking", processor->cpu_mhz);
+ get_float("bogomips", processor->bogomips);
+
+ get_str("FPU", processor->has_fpu);
+ }
+ g_strfreev(tmp);
+ }
+
+ gchar *tmp;
+ tmp = g_strconcat("Motorola ", processor->model_name, NULL);
+ g_free(processor->model_name);
+ processor->model_name = tmp;
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "Name=%s\n"
+ "Frequency=%.2fMHz\n"
+ "BogoMips=%.2f\n"
+ "Byte Order=%s\n",
+ processor->model_name,
+ processor->cpu_mhz,
+ processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ );
+}
diff --git a/modules/devices/mips/processor.c b/modules/devices/mips/processor.c
new file mode 100644
index 00000000..86c9b958
--- /dev/null
+++ b/modules/devices/mips/processor.c
@@ -0,0 +1,75 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("system type", processor->model_name);
+ get_str("cpu model", processor->vendor_id);
+ get_float("cpu MHz", processor->cpu_mhz);
+ get_float("BogoMIPS", processor->bogomips);
+ }
+ g_strfreev(tmp);
+ }
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "System Type=%s\n"
+ "CPU Model=%s\n"
+ "Frequency=%.2fMHz\n"
+ "BogoMIPS=%.2f\n"
+ "Byte Order=%s\n",
+ processor->model_name,
+ processor->vendor_id,
+ processor->cpu_mhz,
+ processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ );
+}
diff --git a/modules/devices/parisc/processor.c b/modules/devices/parisc/processor.c
new file mode 100644
index 00000000..83672126
--- /dev/null
+++ b/modules/devices/parisc/processor.c
@@ -0,0 +1,87 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processors_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("cpu family", processor->model_name);
+ get_str("cpu", processor->vendor_id);
+ get_float("cpu MHz", processor->cpu_mhz);
+ get_float("bogomips", processor->bogomips);
+
+ get_str("model name", processor->strmodel);
+
+ get_int("I-cache", processor->has_fpu);
+ get_int("D-cache", processor->flags);
+
+ }
+ g_strfreev(tmp);
+ }
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "CPU Family=%s\n"
+ "CPU=%s\n"
+ "Frequency=%.2fMHz\n"
+ "Bogomips=%.2f\n"
+ "Model Name=%s\n"
+ "Byte Order=%s\n"
+ "[Cache]\n"
+ "I-Cache=%s\n"
+ "D-Cache=%s\n",
+ processor->model_name,
+ processor->vendor_id,
+ processor->cpu_mhz,
+ processor->bogomips,
+ processor->strmodel,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian",
+#else
+ "Big Endian",
+#endif
+ processor->has_fpu,
+ processor->flags);
+}
diff --git a/modules/devices/pci.c b/modules/devices/pci.c
new file mode 100644
index 00000000..91ff914d
--- /dev/null
+++ b/modules/devices/pci.c
@@ -0,0 +1,247 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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
+ */
+
+/*
+ * TODO: This thing must be rewritten. We really should have a struct with all the
+ * PCI stuff we'll present to the user, and hash them by the PCI ID
+ * (domain:bus:device.function).
+ * This way we'll have ways to better organize the output, instead of relying
+ * on the order the information appears on lspci's output.
+ * Also, the "Resources" thing might be better implemented (and we won't need
+ * copies of information scattered everywhere like we do today).
+ */
+
+#include <string.h>
+
+#include "hardinfo.h"
+#include "devices.h"
+
+GHashTable *_pci_devices = NULL;
+
+void
+scan_pci_do(void)
+{
+ FILE *lspci;
+ gchar buffer[256], *buf, *strhash = NULL, *strdevice = NULL;
+ gchar *category = NULL, *name = NULL, *icon, *lspci_path, *command_line = NULL;
+ gint n = 0, x = 0;
+
+ if ((lspci_path = find_program("lspci")) == NULL) {
+ goto pci_error;
+ } else {
+ command_line = g_strdup_printf("%s -v", lspci_path);
+ }
+
+ if (!_pci_devices) {
+ _pci_devices = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ buf = g_build_filename(g_get_home_dir(), ".hardinfo", "pci.ids", NULL);
+ if (!g_file_test(buf, G_FILE_TEST_EXISTS)) {
+ DEBUG("using system-provided PCI IDs");
+ g_free(buf);
+ if (!(lspci = popen(command_line, "r"))) {
+ goto pci_error;
+ }
+ } else {
+ gchar *tmp;
+
+ tmp = g_strdup_printf("%s -i '%s'", command_line, buf);
+ g_free(buf);
+ buf = tmp;
+
+ DEBUG("using updated PCI IDs (from %s)", buf);
+ if (!(lspci = popen(tmp, "r"))) {
+ g_free(buf);
+ goto pci_error;
+ } else {
+ g_free(buf);
+ }
+ }
+
+ while (fgets(buffer, 256, lspci)) {
+ buf = g_strstrip(buffer);
+
+ if (!strncmp(buf, "Flags", 5)) {
+ gint irq = 0, freq = 0, latency = 0, i;
+ gchar **list;
+ gboolean bus_master;
+
+ buf += 7;
+
+ bus_master = FALSE;
+
+ list = g_strsplit(buf, ", ", 10);
+ for (i = 0; i <= 10; i++) {
+ if (!list[i])
+ break;
+
+ if (!strncmp(list[i], "IRQ", 3))
+ sscanf(list[i], "IRQ %d", &irq);
+ else if (strstr(list[i], "Mhz"))
+ sscanf(list[i], "%dMhz", &freq);
+ else if (!strncmp(list[i], "bus master", 10))
+ bus_master = TRUE;
+ else if (!strncmp(list[i], "latency", 7))
+ sscanf(list[i], "latency %d", &latency);
+ }
+ g_strfreev(list);
+
+ if (irq)
+ strdevice = h_strdup_cprintf("IRQ=%d\n", strdevice, irq);
+ if (freq)
+ strdevice = h_strdup_cprintf("Frequency=%dMHz\n", strdevice, freq);
+ if (latency)
+ strdevice = h_strdup_cprintf("Latency=%d\n", strdevice, latency);
+
+ strdevice = h_strdup_cprintf("Bus Master=%s\n", strdevice, bus_master ? "Yes" : "No");
+ } else if (!strncmp(buf, "Kernel modules", 14)) {
+ WALK_UNTIL(' ');
+ WALK_UNTIL(':');
+ buf++;
+
+ strdevice = h_strdup_cprintf("Kernel modules=%s\n", strdevice, buf);
+ } else if (!strncmp(buf, "Subsystem", 9)) {
+ WALK_UNTIL(' ');
+ buf++;
+ const gchar *oem_vendor_url = vendor_get_url(buf);
+ if (oem_vendor_url)
+ strdevice = h_strdup_cprintf("OEM Vendor=%s (%s)\n",
+ strdevice,
+ vendor_get_name(buf),
+ oem_vendor_url);
+ } else if (!strncmp(buf, "Capabilities", 12)
+ && !strstr(buf, "only to root") &&
+ !strstr(buf, "access denied")) {
+ WALK_UNTIL(' ');
+ WALK_UNTIL(']');
+ buf++;
+ strdevice = h_strdup_cprintf("Capability#%d=%s\n", strdevice, ++x, buf);
+ } else if (!strncmp(buf, "Memory at", 9) && strstr(buf, "[size=")) {
+ gint mem;
+ gchar unit;
+ gboolean prefetch;
+ gboolean _32bit;
+
+ prefetch = strstr(buf, "non-prefetchable") ? FALSE : TRUE;
+ _32bit = strstr(buf, "32-bit") ? TRUE : FALSE;
+
+ WALK_UNTIL('[');
+ sscanf(buf, "[size=%d%c", &mem, &unit);
+
+ strdevice = h_strdup_cprintf("Memory#%d=%d%cB (%s%s)\n",
+ strdevice, ++x,
+ mem,
+ (unit == ']') ? ' ' : unit,
+ _32bit ? "32-bit, " : "",
+ prefetch ? "prefetchable" :
+ "non-prefetchable");
+
+ } else if (!strncmp(buf, "I/O ports at", 12)) {
+ guint io_addr, io_size;
+
+ sscanf(buf, "I/O ports at %x [size=%d]", &io_addr, &io_size);
+
+ strdevice =
+ h_strdup_cprintf("I/O ports at#%d=0x%x - 0x%x\n",
+ strdevice, ++x, io_addr,
+ io_addr + io_size - 1);
+ } else if ((buf[0] >= '0' && buf[0] <= '9') && (buf[4] == ':' || buf[2] == ':')) {
+ gint bus, device, function, domain;
+ gpointer start, end;
+
+ if (strdevice != NULL && strhash != NULL) {
+ moreinfo_add_with_prefix("DEV", strhash, strdevice);
+ g_free(strhash);
+ g_free(category);
+ g_free(name);
+ }
+
+ if (buf[4] == ':') {
+ sscanf(buf, "%x:%x:%x.%d", &domain, &bus, &device, &function);
+ } else {
+ /* lspci without domain field */
+ sscanf(buf, "%x:%x.%x", &bus, &device, &function);
+ domain = 0;
+ }
+
+ WALK_UNTIL(' ');
+
+ start = buf;
+
+ WALK_UNTIL(':');
+ end = buf + 1;
+ *buf = 0;
+
+ buf = start + 1;
+ category = g_strdup(buf);
+
+ buf = end;
+
+ if (strstr(category, "RAM memory")) icon = "mem";
+ else if (strstr(category, "Multimedia")) icon = "media";
+ else if (strstr(category, "USB")) icon = "usb";
+ else icon = "pci";
+
+ name = g_strdup(buf);
+ g_hash_table_insert(_pci_devices,
+ g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),
+ name);
+
+ strhash = g_strdup_printf("PCI%d", n);
+ strdevice = g_strdup_printf("[Device Information]\n"
+ "Name=%s\n"
+ "Class=%s\n"
+ "Domain=%d\n"
+ "Bus, device, function=%d, %d, %d\n",
+ name, category, domain, bus,
+ device, function);
+
+ const gchar *url = vendor_get_url(name);
+ if (url) {
+ strdevice = h_strdup_cprintf("Vendor=%s (%s)\n",
+ strdevice,
+ vendor_get_name(name),
+ url);
+ }
+
+ g_hash_table_insert(_pci_devices,
+ g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),
+ g_strdup(name));
+
+ pci_list = h_strdup_cprintf("$PCI%d$%s=%s\n", pci_list, n, category, name);
+
+ n++;
+ }
+ }
+
+ if (pclose(lspci)) {
+pci_error:
+ /* error (no pci, perhaps?) */
+ pci_list = g_strconcat(pci_list, "No PCI devices found=\n", NULL);
+ } else if (strhash) {
+ /* insert the last device */
+ moreinfo_add_with_prefix("DEV", strhash, strdevice);
+ g_free(strhash);
+ g_free(category);
+ g_free(name);
+ }
+
+ g_free(lspci_path);
+ g_free(command_line);
+}
diff --git a/modules/devices/ppc/processor.c b/modules/devices/ppc/processor.c
new file mode 100644
index 00000000..a7988f97
--- /dev/null
+++ b/modules/devices/ppc/processor.c
@@ -0,0 +1,85 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("cpu", processor->model_name);
+ get_str("machine", processor->vendor_id);
+ get_int("L2 cache", processor->cache_size);
+ get_float("clock", processor->cpu_mhz);
+ get_float("bogomips", processor->bogomips);
+
+ }
+ g_strfreev(tmp);
+ }
+
+ gchar *tmp = g_strdup_printf("PowerPC %s (%.2fMHz)",
+ processor->model_name,
+ processor->cpu_mhz);
+ g_free(processor->model_name);
+ processor->model_name = tmp;
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "Machine=%s\n"
+ "CPU=%s\n"
+ "L2 Cache=%dkB\n"
+ "Frequency=%.2fMHz\n"
+ "BogoMips=%.2f\n"
+ "Byte Order=%s\n",
+ processor->vendor_id,
+ processor->model_name,
+ processor->cache_size,
+ processor->cpu_mhz,
+ processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ );
+}
diff --git a/modules/devices/printers.c b/modules/devices/printers.c
new file mode 100644
index 00000000..77b52a43
--- /dev/null
+++ b/modules/devices/printers.c
@@ -0,0 +1,266 @@
+/*
+ * 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 <stdlib.h>
+#include <time.h>
+
+#include "devices.h"
+
+typedef struct _CUPSDest CUPSDest;
+typedef struct _CUPSOption CUPSOption;
+
+struct _CUPSOption {
+ char *name, *value;
+};
+
+struct _CUPSDest {
+ char *name, *instance;
+ int is_default;
+ int num_options;
+ CUPSOption *options;
+};
+
+static int (*cups_dests_get) (CUPSDest **dests) = NULL;
+static int (*cups_dests_free) (int num_dests, CUPSDest *dests) = NULL;
+static gboolean cups_init = FALSE;
+
+GModule *cups;
+
+void
+init_cups(void)
+{
+ const char *libcups[] = { "libcups", "libcups.so", "libcups.so.1", "libcups.so.2", NULL };
+
+ if (!(cups_dests_get && cups_dests_free)) {
+ int i;
+
+ for (i = 0; libcups[i] != NULL; i++) {
+ cups = g_module_open(libcups[i], G_MODULE_BIND_LAZY);
+ if (cups)
+ break;
+ }
+
+ if (!cups) {
+ cups_init = FALSE;
+ return;
+ }
+
+ if (!g_module_symbol(cups, "cupsGetDests", (gpointer) & cups_dests_get)
+ || !g_module_symbol(cups, "cupsFreeDests", (gpointer) & cups_dests_free)) {
+ g_module_close(cups);
+ cups_init = FALSE;
+ }
+ }
+
+ cups_init = TRUE;
+}
+
+gchar *__cups_callback_ptype(gchar *strvalue)
+{
+ if (strvalue) {
+ unsigned value = atoi(strvalue);
+ gchar *output = g_strdup("\n");
+
+ if (value & 0x0004)
+ output = h_strdup_cprintf(_("\342\232\254 Can do black and white printing=\n"), output);
+ if (value & 0x0008)
+ output = h_strdup_cprintf(_("\342\232\254 Can do color printing=\n"), output);
+ if (value & 0x0010)
+ output = h_strdup_cprintf(_("\342\232\254 Can do duplexing=\n"), output);
+ if (value & 0x0020)
+ output = h_strdup_cprintf(_("\342\232\254 Can do staple output=\n"), output);
+ if (value & 0x0040)
+ output = h_strdup_cprintf(_("\342\232\254 Can do copies=\n"), output);
+ if (value & 0x0080)
+ output = h_strdup_cprintf(_("\342\232\254 Can collate copies=\n"), output);
+ if (value & 0x80000)
+ output = h_strdup_cprintf(_("\342\232\254 Printer is rejecting jobs=\n"), output);
+ if (value & 0x1000000)
+ output = h_strdup_cprintf(_("\342\232\254 Printer was automatically discovered and added=\n"), output);
+
+ return output;
+ } else {
+ return g_strdup(_("Unknown"));
+ }
+}
+
+gchar *__cups_callback_state(gchar *value)
+{
+ if (!value) {
+ return g_strdup(_("Unknown"));
+ }
+
+ if (g_str_equal(value, "3")) {
+ return g_strdup(_("Idle"));
+ } else if (g_str_equal(value, "4")) {
+ return g_strdup(_("Printing a Job"));
+ } else if (g_str_equal(value, "5")) {
+ return g_strdup(_("Stopped"));
+ } else {
+ return g_strdup(_("Unknown"));
+ }
+}
+
+gchar *__cups_callback_state_change_time(gchar *value)
+{
+ struct tm tm;
+ char buf[255];
+
+ if (value) {
+ strptime(value, "%s", &tm);
+ strftime(buf, sizeof(buf), "%c", &tm);
+
+ return g_strdup(buf);
+ } else {
+ return g_strdup(_("Unknown"));
+ }
+}
+
+gchar *__cups_callback_boolean(gchar *value)
+{
+ if (value) {
+ return g_strdup(g_str_equal(value, "1") ? _("Yes") : _("No"));
+ } else {
+ return g_strdup(_("Unknown"));
+ }
+}
+
+const struct {
+ char *key, *name;
+ gchar *(*callback)(gchar *value);
+} cups_fields[] = {
+ { "Printer Information", NULL, NULL },
+ { "printer-info", "Destination Name", NULL },
+ { "printer-make-and-model", "Make and Model", NULL },
+
+ { "Capabilities", NULL, NULL },
+ { "printer-type", "#", __cups_callback_ptype },
+
+ { "Printer State", NULL, NULL },
+ { "printer-state", "State", __cups_callback_state },
+ { "printer-state-change-time", "Change Time", __cups_callback_state_change_time },
+ { "printer-state-reasons", "State Reasons" },
+
+ { "Sharing Information", NULL, NULL },
+ { "printer-is-shared", "Shared?", __cups_callback_boolean },
+ { "printer-location", "Physical Location" },
+ { "auth-info-required", "Authentication Required", __cups_callback_boolean },
+
+ { "Jobs", NULL, NULL },
+ { "job-hold-until", "Hold Until", NULL },
+ { "job-priority", "Priority", NULL },
+ { "printer-is-accepting-jobs", "Accepting Jobs", __cups_callback_boolean },
+
+ { "Media", NULL, NULL },
+ { "media", "Media", NULL },
+ { "finishings", "Finishings", NULL },
+ { "copies", "Copies", NULL },
+};
+
+void
+scan_printers_do(void)
+{
+ int num_dests, i, j;
+ CUPSDest *dests;
+ gchar *prn_id, *prn_moreinfo;
+
+ g_free(printer_list);
+ g_free(printer_icons);
+
+ if (!cups_init) {
+ init_cups();
+
+ printer_icons = g_strdup("");
+ printer_list = g_strdup(_("[Printers]\n"
+ "No suitable CUPS library found="));
+ return;
+ }
+
+ /* remove old devices from global device table */
+ moreinfo_del_with_prefix("DEV:PRN");
+
+ num_dests = cups_dests_get(&dests);
+ if (num_dests > 0) {
+ printer_list = g_strdup_printf(_("[Printers (CUPS)]\n"));
+ printer_icons = g_strdup("");
+ for (i = 0; i < num_dests; i++) {
+ GHashTable *options;
+
+ options = g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (j = 0; j < dests[i].num_options; j++) {
+ g_hash_table_insert(options,
+ g_strdup(dests[i].options[j].name),
+ g_strdup(dests[i].options[j].value));
+ }
+
+ prn_id = g_strdup_printf("PRN%d", i);
+
+ printer_list = h_strdup_cprintf("\n$%s$%s=%s\n",
+ printer_list,
+ prn_id,
+ dests[i].name,
+ dests[i].is_default ? "<i>Default</i>" : "");
+ printer_icons = h_strdup_cprintf("\nIcon$%s$%s=printer.png",
+ printer_icons,
+ prn_id,
+ dests[i].name);
+
+ prn_moreinfo = g_strdup("");
+ for (j = 0; j < G_N_ELEMENTS(cups_fields); j++) {
+ if (!cups_fields[j].name) {
+ prn_moreinfo = h_strdup_cprintf("[%s]\n",
+ prn_moreinfo,
+ cups_fields[j].key);
+ } else {
+ gchar *temp;
+
+ temp = g_hash_table_lookup(options, cups_fields[j].key);
+
+ if (cups_fields[j].callback) {
+ temp = cups_fields[j].callback(temp);
+ } else {
+ if (temp) {
+ /* FIXME Do proper escaping */
+ temp = g_strdup(strreplacechr(temp, "&=", ' '));
+ } else {
+ temp = g_strdup(_("Unknown"));
+ }
+ }
+
+ prn_moreinfo = h_strdup_cprintf("%s=%s\n",
+ prn_moreinfo,
+ cups_fields[j].name,
+ temp);
+
+ g_free(temp);
+ }
+ }
+
+ moreinfo_add_with_prefix("DEV", prn_id, prn_moreinfo);
+ g_free(prn_id);
+ g_hash_table_destroy(options);
+ }
+
+ cups_dests_free(num_dests, dests);
+ } else {
+ printer_list = g_strdup(_("[Printers]\n"
+ "No printers found=\n"));
+ }
+}
diff --git a/modules/devices/resources.c b/modules/devices/resources.c
new file mode 100644
index 00000000..15cb8f21
--- /dev/null
+++ b/modules/devices/resources.c
@@ -0,0 +1,119 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 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 <string.h>
+
+#include "devices.h"
+
+static gchar *_resources = NULL;
+static gboolean _require_root = FALSE;
+
+#if GLIB_CHECK_VERSION(2,14,0)
+static GRegex *_regex_pci = NULL,
+ *_regex_module = NULL;
+
+static gchar *_resource_obtain_name(gchar *name)
+{
+ gchar *temp;
+
+ if (!_regex_pci && !_regex_module) {
+ _regex_pci = g_regex_new("^[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:"
+ "[0-9a-fA-F]{2}\\.[0-9a-fA-F]{1}$",
+ 0, 0, NULL);
+ _regex_module = g_regex_new("^[0-9a-zA-Z\\_\\-]+$", 0, 0, NULL);
+ }
+
+ name = g_strstrip(name);
+
+ if (g_regex_match(_regex_pci, name, 0, NULL)) {
+ temp = module_call_method_param("devices::getPCIDeviceDescription", name);
+ if (temp) {
+ return g_strdup_printf("<b><small>PCI</small></b> %s", (gchar *)idle_free(temp));
+ }
+ } else if (g_regex_match(_regex_module, name, 0, NULL)) {
+ temp = module_call_method_param("computer::getKernelModuleDescription", name);
+ if (temp) {
+ return g_strdup_printf("<b><small>Module</small></b> %s", (gchar *)idle_free(temp));
+ }
+ }
+
+ return g_strdup(name);
+}
+#else
+static gchar *_resource_obtain_name(gchar *name)
+{
+ return g_strdup(name);
+}
+#endif
+
+void scan_device_resources(gboolean reload)
+{
+ SCAN_START();
+ FILE *io;
+ gchar buffer[256];
+ gint i;
+ gint zero_to_zero_addr = 0;
+
+ struct {
+ gchar *file;
+ gchar *description;
+ } resources[] = {
+ { "/proc/ioports", "[I/O Ports]\n" },
+ { "/proc/iomem", "[Memory]\n" },
+ { "/proc/dma", "[DMA]\n" }
+ };
+
+ g_free(_resources);
+ _resources = g_strdup("");
+
+ for (i = 0; i < G_N_ELEMENTS(resources); i++) {
+ if ((io = fopen(resources[i].file, "r"))) {
+ _resources = h_strconcat(_resources, resources[i].description, NULL);
+
+ while (fgets(buffer, 256, io)) {
+ gchar **temp = g_strsplit(buffer, ":", 2);
+ gchar *name = _resource_obtain_name(temp[1]);
+
+ if (strstr(temp[0], "0000-0000"))
+ zero_to_zero_addr++;
+
+ _resources = h_strdup_cprintf("<tt>%s</tt>=%s\n", _resources,
+ temp[0], name);
+
+ g_strfreev(temp);
+ g_free(name);
+ }
+
+ fclose(io);
+ }
+ }
+
+ _require_root = zero_to_zero_addr > 16;
+
+ SCAN_END();
+}
+
+gchar *callback_device_resources(void)
+{
+ return g_strdup(_resources);
+}
+
+gboolean root_required_for_resources(void)
+{
+ return _require_root;
+}
diff --git a/modules/devices/s390/processor.c b/modules/devices/s390/processor.c
new file mode 100644
index 00000000..99f1c8bd
--- /dev/null
+++ b/modules/devices/s390/processor.c
@@ -0,0 +1,78 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("vendor_id", processor->vendor_id);
+ get_float("# processors", processor->cache_size);
+ get_int("bogomips per cpu", processor->bogomips);
+
+ }
+ g_strfreev(tmp);
+ }
+
+ processor->cpu_mhz = 0.0f;
+
+ processor->model_name = g_strconcat("S390 ", processor->vendor_id, NULL);
+ g_free(processor->vendor_id);
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "Model=%s\n"
+ "Processors=%d\n"
+ "BogoMips per CPU=%.2f"
+ "Byte Order=%s\n",
+ processor->model_name,
+ processor->cache_size,
+ processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ );
+}
diff --git a/modules/devices/sensors.c b/modules/devices/sensors.c
new file mode 100644
index 00000000..84e89361
--- /dev/null
+++ b/modules/devices/sensors.c
@@ -0,0 +1,444 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 <string.h>
+
+#include "devices.h"
+#include "expr.h"
+#include "hardinfo.h"
+#include "socket.h"
+
+gchar *sensors = NULL;
+GHashTable *sensor_compute = NULL;
+GHashTable *sensor_labels = NULL;
+
+static void read_sensor_labels(gchar * driver)
+{
+ FILE *conf;
+ gchar buf[256], *line, *p;
+ gboolean lock = FALSE;
+ gint i;
+
+ /* Try to open lm-sensors config file sensors3.conf */
+ conf = fopen("/etc/sensors3.conf", "r");
+
+ /* If it fails, try to open sensors.conf */
+ if (!conf) conf = fopen("/etc/sensors.conf", "r");
+
+ if (!conf) {
+ /* Cannot open config file. */
+ return;
+ }
+
+ while (fgets(buf, 256, conf)) {
+ line = buf;
+
+ remove_linefeed(line);
+ strend(line, '#');
+
+ if (*line == '\0') {
+ continue;
+ } else if (lock && strstr(line, "label")) { /* label lines */
+ gchar **names = g_strsplit(strstr(line, "label") + 5, " ", 0);
+ gchar *name = NULL, *value = NULL;
+
+ for (i = 0; names[i]; i++) {
+ if (names[i][0] == '\0')
+ continue;
+
+ if (!name)
+ name = g_strdup(names[i]);
+ else if (!value)
+ value = g_strdup(names[i]);
+ else
+ value = g_strconcat(value, " ", names[i], NULL);
+ }
+
+ remove_quotes(value);
+ g_hash_table_insert(sensor_labels, name, value);
+
+ g_strfreev(names);
+ } else if (lock && strstr(line, "ignore")) { /* ignore lines */
+ p = strstr(line, "ignore") + 6;
+ if (!strchr(p, ' '))
+ continue;
+
+ while (*p == ' ')
+ p++;
+ g_hash_table_insert(sensor_labels, g_strdup(p), "ignore");
+ } else if (lock && strstr(line, "compute")) { /* compute lines */
+ gchar **formulas =
+ g_strsplit(strstr(line, "compute") + 7, " ", 0);
+ gchar *name = NULL, *formula = NULL;
+
+ for (i = 0; formulas[i]; i++) {
+ if (formulas[i][0] == '\0')
+ continue;
+ if (formulas[i][0] == ',')
+ break;
+
+ if (!name)
+ name = g_strdup(formulas[i]);
+ else if (!formula)
+ formula = g_strdup(formulas[i]);
+ else
+ formula = g_strconcat(formula, formulas[i], NULL);
+ }
+
+ g_strfreev(formulas);
+ g_hash_table_insert(sensor_compute, name,
+ math_string_to_postfix(formula));
+ } else if (g_str_has_prefix(line, "chip")) { /* chip lines (delimiter) */
+ if (lock == FALSE) {
+ gchar **chips = g_strsplit(line, " ", 0);
+
+ for (i = 1; chips[i]; i++) {
+ strend(chips[i], '*');
+
+ if (g_str_has_prefix(chips[i] + 1, driver)) {
+ lock = TRUE;
+ break;
+ }
+ }
+
+ g_strfreev(chips);
+ } else {
+ break;
+ }
+ }
+ }
+
+ fclose(conf);
+}
+
+static gchar *get_sensor_label(gchar * sensor)
+{
+ gchar *ret;
+
+ ret = g_hash_table_lookup(sensor_labels, sensor);
+ if (!ret)
+ ret = g_strdup(sensor);
+ else
+ ret = g_strdup(ret);
+
+ return ret;
+}
+
+static float adjust_sensor(gchar * name, float value)
+{
+ GSList *postfix;
+
+ postfix = g_hash_table_lookup(sensor_compute, name);
+ if (!postfix)
+ return value;
+
+ return math_postfix_eval(postfix, value);
+}
+
+static char *get_sensor_path(int number, const char *prefix)
+{
+ return g_strdup_printf("/sys/class/hwmon/hwmon%d/%s", number, prefix);
+}
+
+static char *determine_driver_for_hwmon_path(char *path)
+{
+ char *tmp, *driver;
+
+ tmp = g_strdup_printf("%s/device/driver", path);
+ driver = g_file_read_link(tmp, NULL);
+ g_free(tmp);
+
+ if (driver) {
+ tmp = g_path_get_basename(driver);
+ g_free(driver);
+ driver = tmp;
+ } else {
+ tmp = g_strdup_printf("%s/device", path);
+ driver = g_file_read_link(tmp, NULL);
+ g_free(tmp);
+ }
+
+ if (!driver) {
+ tmp = g_strdup_printf("%s/name", path);
+ if (!g_file_get_contents(tmp, &driver, NULL, NULL)) {
+ driver = g_strdup("unknown");
+ } else {
+ driver = g_strstrip(driver);
+ }
+ g_free(tmp);
+ }
+
+ return driver;
+}
+
+struct HwmonSensor {
+ const char *friendly_name;
+ const char *path_format;
+ const char *key_format;
+ const char *value_format;
+ const float adjust_ratio;
+ const int begin_at;
+};
+
+static const struct HwmonSensor hwmon_sensors[] = {
+ { "Cooling Fans", "%s/fan%d_input", "fan%d", "%s (%s)=%.0fRPM\n", 1.0, 1 },
+ { "Temperature", "%s/temp%d_input", "temp%d", "%s (%s)=%.2f\302\260C\n", 1000.0, 1 },
+ { "Voltage Values", "%s/in%d_input", "in%d", "%s (%s)=%.3fV\n", 1000.0, 0 },
+ { NULL, NULL, NULL, NULL, 0.0, 0 },
+};
+
+static const char *hwmon_prefix[] = { "device", "", NULL };
+
+static void read_sensors_hwmon(void)
+{
+ int hwmon, count;
+ gchar *path_hwmon, *path_sensor, *tmp, *driver, *name, *mon;
+ const char **prefix;
+
+ for (prefix = hwmon_prefix; *prefix; prefix++) {
+ hwmon = 0;
+ path_hwmon = get_sensor_path(hwmon, *prefix);
+ while (path_hwmon && g_file_test(path_hwmon, G_FILE_TEST_EXISTS)) {
+ const struct HwmonSensor *sensor;
+
+ driver = determine_driver_for_hwmon_path(path_hwmon);
+ DEBUG("hwmon%d has driver=%s", hwmon, driver);
+
+ if (!sensor_labels) {
+ read_sensor_labels(driver);
+ }
+
+ for (sensor = hwmon_sensors; sensor->friendly_name; sensor++) {
+ char *output = NULL;
+ DEBUG("current sensor type=%s", sensor->friendly_name);
+
+ for (count = sensor->begin_at;; count++) {
+ path_sensor = g_strdup_printf(sensor->path_format, path_hwmon, count);
+ DEBUG("should be reading from %s", path_sensor);
+ if (!g_file_get_contents(path_sensor, &tmp, NULL, NULL)) {
+ g_free(path_sensor);
+ if (count<256)
+ continue; // brute-force find all
+ else
+ break;
+ }
+
+ mon = g_strdup_printf(sensor->key_format, count);
+ name = get_sensor_label(mon);
+ if (!g_str_equal(name, "ignore")) {
+ output = h_strdup_cprintf(sensor->value_format,
+ output, name, driver,
+ adjust_sensor(mon,
+ atof(tmp) / sensor->adjust_ratio));
+ }
+
+ g_free(tmp);
+ g_free(mon);
+ g_free(name);
+ g_free(path_sensor);
+ }
+
+ if (output) {
+ sensors = g_strconcat(sensors, "[", sensor->friendly_name, "]\n", output, "\n", NULL);
+ g_free(output);
+ }
+ }
+
+ g_free(path_hwmon);
+ g_free(driver);
+
+ path_hwmon = get_sensor_path(++hwmon, *prefix);
+ }
+
+ g_free(path_hwmon);
+ }
+}
+
+static void read_sensors_acpi(void)
+{
+ const gchar *path_tz = "/proc/acpi/thermal_zone";
+
+ if (g_file_test(path_tz, G_FILE_TEST_EXISTS)) {
+ GDir *tz;
+
+ if ((tz = g_dir_open(path_tz, 0, NULL))) {
+ const gchar *entry;
+ gchar *temp = g_strdup("");
+
+ while ((entry = g_dir_read_name(tz))) {
+ gchar *path =
+ g_strdup_printf("%s/%s/temperature", path_tz, entry);
+ gchar *contents;
+
+ if (g_file_get_contents(path, &contents, NULL, NULL)) {
+ int temperature;
+
+ sscanf(contents, "temperature: %d C", &temperature);
+
+ temp = h_strdup_cprintf("\n%s=%d\302\260C\n",
+ temp, entry, temperature);
+
+ g_free(contents);
+ }
+ }
+
+ if (*temp != '\0')
+ sensors =
+ h_strdup_cprintf("\n[ACPI Thermal Zone]\n%s",
+ sensors, temp);
+
+ g_dir_close(tz);
+ }
+ }
+
+}
+
+static void read_sensors_sys_thermal(void)
+{
+ const gchar *path_tz = "/sys/class/thermal";
+
+ if (g_file_test(path_tz, G_FILE_TEST_EXISTS)) {
+ GDir *tz;
+
+ if ((tz = g_dir_open(path_tz, 0, NULL))) {
+ const gchar *entry;
+ gchar *temp = g_strdup("");
+
+ while ((entry = g_dir_read_name(tz))) {
+ gchar *path =
+ g_strdup_printf("%s/%s/temp", path_tz, entry);
+ gchar *contents;
+
+ if (g_file_get_contents(path, &contents, NULL, NULL)) {
+ int temperature;
+
+ sscanf(contents, "%d", &temperature);
+
+ temp = h_strdup_cprintf("\n%s=%.2f\302\260C\n",
+ temp, entry, (1.0*temperature/1000));
+
+ g_free(contents);
+ }
+ }
+
+ if (*temp != '\0')
+ sensors =
+ h_strdup_cprintf("\n[ACPI Thermal Zone (sysfs)]\n%s",
+ sensors, temp);
+
+ g_dir_close(tz);
+ }
+ }
+
+}
+
+static void read_sensors_omnibook(void)
+{
+ const gchar *path_ob = "/proc/omnibook/temperature";
+ gchar *contents;
+
+ if (g_file_get_contents(path_ob, &contents, NULL, NULL)) {
+ int temperature;
+
+ sscanf(contents, "CPU temperature: %d C", &temperature);
+
+ sensors = h_strdup_cprintf("\n[Omnibook]\n"
+ "CPU temperature=%d\302\260C\n",
+ sensors, temperature);
+
+ g_free(contents);
+ }
+}
+
+static void read_sensors_hddtemp(void)
+{
+ Socket *s;
+ static gchar *old = NULL;
+ gchar buffer[1024];
+ gint len = 0;
+
+ if ((s = sock_connect("127.0.0.1", 7634))) {
+ while (!len)
+ len = sock_read(s, buffer, sizeof(buffer));
+ sock_close(s);
+
+ if (len > 2 && buffer[0] == '|' && buffer[1] == '/') {
+ gchar **disks;
+ int i;
+
+ g_free(old);
+
+ old = g_strdup("[Hard Disk Temperature]\n");
+
+ disks = g_strsplit(buffer, "\n", 0);
+ for (i = 0; disks[i]; i++) {
+ gchar **fields = g_strsplit(disks[i] + 1, "|", 5);
+
+ /*
+ * 0 -> /dev/hda
+ * 1 -> FUJITSU MHV2080AH
+ * 2 -> 41
+ * 3 -> C
+ */
+ old = h_strdup_cprintf("\n%s (%s)=%s\302\260%s\n",
+ old,
+ fields[1], fields[0],
+ fields[2], fields[3]);
+
+ g_strfreev(fields);
+ }
+
+ g_strfreev(disks);
+ }
+ } else {
+ g_free(old);
+ old = NULL;
+ }
+
+ if (old) {
+ sensors = g_strconcat(sensors, "\n", old, NULL);
+ }
+}
+
+void scan_sensors_do(void)
+{
+ g_free(sensors);
+
+ sensors = g_strdup("");
+
+ read_sensors_hwmon();
+ read_sensors_acpi();
+ read_sensors_sys_thermal();
+ read_sensors_omnibook();
+ read_sensors_hddtemp();
+
+ /* FIXME: Add support for ibm acpi and more sensors */
+}
+
+void sensors_init(void)
+{
+ sensor_labels = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+ sensor_compute = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+void sensors_shutdown(void)
+{
+ g_hash_table_destroy(sensor_labels);
+ g_hash_table_destroy(sensor_compute);
+}
diff --git a/modules/devices/sh/processor.c b/modules/devices/sh/processor.c
new file mode 100644
index 00000000..cbd9a60a
--- /dev/null
+++ b/modules/devices/sh/processor.c
@@ -0,0 +1,75 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("machine", processor->model_name);
+ get_str("cpu type", processor->vendor_id);
+ get_float("bogomips", processor->bogomips);
+ processor->cpu_mhz = processor->bogomips;
+ }
+ g_strfreev(tmp);
+ }
+
+ fclose(cpuinfo);
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "System Type=%s\n"
+ "CPU Model=%s\n"
+ "Frequency=%.2fMHz\n"
+ "BogoMIPS=%.2f\n"
+ "Byte Order=%s\n",
+ processor->model_name,
+ processor->vendor_id,
+ processor->cpu_mhz,
+ processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian"
+#else
+ "Big Endian"
+#endif
+ );
+}
diff --git a/modules/devices/sparc/processor.c b/modules/devices/sparc/processor.c
new file mode 100644
index 00000000..594117a7
--- /dev/null
+++ b/modules/devices/sparc/processor.c
@@ -0,0 +1,64 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ while (fgets(buffer, 128, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ if (tmp[0] && tmp[1]) {
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_str("cpu", processor->model_name);
+ get_str("fpu", processor->has_fpu);
+ }
+ g_strfreev(tmp);
+ }
+
+ fclose(cpuinfo);
+
+ processor->cpu_mhz = 0.0f;
+
+ return g_slist_append(NULL, processor);
+}
+
+gchar *
+processor_get_info(GSList *processors)
+{
+ Processor *processor = (Processor *)processors->data;
+
+ return g_strdup_printf("[Processor]\n"
+ "CPU=%s\n"
+ "FPU=%s\n",
+ processor->model_name,
+ processor->has_fpu);
+}
diff --git a/modules/devices/spd-decode.c b/modules/devices/spd-decode.c
new file mode 100644
index 00000000..ac1dd52b
--- /dev/null
+++ b/modules/devices/spd-decode.c
@@ -0,0 +1,1509 @@
+/*
+ * spd-decode.c
+ * Copyright (c) 2010 Leandro A. F. Pereira
+ *
+ * Based on decode-dimms.pl
+ * Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com>
+ * modified by Christian Zuckschwerdt <zany@triq.net>
+ * modified by Burkart Lingner <burkart@bollchen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ctype.h>
+#include <math.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include "hardinfo.h"
+#include "devices.h"
+
+typedef enum {
+ UNKNOWN,
+ DIRECT_RAMBUS,
+ RAMBUS,
+ FPM_DRAM,
+ EDO,
+ PIPELINED_NIBBLE,
+ SDR_SDRAM,
+ MULTIPLEXED_ROM,
+ DDR_SGRAM,
+ DDR_SDRAM,
+ DDR2_SDRAM,
+ DDR3_SDRAM
+} RamType;
+
+char *spd_info = NULL;
+
+static const char *ram_types[] = {
+ "Unknown",
+ "Direct Rambus",
+ "Rambus",
+ "FPM DRAM",
+ "EDO",
+ "Pipelined Nibble",
+ "SDR SDRAM",
+ "Multiplexed ROM",
+ "DDR SGRAM",
+ "DDR SDRAM",
+ "DDR2 SDRAM",
+ "DDR3 SDRAM"
+};
+
+static const char *vendors1[] = { "AMD", "AMI", "Fairchild", "Fujitsu",
+ "GTE", "Harris", "Hitachi", "Inmos",
+ "Intel", "I.T.T.", "Intersil",
+ "Monolithic Memories",
+ "Mostek",
+ "Freescale (former Motorola)",
+ "National", "NEC",
+ "RCA", "Raytheon",
+ "Conexant (Rockwell)", "Seeq",
+ "NXP (former Signetics, Philips Semi.)",
+ "Synertek",
+ "Texas Instruments", "Toshiba",
+ "Xicor", "Zilog", "Eurotechnique",
+ "Mitsubishi",
+ "Lucent (AT&T)", "Exel", "Atmel",
+ "SGS/Thomson",
+ "Lattice Semi.", "NCR",
+ "Wafer Scale Integration", "IBM",
+ "Tristar", "Visic",
+ "Intl. CMOS Technology", "SSSI",
+ "MicrochipTechnology", "Ricoh Ltd.",
+ "VLSI", "Micron Technology",
+ "Hyundai Electronics",
+ "OKI Semiconductor", "ACTEL",
+ "Sharp",
+ "Catalyst", "Panasonic", "IDT",
+ "Cypress",
+ "DEC", "LSI Logic",
+ "Zarlink (former Plessey)", "UTMC",
+ "Thinking Machine", "Thomson CSF",
+ "Integrated CMOS (Vertex)",
+ "Honeywell",
+ "Tektronix", "Sun Microsystems",
+ "SST", "ProMos/Mosel Vitelic",
+ "Infineon (former Siemens)",
+ "Macronix", "Xerox", "Plus Logic",
+ "SunDisk", "Elan Circuit Tech.",
+ "European Silicon Str.",
+ "Apple Computer",
+ "Xilinx", "Compaq",
+ "Protocol Engines", "SCI",
+ "Seiko Instruments", "Samsung",
+ "I3 Design System", "Klic",
+ "Crosspoint Solutions",
+ "Alliance Semiconductor", "Tandem",
+ "Hewlett-Packard",
+ "Intg. Silicon Solutions",
+ "Brooktree", "New Media",
+ "MHS Electronic",
+ "Performance Semi.",
+ "Winbond Electronic",
+ "Kawasaki Steel",
+ "Bright Micro",
+ "TECMAR", "Exar", "PCMCIA",
+ "LG Semi (former Goldstar)",
+ "Northern Telecom", "Sanyo",
+ "Array Microsystems",
+ "Crystal Semiconductor",
+ "Analog Devices", "PMC-Sierra",
+ "Asparix", "Convex Computer",
+ "Quality Semiconductor",
+ "Nimbus Technology", "Transwitch",
+ "Micronas (ITT Intermetall)",
+ "Cannon", "Altera", "NEXCOM",
+ "QUALCOMM",
+ "Sony", "Cray Research",
+ "AMS(Austria Micro)", "Vitesse",
+ "Aster Electronics",
+ "Bay Networks (Synoptic)",
+ "Zentrum or ZMD",
+ "TRW",
+ "Thesys", "Solbourne Computer",
+ "Allied-Signal", "Dialog",
+ "Media Vision",
+ "Level One Communication"
+};
+
+static const char *vendors2[] = { "Cirrus Logic",
+ "National Instruments",
+ "ILC Data Device",
+ "Alcatel Mietec",
+ "Micro Linear",
+ "Univ. of NC",
+ "JTAG Technologies",
+ "BAE Systems",
+ "Nchip",
+ "Galileo Tech",
+ "Bestlink Systems",
+ "Graychip",
+ "GENNUM",
+ "VideoLogic",
+ "Robert Bosch",
+ "Chip Express",
+ "DATARAM",
+ "United Microelec Corp.",
+ "TCSI",
+ "Smart Modular",
+ "Hughes Aircraft",
+ "Lanstar Semiconductor",
+ "Qlogic", "Kingston",
+ "Music Semi",
+ "Ericsson Components",
+ "SpaSE",
+ "Eon Silicon Devices",
+ "Programmable Micro Corp",
+ "DoD",
+ "Integ. Memories Tech.",
+ "Corollary Inc.",
+ "Dallas Semiconductor",
+ "Omnivision",
+ "EIV(Switzerland)",
+ "Novatel Wireless",
+ "Zarlink (former Mitel)",
+ "Clearpoint",
+ "Cabletron",
+ "STEC (former Silicon Technology)",
+ "Vanguard",
+ "Hagiwara Sys-Com",
+ "Vantis", "Celestica",
+ "Century",
+ "Hal Computers",
+ "Rohm Company Ltd.",
+ "Juniper Networks",
+ "Libit Signal Processing",
+ "Mushkin Enhanced Memory",
+ "Tundra Semiconductor",
+ "Adaptec Inc.",
+ "LightSpeed Semi.",
+ "ZSP Corp.",
+ "AMIC Technology",
+ "Adobe Systems",
+ "Dynachip",
+ "PNY Electronics",
+ "Newport Digital",
+ "MMC Networks",
+ "T Square",
+ "Seiko Epson",
+ "Broadcom",
+ "Viking Components",
+ "V3 Semiconductor",
+ "Flextronics (former Orbit)",
+ "Suwa Electronics",
+ "Transmeta",
+ "Micron CMS",
+ "American Computer & Digital Components Inc",
+ "Enhance 3000 Inc",
+ "Tower Semiconductor",
+ "CPU Design",
+ "Price Point",
+ "Maxim Integrated Product",
+ "Tellabs",
+ "Centaur Technology",
+ "Unigen Corporation",
+ "Transcend Information",
+ "Memory Card Technology",
+ "CKD Corporation Ltd.",
+ "Capital Instruments, Inc.",
+ "Aica Kogyo, Ltd.",
+ "Linvex Technology",
+ "MSC Vertriebs GmbH",
+ "AKM Company, Ltd.",
+ "Dynamem, Inc.",
+ "NERA ASA",
+ "GSI Technology",
+ "Dane-Elec (C Memory)",
+ "Acorn Computers",
+ "Lara Technology",
+ "Oak Technology, Inc.",
+ "Itec Memory",
+ "Tanisys Technology",
+ "Truevision",
+ "Wintec Industries",
+ "Super PC Memory",
+ "MGV Memory",
+ "Galvantech",
+ "Gadzoox Nteworks",
+ "Multi Dimensional Cons.",
+ "GateField",
+ "Integrated Memory System",
+ "Triscend", "XaQti",
+ "Goldenram",
+ "Clear Logic",
+ "Cimaron Communications",
+ "Nippon Steel Semi. Corp.",
+ "Advantage Memory",
+ "AMCC",
+ "LeCroy",
+ "Yamaha Corporation",
+ "Digital Microwave",
+ "NetLogic Microsystems",
+ "MIMOS Semiconductor",
+ "Advanced Fibre",
+ "BF Goodrich Data.",
+ "Epigram",
+ "Acbel Polytech Inc.",
+ "Apacer Technology",
+ "Admor Memory",
+ "FOXCONN",
+ "Quadratics Superconductor",
+ "3COM",
+};
+
+static const char *vendors3[] = { "Camintonn Corporation", "ISOA Incorporated",
+ "Agate Semiconductor", "ADMtek Incorporated",
+ "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies",
+ "Ardent Technologies",
+ "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies",
+ "WorkX AG",
+ "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions",
+ "Power General",
+ "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity",
+ "Delkin Devices",
+ "Symagery Microsystems", "C-Port Corporation",
+ "SiberCore Technologies", "Southland Microsystems",
+ "Malleable Technologies", "Kendin Communications",
+ "Great Technology Microcomputer", "Sanmina Corporation",
+ "HADCO Corporation", "Corsair", "Actrans System Inc.",
+ "ALPHA Technologies",
+ "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies",
+ "Align Manufacturing", "Peregrine Semiconductor",
+ "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies",
+ "Chrysalis ITS",
+ "ADTEC Corporation", "Kentron Technologies", "Win Technologies",
+ "Tachyon Semiconductor (former ASIC Designs Inc.)",
+ "Extreme Packet Devices", "RF Micro Devices", "Siemens AG",
+ "Sarnoff Corporation",
+ "Itautec Philco SA", "Radiata Inc.", "Benchmark Elect. (AVEX)",
+ "Legend",
+ "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated",
+ "SwitchOn Networks",
+ "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology",
+ "Virata Corporation",
+ "Excess Bandwidth", "West Bay Semiconductor", "DSP Group",
+ "Newport Communications",
+ "Chip2Chip Incorporated", "Phobos Corporation",
+ "Intellitech Corporation", "Nordic VLSI ASA",
+ "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor",
+ "Agilent Technologies",
+ "Centillium Communications", "W.L. Gore", "HanBit Electronics",
+ "GlobeSpan",
+ "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated",
+ "MetaLink Technologies", "Feiya Technology", "I & C Technology",
+ "Shikatronics",
+ "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions",
+ "Hyperchip", "Gemstone Communications", "Anadigm (former Anadyne)",
+ "3ParData",
+ "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys",
+ "Skyup Technology", "HiNT Corporation", "Chiaro",
+ "MDT Technologies GmbH (former MCI Computer GMBH)",
+ "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory",
+ "Legerity",
+ "Jasmine Networks", "Caspian Networks", "nCUBE",
+ "Silicon Access Networks",
+ "FDK Corporation", "High Bandwidth Access", "MultiLink Technology",
+ "BRECIS",
+ "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic",
+ "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power",
+ "eSilicon", "Morphics Technology", "Accelerant Networks",
+ "Silicon Wave",
+ "SandCraft", "Elpida"
+};
+
+static const char *vendors4[] = { "Solectron", "Optosys Technologies",
+ "Buffalo (former Melco)",
+ "TriMedia Technologies",
+ "Cyan Technologies", "Global Locate",
+ "Optillion",
+ "Terago Communications",
+ "Ikanos Communications",
+ "Princeton Technology",
+ "Nanya Technology",
+ "Elite Flash Storage",
+ "Mysticom", "LightSand Communications",
+ "ATI Technologies",
+ "Agere Systems",
+ "NeoMagic", "AuroraNetics", "Golden Empire",
+ "Mushkin",
+ "Tioga Technologies", "Netlist", "TeraLogic",
+ "Cicada Semiconductor",
+ "Centon Electronics", "Tyco Electronics",
+ "Magis Works", "Zettacom",
+ "Cogency Semiconductor", "Chipcon AS",
+ "Aspex Technology",
+ "F5 Networks",
+ "Programmable Silicon Solutions",
+ "ChipWrights",
+ "Acorn Networks",
+ "Quicklogic",
+ "Kingmax Semiconductor", "BOPS", "Flasys",
+ "BitBlitz Communications",
+ "eMemory Technology", "Procket Networks",
+ "Purple Ray",
+ "Trebia Networks",
+ "Delta Electronics", "Onex Communications",
+ "Ample Communications",
+ "Memory Experts Intl",
+ "Astute Networks", "Azanda Network Devices",
+ "Dibcom", "Tekmos",
+ "API NetWorks", "Bay Microsystems",
+ "Firecron Ltd",
+ "Resonext Communications",
+ "Tachys Technologies", "Equator Technology",
+ "Concept Computer",
+ "SILCOM",
+ "3Dlabs", "c't Magazine", "Sanera Systems",
+ "Silicon Packets",
+ "Viasystems Group", "Simtek",
+ "Semicon Devices Singapore",
+ "Satron Handelsges",
+ "Improv Systems", "INDUSYS GmbH", "Corrent",
+ "Infrant Technologies",
+ "Ritek Corp", "empowerTel Networks",
+ "Hypertec",
+ "Cavium Networks",
+ "PLX Technology", "Massana Design",
+ "Intrinsity",
+ "Valence Semiconductor",
+ "Terawave Communications",
+ "IceFyre Semiconductor", "Primarion",
+ "Picochip Designs Ltd",
+ "Silverback Systems",
+ "Jade Star Technologies",
+ "Pijnenburg Securealink",
+ "TakeMS International AG",
+ "Cambridge Silicon Radio",
+ "Swissbit", "Nazomi Communications",
+ "eWave System",
+ "Rockwell Collins", "Picocel Co., Ltd.",
+ "Alphamosaic Ltd",
+ "Sandburst",
+ "SiCon Video", "NanoAmp Solutions",
+ "Ericsson Technology",
+ "PrairieComm",
+ "Mitac International", "Layer N Networks",
+ "MtekVision",
+ "Allegro Networks",
+ "Marvell Semiconductors",
+ "Netergy Microelectronic", "NVIDIA",
+ "Internet Machines",
+ "Peak Electronics",
+ "Litchfield Communication",
+ "Accton Technology",
+ "Teradiant Networks",
+ "Europe Technologies", "Cortina Systems",
+ "RAM Components",
+ "Raqia Networks",
+ "ClearSpeed", "Matsushita Battery",
+ "Xelerated",
+ "SimpleTech",
+ "Utron Technology", "Astec International",
+ "AVM gmbH",
+ "Redux Communications",
+ "Dot Hill Systems", "TeraChip"
+};
+
+static const char *vendors5[] = { "T-RAM Incorporated",
+ "Innovics Wireless", "Teknovus", "KeyEye Communications",
+ "Runcom Technologies", "RedSwitch", "Dotcast",
+ "Silicon Mountain Memory",
+ "Signia Technologies", "Pixim", "Galazar Networks",
+ "White Electronic Designs",
+ "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology",
+ "Europe Technologies",
+ "Potentia Power Systems", "C-guys Incorporated",
+ "Digital Communications Technology Incorporated",
+ "Silicon-Based Technology",
+ "Fulcrum Microsystems", "Positivo Informatica Ltd",
+ "XIOtech Corporation", "PortalPlayer",
+ "Zhiying Software", "Direct2Data", "Phonex Broadband",
+ "Skyworks Solutions",
+ "Entropic Communications", "Pacific Force Technology", "Zensys A/S",
+ "Legend Silicon Corp.",
+ "sci-worx GmbH", "SMSC (former Oasis Silicon Systems)",
+ "Renesas Technology", "Raza Microelectronics",
+ "Phyworks", "MediaTek", "Non-cents Productions", "US Modular",
+ "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies",
+ "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ",
+ "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies",
+ "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology",
+ "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision",
+ "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom",
+ "Bandspeed",
+ "LeWiz Communications", "CPU Technology", "Ramaxel Technology",
+ "DSP Group",
+ "Axis Communications", "Legacy Electronics", "Chrontel",
+ "Powerchip Semiconductor",
+ "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology",
+ "VirtualDigm",
+ "G Skill Intl", "Quanta Computer", "Yield Microelectronics",
+ "Afa Technologies",
+ "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks",
+ "Advance Modules",
+ "Microsoft", "Open-Silicon", "Goal Semiconductor",
+ "ARC International",
+ "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics",
+ "Adimos", "SiGe Semiconductor", "Fodus Communications",
+ "Credence Systems Corp.",
+ "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies",
+ "GateChange Technologies",
+ "High Density Devices AS", "Synopsys", "Gigaram",
+ "Enigma Semiconductor Inc.",
+ "Century Micro Inc.", "Icera Semiconductor",
+ "Mediaworks Integrated Systems", "O'Neil Product Development",
+ "Supreme Top Technology Ltd.", "MicroDisplay Corporation",
+ "Team Group Inc.", "Sinett Corporation",
+ "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.",
+ "SMaL Camera Technologies", "Thomson SC", "Airgo Networks",
+ "Wisair Ltd.",
+ "SigmaTel", "Arkados", "Compete IT gmbH Co. KG",
+ "Eudar Technology Inc.",
+ "Focus Enhancements", "Xyratex"
+};
+
+static const char *vendors6[] = { "Specular Networks",
+ "Patriot Memory",
+ "U-Chip Technology Corp.",
+ "Silicon Optix",
+ "Greenfield Networks",
+ "CompuRAM GmbH", "Stargen, Inc.",
+ "NetCell Corporation",
+ "Excalibrus Technologies Ltd",
+ "SCM Microsystems",
+ "Xsigo Systems, Inc.",
+ "CHIPS & Systems Inc",
+ "Tier 1 Multichip Solutions",
+ "CWRL Labs", "Teradici",
+ "Gigaram, Inc.",
+ "g2 Microsystems",
+ "PowerFlash Semiconductor",
+ "P.A. Semi, Inc.",
+ "NovaTech Solutions, S.A.",
+ "c2 Microsystems, Inc.",
+ "Level5 Networks",
+ "COS Memory AG",
+ "Innovasic Semiconductor",
+ "02IC Co. Ltd", "Tabula, Inc.",
+ "Crucial Technology",
+ "Chelsio Communications",
+ "Solarflare Communications",
+ "Xambala Inc.", "EADS Astrium",
+ "ATO Semicon Co. Ltd.",
+ "Imaging Works, Inc.",
+ "Astute Networks, Inc.", "Tzero",
+ "Emulex",
+ "Power-One", "Pulse~LINK Inc.",
+ "Hon Hai Precision Industry",
+ "White Rock Networks Inc.",
+ "Telegent Systems USA, Inc.",
+ "Atrua Technologies, Inc.",
+ "Acbel Polytech Inc.",
+ "eRide Inc.",
+ "ULi Electronics Inc.",
+ "Magnum Semiconductor Inc.",
+ "neoOne Technology, Inc.",
+ "Connex Technology, Inc.",
+ "Stream Processors, Inc.",
+ "Focus Enhancements",
+ "Telecis Wireless, Inc.",
+ "uNav Microelectronics",
+ "Tarari, Inc.", "Ambric, Inc.",
+ "Newport Media, Inc.", "VMTS",
+ "Enuclia Semiconductor, Inc.",
+ "Virtium Technology Inc.",
+ "Solid State System Co., Ltd.",
+ "Kian Tech LLC",
+ "Artimi",
+ "Power Quotient International",
+ "Avago Technologies",
+ "ADTechnology", "Sigma Designs",
+ "SiCortex, Inc.",
+ "Ventura Technology Group",
+ "eASIC", "M.H.S. SAS",
+ "Micro Star International",
+ "Rapport Inc.",
+ "Makway International",
+ "Broad Reach Engineering Co.",
+ "Semiconductor Mfg Intl Corp",
+ "SiConnect", "FCI USA Inc.",
+ "Validity Sensors",
+ "Coney Technology Co. Ltd.",
+ "Spans Logic", "Neterion Inc.",
+ "Qimonda",
+ "New Japan Radio Co. Ltd.",
+ "Velogix", "Montalvo Systems",
+ "iVivity Inc.",
+ "Walton Chaintech",
+ "AENEON",
+ "Lorom Industrial Co. Ltd.",
+ "Radiospire Networks",
+ "Sensio Technologies, Inc.",
+ "Nethra Imaging",
+ "Hexon Technology Pte Ltd",
+ "CompuStocx (CSX)",
+ "Methode Electronics, Inc.",
+ "Connect One Ltd.",
+ "Opulan Technologies",
+ "Septentrio NV",
+ "Goldenmars Technology Inc.",
+ "Kreton Corporation",
+ "Cochlear Ltd.",
+ "Altair Semiconductor",
+ "NetEffect, Inc.",
+ "Spansion, Inc.",
+ "Taiwan Semiconductor Mfg",
+ "Emphany Systems Inc.",
+ "ApaceWave Technologies",
+ "Mobilygen Corporation", "Tego",
+ "Cswitch Corporation",
+ "Haier (Beijing) IC Design Co.",
+ "MetaRAM",
+ "Axel Electronics Co. Ltd.",
+ "Tilera Corporation",
+ "Aquantia",
+ "Vivace Semiconductor",
+ "Redpine Signals", "Octalica",
+ "InterDigital Communications",
+ "Avant Technology",
+ "Asrock, Inc.", "Availink",
+ "Quartics, Inc.",
+ "Element CXI",
+ "Innovaciones Microelectronicas",
+ "VeriSilicon Microelectronics",
+ "W5 Networks"
+};
+
+static const char *vendors7[] = { "MOVEKING", "Mavrix Technology, Inc.",
+ "CellGuide Ltd.", "Faraday Technology",
+ "Diablo Technologies, Inc.", "Jennic", "Octasic",
+ "Molex Incorporated",
+ "3Leaf Networks",
+ "Bright Micron Technology", "Netxen", "NextWave Broadband Inc.",
+ "DisplayLink", "ZMOS Technology",
+ "Tec-Hill", "Multigig, Inc.", "Amimon", "Euphonic Technologies, Inc.",
+ "BRN Phoenix",
+ "InSilica", "Ember Corporation", "Avexir Technologies Corporation",
+ "Echelon Corporation",
+ "Edgewater Computer Systems", "XMOS Semiconductor Ltd.",
+ "GENUSION, Inc.", "Memory Corp NV",
+ "SiliconBlue Technologies", "Rambus Inc."
+};
+
+static const char **vendors[7] = { vendors1, vendors2, vendors3, vendors4, vendors5, vendors6,
+ vendors7
+};
+
+/*
+ * We consider that no data was written to this area of the SPD EEPROM if
+ * all bytes read 0x00 or all bytes read 0xff
+ */
+static int spd_written(unsigned char *bytes, int len)
+{
+ do {
+ if (*bytes == 0x00 || *bytes == 0xFF)
+ return 1;
+ } while (--len && bytes++);
+
+ return 0;
+}
+
+static int parity(int value)
+{
+ value ^= value >> 16;
+ value ^= value >> 8;
+ value ^= value >> 4;
+ value &= 0xf;
+
+ return (0x6996 >> value) & 1;
+}
+
+static void decode_sdr_module_size(unsigned char *bytes, int *size)
+{
+ int i, k = 0;
+
+ i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17;
+ if (bytes[5] <= 8 && bytes[17] <= 8) {
+ k = bytes[5] * bytes[17];
+ }
+
+ if (i > 0 && i <= 12 && k > 0) {
+ if (size) {
+ *size = (1 << i) * k;
+ }
+ } else {
+ if (size) {
+ *size = -1;
+ }
+ }
+}
+
+static void decode_sdr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras)
+{
+ float cas[3], ctime;
+ int i, j;
+
+ for (i = 0, j = 0; j < 7; j++) {
+ if (bytes[18] & 1 << j) {
+ cas[i++] = j + 1;
+ }
+ }
+
+ ctime = (bytes[9] >> 4 + bytes[9] & 0xf) * 0.1;
+
+ if (trcd) {
+ *trcd = ceil(bytes[29] / ctime);
+ }
+ if (trp) {
+ *trp = ceil(bytes[27] / ctime);
+ }
+ if (tras) {
+ *tras = ceil(bytes[30] / ctime);
+ }
+ if (tcl) {
+ *tcl = cas[i];
+ }
+}
+
+static void decode_sdr_module_row_address_bits(unsigned char *bytes, char **bits)
+{
+ char *temp;
+
+ switch (bytes[3]) {
+ case 0:
+ temp = "Undefined";
+ break;
+ case 1:
+ temp = "1/16";
+ break;
+ case 2:
+ temp = "2/27";
+ break;
+ case 3:
+ temp = "3/18";
+ break;
+ default:
+ /* printf("%d\n", bytes[3]); */
+ temp = "Unknown";
+ }
+
+ if (bits) {
+ *bits = temp;
+ }
+}
+
+static void decode_sdr_module_col_address_bits(unsigned char *bytes, char **bits)
+{
+ char *temp;
+
+ switch (bytes[4]) {
+ case 0:
+ temp = "Undefined";
+ break;
+ case 1:
+ temp = "1/16";
+ break;
+ case 2:
+ temp = "2/17";
+ break;
+ case 3:
+ temp = "3/18";
+ break;
+ default:
+ /*printf("%d\n", bytes[4]); */
+ temp = "Unknown";
+ }
+
+ if (bits) {
+ *bits = temp;
+ }
+}
+
+static void decode_sdr_module_number_of_rows(unsigned char *bytes, int *rows)
+{
+ if (rows) {
+ *rows = bytes[5];
+ }
+}
+
+static void decode_sdr_module_data_with(unsigned char *bytes, int *width)
+{
+ if (width) {
+ if (bytes[7] > 1) {
+ *width = 0;
+ } else {
+ *width = (bytes[7] * 0xff) + bytes[6];
+ }
+ }
+}
+
+static void decode_sdr_module_interface_signal_levels(unsigned char *bytes, char **signal_levels)
+{
+ char *temp;
+
+ switch (bytes[8]) {
+ case 0:
+ temp = "5.0 Volt/TTL";
+ break;
+ case 1:
+ temp = "LVTTL";
+ break;
+ case 2:
+ temp = "HSTL 1.5";
+ break;
+ case 3:
+ temp = "SSTL 3.3";
+ break;
+ case 4:
+ temp = "SSTL 2.5";
+ break;
+ case 255:
+ temp = "New Table";
+ break;
+ default:
+ temp = "Undefined";
+ }
+
+ if (signal_levels) {
+ *signal_levels = temp;
+ }
+}
+
+static void decode_sdr_module_configuration_type(unsigned char *bytes, char **module_config_type)
+{
+ char *temp;
+
+ switch (bytes[11]) {
+ case 0:
+ temp = "No parity";
+ break;
+ case 1:
+ temp = "Parity";
+ break;
+ case 2:
+ temp = "ECC";
+ break;
+ default:
+ temp = "Undefined";
+ }
+
+ if (module_config_type) {
+ *module_config_type = temp;
+ }
+}
+
+static void decode_sdr_module_refresh_type(unsigned char *bytes, char **refresh_type)
+{
+ char *temp;
+
+ if (bytes[12] & 0x80) {
+ temp = "Self refreshing";
+ } else {
+ temp = "Not self refreshing";
+ }
+
+ if (refresh_type) {
+ *refresh_type = temp;
+ }
+}
+
+static void decode_sdr_module_refresh_rate(unsigned char *bytes, char **refresh_rate)
+{
+ char *temp;
+
+ switch (bytes[12] & 0x7f) {
+ case 0:
+ temp = "Normal (15.625us)";
+ break;
+ case 1:
+ temp = "Reduced (3.9us)";
+ break;
+ case 2:
+ temp = "Reduced (7.8us)";
+ break;
+ case 3:
+ temp = "Extended (31.3us)";
+ break;
+ case 4:
+ temp = "Extended (62.5us)";
+ break;
+ case 5:
+ temp = "Extended (125us)";
+ break;
+ default:
+ temp = "Undefined";
+ }
+
+ if (refresh_rate) {
+ *refresh_rate = temp;
+ }
+}
+
+static gchar *decode_sdr_sdram(unsigned char *bytes, int *size)
+{
+ int rows, data_width;
+ float tcl, trcd, trp, tras;
+ char *row_address_bits, *col_address_bits, *signal_level;
+ char *module_config_type, *refresh_type, *refresh_rate;
+
+ decode_sdr_module_size(bytes, size);
+ decode_sdr_module_timings(bytes, &tcl, &trcd, &trp, &tras);
+ decode_sdr_module_row_address_bits(bytes, &row_address_bits);
+ decode_sdr_module_col_address_bits(bytes, &col_address_bits);
+ decode_sdr_module_number_of_rows(bytes, &rows);
+ decode_sdr_module_data_with(bytes, &data_width);
+ decode_sdr_module_interface_signal_levels(bytes, &signal_level);
+ decode_sdr_module_configuration_type(bytes, &module_config_type);
+ decode_sdr_module_refresh_type(bytes, &refresh_type);
+ decode_sdr_module_refresh_rate(bytes, &refresh_rate);
+
+ /* TODO:
+ - RAS to CAS delay
+ - Supported CAS latencies
+ - Supported CS latencies
+ - Supported WE latencies
+ - Cycle Time / Access time
+ - SDRAM module attributes
+ - SDRAM device attributes
+ - Row densities
+ - Other misc stuff
+ */
+
+ return g_strdup_printf("[Module Information]\n"
+ "Module type=SDR\n"
+ "SPD revision=%d\n"
+ "Row address bits=%s\n"
+ "Column address bits=%s\n"
+ "Number of rows=%d\n"
+ "Data width=%d bits\n"
+ "Interface signal levels=%s\n"
+ "Configuration type=%s\n"
+ "Refresh=%s (%s)\n"
+ "[Timings]\n"
+ "tCL=%.2f\n"
+ "tRCD=%.2f\n"
+ "tRP=%.2f\n"
+ "tRAS=%.2f\n",
+ bytes[62],
+ row_address_bits, col_address_bits, rows,
+ data_width, signal_level, module_config_type,
+ refresh_type, refresh_rate, tcl, trcd, trp, tras);
+}
+
+static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pcclk)
+{
+ float temp, clk;
+ int tbits, pc;
+
+ temp = (bytes[9] >> 4) + (bytes[9] & 0xf) * 0.1;
+ clk = 2 * (1000 / temp);
+ tbits = (bytes[7] * 256) + bytes[6];
+
+ if (bytes[11] == 2 || bytes[11] == 1) {
+ tbits -= 8;
+ }
+
+ pc = clk * tbits / 8;
+ if (pc % 100 > 50) {
+ pc += 100;
+ }
+ pc -= pc % 100;
+
+ if (ddrclk)
+ *ddrclk = (int) clk;
+
+ if (pcclk)
+ *pcclk = pc;
+}
+
+static void decode_ddr_module_size(unsigned char *bytes, int *size)
+{
+ int i, k;
+
+ i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17;
+ k = (bytes[5] <= 8 && bytes[17] <= 8) ? bytes[5] * bytes[17] : 0;
+
+ if (i > 0 && i <= 12 && k > 0) {
+ if (size) {
+ *size = (1 << i) * k;
+ }
+ } else {
+ if (size) {
+ *size = -1;
+ }
+ }
+}
+
+static void *decode_ddr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras)
+{
+ float ctime;
+ float highest_cas = 0;
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ if (bytes[18] & (1 << i)) {
+ highest_cas = 1 + i * 0.5f;
+ }
+ }
+
+ ctime = (bytes[9] >> 4) + (bytes[9] & 0xf) * 0.1;
+
+ if (trcd) {
+ *trcd = (bytes[29] >> 2) + ((bytes[29] & 3) * 0.25);
+ *trcd = ceil(*trcd / ctime);
+ }
+
+ if (trp) {
+ *trp = (bytes[27] >> 2) + ((bytes[27] & 3) * 0.25);
+ *trp = ceil(*trp / ctime);
+ }
+
+ if (tras) {
+ *tras = bytes[30];
+ *tras = ceil(*tras / ctime);
+ }
+
+ if (tcl) {
+ *tcl = highest_cas;
+ }
+}
+
+static gchar *decode_ddr_sdram(unsigned char *bytes, int *size)
+{
+ float ddr_clock;
+ float tcl, trcd, trp, tras;
+ int pc_speed;
+
+ decode_ddr_module_speed(bytes, &ddr_clock, &pc_speed);
+ decode_ddr_module_size(bytes, size);
+ decode_ddr_module_timings(bytes, &tcl, &trcd, &trp, &tras);
+
+ return g_strdup_printf("[Module Information]\n"
+ "Module type=DDR %.2fMHz (PC%d)\n"
+ "SPD revision=%d.%d\n"
+ "[Timings]\n"
+ "tCL=%.2f\n"
+ "tRCD=%.2f\n"
+ "tRP=%.2f\n"
+ "tRAS=%.2f\n", ddr_clock, pc_speed, bytes[62] >> 4, bytes[62] & 0xf, tcl, trcd, trp, tras);
+}
+
+static float decode_ddr2_module_ctime(unsigned char byte)
+{
+ float ctime;
+
+ ctime = (byte >> 4);
+ byte &= 0xf;
+
+ if (byte <= 9) {
+ ctime += byte * 0.1;
+ } else if (byte == 10) {
+ ctime += 0.25;
+ } else if (byte == 11) {
+ ctime += 0.33;
+ } else if (byte == 12) {
+ ctime += 0.66;
+ } else if (byte == 13) {
+ ctime += 0.75;
+ }
+
+ return ctime;
+}
+
+static void decode_ddr2_module_speed(unsigned char *bytes, float *ddr_clock, int *pc2_speed)
+{
+ float ctime;
+ float ddrclk;
+ int tbits, pcclk;
+
+ ctime = decode_ddr2_module_ctime(bytes[9]);
+ ddrclk = 2 * (1000 / ctime);
+
+ tbits = (bytes[7] * 256) + bytes[6];
+ if (bytes[11] & 0x03) {
+ tbits -= 8;
+ }
+
+ pcclk = ddrclk * tbits / 8;
+ pcclk -= pcclk % 100;
+
+ if (ddr_clock) {
+ *ddr_clock = (int) ddrclk;
+ }
+ if (pc2_speed) {
+ *pc2_speed = pcclk;
+ }
+}
+
+static void decode_ddr2_module_size(unsigned char *bytes, int *size)
+{
+ int i, k;
+
+ i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17;
+ k = ((bytes[5] & 0x7) + 1) * bytes[17];
+
+ if (i > 0 && i <= 12 && k > 0) {
+ if (*size) {
+ *size = ((1 << i) * k);
+ }
+ } else {
+ if (*size) {
+ *size = 0;
+ }
+ }
+}
+
+static void decode_ddr2_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras, float *tcl)
+{
+ float ctime;
+ float highest_cas = 0;
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ if (bytes[18] & (1 << i)) {
+ highest_cas = i;
+ }
+ }
+
+ ctime = decode_ddr2_module_ctime(bytes[9]);
+
+ if (trcd) {
+ *trcd = ceil(((bytes[29] >> 2) + ((bytes[29] & 3) * 0.25)) / ctime);
+ }
+
+ if (trp) {
+ *trp = ceil(((bytes[27] >> 2) + ((bytes[27] & 3) * 0.25)) / ctime);
+ }
+
+ if (tras) {
+ *tras = ceil(bytes[30] / ctime);
+ }
+
+ if (tcl) {
+ *tcl = highest_cas;
+ }
+}
+
+static gchar *decode_ddr2_sdram(unsigned char *bytes, int *size)
+{
+ float ddr_clock;
+ float trcd, trp, tras, tcl;
+ int pc2_speed;
+
+ decode_ddr2_module_speed(bytes, &ddr_clock, &pc2_speed);
+ decode_ddr2_module_size(bytes, size);
+ decode_ddr2_module_timings(bytes, &trcd, &trp, &tras, &tcl);
+
+ return g_strdup_printf("[Module Information]\n"
+ "Module type=DDR2 %.2f MHz (PC2-%d)\n"
+ "SPD revision=%d.%d\n"
+ "[Timings]\n"
+ "tCL=%.2f\n"
+ "tRCD=%.2f\n"
+ "tRP=%.2f\n"
+ "tRAS=%.2f\n", ddr_clock, pc2_speed, bytes[62] >> 4, bytes[62] & 0xf, tcl, trcd, trp, tras);
+}
+
+static void decode_ddr3_module_speed(unsigned char *bytes, float *ddr_clock, int *pc3_speed)
+{
+ float ctime;
+ float ddrclk;
+ int tbits, pcclk;
+ float mtb = 0.125;
+
+ if (bytes[10] == 1 && bytes[11] == 8)
+ mtb = 0.125;
+ if (bytes[10] == 1 && bytes[11] == 15)
+ mtb = 0.0625;
+ ctime = mtb * bytes[12];
+
+ ddrclk = 2 * (1000 / ctime);
+
+ tbits = 64;
+ switch (bytes[8]) {
+ case 1:
+ tbits = 16;
+ break;
+ case 4:
+ tbits = 32;
+ break;
+ case 3:
+ case 0xb:
+ tbits = 64;
+ break;
+ }
+
+ pcclk = ddrclk * tbits / 8;
+ pcclk -= pcclk % 100;
+
+ if (ddr_clock) {
+ *ddr_clock = (int) ddrclk;
+ }
+ if (pc3_speed) {
+ *pc3_speed = pcclk;
+ }
+}
+
+static void decode_ddr3_module_size(unsigned char *bytes, int *size)
+{
+ *size = 512 << bytes[4];
+}
+
+static void decode_ddr3_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras, float *tcl)
+{
+ float ctime;
+ float highest_cas = 0;
+ int i;
+ float mtb = 0.125;
+
+ if (bytes[10] == 1 && bytes[11] == 8)
+ mtb = 0.125;
+ if (bytes[10] == 1 && bytes[11] == 15)
+ mtb = 0.0625;
+ ctime = mtb * bytes[12];
+
+ switch (bytes[14]) {
+ case 6:
+ highest_cas = 5;
+ break;
+ case 4:
+ highest_cas = 6;
+ break;
+ case 0xc:
+ highest_cas = 7;
+ break;
+ case 0x1e:
+ highest_cas = 8;
+ break;
+ }
+ if (trcd) {
+ *trcd = bytes[18] * mtb;
+ }
+
+ if (trp) {
+ *trp = bytes[20] * mtb;
+ }
+
+ if (tras) {
+ *tras = (bytes[22] + bytes[21] & 0xf) * mtb;
+ }
+
+ if (tcl) {
+ *tcl = highest_cas;
+ }
+}
+
+static void decode_ddr3_module_type(unsigned char *bytes, const char **type)
+{
+ switch (bytes[3]) {
+ case 0x00:
+ *type = "Undefined";
+ break;
+ case 0x01:
+ *type = "RDIMM (Registered Long DIMM)";
+ break;
+ case 0x02:
+ *type = "UDIMM (Unbuffered Long DIMM)";
+ break;
+ case 0x03:
+ *type = "SODIMM (Small Outline DIMM)";
+ break;
+ default:
+ *type = "Unknown";
+ }
+}
+
+static gchar *decode_ddr3_sdram(unsigned char *bytes, int *size)
+{
+ float ddr_clock;
+ float trcd, trp, tras, tcl;
+ int pc3_speed;
+ const char *type;
+
+ decode_ddr3_module_speed(bytes, &ddr_clock, &pc3_speed);
+ decode_ddr3_module_size(bytes, size);
+ decode_ddr3_module_timings(bytes, &trcd, &trp, &tras, &tcl);
+ decode_ddr3_module_type(bytes, &type);
+
+ return g_strdup_printf("[Module Information]\n"
+ "Module type=DDR3 %.2f MHz (PC3-%d)\n"
+ "SPD revision=%d.%d\n"
+ "Type=%s\n"
+ "[Timings]\n"
+ "tCL=%.2f\n"
+ "tRCD=%.3fns\n"
+ "tRP=%.3fns\n"
+ "tRAS=%.3fns\n",
+ ddr_clock, pc3_speed,
+ bytes[1] >> 4, bytes[1] & 0xf,
+ type,
+ tcl,
+ trcd,
+ trp,
+ tras);
+}
+
+static void decode_ddr3_part_number(unsigned char *bytes, char *part_number)
+{
+ int i;
+ if (part_number) {
+ for (i = 128; i <= 145; i++)
+ *part_number++ = bytes[i];
+ *part_number = '\0';
+ }
+}
+
+static void decode_ddr3_manufacturer(unsigned char *bytes, char **manufacturer)
+{
+ char *out = "Unknown";
+
+ end:
+ if (manufacturer) {
+ *manufacturer = out;
+ }
+}
+
+static void decode_module_manufacturer(unsigned char *bytes, char **manufacturer)
+{
+ char *out = "Unknown";
+ unsigned char first;
+ int ai = 0;
+ int len = 8;
+ unsigned char *initial = bytes;
+
+ if (!spd_written(bytes, 8)) {
+ out = "Undefined";
+ goto end;
+ }
+
+ do {
+ ai++;
+ } while ((--len && (*bytes++ == 0x7f)));
+ first = *--bytes;
+
+ if (ai == 0) {
+ out = "Invalid";
+ goto end;
+ }
+
+ if (parity(first) != 1) {
+ out = "Invalid";
+ goto end;
+ }
+
+ out = (char *) vendors[ai - 1][(first & 0x7f) - 1];
+
+ end:
+ if (manufacturer) {
+ *manufacturer = out;
+ }
+}
+
+static void decode_module_part_number(unsigned char *bytes, char *part_number)
+{
+ if (part_number) {
+ bytes += 8 + 64;
+
+ while (*bytes++ && *bytes >= 32 && *bytes < 127) {
+ *part_number++ = *bytes;
+ }
+ *part_number = '\0';
+ }
+}
+
+static int decode_ram_type(unsigned char *bytes)
+{
+ if (bytes[0] < 4) {
+ switch (bytes[2]) {
+ case 1:
+ return DIRECT_RAMBUS;
+ case 17:
+ return RAMBUS;
+ }
+ } else {
+ switch (bytes[2]) {
+ case 1:
+ return FPM_DRAM;
+ case 2:
+ return EDO;
+ case 3:
+ return PIPELINED_NIBBLE;
+ case 4:
+ return SDR_SDRAM;
+ case 5:
+ return MULTIPLEXED_ROM;
+ case 6:
+ return DDR_SGRAM;
+ case 7:
+ return DDR_SDRAM;
+ case 8:
+ return DDR2_SDRAM;
+ case 11:
+ return DDR3_SDRAM;
+ }
+ }
+
+ return UNKNOWN;
+}
+
+static void read_spd(char *spd_path, int offset, size_t size, int use_sysfs, unsigned char *bytes_out)
+{
+ if (use_sysfs) {
+ FILE *spd;
+ gchar *temp_path;
+
+ temp_path = g_strdup_printf("%s/eeprom", spd_path);
+ if ((spd = fopen(temp_path, "rb"))) {
+ fseek(spd, offset, SEEK_SET);
+ fread(bytes_out, 1, size, spd);
+ fclose(spd);
+ }
+
+ g_free(temp_path);
+ } else {
+ int i;
+
+ for (i = 0; i <= 3; i++) {
+ FILE *spd;
+ char *temp_path;
+
+ temp_path = g_strdup_printf("%s/%02x", spd_path, offset + i * 16);
+ if ((spd = fopen(temp_path, "rb"))) {
+ fread(bytes_out + i * 16, 1, 16, spd);
+ fclose(spd);
+ }
+
+ g_free(temp_path);
+ }
+ }
+}
+
+static gchar *decode_dimms(GSList * dimm_list, gboolean use_sysfs)
+{
+ GSList *dimm;
+ GString *output;
+ gint count = 0;
+
+ output = g_string_new("");
+
+ for (dimm = dimm_list; dimm; dimm = dimm->next, count++) {
+ gchar *spd_path = (gchar *) dimm->data;
+ gchar *manufacturer;
+ gchar *detailed_info;
+ gchar *moreinfo_key;
+ gchar part_number[32];
+ unsigned char bytes[256];
+ int module_size;
+ RamType ram_type;
+
+ shell_status_pulse();
+
+ read_spd(spd_path, 0, 256, use_sysfs, bytes);
+ ram_type = decode_ram_type(bytes);
+
+ switch (ram_type) {
+ case DDR2_SDRAM:
+ detailed_info = decode_ddr2_sdram(bytes, &module_size);
+ decode_module_part_number(bytes, part_number);
+ decode_module_manufacturer(bytes + 64, &manufacturer);
+ break;
+ case DDR3_SDRAM:
+ detailed_info = decode_ddr3_sdram(bytes, &module_size);
+ decode_ddr3_part_number(bytes, part_number);
+ decode_ddr3_manufacturer(bytes, &manufacturer);
+ break;
+ case DDR_SDRAM:
+ detailed_info = decode_ddr_sdram(bytes, &module_size);
+ decode_module_part_number(bytes, part_number);
+ decode_module_manufacturer(bytes + 64, &manufacturer);
+ break;
+ case SDR_SDRAM:
+ detailed_info = decode_sdr_sdram(bytes, &module_size);
+ decode_module_part_number(bytes, part_number);
+ decode_module_manufacturer(bytes + 64, &manufacturer);
+ break;
+ default:
+ DEBUG("Unsupported EEPROM type: %s\n", ram_types[ram_type]);
+ continue;
+ }
+
+
+
+ gchar *key = g_strdup_printf("MEM%d", count);
+ moreinfo_add_with_prefix("DEV", key, g_strdup(detailed_info));
+ g_free(key);
+ g_string_append_printf(output, "$MEM%d$%d=%s|%d MB|%s\n", count, count, part_number, module_size, manufacturer);
+
+ g_free(spd_path);
+ g_free(detailed_info);
+ }
+
+ return g_string_free(output, FALSE);
+}
+
+void scan_spd_do(void)
+{
+ GDir *dir = NULL;
+ GSList *dimm_list = NULL;
+ gboolean use_sysfs = FALSE;
+ gchar *dir_entry;
+ gchar *list;
+
+ if (g_file_test("/sys/bus/i2c/drivers/eeprom", G_FILE_TEST_EXISTS)) {
+ dir = g_dir_open("/sys/bus/i2c/drivers/eeprom", 0, NULL);
+ use_sysfs = TRUE;
+ } else if (g_file_test("/proc/sys/dev/sensors", G_FILE_TEST_EXISTS)) {
+ dir = g_dir_open("/proc/sys/dev/sensors", 0, NULL);
+ }
+
+ if (!dir) {
+ g_free(spd_info);
+ if (!g_file_test("/sys/module/eeprom", G_FILE_TEST_EXISTS)) {
+ spd_info = g_strdup(_("[SPD]\n"
+ "Please load the eeprom module to obtain information about memory SPD=\n"
+ "[$ShellParam$]\n"
+ "ReloadInterval=500\n"));
+ } else {
+ spd_info = g_strdup(_("[SPD]\n" "Reading memory SPD not supported on this system=\n"));
+ }
+
+ return;
+ }
+
+ while ((dir_entry = (char *) g_dir_read_name(dir))) {
+ if (use_sysfs && isdigit(dir_entry[0])) {
+ dimm_list = g_slist_prepend(dimm_list, g_strdup_printf("/sys/bus/i2c/drivers/eeprom/%s", dir_entry));
+ } else if (g_str_has_prefix(dir_entry, "eeprom-")) {
+ dimm_list = g_slist_prepend(dimm_list, g_strdup_printf("/proc/sys/dev/sensors/%s", dir_entry));
+ }
+ }
+
+ g_dir_close(dir);
+
+ list = decode_dimms(dimm_list, use_sysfs);
+ g_slist_free(dimm_list);
+
+ g_free(spd_info);
+ spd_info = g_strdup_printf("[SPD]\n"
+ "%s\n"
+ "[$ShellParam$]\n"
+ "ViewType=1\n"
+ "ColumnTitle$TextValue=Bank\n"
+ "ColumnTitle$Extra1=Size\n"
+ "ColumnTitle$Extra2=Manufacturer\n"
+ "ColumnTitle$Value=Model\n" "ShowColumnHeaders=true\n", list);
+ g_free(list);
+}
diff --git a/modules/devices/storage.c b/modules/devices/storage.c
new file mode 100644
index 00000000..0c393682
--- /dev/null
+++ b/modules/devices/storage.c
@@ -0,0 +1,371 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 <string.h>
+
+#include "hardinfo.h"
+#include "devices.h"
+
+gchar *storage_icons = NULL;
+
+/* SCSI support by Pascal F.Martin <pascalmartin@earthlink.net> */
+void
+__scan_scsi_devices(void)
+{
+ FILE *proc_scsi;
+ gchar buffer[256], *buf;
+ gint n = 0;
+ gint scsi_controller = 0;
+ gint scsi_channel = 0;
+ gint scsi_id = 0 ;
+ gint scsi_lun = 0;
+ gchar *vendor = NULL, *revision = NULL, *model = NULL;
+ gchar *scsi_storage_list;
+
+ /* remove old devices from global device table */
+ moreinfo_del_with_prefix("DEV:SCSI");
+
+ if (!g_file_test("/proc/scsi/scsi", G_FILE_TEST_EXISTS))
+ return;
+
+ scsi_storage_list = g_strdup(_("\n[SCSI Disks]\n"));
+
+ if ((proc_scsi = fopen("/proc/scsi/scsi", "r"))) {
+ while (fgets(buffer, 256, proc_scsi)) {
+ buf = g_strstrip(buffer);
+ if (!strncmp(buf, "Host: scsi", 10)) {
+ sscanf(buf,
+ "Host: scsi%d Channel: %d Id: %d Lun: %d",
+ &scsi_controller, &scsi_channel, &scsi_id, &scsi_lun);
+
+ n++;
+ } else if (!strncmp(buf, "Vendor: ", 8)) {
+ buf[17] = '\0';
+ buf[41] = '\0';
+ buf[53] = '\0';
+
+ vendor = g_strdup(g_strstrip(buf + 8));
+ model = g_strdup_printf("%s %s", vendor, g_strstrip(buf + 24));
+ revision = g_strdup(g_strstrip(buf + 46));
+ } else if (!strncmp(buf, "Type: ", 8)) {
+ char *p;
+ gchar *type = NULL, *icon = NULL;
+
+ if (!(p = strstr(buf, "ANSI SCSI revision"))) {
+ p = strstr(buf, "ANSI SCSI revision");
+ }
+
+ if (p != NULL) {
+ while (*(--p) == ' ');
+ *(++p) = 0;
+
+ static struct {
+ char *type;
+ char *label;
+ char *icon;
+ } type2icon[] = {
+ { "Direct-Access", "Disk", "hdd"},
+ { "Sequential-Access", "Tape", "tape"},
+ { "Printer", "Printer", "lpr"},
+ { "WORM", "CD-ROM", "cdrom"},
+ { "CD-ROM", "CD-ROM", "cdrom"},
+ { "Scanner", "Scanner", "scanner"},
+ { "Flash Disk", "USB Flash Disk", "usbfldisk" },
+ { NULL, "Generic", "scsi"}
+ };
+ int i;
+
+ if (model && strstr(model, "Flash Disk")) {
+ type = "Flash Disk";
+ icon = "usbfldisk";
+ } else {
+ for (i = 0; type2icon[i].type != NULL; i++)
+ if (g_str_equal(buf + 8, type2icon[i].type))
+ break;
+
+ type = type2icon[i].label;
+ icon = type2icon[i].icon;
+ }
+ }
+
+ gchar *devid = g_strdup_printf("SCSI%d", n);
+ scsi_storage_list = h_strdup_cprintf("$%s$%s=\n", scsi_storage_list, devid, model);
+ storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, model, icon);
+
+ gchar *strhash = g_strdup_printf(_("[Device Information]\n"
+ "Model=%s\n"), model);
+
+ const gchar *url = vendor_get_url(model);
+ if (url) {
+ strhash = h_strdup_cprintf(_("Vendor=%s (%s)\n"),
+ strhash,
+ vendor_get_name(model),
+ url);
+ } else {
+ strhash = h_strdup_cprintf(_("Vendor=%s\n"),
+ strhash,
+ vendor_get_name(model));
+ }
+
+ strhash = h_strdup_cprintf(_("Type=%s\n"
+ "Revision=%s\n"
+ "[SCSI Controller]\n"
+ "Controller=scsi%d\n"
+ "Channel=%d\n"
+ "ID=%d\n" "LUN=%d\n"),
+ strhash,
+ type,
+ revision,
+ scsi_controller,
+ scsi_channel,
+ scsi_id,
+ scsi_lun);
+ moreinfo_add_with_prefix("DEV", devid, strhash);
+ g_free(devid);
+
+ g_free(model);
+ g_free(revision);
+ g_free(vendor);
+
+ scsi_controller = scsi_channel = scsi_id = scsi_lun = 0;
+ }
+ }
+ fclose(proc_scsi);
+ }
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, scsi_storage_list, NULL);
+ g_free(scsi_storage_list);
+ }
+}
+
+void __scan_ide_devices(void)
+{
+ FILE *proc_ide;
+ gchar *device, iface, *model, *media, *pgeometry = NULL, *lgeometry = NULL;
+ gint n = 0, i = 0, cache, nn = 0;
+ gchar *capab = NULL, *speed = NULL, *driver = NULL, *ide_storage_list;
+
+ /* remove old devices from global device table */
+ moreinfo_del_with_prefix("DEV:IDE");
+
+ ide_storage_list = g_strdup(_("\n[IDE Disks]\n"));
+
+ iface = 'a';
+ for (i = 0; i <= 16; i++) {
+ device = g_strdup_printf("/proc/ide/hd%c/model", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ gchar buf[128];
+
+ cache = 0;
+
+ proc_ide = fopen(device, "r");
+ if (!proc_ide)
+ continue;
+
+ (void) fgets(buf, 128, proc_ide);
+ fclose(proc_ide);
+
+ buf[strlen(buf) - 1] = 0;
+
+ model = g_strdup(buf);
+
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/media", iface);
+ proc_ide = fopen(device, "r");
+ if (!proc_ide) {
+ free(model);
+ continue;
+ }
+
+ (void) fgets(buf, 128, proc_ide);
+ fclose(proc_ide);
+ buf[strlen(buf) - 1] = 0;
+
+ media = g_strdup(buf);
+ if (g_str_equal(media, "cdrom")) {
+ /* obtain cd-rom drive information from cdrecord */
+ GTimer *timer;
+ gchar *tmp = g_strdup_printf("cdrecord dev=/dev/hd%c -prcap 2>/dev/stdout", iface);
+ FILE *prcap;
+
+ if ((prcap = popen(tmp, "r"))) {
+ /* we need a timeout so cdrecord does not try to get information on cd drives
+ with inserted media, which is not possible currently. half second should be
+ enough. */
+ timer = g_timer_new();
+ g_timer_start(timer);
+
+ while (fgets(buf, 128, prcap)
+ && g_timer_elapsed(timer, NULL) < 0.5) {
+ if (g_str_has_prefix(buf, " Does")) {
+ if (g_str_has_suffix(buf, "media\n")
+ && !strstr(buf, "speed")) {
+ gchar *media_type = g_strstrip(strstr(buf, "Does "));
+ gchar **ttmp = g_strsplit(media_type, " ", 0);
+
+ capab = h_strdup_cprintf("\nCan %s#%d=%s\n", capab, ttmp[1], ++nn, ttmp[2]);
+
+ g_strfreev(ttmp);
+ } else if (strstr(buf, "Buffer-Underrun-Free")) {
+ capab =
+ h_strdup_cprintf
+ ("\nSupports BurnProof=%s\n", capab, strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "multi-session")) {
+ capab =
+ h_strdup_cprintf
+ ("\nCan read multi-session CDs=%s\n",
+ capab, strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "audio CDs")) {
+ capab =
+ h_strdup_cprintf
+ ("\nCan play audio CDs=%s\n", capab, strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "PREVENT/ALLOW")) {
+ capab =
+ h_strdup_cprintf
+ ("\nCan lock media=%s\n", capab, strstr(buf, "Does not") ? "No" : "Yes");
+ }
+ } else if ((strstr(buf, "read")
+ || strstr(buf, "write"))
+ && strstr(buf, "kB/s")) {
+ speed =
+ g_strconcat(speed ? speed : "", strreplacechr(g_strstrip(buf), ":", '='), "\n", NULL);
+ } else if (strstr(buf, "Device seems to be")) {
+ driver = g_strdup_printf(_("Driver=%s\n"), strchr(buf, ':') + 1);
+ }
+ }
+
+ pclose(prcap);
+ g_timer_destroy(timer);
+ }
+
+ g_free(tmp);
+ }
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/cache", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ proc_ide = fopen(device, "r");
+ if (proc_ide) {
+ (void) fscanf(proc_ide, "%d", &cache);
+ fclose(proc_ide);
+ } else {
+ cache = 0;
+ }
+ }
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/geometry", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ gchar *tmp;
+
+ proc_ide = fopen(device, "r");
+ if (proc_ide) {
+ (void) fgets(buf, 64, proc_ide);
+ for (tmp = buf; *tmp; tmp++) {
+ if (*tmp >= '0' && *tmp <= '9')
+ break;
+ }
+
+ pgeometry = g_strdup(g_strstrip(tmp));
+
+ (void) fgets(buf, 64, proc_ide);
+ for (tmp = buf; *tmp; tmp++) {
+ if (*tmp >= '0' && *tmp <= '9')
+ break;
+ }
+ lgeometry = g_strdup(g_strstrip(tmp));
+
+ fclose(proc_ide);
+ } else {
+ pgeometry = g_strdup("Unknown");
+ lgeometry = g_strdup("Unknown");
+ }
+
+ }
+ g_free(device);
+
+ n++;
+
+ gchar *devid = g_strdup_printf("IDE%d", n);
+
+ ide_storage_list = h_strdup_cprintf("$%s$%s=\n", ide_storage_list, devid, model);
+ storage_icons =
+ h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons,
+ devid, model, g_str_equal(media, "cdrom") ? "cdrom" : "hdd");
+
+ gchar *strhash = g_strdup_printf(_("[Device Information]\n" "Model=%s\n"),
+ model);
+
+ const gchar *url = vendor_get_url(model);
+
+ if (url) {
+ strhash = h_strdup_cprintf(_("Vendor=%s (%s)\n"), strhash, vendor_get_name(model), url);
+ } else {
+ strhash = h_strdup_cprintf(_("Vendor=%s\n"), strhash, vendor_get_name(model));
+ }
+
+ strhash = h_strdup_cprintf(_("Device Name=hd%c\n"
+ "Media=%s\n" "Cache=%dkb\n"), strhash, iface, media, cache);
+ if (driver) {
+ strhash = h_strdup_cprintf("%s\n", strhash, driver);
+
+ g_free(driver);
+ driver = NULL;
+ }
+
+ if (pgeometry && lgeometry) {
+ strhash = h_strdup_cprintf(_("[Geometry]\n"
+ "Physical=%s\n" "Logical=%s\n"), strhash, pgeometry, lgeometry);
+
+ g_free(pgeometry);
+ pgeometry = NULL;
+ g_free(lgeometry);
+ lgeometry = NULL;
+ }
+
+ if (capab) {
+ strhash = h_strdup_cprintf(_("[Capabilities]\n%s"), strhash, capab);
+
+ g_free(capab);
+ capab = NULL;
+ }
+
+ if (speed) {
+ strhash = h_strdup_cprintf(_("[Speeds]\n%s"), strhash, speed);
+
+ g_free(speed);
+ speed = NULL;
+ }
+
+ moreinfo_add_with_prefix("DEV", devid, strhash);
+ g_free(devid);
+ g_free(model);
+ } else {
+ g_free(device);
+ }
+
+ iface++;
+ }
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, ide_storage_list, NULL);
+ g_free(ide_storage_list);
+ }
+}
diff --git a/modules/devices/usb.c b/modules/devices/usb.c
new file mode 100644
index 00000000..3a93a3b6
--- /dev/null
+++ b/modules/devices/usb.c
@@ -0,0 +1,381 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 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
+ */
+/*
+ * FIXME:
+ * - listing with sysfs does not generate device hierarchy
+ */
+
+#include <string.h>
+
+#include "hardinfo.h"
+#include "devices.h"
+
+gchar *usb_list = NULL;
+
+void __scan_usb_sysfs_add_device(gchar * endpoint, int n)
+{
+ gchar *manufacturer, *product, *mxpwr, *tmp, *strhash;
+ gint bus, classid, vendor, prodid;
+ gfloat version, speed;
+
+ classid = h_sysfs_read_int(endpoint, "bDeviceClass");
+ vendor = h_sysfs_read_int(endpoint, "idVendor");
+ prodid = h_sysfs_read_int(endpoint, "idProduct");
+ bus = h_sysfs_read_int(endpoint, "busnum");
+ speed = h_sysfs_read_float(endpoint, "speed");
+ version = h_sysfs_read_float(endpoint, "version");
+
+ if (!(mxpwr = h_sysfs_read_string(endpoint, "bMaxPower"))) {
+ mxpwr = g_strdup("0 mA");
+ }
+
+ if (!(manufacturer = h_sysfs_read_string(endpoint, "manufacturer"))) {
+ manufacturer = g_strdup("Unknown");
+ }
+
+ if (!(product = h_sysfs_read_string(endpoint, "product"))) {
+ if (classid == 9) {
+ product = g_strdup_printf("USB %.2f Hub", version);
+ } else {
+ product = g_strdup_printf("Unknown USB %.2f Device (class %d)", version, classid);
+ }
+ }
+
+ const gchar *url = vendor_get_url(manufacturer);
+ if (url) {
+ tmp = g_strdup_printf("%s (%s)", vendor_get_name(manufacturer), url);
+
+ g_free(manufacturer);
+ manufacturer = tmp;
+ }
+
+ tmp = g_strdup_printf("USB%d", n);
+ usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product);
+
+ strhash = g_strdup_printf("[Device Information]\n"
+ "Product=%s\n"
+ "Manufacturer=%s\n"
+ "Speed=%.2fMbit/s\n"
+ "Max Current=%s\n"
+ "[Misc]\n"
+ "USB Version=%.2f\n"
+ "Class=0x%x\n"
+ "Vendor=0x%x\n"
+ "Product ID=0x%x\n"
+ "Bus=%d\n",
+ product,
+ manufacturer,
+ speed,
+ mxpwr,
+ version, classid, vendor, prodid, bus);
+
+ moreinfo_add_with_prefix("DEV", tmp, strhash);
+ g_free(tmp);
+ g_free(manufacturer);
+ g_free(product);
+ g_free(mxpwr);
+}
+
+gboolean __scan_usb_sysfs(void)
+{
+ GDir *sysfs;
+ gchar *filename;
+ const gchar *sysfs_path = "/sys/class/usb_endpoint";
+ gint usb_device_number = 0;
+
+ if (!(sysfs = g_dir_open(sysfs_path, 0, NULL))) {
+ return FALSE;
+ }
+
+ if (usb_list) {
+ moreinfo_del_with_prefix("DEV:USB");
+ g_free(usb_list);
+ }
+ usb_list = g_strdup("[USB Devices]\n");
+
+ while ((filename = (gchar *) g_dir_read_name(sysfs))) {
+ gchar *endpoint =
+ g_build_filename(sysfs_path, filename, "device", NULL);
+ gchar *temp;
+
+ temp = g_build_filename(endpoint, "idVendor", NULL);
+ if (g_file_test(temp, G_FILE_TEST_EXISTS)) {
+ __scan_usb_sysfs_add_device(endpoint, ++usb_device_number);
+ }
+
+ g_free(temp);
+ g_free(endpoint);
+ }
+
+ g_dir_close(sysfs);
+
+ return usb_device_number > 0;
+}
+
+gboolean __scan_usb_procfs(void)
+{
+ FILE *dev;
+ gchar buffer[128];
+ gchar *tmp, *manuf = NULL, *product = NULL, *mxpwr = NULL;
+ gint bus = 0, level = 0, port = 0, classid = 0, trash;
+ gint vendor = 0, prodid = 0;
+ gfloat ver = 0.0f, rev = 0.0f, speed = 0.0f;
+ int n = 0;
+
+ dev = fopen("/proc/bus/usb/devices", "r");
+ if (!dev)
+ return 0;
+
+ if (usb_list) {
+ moreinfo_del_with_prefix("DEV:USB");
+ g_free(usb_list);
+ }
+ usb_list = g_strdup("[USB Devices]\n");
+
+ while (fgets(buffer, 128, dev)) {
+ tmp = buffer;
+
+ switch (*tmp) {
+ case 'T':
+ sscanf(tmp,
+ "T: Bus=%d Lev=%d Prnt=%d Port=%d Cnt=%d Dev#=%d Spd=%f",
+ &bus, &level, &trash, &port, &trash, &trash, &speed);
+ break;
+ case 'D':
+ sscanf(tmp, "D: Ver=%f Cls=%x", &ver, &classid);
+ break;
+ case 'P':
+ sscanf(tmp, "P: Vendor=%x ProdID=%x Rev=%f", &vendor, &prodid, &rev);
+ break;
+ case 'S':
+ if (strstr(tmp, "Manufacturer=")) {
+ manuf = g_strdup(strchr(tmp, '=') + 1);
+ remove_linefeed(manuf);
+ } else if (strstr(tmp, "Product=")) {
+ product = g_strdup(strchr(tmp, '=') + 1);
+ remove_linefeed(product);
+ }
+ break;
+ case 'C':
+ mxpwr = strstr(buffer, "MxPwr=") + 6;
+
+ tmp = g_strdup_printf("USB%d", ++n);
+
+ if (product && *product == '\0') {
+ g_free(product);
+ if (classid == 9) {
+ product = g_strdup_printf("USB %.2f Hub", ver);
+ } else {
+ product = g_strdup_printf("Unknown USB %.2f Device (class %d)", ver, classid);
+ }
+ }
+
+ if (classid == 9) { /* hub */
+ usb_list = h_strdup_cprintf("[%s#%d]\n", usb_list, product, n);
+ } else { /* everything else */
+ usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product);
+
+ const gchar *url = vendor_get_url(manuf);
+ if (url) {
+ gchar *tmp = g_strdup_printf("%s (%s)", vendor_get_name(manuf),
+ url);
+ g_free(manuf);
+ manuf = tmp;
+ }
+
+ gchar *strhash = g_strdup_printf("[Device Information]\n" "Product=%s\n",
+ product);
+ if (manuf && strlen(manuf))
+ strhash = h_strdup_cprintf("Manufacturer=%s\n", strhash, manuf);
+
+ strhash = h_strdup_cprintf("[Port #%d]\n"
+ "Speed=%.2fMbit/s\n"
+ "Max Current=%s\n"
+ "[Misc]\n"
+ "USB Version=%.2f\n"
+ "Revision=%.2f\n"
+ "Class=0x%x\n"
+ "Vendor=0x%x\n"
+ "Product ID=0x%x\n"
+ "Bus=%d\n" "Level=%d\n",
+ strhash, port, speed, mxpwr, ver, rev, classid, vendor, prodid, bus, level);
+
+ moreinfo_add_with_prefix("DEV", tmp, strhash);
+ g_free(tmp);
+ }
+
+ g_free(manuf);
+ g_free(product);
+ manuf = g_strdup("");
+ product = g_strdup("");
+ port = classid = 0;
+ }
+ }
+
+ fclose(dev);
+
+ return n > 0;
+}
+
+
+void __scan_usb_lsusb_add_device(char *buffer, int bufsize, FILE * lsusb, int usb_device_number)
+{
+ gint bus, device, vendor_id, product_id;
+ gchar *version = NULL, *product = NULL, *vendor = NULL, *dev_class = NULL, *int_class = NULL;
+ gchar *max_power = NULL, *name = NULL;
+ gchar *tmp, *strhash;
+ long position = 0;
+
+ g_strstrip(buffer);
+ sscanf(buffer, "Bus %d Device %d: ID %x:%x", &bus, &device, &vendor_id, &product_id);
+ name = g_strdup(buffer + 33);
+
+ for (fgets(buffer, bufsize, lsusb); position >= 0 && fgets(buffer, bufsize, lsusb); position = ftell(lsusb)) {
+ g_strstrip(buffer);
+
+ if (g_str_has_prefix(buffer, "idVendor")) {
+ g_free(vendor);
+ vendor = g_strdup(buffer + 26);
+ } else if (g_str_has_prefix(buffer, "idProduct")) {
+ g_free(product);
+ product = g_strdup(buffer + 26);
+ } else if (g_str_has_prefix(buffer, "MaxPower")) {
+ g_free(max_power);
+ max_power = g_strdup(buffer + 9);
+ } else if (g_str_has_prefix(buffer, "bcdUSB")) {
+ g_free(version);
+ version = g_strdup(buffer + 7);
+ } else if (g_str_has_prefix(buffer, "bDeviceClass")) {
+ g_free(dev_class);
+ dev_class = g_strdup(buffer + 14);
+ } else if (g_str_has_prefix(buffer, "bInterfaceClass")) {
+ g_free(int_class);
+ int_class = g_strdup(buffer + 16);
+ } else if (g_str_has_prefix(buffer, "Bus ")) {
+ /* device separator */
+ fseek(lsusb, position, SEEK_SET);
+ break;
+ }
+ }
+
+ if (dev_class && strstr(dev_class, "0 (Defined at Interface level)")) {
+ g_free(dev_class);
+ if (int_class) {
+ dev_class = int_class;
+ } else {
+ dev_class = g_strdup("Unknown");
+ }
+ } else
+ dev_class = g_strdup("Unknown");
+
+ tmp = g_strdup_printf("USB%d", usb_device_number);
+ usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, name);
+
+ strhash = g_strdup_printf("[Device Information]\n"
+ "Product=%s\n"
+ "Manufacturer=%s\n"
+ "Max Current=%s\n"
+ "[Misc]\n"
+ "USB Version=%s\n"
+ "Class=%s\n"
+ "Vendor=0x%x\n"
+ "Product ID=0x%x\n"
+ "Bus=%d\n",
+ product ? g_strstrip(product) : "Unknown",
+ vendor ? g_strstrip(vendor) : "Unknown",
+ max_power ? g_strstrip(max_power) : "Unknown",
+ version ? g_strstrip(version) : "Unknown",
+ dev_class ? g_strstrip(dev_class) : "Unknown", vendor_id, product_id, bus);
+
+ moreinfo_add_with_prefix("DEV", tmp, strhash);
+ g_free(vendor);
+ g_free(product);
+ g_free(max_power);
+ g_free(dev_class);
+ g_free(version);
+ g_free(tmp);
+ g_free(name);
+}
+
+gboolean __scan_usb_lsusb(void)
+{
+ static gchar *lsusb_path = NULL;
+ int usb_device_number = 0;
+ FILE *lsusb;
+ FILE *temp_lsusb;
+ char buffer[512], *temp;
+
+ if (!lsusb_path) {
+ if (!(lsusb_path = find_program("lsusb"))) {
+ DEBUG("lsusb not found");
+
+ return FALSE;
+ }
+ }
+
+ temp = g_strdup_printf("%s -v | tr '[]' '()'", lsusb_path);
+ if (!(lsusb = popen(temp, "r"))) {
+ DEBUG("cannot run %s", lsusb_path);
+
+ g_free(temp);
+ return FALSE;
+ }
+
+ temp_lsusb = tmpfile();
+ if (!temp_lsusb) {
+ DEBUG("cannot create temporary file for lsusb");
+ pclose(lsusb);
+ return FALSE;
+ }
+
+ while (fgets(buffer, sizeof(buffer), lsusb)) {
+ fputs(buffer, temp_lsusb);
+ }
+
+ pclose(lsusb);
+
+ // rewind file so we can read from it
+ fseek(temp_lsusb, 0, SEEK_SET);
+
+ g_free(temp);
+
+ if (usb_list) {
+ moreinfo_del_with_prefix("DEV:USB");
+ g_free(usb_list);
+ }
+ usb_list = g_strdup("[USB Devices]\n");
+
+ while (fgets(buffer, sizeof(buffer), temp_lsusb)) {
+ if (g_str_has_prefix(buffer, "Bus ")) {
+ __scan_usb_lsusb_add_device(buffer, sizeof(buffer), temp_lsusb, ++usb_device_number);
+ }
+ }
+
+ fclose(temp_lsusb);
+
+ return usb_device_number > 0;
+}
+
+void __scan_usb(void)
+{
+ if (!__scan_usb_procfs()) {
+ if (!__scan_usb_sysfs()) {
+ __scan_usb_lsusb();
+ }
+ }
+}
diff --git a/modules/devices/x86/processor.c b/modules/devices/x86/processor.c
new file mode 100644
index 00000000..7935a83d
--- /dev/null
+++ b/modules/devices/x86/processor.c
@@ -0,0 +1,727 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 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 "hardinfo.h"
+#include "devices.h"
+
+/*
+ * This function is partly based on x86cpucaps
+ * by Osamu Kayasono <jacobi@jcom.home.ne.jp>
+ */
+void get_processor_strfamily(Processor * processor)
+{
+ gint family = processor->family;
+ gint model = processor->model;
+
+ if (g_str_equal(processor->vendor_id, "GenuineIntel")) {
+ if (family == 4) {
+ processor->strmodel = g_strdup("i486 series");
+ } else if (family == 5) {
+ if (model < 4) {
+ processor->strmodel = g_strdup("Pentium Classic");
+ } else {
+ processor->strmodel = g_strdup("Pentium MMX");
+ }
+ } else if (family == 6) {
+ if (model <= 1) {
+ processor->strmodel = g_strdup("Pentium Pro");
+ } else if (model < 7) {
+ processor->strmodel = g_strdup("Pentium II/Pentium II Xeon/Celeron");
+ } else if (model == 9) {
+ processor->strmodel = g_strdup("Pentium M");
+ } else {
+ processor->strmodel = g_strdup("Pentium III/Pentium III Xeon/Celeron/Core Duo/Core Duo 2");
+ }
+ } else if (family > 6) {
+ processor->strmodel = g_strdup("Pentium 4");
+ } else {
+ processor->strmodel = g_strdup("i386 class");
+ }
+ } else if (g_str_equal(processor->vendor_id, "AuthenticAMD")) {
+ if (family == 4) {
+ if (model <= 9) {
+ processor->strmodel = g_strdup("AMD i80486 series");
+ } else {
+ processor->strmodel = g_strdup("AMD 5x86");
+ }
+ } else if (family == 5) {
+ if (model <= 3) {
+ processor->strmodel = g_strdup("AMD K5");
+ } else if (model <= 7) {
+ processor->strmodel = g_strdup("AMD K6");
+ } else if (model == 8) {
+ processor->strmodel = g_strdup("AMD K6-2");
+ } else if (model == 9) {
+ processor->strmodel = g_strdup("AMD K6-III");
+ } else {
+ processor->strmodel = g_strdup("AMD K6-2+/III+");
+ }
+ } else if (family == 6) {
+ if (model == 1) {
+ processor->strmodel = g_strdup("AMD Athlon (K7)");
+ } else if (model == 2) {
+ processor->strmodel = g_strdup("AMD Athlon (K75)");
+ } else if (model == 3) {
+ processor->strmodel = g_strdup("AMD Duron (Spitfire)");
+ } else if (model == 4) {
+ processor->strmodel = g_strdup("AMD Athlon (Thunderbird)");
+ } else if (model == 6) {
+ processor->strmodel = g_strdup("AMD Athlon XP/MP/4 (Palomino)");
+ } else if (model == 7) {
+ processor->strmodel = g_strdup("AMD Duron (Morgan)");
+ } else if (model == 8) {
+ processor->strmodel = g_strdup("AMD Athlon XP/MP (Thoroughbred)");
+ } else if (model == 10) {
+ processor->strmodel = g_strdup("AMD Athlon XP/MP (Barton)");
+ } else {
+ processor->strmodel = g_strdup("AMD Athlon (unknown)");
+ }
+ } else if (family > 6) {
+ processor->strmodel = g_strdup("AMD Opteron/Athlon64/FX");
+ } else {
+ processor->strmodel = g_strdup("AMD i386 class");
+ }
+ } else if (g_str_equal(processor->vendor_id, "CyrixInstead")) {
+ if (family == 4) {
+ processor->strmodel = g_strdup("Cyrix 5x86");
+ } else if (family == 5) {
+ processor->strmodel = g_strdup("Cyrix M1 (6x86)");
+ } else if (family == 6) {
+ if (model == 0) {
+ processor->strmodel = g_strdup("Cyrix M2 (6x86MX)");
+ } else if (model <= 5) {
+ processor->strmodel = g_strdup("VIA Cyrix III (M2 core)");
+ } else if (model == 6) {
+ processor->strmodel = g_strdup("VIA Cyrix III (WinChip C5A)");
+ } else if (model == 7) {
+ processor->strmodel = g_strdup("VIA Cyrix III (WinChip C5B/C)");
+ } else {
+ processor->strmodel = g_strdup("VIA Cyrix III (WinChip C5C-T)");
+ }
+ } else {
+ processor->strmodel = g_strdup("Cyrix i386 class");
+ }
+ } else if (g_str_equal(processor->vendor_id, "CentaurHauls")) {
+ if (family == 5) {
+ if (model <= 4) {
+ processor->strmodel = g_strdup("Centaur WinChip C6");
+ } else if (model <= 8) {
+ processor->strmodel = g_strdup("Centaur WinChip 2");
+ } else {
+ processor->strmodel = g_strdup("Centaur WinChip 2A");
+ }
+ } else {
+ processor->strmodel = g_strdup("Centaur i386 class");
+ }
+ } else if (g_str_equal(processor->vendor_id, "GenuineTMx86")) {
+ processor->strmodel = g_strdup("Transmeta Crusoe TM3x00/5x00");
+ } else {
+ processor->strmodel = g_strdup("Unknown");
+ }
+}
+
+static gchar *__cache_get_info_as_string(Processor *processor)
+{
+ gchar *result = g_strdup("");
+ GSList *cache_list;
+ ProcessorCache *cache;
+
+ if (!processor->cache) {
+ return g_strdup(_("Cache information not available=\n"));
+ }
+
+ for (cache_list = processor->cache; cache_list; cache_list = cache_list->next) {
+ cache = (ProcessorCache *)cache_list->data;
+
+ result = h_strdup_cprintf("Level %d (%s)=%d-way set-associative, %d sets, %dKB size\n",
+ result,
+ cache->level,
+ cache->type,
+ cache->ways_of_associativity,
+ cache->number_of_sets,
+ cache->size);
+ }
+
+ return result;
+}
+
+static void __cache_obtain_info(Processor *processor)
+{
+ ProcessorCache *cache;
+ gchar *endpoint, *entry, *index;
+ gint i;
+ gint processor_number = processor->id;
+
+ endpoint = g_strdup_printf("/sys/devices/system/cpu/cpu%d/cache", processor_number);
+
+ for (i = 0; ; i++) {
+ cache = g_new0(ProcessorCache, 1);
+
+ index = g_strdup_printf("index%d/", i);
+
+ entry = g_strconcat(index, "type", NULL);
+ cache->type = h_sysfs_read_string(endpoint, entry);
+ g_free(entry);
+
+ if (!cache->type) {
+ g_free(cache);
+ g_free(index);
+ goto fail;
+ }
+
+ entry = g_strconcat(index, "level", NULL);
+ cache->level = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ entry = g_strconcat(index, "number_of_sets", NULL);
+ cache->number_of_sets = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ entry = g_strconcat(index, "physical_line_partition", NULL);
+ cache->physical_line_partition = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ entry = g_strconcat(index, "size", NULL);
+ cache->size = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+
+ entry = g_strconcat(index, "ways_of_associativity", NULL);
+ cache->ways_of_associativity = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ g_free(index);
+
+ processor->cache = g_slist_append(processor->cache, cache);
+ }
+
+fail:
+ g_free(endpoint);
+}
+
+int processor_has_flag(gchar * strflags, gchar * strflag)
+{
+ gchar **flags;
+ gint ret = 0;
+ if (strflags == NULL || strflag == NULL)
+ return 0;
+ flags = g_strsplit(strflags, " ", 0);
+ ret = g_strv_contains((const gchar * const *)flags, strflag);
+ g_strfreev(flags);
+ return ret;
+}
+
+static gint get_cpu_int(const gchar* file, gint cpuid) {
+ gchar *tmp0 = NULL;
+ gchar *tmp1 = NULL;
+ gint ret = 0;
+
+ tmp0 = g_strdup_printf("/sys/devices/system/cpu/cpu%d/%s", cpuid, file);
+ g_file_get_contents(tmp0, &tmp1, NULL, NULL);
+ if (tmp1)
+ ret = atol(tmp1);
+
+ g_free(tmp0);
+ g_free(tmp1);
+ return ret;
+}
+
+GSList *processor_scan(void)
+{
+ GSList *procs = NULL, *l = NULL;
+ Processor *processor = NULL;
+ FILE *cpuinfo;
+ gchar buffer[512];
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (!cpuinfo)
+ return NULL;
+
+ while (fgets(buffer, 512, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+ if (!tmp[1] || !tmp[0]) {
+ g_strfreev(tmp);
+ continue;
+ }
+
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ if (g_str_has_prefix(tmp[0], "processor")) {
+ /* finish previous */
+ if (processor)
+ procs = g_slist_append(procs, processor);
+
+ /* start next */
+ processor = g_new0(Processor, 1);
+ processor->id = atol(tmp[1]);
+ g_strfreev(tmp);
+ continue;
+ }
+
+ if (processor) {
+ get_str("model name", processor->model_name);
+ get_str("vendor_id", processor->vendor_id);
+ get_str("flags", processor->flags);
+ get_str("bugs", processor->bugs);
+ get_str("power management", processor->pm);
+ get_int("cache size", processor->cache_size);
+ get_float("cpu MHz", processor->cpu_mhz);
+ get_float("bogomips", processor->bogomips);
+
+ get_str("fpu", processor->has_fpu);
+
+ get_str("fdiv_bug", processor->bug_fdiv);
+ get_str("hlt_bug", processor->bug_hlt);
+ get_str("f00f_bug", processor->bug_f00f);
+ get_str("coma_bug", processor->bug_coma);
+
+ get_int("model", processor->model);
+ get_int("cpu family", processor->family);
+ get_int("stepping", processor->stepping);
+ }
+ g_strfreev(tmp);
+ }
+
+ /* finish last */
+ if (processor)
+ procs = g_slist_append(procs, processor);
+
+ for (l = procs; l; l = l->next) {
+ processor = (Processor *) l->data;
+
+ get_processor_strfamily(processor);
+ __cache_obtain_info(processor);
+
+ if (processor->bugs == NULL || g_strcmp0(processor->bugs, "") == 0) {
+ g_free(processor->bugs);
+ /* make bugs list on old kernels that don't offer one */
+ processor->bugs = g_strdup_printf("%s%s%s%s%s%s%s%s%s%s",
+ /* the oldest bug workarounds indicated in /proc/cpuinfo */
+ processor->bug_fdiv ? " fdiv" : "",
+ processor->bug_hlt ? " _hlt" : "",
+ processor->bug_f00f ? " f00f" : "",
+ processor->bug_coma ? " coma" : "",
+ /* these bug workarounds were reported as "features" in older kernels */
+ processor_has_flag(processor->flags, "fxsave_leak") ? " fxsave_leak" : "",
+ processor_has_flag(processor->flags, "clflush_monitor") ? " clflush_monitor" : "",
+ processor_has_flag(processor->flags, "11ap") ? " 11ap" : "",
+ processor_has_flag(processor->flags, "tlb_mmatch") ? " tlb_mmatch" : "",
+ processor_has_flag(processor->flags, "apic_c1e") ? " apic_c1e" : "",
+ ""); /* just to make adding lines easier */
+ g_strchug(processor->bugs);
+ }
+
+ if (processor->pm == NULL || g_strcmp0(processor->pm, "") == 0) {
+ g_free(processor->pm);
+ /* make power management list on old kernels that don't offer one */
+ processor->pm = g_strdup_printf("%s%s",
+ /* "hw_pstate" -> "hwpstate" */
+ processor_has_flag(processor->flags, "hw_pstate") ? " hwpstate" : "",
+ ""); /* just to make adding lines easier */
+ g_strchug(processor->pm);
+ }
+
+ /* freq */
+ processor->cpukhz_cur = get_cpu_int("cpufreq/scaling_cur_freq", processor->id);
+ processor->cpukhz_min = get_cpu_int("cpufreq/scaling_min_freq", processor->id);
+ processor->cpukhz_max = get_cpu_int("cpufreq/scaling_max_freq", processor->id);
+ if (processor->cpukhz_max)
+ processor->cpu_mhz = processor->cpukhz_max / 1000;
+ }
+
+ fclose(cpuinfo);
+
+ return procs;
+}
+
+/*
+ * Sources:
+ * - Linux' cpufeature.h
+ * - http://gentoo-wiki.com/Cpuinfo
+ * - Intel IA-32 Architecture Software Development Manual
+ * - https://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean
+ */
+static struct {
+ char *name, *meaning;
+} flag_meaning[] = {
+ { "3dnow", "3DNow! Technology" },
+ { "3dnowext", "Extended 3DNow! Technology" },
+ { "fpu", "Floating Point Unit" },
+ { "vme", "Virtual 86 Mode Extension" },
+ { "de", "Debug Extensions - I/O breakpoints" },
+ { "pse", "Page Size Extensions (4MB pages)" },
+ { "tsc", "Time Stamp Counter and RDTSC instruction" },
+ { "msr", "Model Specific Registers" },
+ { "pae", "Physical Address Extensions" },
+ { "mce", "Machine Check Architeture" },
+ { "cx8", "CMPXCHG8 instruction" },
+ { "apic", "Advanced Programmable Interrupt Controller" },
+ { "sep", "Fast System Call (SYSENTER/SYSEXIT)" },
+ { "mtrr", "Memory Type Range Registers" },
+ { "pge", "Page Global Enable" },
+ { "mca", "Machine Check Architecture" },
+ { "cmov", "Conditional Move instruction" },
+ { "pat", "Page Attribute Table" },
+ { "pse36", "36bit Page Size Extensions" },
+ { "psn", "96 bit Processor Serial Number" },
+ { "mmx", "MMX technology" },
+ { "mmxext", "Extended MMX Technology" },
+ { "cflush", "Cache Flush" },
+ { "dtes", "Debug Trace Store" },
+ { "fxsr", "FXSAVE and FXRSTOR instructions" },
+ { "kni", "Streaming SIMD instructions" },
+ { "xmm", "Streaming SIMD instructions" },
+ { "ht", "HyperThreading" },
+ { "mp", "Multiprocessing Capable" },
+ { "sse", "SSE instructions" },
+ { "sse2", "SSE2 (WNI) instructions" },
+ { "acc", "Automatic Clock Control" },
+ { "ia64", "IA64 Instructions" },
+ { "syscall", "SYSCALL and SYSEXIT instructions" },
+ { "nx", "No-execute Page Protection" },
+ { "xd", "Execute Disable" },
+ { "clflush", "Cache Line Flush instruction" },
+ { "acpi", "Thermal Monitor and Software Controlled Clock" },
+ { "dts", "Debug Store" },
+ { "ss", "Self Snoop" },
+ { "tm", "Thermal Monitor" },
+ { "pbe", "Pending Break Enable" },
+ { "pb", "Pending Break Enable" },
+ { "pn", "Processor serial number" },
+ { "ds", "Debug Store" },
+ { "xmm2", "Streaming SIMD Extensions-2" },
+ { "xmm3", "Streaming SIMD Extensions-3" },
+ { "selfsnoop", "CPU self snoop" },
+ { "rdtscp", "RDTSCP" },
+ { "recovery", "CPU in recovery mode" },
+ { "longrun", "Longrun power control" },
+ { "lrti", "LongRun table interface" },
+ { "cxmmx", "Cyrix MMX extensions" },
+ { "k6_mtrr", "AMD K6 nonstandard MTRRs" },
+ { "cyrix_arr", "Cyrix ARRs (= MTRRs)" },
+ { "centaur_mcr","Centaur MCRs (= MTRRs)" },
+ { "constant_tsc","TSC ticks at a constant rate" },
+ { "up", "smp kernel running on up" },
+ { "fxsave_leak","FXSAVE leaks FOP/FIP/FOP" },
+ { "arch_perfmon","Intel Architectural PerfMon" },
+ { "pebs", "Precise-Event Based Sampling" },
+ { "bts", "Branch Trace Store" },
+ { "sync_rdtsc", "RDTSC synchronizes the CPU" },
+ { "rep_good", "rep microcode works well on this CPU" },
+ { "mwait", "Monitor/Mwait support" },
+ { "ds_cpl", "CPL Qualified Debug Store" },
+ { "est", "Enhanced SpeedStep" },
+ { "tm2", "Thermal Monitor 2" },
+ { "cid", "Context ID" },
+ { "xtpr", "Send Task Priority Messages" },
+ { "xstore", "on-CPU RNG present (xstore insn)" },
+ { "xstore_en", "on-CPU RNG enabled" },
+ { "xcrypt", "on-CPU crypto (xcrypt insn)" },
+ { "xcrypt_en", "on-CPU crypto enabled" },
+ { "ace2", "Advanced Cryptography Engine v2" },
+ { "ace2_en", "ACE v2 enabled" },
+ { "phe", "PadLock Hash Engine" },
+ { "phe_en", "PHE enabled" },
+ { "pmm", "PadLock Montgomery Multiplier" },
+ { "pmm_en", "PMM enabled" },
+ { "lahf_lm", "LAHF/SAHF in long mode" },
+ { "cmp_legacy", "HyperThreading not valid" },
+ { "lm", "LAHF/SAHF in long mode" },
+ { "ds_cpl", "CPL Qualified Debug Store" },
+ { "vmx", "Virtualization support (Intel)" },
+ { "svm", "Virtualization support (AMD)" },
+ { "est", "Enhanced SpeedStep" },
+ { "tm2", "Thermal Monitor 2" },
+ { "ssse3", "Supplemental Streaming SIMD Extension 3" },
+ { "cx16", "CMPXCHG16B instruction" },
+ { "xptr", "Send Task Priority Messages" },
+ { "pebs", "Precise Event Based Sampling" },
+ { "bts", "Branch Trace Store" },
+ { "ida", "Intel Dynamic Acceleration" },
+ { "arch_perfmon","Intel Architectural PerfMon" },
+ { "pni", "Streaming SIMD Extension 3 (Prescott New Instruction)" },
+ { "rep_good", "rep microcode works well on this CPU" },
+ { "ts", "Thermal Sensor" },
+ { "sse3", "Streaming SIMD Extension 3" },
+ { "sse4", "Streaming SIMD Extension 4" },
+ { "tni", "Tejas New Instruction" },
+ { "nni", "Nehalem New Instruction" },
+ { "tpr", "Task Priority Register" },
+ { "vid", "Voltage Identifier" },
+ { "fid", "Frequency Identifier" },
+ { "dtes64", "64-bit Debug Store" },
+ { "monitor", "Monitor/Mwait support" },
+ { "sse4_1", "Streaming SIMD Extension 4.1" },
+ { "sse4_2", "Streaming SIMD Extension 4.2" },
+ { "nopl", "NOPL instructions" },
+ { "cxmmx", "Cyrix MMX extensions" },
+ { "xtopology", "CPU topology enum extensions" },
+ { "nonstop_tsc", "TSC does not stop in C states" },
+ { "eagerfpu", "Non lazy FPU restor" },
+ { "pclmulqdq", "Perform a Carry-Less Multiplication of Quadword instruction" },
+ { "smx", "Safer mode: TXT (TPM support)" },
+ { "pdcm", "Performance capabilities" },
+ { "pcid", "Process Context Identifiers" },
+ { "x2apic", "x2APIC" },
+ { "popcnt", "Set bit count instructions" },
+ { "aes", "Advanced Encryption Standard" },
+ { "aes-ni", "Advanced Encryption Standard (New Instructions)" },
+ { "xsave", "Save Processor Extended States" },
+ { "avx", "Advanced Vector Instructions" },
+ { NULL, NULL },
+};
+
+static struct {
+ char *name, *meaning;
+} bug_meaning[] = {
+ { "f00f", "Intel F00F bug" },
+ { "fdiv", "FPU FDIV" },
+ { "coma", "Cyrix 6x86 coma" },
+ { "tlb_mmatch", "AMD Erratum 383" },
+ { "apic_c1e", "AMD Erratum 400" },
+ { "11ap", "Bad local APIC aka 11AP" },
+ { "fxsave_leak", "FXSAVE leaks FOP/FIP/FOP" },
+ { "clflush_monitor", "AAI65, CLFLUSH required before MONITOR" },
+ { "sysret_ss_attrs", "SYSRET doesn't fix up SS attrs" },
+ { "espfix", "IRET to 16-bit SS corrupts ESP/RSP high bits" },
+ { "null_seg", "Nulling a selector preserves the base" }, /* see: detect_null_seg_behavior() */
+ { "swapgs_fence","SWAPGS without input dep on GS" },
+ { "monitor", "IPI required to wake up remote CPU" },
+ { "amd_e400", "AMD Erratum 400" },
+ { NULL, NULL },
+};
+
+/* from arch/x86/kernel/cpu/powerflags.h */
+static struct {
+ char *name, *meaning;
+} pm_meaning[] = {
+ { "ts", "temperature sensor" },
+ { "fid", "frequency id control" },
+ { "vid", "voltage id control" },
+ { "ttp", "thermal trip" },
+ { "tm", "hardware thermal control" },
+ { "stc", "software thermal control" },
+ { "100mhzsteps", "100 MHz multiplier control" },
+ { "hwpstate", "hardware P-state control" },
+/* { "", "tsc invariant mapped to constant_tsc" }, */
+ { "cpb", "core performance boost" },
+ { "eff_freq_ro", "Readonly aperf/mperf" },
+ { "proc_feedback", "processor feedback interface" },
+ { "acc_power", "accumulated power mechanism" },
+ { NULL, NULL },
+};
+
+GHashTable *cpu_flags = NULL;
+
+static void
+populate_cpu_flags_list_internal()
+{
+ int i;
+
+ DEBUG("using internal CPU flags database");
+
+ for (i = 0; flag_meaning[i].name != NULL; i++) {
+ g_hash_table_insert(cpu_flags, flag_meaning[i].name,
+ flag_meaning[i].meaning);
+ }
+ for (i = 0; bug_meaning[i].name != NULL; i++) {
+ g_hash_table_insert(cpu_flags, bug_meaning[i].name,
+ bug_meaning[i].meaning);
+ }
+ for (i = 0; pm_meaning[i].name != NULL; i++) {
+ g_hash_table_insert(cpu_flags, pm_meaning[i].name,
+ pm_meaning[i].meaning);
+ }
+}
+
+void cpu_flags_init(void)
+{
+ gint i;
+ gchar *path;
+
+ cpu_flags = g_hash_table_new(g_str_hash, g_str_equal);
+
+ path = g_build_filename(g_get_home_dir(), ".hardinfo", "cpuflags.conf", NULL);
+ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ populate_cpu_flags_list_internal();
+ } else {
+ GKeyFile *flags_file;
+
+ DEBUG("using %s as CPU flags database", path);
+
+ flags_file = g_key_file_new();
+ if (g_key_file_load_from_file(flags_file, path, 0, NULL)) {
+ gchar **flag_keys;
+
+ flag_keys = g_key_file_get_keys(flags_file, "flags",
+ NULL, NULL);
+ if (!flag_keys) {
+ DEBUG("error while using %s as CPU flags database, falling back to internal",
+ path);
+ populate_cpu_flags_list_internal();
+ } else {
+ for (i = 0; flag_keys[i]; i++) {
+ gchar *meaning;
+
+ meaning = g_key_file_get_string(flags_file, "flags",
+ flag_keys[i], NULL);
+
+ g_hash_table_insert(cpu_flags, g_strdup(flag_keys[i]), meaning);
+
+ /* can't free meaning */
+ }
+
+ g_strfreev(flag_keys);
+ }
+ }
+
+ g_key_file_free(flags_file);
+ }
+
+ g_free(path);
+}
+
+gchar *processor_get_capabilities_from_flags(gchar * strflags)
+{
+ /* FIXME:
+ * - Separate between processor capabilities, additional instructions and whatnot.
+ */
+ gchar **flags, **old;
+ gchar *tmp = NULL;
+ gint j = 0;
+
+ if (!cpu_flags) {
+ cpu_flags_init();
+ }
+
+ flags = g_strsplit(strflags, " ", 0);
+ old = flags;
+
+ while (flags[j]) {
+ gchar *meaning = g_hash_table_lookup(cpu_flags, flags[j]);
+
+ if (meaning) {
+ tmp = h_strdup_cprintf("%s=%s\n", tmp, flags[j], meaning);
+ } else {
+ tmp = h_strdup_cprintf("%s=\n", tmp, flags[j]);
+ }
+ j++;
+ }
+ if (tmp == NULL || g_strcmp0(tmp, "") == 0)
+ tmp = g_strdup_printf("%s=%s\n", "empty", _("Empty List"));
+
+ g_strfreev(old);
+ return tmp;
+}
+
+gchar *processor_get_detailed_info(Processor * processor)
+{
+ gchar *tmp_flags, *tmp_bugs, *tmp_pm, *ret, *cache_info;
+
+ tmp_flags = processor_get_capabilities_from_flags(processor->flags);
+ tmp_bugs = processor_get_capabilities_from_flags(processor->bugs);
+ tmp_pm = processor_get_capabilities_from_flags(processor->pm);
+ cache_info = __cache_get_info_as_string(processor);
+
+ ret = g_strdup_printf(_("[Processor]\n"
+ "Name=%s\n"
+ "Family, model, stepping=%d, %d, %d (%s)\n"
+ "Vendor=%s\n"
+ "[Configuration]\n"
+ "Cache Size=%dkb\n"
+ "Frequency=%.2fMHz\n"
+ "BogoMIPS=%.2f\n"
+ "Byte Order=%s\n"
+ "[Frequency Scaling]\n"
+ "Minimum=%d kHz\n"
+ "Maximum=%d kHz\n"
+ "Current=%d kHz\n"
+ "[Features]\n"
+ "Has FPU=%s\n"
+ "[Cache]\n"
+ "%s\n"
+ "[Power Management]\n"
+ "%s"
+ "[Bugs]\n"
+ "%s"
+ "[Capabilities]\n"
+ "%s"),
+ processor->model_name,
+ processor->family,
+ processor->model,
+ processor->stepping,
+ processor->strmodel,
+ vendor_get_name(processor->vendor_id),
+ processor->cache_size,
+ processor->cpu_mhz, processor->bogomips,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "Little Endian",
+#else
+ "Big Endian",
+#endif
+ processor->cpukhz_min,
+ processor->cpukhz_max,
+ processor->cpukhz_cur,
+ processor->has_fpu ? processor->has_fpu : "no",
+ cache_info,
+ tmp_pm, tmp_bugs, tmp_flags);
+ g_free(tmp_flags);
+ g_free(tmp_bugs);
+ g_free(tmp_pm);
+ g_free(cache_info);
+
+ return ret;
+}
+
+gchar *processor_get_info(GSList * processors)
+{
+ Processor *processor;
+
+ if (g_slist_length(processors) > 1) {
+ gchar *ret, *tmp, *hashkey;
+ GSList *l;
+
+ tmp = g_strdup("");
+
+ for (l = processors; l; l = l->next) {
+ processor = (Processor *) l->data;
+
+ tmp = g_strdup_printf(_("%s$CPU%d$%s=%.2fMHz\n"),
+ tmp, processor->id,
+ processor->model_name,
+ processor->cpu_mhz);
+
+ hashkey = g_strdup_printf("CPU%d", processor->id);
+ moreinfo_add_with_prefix("DEV", hashkey,
+ processor_get_detailed_info(processor));
+ g_free(hashkey);
+ }
+
+ ret = g_strdup_printf("[$ShellParam$]\n"
+ "ViewType=1\n"
+ "[Processors]\n"
+ "%s", tmp);
+ g_free(tmp);
+
+ return ret;
+ }
+
+ processor = (Processor *) processors->data;
+ return processor_get_detailed_info(processor);
+}
diff --git a/modules/devices/x86_64 b/modules/devices/x86_64
new file mode 120000
index 00000000..de1ff735
--- /dev/null
+++ b/modules/devices/x86_64
@@ -0,0 +1 @@
+./x86 \ No newline at end of file
diff --git a/modules/network.c b/modules/network.c
new file mode 100644
index 00000000..18f8ba65
--- /dev/null
+++ b/modules/network.c
@@ -0,0 +1,438 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 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 <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <config.h>
+#include <time.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <hardinfo.h>
+#include <iconcache.h>
+#include <shell.h>
+
+#include <vendor.h>
+
+#include "network.h"
+
+/* Callbacks */
+gchar *callback_network();
+gchar *callback_route();
+gchar *callback_dns();
+gchar *callback_connections();
+gchar *callback_shares();
+gchar *callback_arp();
+gchar *callback_statistics();
+
+/* Scan callbacks */
+void scan_network(gboolean reload);
+void scan_route(gboolean reload);
+void scan_dns(gboolean reload);
+void scan_connections(gboolean reload);
+void scan_shares(gboolean reload);
+void scan_arp(gboolean reload);
+void scan_statistics(gboolean reload);
+
+static ModuleEntry entries[] = {
+ {N_("Interfaces"), "network-interface.png", callback_network, scan_network, MODULE_FLAG_NONE},
+ {N_("IP Connections"), "network-connections.png", callback_connections, scan_connections, MODULE_FLAG_NONE},
+ {N_("Routing Table"), "network.png", callback_route, scan_route, MODULE_FLAG_NONE},
+ {N_("ARP Table"), "module.png", callback_arp, scan_arp, MODULE_FLAG_NONE},
+ {N_("DNS Servers"), "dns.png", callback_dns, scan_dns, MODULE_FLAG_NONE},
+ {N_("Statistics"), "network-statistics.png", callback_statistics, scan_statistics, MODULE_FLAG_NONE},
+ {N_("Shared Directories"), "shares.png", callback_shares, scan_shares, MODULE_FLAG_NONE},
+ {NULL},
+};
+
+void scan_shares(gboolean reload)
+{
+ SCAN_START();
+ scan_samba();
+ scan_nfs_shared_directories();
+ SCAN_END();
+}
+
+static gchar *__statistics = NULL;
+void scan_statistics(gboolean reload)
+{
+ FILE *netstat;
+ gchar buffer[256];
+ gchar *netstat_path;
+
+ SCAN_START();
+
+ g_free(__statistics);
+ __statistics = g_strdup("");
+
+ if ((netstat_path = find_program("netstat"))) {
+ gchar *command_line = g_strdup_printf("%s -s", netstat_path);
+
+ if ((netstat = popen(command_line, "r"))) {
+ while (fgets(buffer, 256, netstat)) {
+ if (!isspace(buffer[0]) && strchr(buffer, ':')) {
+ gchar *tmp;
+
+ tmp = g_ascii_strup(strend(buffer, ':'), -1);
+
+ __statistics = h_strdup_cprintf("[%s]\n",
+ __statistics,
+ tmp);
+
+ g_free(tmp);
+ } else if (isdigit(buffer[4])) {
+ gchar *tmp1 = buffer + 4,
+ *tmp2 = tmp1;
+
+ while (*tmp2 && !isspace(*tmp2)) tmp2++;
+ *tmp2 = 0;
+ tmp2++;
+
+ *tmp2 = toupper(*tmp2);
+
+ __statistics = h_strdup_cprintf("%s=%s\n",
+ __statistics,
+ g_strstrip(tmp1),
+ g_strstrip(tmp2));
+ }
+ }
+
+ pclose(netstat);
+ }
+
+ g_free(command_line);
+ g_free(netstat_path);
+ }
+
+ SCAN_END();
+}
+
+static gchar *__nameservers = NULL;
+void scan_dns(gboolean reload)
+{
+ FILE *resolv;
+ gchar buffer[256];
+
+ SCAN_START();
+
+ g_free(__nameservers);
+ __nameservers = g_strdup("");
+
+ if ((resolv = fopen("/etc/resolv.conf", "r"))) {
+ while (fgets(buffer, 256, resolv)) {
+ if (g_str_has_prefix(buffer, "nameserver")) {
+ gchar *ip;
+ struct sockaddr_in sa;
+ char hbuf[NI_MAXHOST];
+
+ ip = g_strstrip(buffer + sizeof("nameserver"));
+
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = inet_addr(ip);
+
+ if (getnameinfo((struct sockaddr *)&sa, sizeof(sa), hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD)) {
+ __nameservers = h_strdup_cprintf("%s=\n",
+ __nameservers,
+ ip);
+ } else {
+ __nameservers = h_strdup_cprintf("%s=%s\n",
+ __nameservers,
+ ip, hbuf);
+
+ }
+
+ shell_status_pulse();
+ }
+ }
+ fclose(resolv);
+ }
+
+ SCAN_END();
+}
+
+void scan_network(gboolean reload)
+{
+ SCAN_START();
+ scan_net_interfaces();
+ SCAN_END();
+}
+
+static gchar *__routing_table = NULL;
+void scan_route(gboolean reload)
+{
+ FILE *route;
+ gchar buffer[256];
+ gchar *route_path;
+
+ SCAN_START();
+
+ g_free(__routing_table);
+ __routing_table = g_strdup("");
+
+ if ((route_path = find_program("route"))) {
+ gchar *command_line = g_strdup_printf("%s -n", route_path);
+
+ if ((route = popen(command_line, "r"))) {
+ /* eat first two lines */
+ (void)fgets(buffer, 256, route);
+ (void)fgets(buffer, 256, route);
+
+ while (fgets(buffer, 256, route)) {
+ buffer[15] = '\0';
+ buffer[31] = '\0';
+ buffer[47] = '\0';
+ buffer[53] = '\0';
+
+ __routing_table = h_strdup_cprintf("%s / %s=%s|%s|%s\n",
+ __routing_table,
+ g_strstrip(buffer), g_strstrip(buffer + 16),
+ g_strstrip(buffer + 72),
+ g_strstrip(buffer + 48),
+ g_strstrip(buffer + 32));
+ }
+
+ pclose(route);
+ }
+
+ g_free(command_line);
+ g_free(route_path);
+ }
+
+ SCAN_END();
+}
+
+static gchar *__arp_table = NULL;
+void scan_arp(gboolean reload)
+{
+ FILE *arp;
+ gchar buffer[256];
+
+ SCAN_START();
+
+ g_free(__arp_table);
+ __arp_table = g_strdup("");
+
+ if ((arp = fopen("/proc/net/arp", "r"))) {
+ /* eat first line */
+ (void)fgets(buffer, 256, arp);
+
+ while (fgets(buffer, 256, arp)) {
+ buffer[15] = '\0';
+ buffer[58] = '\0';
+
+ __arp_table = h_strdup_cprintf("%s=%s|%s\n",
+ __arp_table,
+ g_strstrip(buffer),
+ g_strstrip(buffer + 72),
+ g_strstrip(buffer + 41));
+ }
+
+ fclose(arp);
+ }
+
+ SCAN_END();
+}
+
+static gchar *__connections = NULL;
+void scan_connections(gboolean reload)
+{
+ FILE *netstat;
+ gchar buffer[256];
+ gchar *netstat_path;
+
+ SCAN_START();
+
+ g_free(__connections);
+ __connections = g_strdup("");
+
+ if ((netstat_path = find_program("netstat"))) {
+ gchar *command_line = g_strdup_printf("%s -an", netstat_path);
+
+ if ((netstat = popen("netstat -an", "r"))) {
+ while (fgets(buffer, 256, netstat)) {
+ buffer[6] = '\0';
+ buffer[43] = '\0';
+ buffer[67] = '\0';
+
+ if (g_str_has_prefix(buffer, "tcp") || g_str_has_prefix(buffer, "udp")) {
+ __connections = h_strdup_cprintf("%s=%s|%s|%s\n",
+ __connections,
+ g_strstrip(buffer + 20), /* local address */
+ g_strstrip(buffer), /* protocol */
+ g_strstrip(buffer + 44), /* foreign address */
+ g_strstrip(buffer + 68)); /* state */
+ }
+ }
+
+ pclose(netstat);
+ }
+
+ g_free(command_line);
+ g_free(netstat_path);
+ }
+
+ SCAN_END();
+}
+
+gchar *callback_arp()
+{
+ return g_strdup_printf(_("[ARP Table]\n"
+ "%s\n"
+ "[$ShellParam$]\n"
+ "ReloadInterval=3000\n"
+ "ColumnTitle$TextValue=IP Address\n"
+ "ColumnTitle$Value=Interface\n"
+ "ColumnTitle$Extra1=MAC Address\n"
+ "ShowColumnHeaders=true\n"),
+ __arp_table);
+}
+
+gchar *callback_shares()
+{
+ return g_strdup_printf("[SAMBA]\n"
+ "%s\n"
+ "[NFS]\n"
+ "%s", smb_shares_list, nfs_shares_list);
+}
+
+gchar *callback_dns()
+{
+ return g_strdup_printf(_("[Name servers]\n"
+ "%s\n"
+ "[$ShellParam$]\n"
+ "ColumnTitle$TextValue=IP Address\n"
+ "ColumnTitle$Value=Name\n"
+ "ShowColumnHeaders=true\n"), __nameservers);
+}
+
+gchar *callback_connections()
+{
+ return g_strdup_printf(_("[Connections]\n"
+ "%s\n"
+ "[$ShellParam$]\n"
+ "ReloadInterval=3000\n"
+ "ColumnTitle$TextValue=Local Address\n"
+ "ColumnTitle$Value=Protocol\n"
+ "ColumnTitle$Extra1=Foreign Address\n"
+ "ColumnTitle$Extra2=State\n"
+ "ShowColumnHeaders=true\n"),
+ __connections);
+}
+
+gchar *callback_network()
+{
+ return g_strdup_printf(_("%s\n"
+ "[$ShellParam$]\n"
+ "ReloadInterval=3000\n"
+ "ViewType=1\n"
+ "ColumnTitle$TextValue=Interface\n"
+ "ColumnTitle$Value=IP Address\n"
+ "ColumnTitle$Extra1=Sent\n"
+ "ColumnTitle$Extra2=Received\n"
+ "ShowColumnHeaders=true\n"
+ "%s"),
+ network_interfaces,
+ network_icons);
+}
+
+gchar *callback_route()
+{
+ return g_strdup_printf(_("[IP routing table]\n"
+ "%s\n"
+ "[$ShellParam$]\n"
+ "ViewType=0\n"
+ "ReloadInterval=3000\n"
+ "ColumnTitle$TextValue=Destination / Gateway\n"
+ "ColumnTitle$Value=Interface\n"
+ "ColumnTitle$Extra1=Flags\n"
+ "ColumnTitle$Extra2=Mask\n"
+ "ShowColumnHeaders=true\n"),
+ __routing_table);
+}
+
+gchar *callback_statistics()
+{
+ return g_strdup_printf("%s\n"
+ "[$ShellParam$]\n"
+ "ReloadInterval=3000\n",
+ __statistics);
+}
+
+gchar *hi_more_info(gchar * entry)
+{
+ gchar *info = moreinfo_lookup_with_prefix("NET", entry);
+
+ if (info)
+ return g_strdup(info);
+
+ return g_strdup_printf("[%s]", entry);
+}
+
+ModuleEntry *hi_module_get_entries(void)
+{
+ return entries;
+}
+
+gchar *hi_module_get_name(void)
+{
+ return g_strdup(_("Network"));
+}
+
+guchar hi_module_get_weight(void)
+{
+ return 160;
+}
+
+void hi_module_init(void)
+{
+}
+
+void hi_module_deinit(void)
+{
+ moreinfo_del_with_prefix("NET");
+
+ g_free(smb_shares_list);
+ g_free(nfs_shares_list);
+ g_free(network_interfaces);
+ g_free(network_icons);
+
+ g_free(__statistics);
+ g_free(__nameservers);
+ g_free(__arp_table);
+ g_free(__routing_table);
+ g_free(__connections);
+}
+
+ModuleAbout *hi_module_get_about(void)
+{
+ static ModuleAbout ma[] = {
+ {
+ .author = "Leandro A. F. Pereira",
+ .description = N_("Gathers information about this computer's network connection"),
+ .version = VERSION,
+ .license = "GNU GPL version 2"}
+ };
+
+ return ma;
+}
diff --git a/modules/network/net.c b/modules/network/net.c
new file mode 100644
index 00000000..ebb0612a
--- /dev/null
+++ b/modules/network/net.c
@@ -0,0 +1,452 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 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
+ */
+/*
+ * Wireless Extension Example
+ * http://www.krugle.org/examples/p-OZYzuisV6gyQIaTu/iwconfig.c
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <linux/sockios.h>
+
+#include <arpa/inet.h>
+
+#ifdef HAS_LINUX_WE
+#include <linux/if.h>
+#include <linux/wireless.h>
+#else
+#include <net/if.h>
+#endif /* HAS_LINUX_WE */
+
+#include "hardinfo.h"
+#include "network.h"
+
+gchar *network_interfaces = NULL, *network_icons = NULL;
+
+typedef struct _NetInfo NetInfo;
+struct _NetInfo {
+ char name[16];
+ int mtu;
+ unsigned char mac[8];
+ char ip[16];
+ char mask[16];
+ char broadcast[16];
+
+#ifdef HAS_LINUX_WE
+ char wi_essid[IW_ESSID_MAX_SIZE + 1];
+ int wi_rate;
+ int wi_mode, wi_status;
+ gboolean wi_has_txpower;
+ struct iw_param wi_txpower;
+ int wi_quality_level, wi_signal_level, wi_noise_level;
+ gboolean is_wireless;
+#endif
+};
+
+#ifdef HAS_LINUX_WE
+const gchar *wi_operation_modes[] = { "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Unknown" };
+
+void get_wireless_info(int fd, NetInfo *netinfo)
+{
+ FILE *wrls;
+ char wbuf[256];
+ struct iwreq wi_req;
+ int r, trash;
+
+ netinfo->is_wireless = FALSE;
+
+ if ((wrls = fopen("/proc/net/wireless", "r"))) {
+ while (fgets(wbuf, 256, wrls)) {
+ if (strchr(wbuf, ':') && strstr(wbuf, netinfo->name)) {
+ gchar *buf1 = wbuf;
+
+ netinfo->is_wireless = TRUE;
+
+ buf1 = strchr(buf1, ':') + 1;
+
+ if (strchr(buf1, '.')) {
+ sscanf(buf1, "%d %d. %d. %d %d %d %d %d %d %d",
+ &(netinfo->wi_status),
+ &(netinfo->wi_quality_level),
+ &(netinfo->wi_signal_level),
+ &(netinfo->wi_noise_level),
+ &trash, &trash, &trash, &trash, &trash, &trash);
+ } else {
+ sscanf(buf1, "%d %d %d %d %d %d %d %d %d %d",
+ &(netinfo->wi_status),
+ &(netinfo->wi_quality_level),
+ &(netinfo->wi_signal_level),
+ &(netinfo->wi_noise_level),
+ &trash, &trash, &trash, &trash, &trash,
+ &trash);
+ }
+
+ break;
+ }
+ }
+ fclose(wrls);
+ }
+
+ if (!netinfo->is_wireless)
+ return;
+
+ strncpy(wi_req.ifr_name, netinfo->name, 16);
+
+ /* obtain essid */
+ wi_req.u.essid.pointer = netinfo->wi_essid;
+ wi_req.u.essid.length = IW_ESSID_MAX_SIZE + 1;
+ wi_req.u.essid.flags = 0;
+
+ if (ioctl(fd, SIOCGIWESSID, &wi_req) < 0) {
+ strcpy(netinfo->wi_essid, "");
+ } else {
+ netinfo->wi_essid[wi_req.u.essid.length] = '\0';
+ }
+
+ /* obtain bit rate */
+ if (ioctl(fd, SIOCGIWRATE, &wi_req) < 0) {
+ netinfo->wi_rate = 0;
+ } else {
+ netinfo->wi_rate = wi_req.u.bitrate.value;
+ }
+
+ /* obtain operation mode */
+ if (ioctl(fd, SIOCGIWMODE, &wi_req) < 0) {
+ netinfo->wi_mode = 0;
+ } else {
+ if (wi_req.u.mode >= 0 && wi_req.u.mode < 6) {
+ netinfo->wi_mode = wi_req.u.mode;
+ } else {
+ netinfo->wi_mode = 6;
+ }
+ }
+
+#if WIRELESS_EXT >= 10
+ /* obtain txpower */
+ if (ioctl(fd, SIOCGIWTXPOW, &wi_req) < 0) {
+ netinfo->wi_has_txpower = FALSE;
+ } else {
+ netinfo->wi_has_txpower = TRUE;
+
+ memcpy(&netinfo->wi_txpower, &wi_req.u.txpower, sizeof(struct iw_param));
+ }
+#else
+ netinfo->wi_has_txpower = FALSE;
+#endif /* WIRELESS_EXT >= 10 */
+}
+#endif /* HAS_LINUX_WE */
+
+void get_net_info(char *if_name, NetInfo * netinfo)
+{
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ /* IPv4 */
+ ifr.ifr_addr.sa_family = AF_INET;
+ strncpy(netinfo->name, if_name, sizeof(netinfo->name));
+
+ /* MTU */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ netinfo->mtu = 0;
+ } else {
+ netinfo->mtu = ifr.ifr_mtu;
+ }
+
+ /* HW Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ memset(netinfo->mac, 0, 8);
+ } else {
+ memcpy(netinfo->mac, ifr.ifr_ifru.ifru_hwaddr.sa_data, 8);
+ }
+
+ /* IP Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
+ netinfo->ip[0] = 0;
+ } else {
+ snprintf(netinfo->ip, sizeof(netinfo->ip), "%s",
+ inet_ntoa(((struct sockaddr_in *) &ifr.ifr_addr)->
+ sin_addr));
+ }
+
+ /* Mask Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) {
+ netinfo->mask[0] = 0;
+ } else {
+ snprintf(netinfo->mask, sizeof(netinfo->mask), "%s",
+ inet_ntoa(((struct sockaddr_in *) &ifr.ifr_addr)->
+ sin_addr));
+ }
+
+ /* Broadcast Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) {
+ netinfo->broadcast[0] = 0;
+ } else {
+ snprintf(netinfo->broadcast, sizeof(netinfo->broadcast), "%s",
+ inet_ntoa(((struct sockaddr_in *) &ifr.ifr_addr)->
+ sin_addr));
+ }
+
+#ifdef HAS_LINUX_WE
+ get_wireless_info(fd, netinfo);
+#endif
+
+ shutdown(fd, 0);
+ close(fd);
+}
+
+static struct {
+ char *type;
+ char *label;
+ char *icon;
+} netdev2type[] = {
+ { "eth", "Ethernet", "network-interface" },
+ { "lo", "Loopback", "network" },
+ { "ppp", "Point-to-Point", "modem" },
+ { "ath", "Wireless", "wireless" },
+ { "wlan", "Wireless", "wireless" },
+ { "ra", "Wireless", "wireless" },
+ { "wl", "Wireless", "wireless" },
+ { "wmaster", "Wireless", "wireless" },
+ { "tun", "Virtual Point-to-Point (TUN)", "network" },
+ { "tap", "Ethernet (TAP)", "network" },
+ { "plip", "Parallel Line Internet Protocol", "network" },
+ { "irlan", "Infrared", "network" },
+ { "slip", "Serial Line Internet Protocol", "network" },
+ { "isdn", "Integrated Services Digital Network", "modem" },
+ { "sit", "IPv6-over-IPv4 Tunnel", "network" },
+ { "vmnet8", "VMWare Virtual Network Interface (NAT)", "computer" },
+ { "vmnet", "VMWare Virtual Network Interface", "computer" },
+ { "pan", "Personal Area Network (PAN)", "bluetooth" },
+ { "bnep", "Bluetooth", "bluetooth" },
+ { "br", "Bridge Interface", "network" },
+ { "ham", "Hamachi Virtual Personal Network", "network"},
+ { "net", "Ethernet", "network-interface" },
+ { "ifb", "Intermediate Functional Block", "network" },
+ { "gre", "GRE Network Tunnel", "network" },
+ { "msh", "Mesh Network", "wireless" },
+ { "wmaster", "Wireless Master Interface", "wireless" },
+ { "vboxnet", "VirtualBox Virtual Network Interface", "network" },
+ { NULL, "Unknown", "network" },
+};
+
+static void net_get_iface_type(gchar * name, gchar ** type, gchar ** icon, NetInfo *ni)
+{
+ int i;
+
+#ifdef HAS_LINUX_WE
+ if (ni->is_wireless) {
+ *type = "Wireless";
+ *icon = "wireless";
+
+ return;
+ }
+#endif
+
+ for (i = 0; netdev2type[i].type; i++) {
+ if (g_str_has_prefix(name, netdev2type[i].type))
+ break;
+ }
+
+ *type = netdev2type[i].label;
+ *icon = netdev2type[i].icon;
+}
+
+static gboolean
+remove_net_devices(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "NET");
+}
+
+static void scan_net_interfaces_24(void)
+{
+ FILE *proc_net;
+ NetInfo ni;
+ gchar buffer[256];
+ gchar *devid, *detailed;
+ gdouble recv_bytes;
+ gdouble recv_errors;
+ gdouble recv_packets;
+
+ gdouble trans_bytes;
+ gdouble trans_errors;
+ gdouble trans_packets;
+
+ if (!g_file_test("/proc/net/dev", G_FILE_TEST_EXISTS)) {
+ if (network_interfaces) {
+ g_free(network_interfaces);
+ network_interfaces = g_strdup("[Network Interfaces]\n"
+ "None found=\n");
+ }
+
+ return;
+ }
+
+ g_free(network_interfaces);
+
+ g_free(network_icons);
+
+ network_interfaces = g_strdup("[Network Interfaces]\n");
+ network_icons = g_strdup("");
+
+ proc_net = fopen("/proc/net/dev", "r");
+ if (!proc_net)
+ return;
+
+ while (fgets(buffer, 256, proc_net)) {
+ if (strchr(buffer, ':')) {
+ gint trash;
+ gchar ifacename[16];
+ gchar *buf = buffer;
+ gchar *iface_type, *iface_icon;
+ gint i;
+
+ buf = g_strstrip(buf);
+
+ memset(ifacename, 0, 16);
+
+ for (i = 0; buffer[i] != ':' && i < 16; i++) {
+ ifacename[i] = buffer[i];
+ }
+
+ buf = strchr(buf, ':') + 1;
+
+ /* iface: bytes packets errs drop fifo frame compressed multicast */
+ sscanf(buf, "%lf %lf %lf %d %d %d %d %d %lf %lf %lf",
+ &recv_bytes, &recv_packets,
+ &recv_errors, &trash, &trash, &trash, &trash,
+ &trash, &trans_bytes, &trans_packets, &trans_errors);
+
+ gdouble recv_mb = recv_bytes / 1048576.0;
+ gdouble trans_mb = trans_bytes / 1048576.0;
+
+ get_net_info(ifacename, &ni);
+
+ devid = g_strdup_printf("NET%s", ifacename);
+
+ network_interfaces =
+ h_strdup_cprintf
+ ("$%s$%s=%s|%.2lfMiB|%.2lfMiB\n",
+ network_interfaces, devid, ifacename, ni.ip[0] ? ni.ip : "",
+ trans_mb, recv_mb);
+ net_get_iface_type(ifacename, &iface_type, &iface_icon, &ni);
+
+ network_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n",
+ network_icons, devid,
+ ifacename, iface_icon);
+
+ detailed = g_strdup_printf("[Network Adapter Properties]\n"
+ "Interface Type=%s\n"
+ "Hardware Address (MAC)=%02x:%02x:%02x:%02x:%02x:%02x\n"
+ "MTU=%d\n"
+ "[Transfer Details]\n"
+ "Bytes Received=%.0lf (%.2fMiB)\n"
+ "Bytes Sent=%.0lf (%.2fMiB)\n",
+ iface_type,
+ ni.mac[0], ni.mac[1],
+ ni.mac[2], ni.mac[3],
+ ni.mac[4], ni.mac[5],
+ ni.mtu,
+ recv_bytes, recv_mb,
+ trans_bytes, trans_mb);
+
+#ifdef HAS_LINUX_WE
+ if (ni.is_wireless) {
+ gchar *txpower;
+
+ if (ni.wi_has_txpower) {
+ gint mw, dbm;
+
+ if (ni.wi_txpower.flags & IW_TXPOW_MWATT) {
+ mw = ni.wi_txpower.value;
+ dbm = (int) ceil(10.0 * log10((double) ni.wi_txpower.value));
+ } else {
+ dbm = ni.wi_txpower.value;
+ mw = (int) floor(pow(10.0, ((double) dbm / 10.0)));
+ }
+
+ txpower = g_strdup_printf("%ddBm (%dmW)", dbm, mw);
+ } else {
+ txpower = g_strdup("Unknown");
+ }
+
+ detailed = h_strdup_cprintf("\n[Wireless Properties]\n"
+ "Network Name (SSID)=%s\n"
+ "Bit Rate=%dMb/s\n"
+ "Transmission Power=%s\n"
+ "Mode=%s\n"
+ "Status=%d\n"
+ "Link Quality=%d\n"
+ "Signal / Noise=%d dBm / %d dBm\n",
+ detailed,
+ ni.wi_essid,
+ ni.wi_rate / 1000000,
+ txpower,
+ wi_operation_modes[ni.wi_mode],
+ ni.wi_status,
+ ni.wi_quality_level,
+ ni.wi_signal_level,
+ ni.wi_noise_level);
+
+ g_free(txpower);
+ }
+#endif
+
+ if (ni.ip[0] || ni.mask[0] || ni.broadcast[0]) {
+ detailed =
+ h_strdup_cprintf("\n[Internet Protocol (IPv4)]\n"
+ "IP Address=%s\n" "Mask=%s\n"
+ "Broadcast Address=%s\n", detailed,
+ ni.ip[0] ? ni.ip : "Not set",
+ ni.mask[0] ? ni.mask : "Not set",
+ ni.broadcast[0] ? ni.
+ broadcast : "Not set");
+ }
+
+ moreinfo_add_with_prefix("NET", devid, detailed);
+ g_free(devid);
+ }
+ }
+ fclose(proc_net);
+}
+
+void scan_net_interfaces(void)
+{
+ /* FIXME: See if we're running Linux 2.6 and if /sys is mounted, then use
+ that instead of /proc/net/dev */
+
+ /* remove old devices from global device table */
+ moreinfo_del_with_prefix("NET");
+
+ scan_net_interfaces_24();
+}
diff --git a/modules/network/nfs.c b/modules/network/nfs.c
new file mode 100644
index 00000000..54bbfe0e
--- /dev/null
+++ b/modules/network/nfs.c
@@ -0,0 +1,59 @@
+/*
+ * 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 <string.h>
+
+#include "hardinfo.h"
+#include "network.h"
+
+gchar *nfs_shares_list = NULL;
+
+void
+scan_nfs_shared_directories(void)
+{
+ FILE *exports;
+ gint count = 0;
+ gchar buf[512];
+
+ g_free(nfs_shares_list);
+
+ nfs_shares_list = g_strdup("");
+
+ if ((exports = fopen("/etc/exports", "r"))) {
+ while (fgets(buf, 512, exports)) {
+ if (buf[0] != '/')
+ continue;
+
+ strend(buf, ' ');
+ strend(buf, '\t');
+
+ nfs_shares_list = h_strdup_cprintf("%s=\n",
+ nfs_shares_list, buf);
+ count++;
+ }
+
+ fclose(exports);
+ }
+
+ if (!count) {
+ g_free(nfs_shares_list);
+
+ nfs_shares_list = g_strdup("No NFS exports=\n");
+ }
+}
+
diff --git a/modules/network/samba.c b/modules/network/samba.c
new file mode 100644
index 00000000..71ba6ab6
--- /dev/null
+++ b/modules/network/samba.c
@@ -0,0 +1,124 @@
+/*
+ * 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 <string.h>
+
+#include "hardinfo.h"
+#include "network.h"
+
+gchar *smb_shares_list = NULL;
+
+void scan_samba_from_string(gchar *str, gsize length);
+void scan_samba_usershares(void);
+
+void
+scan_samba(void)
+{
+ gchar *str;
+ gsize length;
+
+ if (smb_shares_list) {
+ g_free(smb_shares_list);
+ smb_shares_list = g_strdup("");
+ }
+
+ if (g_file_get_contents("/etc/samba/smb.conf",
+ &str, &length, NULL)) {
+ shell_status_update("Scanning SAMBA shares...");
+ scan_samba_from_string(str, length);
+ g_free(str);
+ }
+
+ scan_samba_usershares();
+}
+
+void
+scan_samba_usershares(void)
+{
+ FILE *usershare_list;
+
+ if ((usershare_list = popen("net usershare list", "r"))) {
+ char buffer[512];
+
+ shell_status_update("Scanning SAMBA user shares...");
+
+ while (fgets(buffer, 512, usershare_list)) {
+ gchar *usershare, *cmdline;
+ gsize length;
+
+ cmdline = g_strdup_printf("net usershare info '%s'",
+ strend(buffer, '\n'));
+ if (g_spawn_command_line_sync(cmdline,
+ &usershare, NULL,
+ NULL, NULL)) {
+ length = strlen(usershare);
+ scan_samba_from_string(usershare, length);
+ g_free(usershare);
+ }
+
+ g_free(cmdline);
+
+ shell_status_pulse();
+ }
+
+ pclose(usershare_list);
+ }
+}
+
+void
+scan_samba_from_string(gchar *str, gsize length)
+{
+ GKeyFile *keyfile;
+ GError *error = NULL;
+ gchar **groups;
+ gint i = 0;
+
+ keyfile = g_key_file_new();
+
+ gchar *_smbconf = str;
+ for (; *_smbconf; _smbconf++)
+ if (*_smbconf == ';') *_smbconf = '\0';
+
+ if (!g_key_file_load_from_data(keyfile, str, length, 0, &error)) {
+ smb_shares_list = g_strdup("Cannot parse smb.conf=\n");
+ if (error)
+ g_error_free(error);
+ goto cleanup;
+ }
+
+ groups = g_key_file_get_groups(keyfile, NULL);
+ while (groups[i]) {
+ shell_status_pulse();
+
+ if (g_key_file_has_key(keyfile, groups[i], "path", NULL)) {
+ gchar *path = g_key_file_get_string(keyfile, groups[i], "path", NULL);
+ smb_shares_list = h_strdup_cprintf("%s=%s\n",
+ smb_shares_list,
+ groups[i], path);
+ g_free(path);
+ }
+
+ i++;
+ }
+
+ g_strfreev(groups);
+
+ cleanup:
+ g_key_file_free(keyfile);
+}
+
diff --git a/modules/placeholder b/modules/placeholder
deleted file mode 100644
index e69de29b..00000000
--- a/modules/placeholder
+++ /dev/null