diff options
Diffstat (limited to 'modules')
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, "<none>")) { + 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 |