diff options
Diffstat (limited to 'modules')
75 files changed, 9130 insertions, 3775 deletions
diff --git a/modules/benchmark.c b/modules/benchmark.c index 26de9557..018e30fe 100644 --- a/modules/benchmark.c +++ b/modules/benchmark.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2009 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,48 +16,84 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE +#include <config.h> #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/time.h> -#include <sys/types.h> #include <signal.h> +#include <sys/types.h> +#include "appf.h" #include "benchmark.h" +#include "cpu_util.h" #include "benchmark/bench_results.c" bench_value bench_results[BENCHMARK_N_ENTRIES]; static void do_benchmark(void (*benchmark_function)(void), int entry); -static gchar *benchmark_include_results_reverse(bench_value result, const gchar * benchmark); -static gchar *benchmark_include_results(bench_value result, const gchar * benchmark); +static gchar *benchmark_include_results_reverse(bench_value result, + const gchar *benchmark); +static gchar *benchmark_include_results(bench_value result, + const gchar *benchmark); /* ModuleEntry entries, scan_*(), callback_*(), etc. */ #include "benchmark/benches.c" -static gboolean sending_benchmark_results = FALSE; - -char *bench_value_to_str(bench_value r) { - return g_strdup_printf("%lf; %lf; %d", r.result, r.elapsed_time, r.threads_used); +char *bench_value_to_str(bench_value r) +{ + gboolean has_rev = r.revision >= 0; + gboolean has_extra = r.extra && *r.extra != 0; + gboolean has_user_note = r.user_note && *r.user_note != 0; + char *ret = g_strdup_printf("%lf; %lf; %d", r.result, r.elapsed_time, + r.threads_used); + if (has_rev || has_extra || has_user_note) + ret = appf(ret, "; ", "%d", r.revision); + if (has_extra || has_user_note) + ret = appf(ret, "; ", "%s", r.extra); + if (has_user_note) + ret = appf(ret, "; ", "%s", r.user_note); + return ret; } -bench_value bench_value_from_str(const char* str) { +bench_value bench_value_from_str(const char *str) +{ bench_value ret = EMPTY_BENCH_VALUE; - double r, e; - int t, c; + char rstr[32] = "", estr[32] = "", *p; + int t, c, v; + char extra[256], user_note[256]; if (str) { - c = sscanf(str, "%lf; %lf; %d", &r, &e, &t); + /* try to handle floats from locales that use ',' or '.' as decimal sep + */ + c = sscanf( + str, "%[-+0-9.,]; %[-+0-9.,]; %d; %d; %255[^\r\n;|]; %255[^\r\n;|]", + rstr, estr, &t, &v, extra, user_note); if (c >= 3) { - ret.result = r; - ret.elapsed_time = e; + if ((p = strchr(rstr, ','))) { + *p = '.'; + } + if ((p = strchr(estr, ','))) { + *p = '.'; + } + ret.result = g_ascii_strtod(rstr, NULL); + ret.elapsed_time = g_ascii_strtod(estr, NULL); ret.threads_used = t; } + if (c >= 4) { + ret.revision = v; + } + if (c >= 5) { + strcpy(ret.extra, extra); + } + if (c >= 6) { + strcpy(ret.user_note, user_note); + } } return ret; } @@ -65,46 +101,51 @@ bench_value bench_value_from_str(const char* str) { typedef struct _ParallelBenchTask ParallelBenchTask; struct _ParallelBenchTask { - gint thread_number; - guint start, end; - gpointer data, callback; + gint thread_number; + guint start, end; + gpointer data, callback; int *stop; }; static gpointer benchmark_crunch_for_dispatcher(gpointer data) { - ParallelBenchTask *pbt = (ParallelBenchTask *)data; + ParallelBenchTask *pbt = (ParallelBenchTask *)data; gpointer (*callback)(void *data, gint thread_number); - gpointer return_value = g_malloc(sizeof(int)); + gpointer return_value = g_malloc(sizeof(double)); int count = 0; if ((callback = pbt->callback)) { - while(!*pbt->stop) { + while (!*pbt->stop) { callback(pbt->data, pbt->thread_number); /* don't count if didn't finish in time */ if (!*pbt->stop) count++; } } else { - DEBUG("this is thread %p; callback is NULL and it should't be!", g_thread_self()); + DEBUG("this is thread %p; callback is NULL and it should't be!", + g_thread_self()); } g_free(pbt); - *(double*)return_value = (double)count; + *(double *)return_value = (double)count; return return_value; } -bench_value benchmark_crunch_for(float seconds, gint n_threads, - gpointer callback, gpointer callback_data) { - int cpu_procs, cpu_cores, cpu_threads, thread_number, stop = 0; +bench_value benchmark_crunch_for(float seconds, + gint n_threads, + gpointer callback, + gpointer callback_data) +{ + int cpu_procs, cpu_cores, cpu_threads, cpu_nodes; + int thread_number, stop = 0; GSList *threads = NULL, *t; GTimer *timer; bench_value ret = EMPTY_BENCH_VALUE; timer = g_timer_new(); - cpu_procs_cores_threads(&cpu_procs, &cpu_cores, &cpu_threads); + cpu_procs_cores_threads_nodes(&cpu_procs, &cpu_cores, &cpu_threads, &cpu_nodes); if (n_threads > 0) ret.threads_used = n_threads; else if (n_threads < 0) @@ -120,19 +161,22 @@ bench_value benchmark_crunch_for(float seconds, gint n_threads, DEBUG("launching thread %d", thread_number); pbt->thread_number = thread_number; - pbt->data = callback_data; + pbt->data = callback_data; pbt->callback = callback; pbt->stop = &stop; - thread = g_thread_new("dispatcher", - (GThreadFunc)benchmark_crunch_for_dispatcher, pbt); +#if GLIB_CHECK_VERSION(2,32,0) + thread = g_thread_new("dispatcher", (GThreadFunc)benchmark_crunch_for_dispatcher, pbt); +#else + thread = g_thread_create((GThreadFunc)benchmark_crunch_for_dispatcher, pbt,TRUE,NULL); +#endif threads = g_slist_prepend(threads, thread); DEBUG("thread %d launched as context %p", thread_number, thread); } /* wait for time */ - //while ( g_timer_elapsed(timer, NULL) < seconds ) { } + // while ( g_timer_elapsed(timer, NULL) < seconds ) { } g_usleep(seconds * 1000000); /* signal all threads to stop */ @@ -144,7 +188,7 @@ bench_value benchmark_crunch_for(float seconds, gint n_threads, for (t = threads; t; t = t->next) { DEBUG("waiting for thread with context %p", t->data); gpointer *rv = g_thread_join((GThread *)t->data); - ret.result += *(double*)rv; + ret.result += *(double *)rv; g_free(rv); } @@ -158,17 +202,21 @@ bench_value benchmark_crunch_for(float seconds, gint n_threads, 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; + 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); + 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()); + DEBUG("this is thread %p; callback is NULL and it should't be!", + g_thread_self()); } g_free(pbt); @@ -177,31 +225,43 @@ static gpointer benchmark_parallel_for_dispatcher(gpointer data) } /* one call for each thread to be used */ -bench_value benchmark_parallel(gint n_threads, gpointer callback, gpointer callback_data) { - int cpu_procs, cpu_cores, cpu_threads; - cpu_procs_cores_threads(&cpu_procs, &cpu_cores, &cpu_threads); - if (n_threads == 0) n_threads = cpu_threads; - else if (n_threads == -1) n_threads = cpu_cores; - return benchmark_parallel_for(n_threads, 0, n_threads, callback, callback_data); +bench_value +benchmark_parallel(gint n_threads, gpointer callback, gpointer callback_data) +{ + int cpu_procs, cpu_cores, cpu_threads, cpu_nodes; + cpu_procs_cores_threads_nodes(&cpu_procs, &cpu_cores, &cpu_threads, &cpu_nodes); + + if (n_threads == 0) + n_threads = cpu_threads; + else if (n_threads == -1) + n_threads = cpu_cores; + + return benchmark_parallel_for(n_threads, 0, n_threads, callback, + callback_data); } /* Note: * benchmark_parallel_for(): element [start] included, but [end] is excluded. - * callback(): expected to processes elements [start] through [end] inclusive. + * callback(): expected to processes elements [start] through [end] + * inclusive. */ -bench_value benchmark_parallel_for(gint n_threads, guint start, guint end, - gpointer callback, gpointer callback_data) { - gchar *temp; - int cpu_procs, cpu_cores, cpu_threads; - guint iter_per_thread, iter, thread_number = 0; - GSList *threads = NULL, *t; - GTimer *timer; +bench_value benchmark_parallel_for(gint n_threads, + guint start, + guint end, + gpointer callback, + gpointer callback_data) +{ + gchar *temp; + int cpu_procs, cpu_cores, cpu_threads, cpu_nodes; + guint iter_per_thread, iter, thread_number = 0; + GSList *threads = NULL, *t; + GTimer *timer; bench_value ret = EMPTY_BENCH_VALUE; timer = g_timer_new(); - cpu_procs_cores_threads(&cpu_procs, &cpu_cores, &cpu_threads); + cpu_procs_cores_threads_nodes(&cpu_procs, &cpu_cores, &cpu_threads, &cpu_nodes); if (n_threads > 0) ret.threads_used = n_threads; @@ -214,18 +274,19 @@ bench_value benchmark_parallel_for(gint n_threads, guint start, guint end, iter_per_thread = (end - start) / ret.threads_used; if (iter_per_thread == 0) { - DEBUG("not enough items per thread; disabling one thread"); - ret.threads_used--; + DEBUG("not enough items per thread; disabling one thread"); + ret.threads_used--; } else { - break; + break; } } - DEBUG("Using %d threads across %d logical processors; processing %d elements (%d per thread)", + DEBUG("Using %d threads across %d logical processors; processing %d " + "elements (%d per thread)", ret.threads_used, cpu_threads, (end - start), iter_per_thread); g_timer_start(timer); - for (iter = start; iter < end; ) { + for (iter = start; iter < end;) { ParallelBenchTask *pbt = g_new0(ParallelBenchTask, 1); GThread *thread; @@ -238,13 +299,17 @@ bench_value benchmark_parallel_for(gint n_threads, guint start, guint end, DEBUG("launching thread %d", 1 + thread_number); pbt->thread_number = thread_number++; - pbt->start = ts; - pbt->end = te - 1; - pbt->data = callback_data; + pbt->start = ts; + pbt->end = te - 1; + pbt->data = callback_data; pbt->callback = callback; - thread = g_thread_new("dispatcher", - (GThreadFunc)benchmark_parallel_for_dispatcher, pbt); +#if GLIB_CHECK_VERSION(2,32,0) + thread = g_thread_new("dispatcher", (GThreadFunc)benchmark_parallel_for_dispatcher, pbt); +#else + thread = g_thread_create((GThreadFunc)benchmark_parallel_for_dispatcher, pbt,TRUE,NULL); +#endif + threads = g_slist_prepend(threads, thread); DEBUG("thread %d launched as context %p", thread_number, thread); @@ -255,8 +320,9 @@ bench_value benchmark_parallel_for(gint n_threads, guint start, guint end, DEBUG("waiting for thread with context %p", t->data); gpointer *rv = g_thread_join((GThread *)t->data); if (rv) { - if (ret.result == -1.0) ret.result = 0; - ret.result += *(double*)rv; + if (ret.result == -1.0) + ret.result = 0; + ret.result += *(double *)rv; } g_free(rv); } @@ -272,140 +338,256 @@ bench_value benchmark_parallel_for(gint n_threads, guint start, guint end, return ret; } -static gchar *clean_cpuname(gchar *cpuname) +gchar *hi_more_info(gchar *entry) { - gchar *ret = NULL, *tmp; - gchar *remove[] = { - "(R)", "(r)", "(TM)", "(tm)", "Processor", - "Technology", "processor", "CPU", - "cpu", "Genuine", "Authentic", NULL - }; - gint i; + const gchar *info = moreinfo_lookup_with_prefix("BENCH", entry); + return g_strdup(info ? info : "?"); +} + +gchar *hi_get_field(gchar *field) +{ + const gchar *info = moreinfo_lookup_with_prefix("BENCH", field); + return g_strdup(info ? info : field); +} - ret = g_strdup(cpuname); - for (i = 0; remove[i]; i++) { - tmp = strreplace(ret, remove[i], ""); - g_free(ret); - ret = tmp; +static void br_mi_add(char **results_list, bench_result *b, gboolean select) +{ + static unsigned int ri = 0; /* to ensure key is unique */ + gchar *rkey, *lbl, *elbl, *this_marker; + + if (select) { + this_marker = format_with_ansi_color(_("This Machine"), "0;30;43", + params.fmt_opts); + } else { + this_marker = ""; } - ret = strend(ret, '@'); - ret = g_strstrip(ret); + rkey = g_strdup_printf("%s__%d", b->machine->mid, ri++); - tmp = g_strdup(ret); - g_free(ret); + lbl = g_strdup_printf("%s%s%s%s", this_marker, select ? " " : "", + b->machine->cpu_name, + b->legacy ? problem_marker() : ""); + elbl = key_label_escape(lbl); - return tmp; -} + *results_list = h_strdup_cprintf("$@%s%s$%s=%.2f|%s\n", *results_list, + select ? "*" : "", rkey, elbl, + b->bvalue.result, b->machine->cpu_config); -gchar *hi_more_info(gchar * entry) + moreinfo_add_with_prefix("BENCH", rkey, bench_result_more_info(b)); + + g_free(lbl); + g_free(elbl); + g_free(rkey); + if (*this_marker) + g_free(this_marker); +} +gint bench_result_sort(gconstpointer a, gconstpointer b) { - gchar *info = moreinfo_lookup_with_prefix("BENCH", entry); - if (info) - return g_strdup(info); - return g_strdup("?"); + bench_result *A = (bench_result *)a, *B = (bench_result *)b; + if (A->bvalue.result < B->bvalue.result) + return -1; + if (A->bvalue.result > B->bvalue.result) + return 1; + return 0; } -gchar *hi_get_field(gchar * field) +struct append_machine_result_json_data { + GSList **result_list; + const gchar *benchmark_name; +}; + +static void append_machine_result_json(JsonArray *array, + guint index, + JsonNode *element_node, + gpointer user_data) { - gchar *info = moreinfo_lookup_with_prefix("BENCH", field); - if (info) - return g_strdup(info); - return g_strdup(field); + struct append_machine_result_json_data *data = user_data; + bench_result *result; + + result = bench_result_benchmarkjson(data->benchmark_name, element_node); + *data->result_list = g_slist_append(*data->result_list, result); } -static void br_mi_add(char **results_list, bench_result *b, gboolean select) { - gchar *ckey, *rkey; +static GSList *benchmark_include_results_json(const gchar *path, + bench_value r, + const gchar *benchmark) +{ + JsonParser *parser; + JsonNode *root; + bench_result *this_machine = NULL; + GSList *result_list = NULL; + GError *error=NULL; + + DEBUG("Loading benchmark results from JSON file %s", path); + + parser = json_parser_new(); + json_parser_load_from_file(parser, path, &error); + if(error){ + DEBUG ("Unable to parse JSON %s %s", path, error->message); + g_error_free(error); + g_object_unref(parser); + return result_list; + } - ckey = hardinfo_clean_label(b->machine->cpu_name, 0); - rkey = strdup(b->machine->mid); + root = json_parser_get_root(parser); + if (json_node_get_node_type(root) != JSON_NODE_OBJECT) goto out; - *results_list = h_strdup_cprintf("$%s%s$%s=%.2f|%s\n", *results_list, - select ? "*" : "", rkey, ckey, - b->bvalue.result, b->machine->cpu_config); + JsonObject *results = json_node_get_object(root); + if (results) { + JsonArray *machines = json_object_get_array_member(results, benchmark); - moreinfo_add_with_prefix("BENCH", rkey, bench_result_more_info(b) ); + if (machines) { + struct append_machine_result_json_data data = { + .result_list = &result_list, + .benchmark_name = benchmark, + }; + json_array_foreach_element(machines, append_machine_result_json, + &data); + } + } - g_free(ckey); - g_free(rkey); +out: + g_object_unref(parser); + + return result_list; } -static gchar *__benchmark_include_results(bench_value r, - const gchar * benchmark, - ShellOrderType order_type) +static gchar *find_benchmark_conf(void) { - bench_result *b = NULL; - GKeyFile *conf; - gchar **machines, *temp = NULL;; - gchar *path, *results = g_strdup(""), *return_value, *processor_frequency, *processor_name; - int i, n_threads; + const gchar *config_dir = g_get_user_config_dir(); + gchar *path; - moreinfo_del_with_prefix("BENCH"); + path = g_build_filename(config_dir, "hardinfo2", "benchmark.json", NULL); + if (g_file_test(path, G_FILE_TEST_EXISTS)) + return path; + g_free(path); - if (r.result > 0.0) { - b = bench_result_this_machine(benchmark, r); - br_mi_add(&results, b, 1); + path = g_build_filename(params.path_data, "benchmark.json", NULL); + if (g_file_test(path, G_FILE_TEST_EXISTS)) + return path; + g_free(path); + + return NULL; +} - temp = bench_result_benchmarkconf_line(b); - printf("[%s]\n%s", benchmark, temp); - g_free(temp); temp = NULL; +struct bench_window { + int min, max; +}; + +static struct bench_window get_bench_window(GSList *result_list, + const bench_result *this_machine) +{ + struct bench_window window = {}; + int size = params.max_bench_results; + int len = g_slist_length(result_list); + + if (size == 0) + size = 1; + else if (size < 0) + size = len; + + int loc = g_slist_index(result_list, this_machine); /* -1 if not found */ + if (loc >= 0) { + window.min = loc - size / 2; + window.max = window.min + size; + if (window.min < 0) { + window.min = 0; + window.max = MIN(size, len); + } else if (window.max > len) { + window.max = len; + window.min = MAX(len - size, 0); + } + } else { + window.min = 0; + window.max = len; } - conf = g_key_file_new(); + DEBUG("...len: %d, loc: %d, win_size: %d, win: [%d..%d]\n", len, loc, size, + window.min, window.max - 1); + + return window; +} + +static gboolean is_in_bench_window(const struct bench_window *window, int i) +{ + return i >= window->min && i < window->max; +} - 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); +static gchar *benchmark_include_results_internal(bench_value this_machine_value, + const gchar *benchmark, + ShellOrderType order_type) +{ + bench_result *this_machine; + GSList *result_list, *li; + gchar *results = g_strdup(""); + gchar *output; + gchar *path; + gint i; + + path = find_benchmark_conf(); + if (path) { + result_list = benchmark_include_results_json( + path, this_machine_value, benchmark); } - g_key_file_load_from_file(conf, path, 0, NULL); - g_key_file_set_list_separator(conf, '|'); + /* this result */ + if (this_machine_value.result > 0.0) { + this_machine = bench_result_this_machine(benchmark, this_machine_value); + result_list = g_slist_prepend(result_list, this_machine); + } else { + this_machine = NULL; + } - machines = g_key_file_get_keys(conf, benchmark, NULL, NULL); - for (i = 0; machines && machines[i]; i++) { - gchar **values; - bench_result *sbr; + /* sort */ + result_list = g_slist_sort(result_list, bench_result_sort); + if (order_type == SHELL_ORDER_DESCENDING) + result_list = g_slist_reverse(result_list); - values = g_key_file_get_string_list(conf, benchmark, machines[i], NULL, NULL); + /* prepare for shell */ + moreinfo_del_with_prefix("BENCH"); + + const struct bench_window window = + get_bench_window(result_list, this_machine); + for (i = 0, li = result_list; li; li = g_slist_next(li), i++) { + bench_result *br = li->data; - sbr = bench_result_benchmarkconf(benchmark, machines[i], values); - br_mi_add(&results, sbr, 0); + if (is_in_bench_window(&window, i)) + br_mi_add(&results, br, br == this_machine); - bench_result_free(sbr); - g_strfreev(values); + bench_result_free(br); /* no longer needed */ } + g_slist_free(result_list); + + output = g_strdup_printf("[$ShellParam$]\n" + "Zebra=1\n" + "OrderType=%d\n" + "ViewType=4\n" + "ColumnTitle$Extra1=%s\n" /* CPU Clock */ + "ColumnTitle$Progress=%s\n" /* Results */ + "ColumnTitle$TextValue=%s\n" /* CPU */ + "ShowColumnHeaders=true\n" + "[%s]\n%s", + order_type, _("CPU Config"), _("Results"), + _("CPU"), benchmark, results); - g_strfreev(machines); g_free(path); - g_key_file_free(conf); - - return_value = g_strdup_printf("[$ShellParam$]\n" - "Zebra=1\n" - "OrderType=%d\n" - "ViewType=4\n" - "ColumnTitle$Extra1=%s\n" /* CPU Clock */ - "ColumnTitle$Progress=%s\n" /* Results */ - "ColumnTitle$TextValue=%s\n" /* CPU */ - "ShowColumnHeaders=true\n" - "[%s]\n%s", - order_type, - _("CPU Config"), _("Results"), _("CPU"), - benchmark, results); - - bench_result_free(b); - return return_value; + g_free(results); + + return output; } -static gchar *benchmark_include_results_reverse(bench_value result, const gchar * benchmark) +static gchar *benchmark_include_results_reverse(bench_value result, + const gchar *benchmark) { - return __benchmark_include_results(result, benchmark, SHELL_ORDER_DESCENDING); + return benchmark_include_results_internal(result, benchmark, + SHELL_ORDER_DESCENDING); } -static gchar *benchmark_include_results(bench_value result, const gchar * benchmark) +static gchar *benchmark_include_results(bench_value result, + const gchar *benchmark) { - return __benchmark_include_results(result, benchmark, SHELL_ORDER_ASCENDING); + return benchmark_include_results_internal(result, benchmark, + SHELL_ORDER_ASCENDING); } typedef struct _BenchmarkDialog BenchmarkDialog; @@ -414,11 +596,10 @@ struct _BenchmarkDialog { bench_value r; }; -static gboolean do_benchmark_handler(GIOChannel *source, - GIOCondition condition, - gpointer data) +static gboolean +do_benchmark_handler(GIOChannel *source, GIOCondition condition, gpointer data) { - BenchmarkDialog *bench_dialog = (BenchmarkDialog*)data; + BenchmarkDialog *bench_dialog = (BenchmarkDialog *)data; GIOStatus status; gchar *result; bench_value r = EMPTY_BENCH_VALUE; @@ -433,6 +614,9 @@ static gboolean do_benchmark_handler(GIOChannel *source, } r = bench_value_from_str(result); + /* attach a user note */ + if (params.bench_user_note) + strncpy(r.user_note, params.bench_user_note, 255); bench_dialog->r = r; gtk_widget_destroy(bench_dialog->dialog); @@ -445,118 +629,127 @@ 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_value r = EMPTY_BENCH_VALUE; - bench_results[entry] = r; - - 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); - -#if GTK_CHECK_VERSION(3, 0, 0) - GtkWidget *button; - GtkWidget *content_area; - GtkWidget *hbox; - GtkWidget *label; - - bench_dialog = gtk_dialog_new_with_buttons("", - NULL, - GTK_DIALOG_MODAL, - _("Cancel"), - GTK_RESPONSE_ACCEPT, - NULL); - content_area = gtk_dialog_get_content_area(GTK_DIALOG(bench_dialog)); - label = gtk_label_new(_("Benchmarking. Please do not move your mouse " \ - "or press any keys.")); - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); - gtk_box_pack_start(GTK_BOX(hbox), bench_image, TRUE, TRUE, 5); - gtk_box_pack_end(GTK_BOX(hbox), label, TRUE, TRUE, 5); - gtk_container_add(GTK_CONTAINER (content_area), hbox); - gtk_widget_show_all(bench_dialog); + if (params.skip_benchmarks) + return; + + if (params.gui_running) { + 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; + GtkWidget *content_area, *box, *label; + bench_value r = EMPTY_BENCH_VALUE; + bench_results[entry] = r; + + 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"); + + bench_dialog = gtk_dialog_new_with_buttons ("Benchmarking...", + GTK_WINDOW(shell_get_main_shell()->transient_dialog), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + "Stop", + GTK_BUTTONS_CLOSE, + NULL); + + gtk_widget_set_sensitive(GTK_WIDGET(shell_get_main_shell()->transient_dialog), FALSE); + + content_area = gtk_dialog_get_content_area (GTK_DIALOG(bench_dialog)); + +#if GTK_CHECK_VERSION(3,0,0) + box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1); #else - 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.")); - 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); + box = gtk_hbox_new(FALSE, 1); #endif + label = gtk_label_new ("Please do not move your mouse\n" + "or press any keys."); - while (gtk_events_pending()) { - gtk_main_iteration(); - } + gtk_widget_show (bench_image); - benchmark_dialog = g_new0(BenchmarkDialog, 1); - benchmark_dialog->dialog = bench_dialog; - benchmark_dialog->r = r; +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_halign (bench_image, GTK_ALIGN_START); +#else + gtk_misc_set_alignment(GTK_MISC(bench_image), 0.0, 0.0); +#endif + + g_signal_connect_swapped (bench_dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + bench_dialog); - if (!g_path_is_absolute(params.argv0)) { - spawn_flags |= G_SPAWN_SEARCH_PATH; - } + gtk_box_pack_start (GTK_BOX(box), bench_image, TRUE, TRUE, 10); + gtk_box_pack_start (GTK_BOX(box), label, TRUE, TRUE, 10); + gtk_container_add (GTK_CONTAINER(content_area), box); - 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; + gtk_window_set_deletable(GTK_WINDOW(bench_dialog), FALSE); + gtk_widget_show_all (bench_dialog); - DEBUG("spawning benchmark; pid=%d", bench_pid); + while (gtk_events_pending()) { + gtk_main_iteration(); + } - channel = g_io_channel_unix_new(bench_stdout); - watch_id = g_io_add_watch(channel, G_IO_IN, do_benchmark_handler, - benchmark_dialog); + benchmark_dialog = g_new0(BenchmarkDialog, 1); + benchmark_dialog->dialog = bench_dialog; + benchmark_dialog->r = r; - switch (gtk_dialog_run(GTK_DIALOG(bench_dialog))) { + 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; + DEBUG("benchmark finished"); + break; case GTK_RESPONSE_ACCEPT: - DEBUG("cancelling benchmark"); + DEBUG("cancelling benchmark"); - gtk_widget_destroy(bench_dialog); - g_source_remove(watch_id); - kill(bench_pid, SIGINT); - } + gtk_widget_destroy(bench_dialog); + g_source_remove(watch_id); + kill(bench_pid, SIGINT); + } - bench_results[entry] = benchmark_dialog->r; + bench_results[entry] = benchmark_dialog->r; - g_io_channel_unref(channel); - shell_view_set_enabled(TRUE); - shell_status_set_enabled(TRUE); - g_free(benchmark_dialog); + g_io_channel_unref(channel); + shell_view_set_enabled(TRUE); + shell_status_set_enabled(TRUE); + gtk_widget_set_sensitive( + GTK_WIDGET(shell_get_main_shell()->transient_dialog), TRUE); + g_free(benchmark_dialog); - shell_status_update(_("Done.")); + shell_status_update(_("Done.")); - return; - } + return; + } - gtk_widget_destroy(bench_dialog); - g_free(benchmark_dialog); - shell_status_set_enabled(TRUE); - shell_status_update(_("Done.")); + gtk_widget_destroy(bench_dialog); + g_free(benchmark_dialog); + shell_status_set_enabled(TRUE); + shell_status_update(_("Done.")); } setpriority(PRIO_PROCESS, 0, -20); @@ -564,79 +757,113 @@ static void do_benchmark(void (*benchmark_function)(void), int entry) setpriority(PRIO_PROCESS, 0, old_priority); } -gchar *hi_module_get_name(void) -{ - return g_strdup(_("Benchmarks")); -} +gchar *hi_module_get_name(void) { return g_strdup(_("Benchmarks")); } -guchar hi_module_get_weight(void) -{ - return 240; -} +guchar hi_module_get_weight(void) { return 240; } -ModuleEntry *hi_module_get_entries(void) -{ - return entries; -} +ModuleEntry *hi_module_get_entries(void) { return entries; } -ModuleAbout *hi_module_get_about(void) +const 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"} + static const ModuleAbout ma = { + .author = "L. A. F. Pereira", + .description = N_("Perform tasks and compare with other systems"), + .version = VERSION, + .license = "GNU GPL version 2 or later.", }; - return ma; + return &ma; } -static gchar *get_benchmark_results() +static gchar *get_benchmark_results(gsize *len) { - 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); + void (*scan_callback)(gboolean); + JsonBuilder *builder; + JsonGenerator *generator; + JsonNode *root; + bench_machine *this_machine; + gchar *out; + guint i; + for (i = 0; i < G_N_ELEMENTS(entries); i++) { - scan_callback = entries[i].scan_callback; - if (!scan_callback) + if (!entries[i].name || !entries[i].scan_callback) + continue; + if (entries[i].flags & MODULE_FLAG_HIDE) continue; + scan_callback = entries[i].scan_callback; + if (scan_callback) + scan_callback(bench_results[i].result < 0.0); + } + + this_machine = bench_machine_this(); + builder = json_builder_new(); + json_builder_begin_object(builder); + for (i = 0; i < G_N_ELEMENTS(entries); i++) { + if (!entries[i].name || entries[i].flags & MODULE_FLAG_HIDE) + continue; if (bench_results[i].result < 0.0) { - /* benchmark was cancelled */ - scan_callback(TRUE); - } else { - scan_callback(FALSE); + /* Benchmark failed? */ + continue; } - result = h_strdup_cprintf("[bench%d]\n" - "name=%s\n" - "value=%f\n", - result, - i, entries[i].name, bench_results[i]); + json_builder_set_member_name(builder, entries[i].name); + + json_builder_begin_object(builder); + +#define ADD_JSON_VALUE(type, name, value) \ + do { \ + json_builder_set_member_name(builder, (name)); \ + json_builder_add_##type##_value(builder, (value)); \ + } while (0) + + ADD_JSON_VALUE(string, "Board", this_machine->board); + ADD_JSON_VALUE(int, "MemoryInKiB", this_machine->memory_kiB); + ADD_JSON_VALUE(string, "CpuName", this_machine->cpu_name); + ADD_JSON_VALUE(string, "CpuDesc", this_machine->cpu_desc); + ADD_JSON_VALUE(string, "CpuConfig", this_machine->cpu_config); + ADD_JSON_VALUE(string, "CpuConfig", this_machine->cpu_config); + ADD_JSON_VALUE(string, "OpenGlRenderer", this_machine->ogl_renderer); + ADD_JSON_VALUE(string, "GpuDesc", this_machine->gpu_desc); + ADD_JSON_VALUE(int, "NumCpus", this_machine->processors); + ADD_JSON_VALUE(int, "NumCores", this_machine->cores); + ADD_JSON_VALUE(int, "NumNodes", this_machine->nodes); + ADD_JSON_VALUE(int, "NumThreads", this_machine->threads); + ADD_JSON_VALUE(string, "MachineId", this_machine->mid); + ADD_JSON_VALUE(int, "PointerBits", this_machine->ptr_bits); + ADD_JSON_VALUE(boolean, "DataFromSuperUser", this_machine->is_su_data); + ADD_JSON_VALUE(int, "PhysicalMemoryInMiB", + this_machine->memory_phys_MiB); + ADD_JSON_VALUE(string, "MemoryTypes", this_machine->ram_types); + ADD_JSON_VALUE(int, "MachineDataVersion", + this_machine->machine_data_version); + ADD_JSON_VALUE(string, "MachineType", this_machine->machine_type); + + ADD_JSON_VALUE(boolean, "Legacy", FALSE); + ADD_JSON_VALUE(string, "ExtraInfo", bench_results[i].extra); + ADD_JSON_VALUE(string, "UserNote", bench_results[i].user_note); + ADD_JSON_VALUE(double, "BenchmarkResult", bench_results[i].result); + ADD_JSON_VALUE(double, "ElapsedTime", bench_results[i].elapsed_time); + ADD_JSON_VALUE(int, "UsedThreads", bench_results[i].threads_used); + ADD_JSON_VALUE(int, "BenchmarkVersion", bench_results[i].revision); + +#undef ADD_JSON_VALUE + + json_builder_end_object(builder); } + json_builder_end_object(builder); + + generator = json_generator_new(); + json_generator_set_root(generator, json_builder_get_root(builder)); + json_generator_set_pretty(generator, TRUE); - g_free(machine); - g_free(machineclock); - g_free(machineram); + out = json_generator_to_data(generator, len); - sending_benchmark_results = FALSE; + g_object_unref(generator); + g_object_unref(builder); + bench_machine_free(this_machine); - return result; + return out; } static gchar *run_benchmark(gchar *name) @@ -646,42 +873,44 @@ static gchar *run_benchmark(gchar *name) 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); - -#define CHK_RESULT_FORMAT(F) (params.result_format && strcmp(params.result_format, F) == 0) - - if (params.run_benchmark) { - if (CHK_RESULT_FORMAT("conf") ) { - bench_result *b = bench_result_this_machine(name, bench_results[i]); - char *temp = bench_result_benchmarkconf_line(b); - bench_result_free(b); - return temp; - } else if (CHK_RESULT_FORMAT("shell") ) { - bench_result *b = bench_result_this_machine(name, bench_results[i]); - char *temp = bench_result_more_info_complete(b); - bench_result_free(b); - return temp; + if (g_str_equal(entries[i].name, name)) { + void (*scan_callback)(gboolean rescan); + + if ((scan_callback = entries[i].scan_callback)) { + scan_callback(FALSE); + +#define CHK_RESULT_FORMAT(F) \ + (params.result_format && strcmp(params.result_format, F) == 0) + + if (params.run_benchmark) { + /* attach the user note */ + if (params.bench_user_note) + strncpy(bench_results[i].user_note, + params.bench_user_note, 255); + + if (CHK_RESULT_FORMAT("shell")) { + bench_result *b = + bench_result_this_machine(name, bench_results[i]); + char *temp = bench_result_more_info_complete(b); + bench_result_free(b); + return temp; + } + /* defaults to "short" which is below */ + } + + return bench_value_to_str(bench_results[i]); } - /* defaults to "short" which is below*/ - } - - return bench_value_to_str(bench_results[i]); } - } } return NULL; } -ShellModuleMethod *hi_exported_methods(void) +const ShellModuleMethod *hi_exported_methods(void) { - static ShellModuleMethod m[] = { + static const ShellModuleMethod m[] = { {"runBenchmark", run_benchmark}, - {NULL} + {NULL}, }; return m; @@ -690,31 +919,28 @@ ShellModuleMethod *hi_exported_methods(void) 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} + { + .name = N_("Send benchmark results"), + .file_name = "benchmark.json", + .generate_contents_for_upload = get_benchmark_results, + }, + { + .name = N_("Receive benchmark results"), + .file_name = "benchmark.json", + }, }; sync_manager_add_entry(&se[0]); sync_manager_add_entry(&se[1]); - bench_value er = EMPTY_BENCH_VALUE; - int i; - for (i = 0; i < G_N_ELEMENTS(entries) - 1; i++) { - bench_results[i] = er; - } + guint i; + for (i = 0; i < G_N_ELEMENTS(entries) - 1 /* account for NULL */; i++) + bench_results[i] = (bench_value)EMPTY_BENCH_VALUE; } gchar **hi_module_get_dependencies(void) { - static gchar *deps[] = { "devices.so", NULL }; + static gchar *deps[] = {"devices.so", NULL}; return deps; } diff --git a/modules/benchmark/bench_results.c b/modules/benchmark/bench_results.c index 27a33a65..18ed0739 100644 --- a/modules/benchmark/bench_results.c +++ b/modules/benchmark/bench_results.c @@ -1,12 +1,12 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2017 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2020 L. A. F. Pereira <l@tia.mat.br> * This file: * 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, version 2. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,20 +18,39 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/*/ Used for an unknown value. Having it in only one place cleans up the .po line references */ +#include <stdlib.h> +#include <locale.h> +#include <inttypes.h> +#include <json-glib/json-glib.h> +#include "nice_name.h" + +/* in dmi_memory.c */ +uint64_t memory_devices_get_system_memory_MiB(); +gchar *memory_devices_get_system_memory_types_str(); + +/*/ Used for an unknown value. Having it in only one place cleans up the .po + * line references */ static const char *unk = N_("(Unknown)"); typedef struct { char *board; - int memory_kiB; + uint64_t memory_kiB; /* from /proc/meminfo -> MemTotal */ char *cpu_name; char *cpu_desc; char *cpu_config; char *ogl_renderer; + char *gpu_desc; int processors; int cores; int threads; + int nodes; char *mid; + int ptr_bits; /* 32, 64... BENCH_PTR_BITS; 0 for unspecified */ + int is_su_data; /* 1 = data collected as root */ + uint64_t memory_phys_MiB; /* from DMI/SPD/DTree/Table/Blocks, etc. */ + char *ram_types; + int machine_data_version; + char *machine_type; } bench_machine; typedef struct { @@ -41,7 +60,8 @@ typedef struct { int legacy; /* an old benchmark.conf result */ } bench_result; -static char *cpu_config_retranslate(char *str, int force_en, int replacing) { +static char *cpu_config_retranslate(char *str, int force_en, int replacing) +{ char *new_str = NULL; char *mhz = (force_en) ? "MHz" : _("MHz"); char *c = str, *tmp; @@ -51,19 +71,19 @@ static char *cpu_config_retranslate(char *str, int force_en, int replacing) { if (str != NULL) { new_str = strdup(""); if (strchr(str, 'x')) { - while (c != NULL && sscanf(c, "%dx %f", &t, &f) ) { - tmp = g_strdup_printf("%s%s%dx %.2f %s", - new_str, strlen(new_str) ? " + " : "", - t, f, mhz ); + while (c != NULL && (sscanf(c, "%dx %f", &t, &f)==2)) { + tmp = g_strdup_printf("%s%s%dx %.2f %s", new_str, + strlen(new_str) ? " + " : "", t, f, mhz); free(new_str); new_str = tmp; - c = strchr(c+1, '+'); + c = strchr(c + 1, '+'); + if (c) + c++; /* move past the + */ } } else { sscanf(c, "%f", &f); - tmp = g_strdup_printf("%s%s%dx %.2f %s", - new_str, strlen(new_str) ? " + " : "", - 1, f, mhz ); + tmp = g_strdup_printf("%s%s%dx %.2f %s", new_str, + strlen(new_str) ? " + " : "", 1, f, mhz); free(new_str); new_str = tmp; } @@ -71,19 +91,23 @@ static char *cpu_config_retranslate(char *str, int force_en, int replacing) { if (replacing) free(str); } + return new_str; } /* "2x 1400.00 MHz + 2x 800.00 MHz" -> 4400.0 */ -static float cpu_config_val(char *str) { +static float cpu_config_val(char *str) +{ char *c = str; int t; float f, r = 0.0; if (str != NULL) { if (strchr(str, 'x')) { - while (c != NULL && sscanf(c, "%dx %f", &t, &f) ) { + while (c != NULL && (sscanf(c, "%dx %f", &t, &f)==2)) { r += f * t; - c = strchr(c+1, '+'); + c = strchr(c + 1, '+'); + if (c) + c++; /* move past the + */ } } else { sscanf(c, "%f", &r); @@ -92,16 +116,20 @@ static float cpu_config_val(char *str) { return r; } -static int cpu_config_cmp(char *str0, char *str1) { +static int cpu_config_cmp(char *str0, char *str1) +{ float r0, r1; r0 = cpu_config_val(str0); r1 = cpu_config_val(str1); - if (r0 == r1) return 0; - if (r0 < r1) return -1; + if (r0 == r1) + return 0; + if (r0 < r1) + return -1; return 1; } -static int cpu_config_is_close(char *str0, char *str1) { +static int cpu_config_is_close(char *str0, char *str1) +{ float r0, r1, r1n; r0 = cpu_config_val(str0); r1 = cpu_config_val(str1); @@ -111,76 +139,85 @@ static int cpu_config_is_close(char *str0, char *str1) { return 0; } -static gen_machine_id(bench_machine *m) { +static void gen_machine_id(bench_machine *m) +{ char *s; + if (m) { if (m->mid != NULL) free(m->mid); - /* Don't try and translate unknown. The mid string needs to be made of all - * untranslated elements.*/ + + /* Don't try and translate unknown. The mid string needs to be made of + * all untranslated elements.*/ m->mid = g_strdup_printf("%s;%s;%.2f", - (m->board != NULL) ? m->board : "(Unknown)", m->cpu_name, cpu_config_val(m->cpu_config) ); - s = m->mid; - while (*s != 0) { - if (!isalnum(*s)) { - if (*s != ';' - && *s != '(' - && *s != '(' - && *s != ')') + (m->board != NULL) ? m->board : "(Unknown)", + m->cpu_name, cpu_config_val(m->cpu_config)); + for (s = m->mid; *s; s++) { + if (!isalnum(*s) && *s != '(' && *s != ')' && *s != ';') *s = '_'; - } - s++; } } } -bench_machine *bench_machine_new() { - bench_machine *m = NULL; - m = malloc(sizeof(bench_machine)); - if (m) - memset(m, 0, sizeof(bench_machine)); - return m; +bench_machine *bench_machine_new() +{ + return calloc(1, sizeof(bench_machine)); } -bench_machine *bench_machine_this() { +bench_machine *bench_machine_this() +{ bench_machine *m = NULL; char *tmp; m = bench_machine_new(); if (m) { + m->ptr_bits = BENCH_PTR_BITS; + m->is_su_data = (getuid() == 0); m->board = module_call_method("devices::getMotherboard"); m->cpu_name = module_call_method("devices::getProcessorName"); m->cpu_desc = module_call_method("devices::getProcessorDesc"); - m->cpu_config = module_call_method("devices::getProcessorFrequencyDesc"); + m->cpu_config = + module_call_method("devices::getProcessorFrequencyDesc"); + m->gpu_desc = module_call_method("devices::getGPUList"); m->ogl_renderer = module_call_method("computer::getOGLRenderer"); - tmp = module_call_method("devices::getMemoryTotal"); - m->memory_kiB = atoi(tmp); + tmp = module_call_method("computer::getMemoryTotal"); + m->memory_kiB = strtoull(tmp, NULL, 10); + m->memory_phys_MiB = memory_devices_get_system_memory_MiB(); + m->ram_types = memory_devices_get_system_memory_types_str(); + m->machine_type = module_call_method("computer::getMachineType"); free(tmp); - cpu_procs_cores_threads(&m->processors, &m->cores, &m->threads); + cpu_procs_cores_threads_nodes(&m->processors, &m->cores, &m->threads, &m->nodes); gen_machine_id(m); } return m; } -void bench_machine_free(bench_machine *s) { +void bench_machine_free(bench_machine *s) +{ if (s) { free(s->board); free(s->cpu_name); free(s->cpu_desc); free(s->cpu_config); free(s->mid); + free(s->ram_types); + free(s->machine_type); + free(s); } } -void bench_result_free(bench_result *s) { +void bench_result_free(bench_result *s) +{ if (s) { free(s->name); bench_machine_free(s->machine); + g_free(s); } } -bench_result *bench_result_this_machine(const char *bench_name, bench_value r) { +bench_result *bench_result_this_machine(const char *bench_name, bench_value r) +{ bench_result *b = NULL; b = malloc(sizeof(bench_result)); @@ -195,13 +232,14 @@ bench_result *bench_result_this_machine(const char *bench_name, bench_value r) { } /* -1 for none */ -static int nx_prefix(const char *str) { +static int nx_prefix(const char *str) +{ char *s, *x; if (str != NULL) { - s = (char*)str; + s = (char *)str; x = strchr(str, 'x'); - if (x && x-s >= 1) { - while(s != x) { + if (x && x - s >= 1) { + while (s != x) { if (!isdigit(*s)) return -1; s++; @@ -214,11 +252,13 @@ static int nx_prefix(const char *str) { } /* old results didn't store the actual number of threads used */ -static int guess_threads_old_result(const char *bench_name, int threads_available) { +static int guess_threads_old_result(const char *bench_name, + int threads_available) +{ #define CHKBNAME(BN) (strcmp(bench_name, BN) == 0) - if (CHKBNAME("CPU Fibonacci") ) + if (CHKBNAME("CPU Fibonacci")) return 1; - if (CHKBNAME("FPU FFT") ) { + if (CHKBNAME("FPU FFT")) { if (threads_available >= 4) return 4; else if (threads_available >= 2) @@ -226,7 +266,7 @@ static int guess_threads_old_result(const char *bench_name, int threads_availabl else return 1; } - if (CHKBNAME("CPU N-Queens") ) { + if (CHKBNAME("CPU N-Queens")) { if (threads_available >= 10) return 10; else if (threads_available >= 5) @@ -239,204 +279,327 @@ static int guess_threads_old_result(const char *bench_name, int threads_availabl return threads_available; } -bench_result *bench_result_benchmarkconf(const char *section, const char *key, char **values) { - bench_result *b = NULL; - char *s0, *s1, *s2; - int nx = 0, vl = 0; - float n, m; +static gboolean cpu_name_needs_cleanup(const char *cpu_name) +{ + return strstr(cpu_name, "Intel") || strstr(cpu_name, "AMD") || + strstr(cpu_name, "VIA") || strstr(cpu_name, "Cyrix"); +} - vl = g_strv_length(values); +static void filter_invalid_chars(gchar *str) +{ + gchar *p; - b = malloc(sizeof(bench_result)); - if (b) { - memset(b, 0, sizeof(bench_result)); - b->machine = bench_machine_new(); - b->name = strdup(section); - - if (vl >= 10) { /* the 11th could be empty */ - b->machine->mid = strdup(key); - /* first try as bench_value, then try as double 'result' only */ - b->bvalue = bench_value_from_str(values[0]); - if (b->bvalue.result == -1) - b->bvalue.result = atoi(values[0]); - b->bvalue.threads_used = atoi(values[1]); - b->machine->board = strdup(values[2]); - b->machine->cpu_name = strdup(values[3]); - b->machine->cpu_desc = strdup(values[4]); - b->machine->cpu_config = strdup(values[5]); - b->machine->memory_kiB = atoi(values[6]); - b->machine->processors = atoi(values[7]); - b->machine->cores = atoi(values[8]); - b->machine->threads = atoi(values[9]); - if (vl >= 11) - b->machine->ogl_renderer = strdup(values[10]); - b->legacy = 0; - } else if (vl >= 2) { - b->bvalue.result = atof(values[0]); - b->legacy = 1; - - /* old old format has prefix before cpu name (ex: 4x Pentium...) */ - nx = nx_prefix(key); - if (nx > 0) { - b->machine->cpu_name = strdup(strchr(key, 'x') + 1); - b->machine->threads = nx; - } else { - b->machine->cpu_name = strdup(key); - b->machine->threads = 1; - } + for (p = str; *p; p++) { + if (*p == '\n' || *p == ';' || *p == '|') + *p = '_'; + } +} - b->machine->cpu_config = strdup(values[1]); - /* new old format has cpu_config string with nx prefix */ - nx = nx_prefix(values[1]); - if (nx > 0) { - b->machine->threads = nx; - } +static gboolean json_get_boolean(JsonObject *obj, const gchar *key) +{ + if (!json_object_has_member(obj, key)) + return FALSE; + return json_object_get_boolean_member(obj, key); +} - b->bvalue.threads_used = guess_threads_old_result(section, b->machine->threads); - - /* If the clock rate in the id string is more than the - * config string, use that. Older hardinfo used current cpu freq - * instead of max freq. - * "...@ 2.00GHz" -> 2000.0 */ - s0 = b->machine->cpu_name; - s2 = strstr(s0, "Hz"); - if (s2 && s2 > s0 + 2) { - m = 1; /* assume M */ - if (*(s2-1) == 'G') - m = 1000; - s1 = s2 - 2; - while (s1 > s0) { - if (!( isdigit(*s1) || *s1 == '.' || *s1 == ' ')) - break; - s1--; - } - - if (s1 > s0) { - n = atof(s1+1); - n *= m; - - s1 = g_strdup_printf("%dx %.2f %s", b->bvalue.threads_used, n, _("MHz")); - if ( cpu_config_cmp(b->machine->cpu_config, s1) == -1 - && !cpu_config_is_close(b->machine->cpu_config, s1) ) { - free(b->machine->cpu_config); - b->machine->cpu_config = s1; - } else { - free(s1); - } - } - } +static double json_get_double(JsonObject *obj, const gchar *key) +{ + if (!json_object_has_member(obj, key)) + return 0; + return json_object_get_double_member(obj, key); +} - /* old results only give threads */ - b->machine->processors = -1; - b->machine->cores = -1; - } +static int json_get_int(JsonObject *obj, const gchar *key) +{ + if (!json_object_has_member(obj, key)) + return 0; + return json_object_get_int_member(obj, key); +} - b->machine->cpu_config = cpu_config_retranslate(b->machine->cpu_config, 0, 1); - if (b->machine->board != NULL && strlen(b->machine->board) == 0) { - free(b->machine->board); - b->machine->board = NULL; - } - if (b->machine->cpu_desc != NULL && strlen(b->machine->cpu_desc) == 0) { - free(b->machine->cpu_desc); - b->machine->cpu_desc = NULL; - } - gen_machine_id(b->machine); - } - return b; +static const gchar *json_get_string(JsonObject *obj, const gchar *key) +{ + if (!json_object_has_member(obj, key)) + return ""; + return json_object_get_string_member(obj, key); +} + +static gchar *json_get_string_dup(JsonObject *obj, const gchar *key) +{ + return g_strdup(json_get_string(obj, key)); +} + +static double parse_frequency(const char *freq) +{ + static locale_t locale; + + if (!locale) + locale = newlocale(LC_NUMERIC_MASK, "C", NULL); + + return strtod_l(freq, NULL, locale); +} + +static void append_cpu_config(JsonObject *object, + const gchar *member_name, + JsonNode *member_node, + gpointer user_data) +{ + GString *output = user_data; + + if (output->len) + g_string_append(output, ", "); + + g_string_append_printf(output, "%ldx %.2f %s", (long int)json_node_get_int(member_node), + parse_frequency(member_name), _("MHz")); } -char *bench_result_benchmarkconf_line(bench_result *b) { - char *cpu_config = cpu_config_retranslate(b->machine->cpu_config, 1, 0); - char *bv = bench_value_to_str(b->bvalue); - char *ret = g_strdup_printf("%s=%s|%d|%s|%s|%s|%s|%d|%d|%d|%d|%s\n", - b->machine->mid, bv, b->bvalue.threads_used, - (b->machine->board != NULL) ? b->machine->board : "", - b->machine->cpu_name, - (b->machine->cpu_desc != NULL) ? b->machine->cpu_desc : "", - cpu_config, - b->machine->memory_kiB, - b->machine->processors, b->machine->cores, b->machine->threads, - (b->machine->ogl_renderer != NULL) ? b->machine->ogl_renderer : "" - ); - free(cpu_config); - free(bv); +static gchar *get_cpu_config(JsonObject *machine) +{ + JsonObject *cpu_config_map = + json_object_get_object_member(machine, "CpuConfigMap"); + + if (!cpu_config_map) + return json_get_string_dup(machine, "CpuConfig"); + + GString *output = g_string_new(NULL); + json_object_foreach_member(cpu_config_map, append_cpu_config, output); + return g_string_free(output, FALSE); +} + +static gchar *get_cpu_desc(JsonObject *machine) +{ + int num_cpus = json_get_int(machine, "NumCpus"); + + if (!num_cpus) + return json_get_string_dup(machine, "CpuDesc"); + + /* FIXME: This is adapted from processor_describe_default() in + * devices.c! */ + + int num_cores = json_get_int(machine, "NumCores"); + int num_threads = json_get_int(machine, "NumThreads"); + int num_nodes = json_get_int(machine, "NumNodes"); + const char *packs_fmt = + ngettext("%d physical processor", "%d physical processors", num_cpus); + const char *cores_fmt = ngettext("%d core", "%d cores", num_cores); + const char *threads_fmt = ngettext("%d thread", "%d threads", num_threads); + char *full_fmt, *ret; + + if (num_nodes > 1) { + const char *nodes_fmt = + ngettext("%d NUMA node", "%d NUMA nodes", num_nodes); + + full_fmt = g_strdup_printf( + _(/*/NP procs; NC cores across NN nodes; NT threads*/ + "%s; %s across %s; %s"), + packs_fmt, cores_fmt, nodes_fmt, threads_fmt); + ret = g_strdup_printf(full_fmt, num_cpus, num_cores * num_nodes, num_nodes, num_threads); + } else { + full_fmt = + g_strdup_printf(_(/*/NP procs; NC cores; NT threads*/ "%s; %s; %s"), + packs_fmt, cores_fmt, threads_fmt); + ret = g_strdup_printf(full_fmt, num_cpus, num_cores, num_threads); + } + + free(full_fmt); return ret; } -static char *bench_result_more_info_less(bench_result *b) { - char *memory = - (b->machine->memory_kiB > 0) - ? g_strdup_printf("%d %s", b->machine->memory_kiB, _("kiB") ) - : g_strdup(_(unk) ); - - char *ret = g_strdup_printf("[%s]\n" - /* threads */ "%s=%d\n" - /* legacy */ "%s=%s\n" - "[%s]\n" - /* board */ "%s=%s\n" - /* cpu */ "%s=%s\n" - /* cpudesc */ "%s=%s\n" - /* cpucfg */ "%s=%s\n" - /* threads */ "%s=%d\n" - /* ogl rend */ "%s=%s\n" - /* mem */ "%s=%s\n", - _("Benchmark Result"), - _("Threads"), b->bvalue.threads_used, - b->legacy ? _("Note") : "#Note", - b->legacy ? _("This result is from an old version of HardInfo. Results might not be comparable to current version. Some details are missing.") : "", - _("Machine"), - _("Board"), (b->machine->board != NULL) ? b->machine->board : _(unk), - _("CPU Name"), b->machine->cpu_name, - _("CPU Description"), (b->machine->cpu_desc != NULL) ? b->machine->cpu_desc : _(unk), - _("CPU Config"), b->machine->cpu_config, - _("Threads Available"), b->machine->threads, - _("OpenGL Renderer"), (b->machine->ogl_renderer != NULL) ? b->machine->ogl_renderer : _(unk), - _("Memory"), memory - ); +bench_result *bench_result_benchmarkjson(const gchar *bench_name, + JsonNode *node) +{ + JsonObject *machine; + bench_result *b; + gchar *p; + + if (json_node_get_node_type(node) != JSON_NODE_OBJECT) + return NULL; + + machine = json_node_get_object(node); + + b = g_new0(bench_result, 1); + b->name = g_strdup(bench_name); + b->legacy = json_get_boolean(machine, "Legacy"); + + b->bvalue = (bench_value){ + .result = json_get_double(machine, "BenchmarkResult"), + .elapsed_time = json_get_double(machine, "ElapsedTime"), + .threads_used = json_get_int(machine, "UsedThreads"), + .revision = json_get_int(machine, "BenchmarkRevision"), + }; + + snprintf(b->bvalue.extra, sizeof(b->bvalue.extra), "%s", + json_get_string(machine, "ExtraInfo")); + filter_invalid_chars(b->bvalue.extra); + + snprintf(b->bvalue.user_note, sizeof(b->bvalue.user_note), "%s", + json_get_string(machine, "UserNote")); + filter_invalid_chars(b->bvalue.user_note); + + int nodes = json_get_int(machine, "NumNodes"); + + if (nodes == 0) + nodes = 1; + + b->machine = bench_machine_new(); + *b->machine = (bench_machine){ + .board = json_get_string_dup(machine, "Board"), + .memory_kiB = json_get_int(machine, "MemoryInKiB"), + .cpu_name = json_get_string_dup(machine, "CpuName"), + .cpu_desc = get_cpu_desc(machine), + .cpu_config = get_cpu_config(machine), + .ogl_renderer = json_get_string_dup(machine, "OpenGlRenderer"), + .gpu_desc = json_get_string_dup(machine, "GpuDesc"), + .processors = json_get_int(machine, "NumCpus"), + .cores = json_get_int(machine, "NumCores"), + .threads = json_get_int(machine, "NumThreads"), + .nodes = nodes, + .mid = json_get_string_dup(machine, "MachineId"), + .ptr_bits = json_get_int(machine, "PointerBits"), + .is_su_data = json_get_boolean(machine, "DataFromSuperUser"), + .memory_phys_MiB = json_get_int(machine, "PhysicalMemoryInMiB"), + .ram_types = json_get_string_dup(machine, "MemoryTypes"), + .machine_data_version = json_get_int(machine, "MachineDataVersion"), + .machine_type = json_get_string_dup(machine, "MachineType"), + }; + + return b; +} + +static char *bench_result_more_info_less(bench_result *b) +{ + char *memory = NULL; + if (b->machine->memory_phys_MiB) { + memory = + g_strdup_printf("%" PRId64 " %s %s", b->machine->memory_phys_MiB, + _("MiB"), b->machine->ram_types); + } else { + memory = + (b->machine->memory_kiB > 0) + ? g_strdup_printf("%" PRId64 " %s %s", b->machine->memory_kiB, + _("kiB"), problem_marker()) + : g_strdup(_(unk)); + } + char bench_str[256] = ""; + if (b->bvalue.revision >= 0) + snprintf(bench_str, 127, "%d", b->bvalue.revision); + char bits[24] = ""; + if (b->machine->ptr_bits) + snprintf(bits, 23, _("%d-bit"), b->machine->ptr_bits); + + char *ret = g_strdup_printf( + "[%s]\n" + /* threads */ "%s=%d\n" + /* elapsed */ "%s=%0.4f %s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + /* legacy */ "%s%s=%s\n" + "[%s]\n" + /* board */ "%s=%s\n" + /* machine_type */ "%s=%s\n" + /* cpu */ "%s=%s\n" + /* cpudesc */ "%s=%s\n" + /* cpucfg */ "%s=%s\n" + /* threads */ "%s=%d\n" + /* gpu desc */ "%s=%s\n" + /* ogl rend */ "%s=%s\n" + /* mem */ "%s=%s\n" + /* bits */ "%s=%s\n", + _("Benchmark Result"), _("Threads"), b->bvalue.threads_used, + _("Elapsed Time"), b->bvalue.elapsed_time, _("seconds"), + *bench_str ? _("Revision") : "#Revision", bench_str, + *b->bvalue.extra ? _("Extra Information") : "#Extra", b->bvalue.extra, + *b->bvalue.user_note ? _("User Note") : "#User Note", + b->bvalue.user_note, b->legacy ? problem_marker() : "", + b->legacy ? _("Note") : "#Note", + b->legacy ? _("This result is from an old version of HardInfo. Results " + "might not be comparable to current version. Some " + "details are missing.") + : "", + _("Machine"), + _("Board"), (b->machine->board != NULL) ? b->machine->board : _(unk), + _("Machine Type"), (b->machine->machine_type != NULL) ? b->machine->machine_type : _(unk), + _("CPU Name"), b->machine->cpu_name, + _("CPU Description"), (b->machine->cpu_desc != NULL) ? b->machine->cpu_desc : _(unk), + _("CPU Config"), b->machine->cpu_config, + _("Threads Available"), b->machine->threads, + _("GPU"), (b->machine->gpu_desc != NULL) ? b->machine->gpu_desc : _(unk), + _("OpenGL Renderer"), (b->machine->ogl_renderer != NULL) ? b->machine->ogl_renderer : _(unk), + _("Memory"), memory, + b->machine->ptr_bits ? _("Pointer Size") : "#AddySize", bits); free(memory); return ret; } -static char *bench_result_more_info_complete(bench_result *b) { - return g_strdup_printf("[%s]\n" - /* bench name */"%s=%s\n" - /* threads */ "%s=%d\n" - /* result */ "%s=%0.2f\n" - /* elapsed */ "%s=%0.2f\n" - /* legacy */ "%s=%s\n" - "[%s]\n" - /* board */ "%s=%s\n" - /* cpu */ "%s=%s\n" - /* cpudesc */ "%s=%s\n" - /* cpucfg */ "%s=%s\n" - /* threads */ "%s=%d\n" - /* ogl rend */ "%s=%s\n" - /* mem */ "%s=%d %s\n" - "[%s]\n" - /* mid */ "%s=%s\n" - /* cfg_val */ "%s=%.2f\n", - _("Benchmark Result"), - _("Benchmark"), b->name, - _("Threads"), b->bvalue.threads_used, - _("Result"), b->bvalue.result, - _("Elapsed Time"), b->bvalue.elapsed_time, - b->legacy ? _("Note") : "#Note", - b->legacy ? _("This result is from an old version of HardInfo. Results might not be comparable to current version. Some details are missing.") : "", - _("Machine"), - _("Board"), (b->machine->board != NULL) ? b->machine->board : _(unk), - _("CPU Name"), b->machine->cpu_name, - _("CPU Description"), (b->machine->cpu_desc != NULL) ? b->machine->cpu_desc : _(unk), - _("CPU Config"), b->machine->cpu_config, - _("Threads Available"), b->machine->threads, - _("OpenGL Renderer"), (b->machine->ogl_renderer != NULL) ? b->machine->ogl_renderer : _(unk), - _("Memory"), b->machine->memory_kiB, _("kiB"), - _("Handles"), - _("mid"), b->machine->mid, - _("cfg_val"), cpu_config_val(b->machine->cpu_config) - ); +static char *bench_result_more_info_complete(bench_result *b) +{ + char bench_str[256] = ""; + strncpy(bench_str, b->name, 127); + if (b->bvalue.revision >= 0) + snprintf(bench_str + strlen(bench_str), 127, " (r%d)", + b->bvalue.revision); + char bits[24] = ""; + if (b->machine->ptr_bits) + snprintf(bits, 23, _("%d-bit"), b->machine->ptr_bits); + + return g_strdup_printf( + "[%s]\n" + /* bench name */ "%s=%s\n" + /* threads */ "%s=%d\n" + /* result */ "%s=%0.2f\n" + /* elapsed */ "%s=%0.4f %s\n" + "%s=%s\n" + "%s=%s\n" + /* legacy */ "%s%s=%s\n" + "[%s]\n" + /* board */ "%s=%s\n" + /* machine_type */ "%s=%s\n" + /* cpu */ "%s=%s\n" + /* cpudesc */ "%s=%s\n" + /* cpucfg */ "%s=%s\n" + /* threads */ "%s=%d\n" + /* gpu desc */ "%s=%s\n" + /* ogl rend */ "%s=%s\n" + /* mem */ "%s=%" PRId64 " %s\n" + /* mem phys */ "%s=%" PRId64 " %s %s\n" + /* bits */ "%s=%s\n" + "%s=%d\n" + "%s=%d\n" + "[%s]\n" + /* mid */ "%s=%s\n" + /* cfg_val */ "%s=%.2f\n", + _("Benchmark Result"), _("Benchmark"), bench_str, _("Threads"), + b->bvalue.threads_used, _("Result"), b->bvalue.result, + _("Elapsed Time"), b->bvalue.elapsed_time, _("seconds"), + *b->bvalue.extra ? _("Extra Information") : "#Extra", b->bvalue.extra, + *b->bvalue.user_note ? _("User Note") : "#User Note", + b->bvalue.user_note, b->legacy ? problem_marker() : "", + b->legacy ? _("Note") : "#Note", + b->legacy ? _("This result is from an old version of HardInfo. Results " + "might not be comparable to current version. Some " + "details are missing.") + : "", + _("Machine"), _("Board"), + (b->machine->board != NULL) ? b->machine->board : _(unk), + _("Machine Type"), (b->machine->machine_type != NULL) ? b->machine->machine_type : _(unk), + _("CPU Name"), + b->machine->cpu_name, _("CPU Description"), + (b->machine->cpu_desc != NULL) ? b->machine->cpu_desc : _(unk), + _("CPU Config"), b->machine->cpu_config, _("Threads Available"), + b->machine->threads, _("GPU"), + (b->machine->gpu_desc != NULL) ? b->machine->gpu_desc : _(unk), + _("OpenGL Renderer"), + (b->machine->ogl_renderer != NULL) ? b->machine->ogl_renderer : _(unk), + _("Memory"), b->machine->memory_kiB, _("kiB"), _("Physical Memory"), + b->machine->memory_phys_MiB, _("MiB"), b->machine->ram_types, + b->machine->ptr_bits ? _("Pointer Size") : "#AddySize", bits, + ".machine_data_version", b->machine->machine_data_version, + ".is_su_data", b->machine->is_su_data, _("Handles"), _("mid"), + b->machine->mid, _("cfg_val"), cpu_config_val(b->machine->cpu_config)); } -char *bench_result_more_info(bench_result *b) { - //return bench_result_more_info_complete(b); +char *bench_result_more_info(bench_result *b) +{ + // return bench_result_more_info_complete(b); return bench_result_more_info_less(b); } diff --git a/modules/benchmark/bench_util.c b/modules/benchmark/bench_util.c new file mode 100644 index 00000000..d9e5bc55 --- /dev/null +++ b/modules/benchmark/bench_util.c @@ -0,0 +1,58 @@ + +#include "benchmark.h" +#include "md5.h" + +gchar *get_test_data(gsize min_size) { + gchar *bdata_path, *data; + gsize data_size; + + gchar *exp_data, *p; + gsize sz; + + bdata_path = g_build_filename(params.path_data, "benchmark.data", NULL); + if (!g_file_get_contents(bdata_path, &data, &data_size, NULL)) { + g_free(bdata_path); + return NULL; + } + + if (data_size < min_size) { + DEBUG("expanding %lu bytes of test data to %lu bytes", data_size, min_size); + exp_data = g_malloc(min_size + 1); + memcpy(exp_data, data, data_size); + p = exp_data + data_size; + sz = data_size; + while (sz < (min_size - data_size) ) { + memcpy(p, data, data_size); + p += data_size; + sz += data_size; + } + strncpy(p, data, min_size - sz); + g_free(data); + data = exp_data; + } + g_free(bdata_path); + + return data; +} + +char *digest_to_str(const char *digest, int len) { + int max = len * 2; + char *ret = malloc(max+1); + char *p = ret; + memset(ret, 0, max+1); + int i = 0; + for(; i < len; i++) { + unsigned char byte = digest[i]; + p += sprintf(p, "%02x", byte); + } + return ret; +} + +char *md5_digest_str(const char *data, unsigned int len) { + struct MD5Context ctx; + guchar digest[16]; + MD5Init(&ctx); + MD5Update(&ctx, (guchar *)data, len); + MD5Final(digest, &ctx); + return digest_to_str(digest, 16); +} diff --git a/modules/benchmark/benches.c b/modules/benchmark/benches.c index e09dedcc..c621d695 100644 --- a/modules/benchmark/benches.c +++ b/modules/benchmark/benches.c @@ -1,10 +1,10 @@ /* - * HardInfo - Displays System Information - * Copyright (C) 2003-2017 Leandro A. F. Pereira <leandro@hardinfo.org> + * HardInfo - System Information and Benchmark + * Copyright (C) 2003-2017 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,15 +26,6 @@ gchar *CN() { \ return benchmark_include_results(bench_results[BID], BN); \ } -BENCH_CALLBACK(callback_gui, "GPU Drawing", BENCHMARK_GUI, 1); -BENCH_CALLBACK(callback_fft, "FPU FFT", BENCHMARK_FFT, 0); -BENCH_CALLBACK(callback_nqueens, "CPU N-Queens", BENCHMARK_NQUEENS, 0); -BENCH_CALLBACK(callback_raytr, "FPU Raytracing", BENCHMARK_RAYTRACE, 0); -BENCH_CALLBACK(callback_bfsh, "CPU Blowfish", BENCHMARK_BLOWFISH, 0); -BENCH_CALLBACK(callback_cryptohash, "CPU CryptoHash", BENCHMARK_CRYPTOHASH, 1); -BENCH_CALLBACK(callback_fib, "CPU Fibonacci", BENCHMARK_FIB, 0); -BENCH_CALLBACK(callback_zlib, "CPU Zlib", BENCHMARK_ZLIB, 0); - #define BENCH_SCAN_SIMPLE(SN, BF, BID) \ void SN(gboolean reload) { \ SCAN_START(); \ @@ -42,14 +33,30 @@ void SN(gboolean reload) { \ SCAN_END(); \ } -BENCH_SCAN_SIMPLE(scan_fft, benchmark_fft, BENCHMARK_FFT); -BENCH_SCAN_SIMPLE(scan_nqueens, benchmark_nqueens, BENCHMARK_NQUEENS); -BENCH_SCAN_SIMPLE(scan_raytr, benchmark_raytrace, BENCHMARK_RAYTRACE); -BENCH_SCAN_SIMPLE(scan_bfsh, benchmark_fish, BENCHMARK_BLOWFISH); -BENCH_SCAN_SIMPLE(scan_cryptohash, benchmark_cryptohash, BENCHMARK_CRYPTOHASH); -BENCH_SCAN_SIMPLE(scan_fib, benchmark_fib, BENCHMARK_FIB); -BENCH_SCAN_SIMPLE(scan_zlib, benchmark_zlib, BENCHMARK_ZLIB); +#define BENCH_SIMPLE(BID, BN, BF, R) \ + BENCH_CALLBACK(callback_##BF, BN, BID, R); \ + BENCH_SCAN_SIMPLE(scan_##BF, BF, BID); +// ID, NAME, FUNCTION, R (0 = lower is better, 1 = higher is better) +BENCH_SIMPLE(BENCHMARK_FIB, "CPU Fibonacci", benchmark_fib, 1); +BENCH_SIMPLE(BENCHMARK_NQUEENS, "CPU N-Queens", benchmark_nqueens, 1); +BENCH_SIMPLE(BENCHMARK_FFT, "FPU FFT", benchmark_fft, 1); +BENCH_SIMPLE(BENCHMARK_RAYTRACE, "FPU Raytracing (Single-thread)", benchmark_raytrace, 1); +BENCH_SIMPLE(BENCHMARK_BLOWFISH_SINGLE, "CPU Blowfish (Single-thread)", benchmark_bfish_single, 1); +BENCH_SIMPLE(BENCHMARK_BLOWFISH_THREADS, "CPU Blowfish (Multi-thread)", benchmark_bfish_threads, 1); +BENCH_SIMPLE(BENCHMARK_BLOWFISH_CORES, "CPU Blowfish (Multi-core)", benchmark_bfish_cores, 1); +BENCH_SIMPLE(BENCHMARK_ZLIB, "CPU Zlib", benchmark_zlib, 1); +BENCH_SIMPLE(BENCHMARK_CRYPTOHASH, "CPU CryptoHash", benchmark_cryptohash, 1); +BENCH_SIMPLE(BENCHMARK_SBCPU_SINGLE, "SysBench CPU (Single-thread)", benchmark_sbcpu_single, 1); +BENCH_SIMPLE(BENCHMARK_SBCPU_ALL, "SysBench CPU (Multi-thread)", benchmark_sbcpu_all, 1); +BENCH_SIMPLE(BENCHMARK_SBCPU_QUAD, "SysBench CPU (Four threads)", benchmark_sbcpu_quad, 1); +BENCH_SIMPLE(BENCHMARK_MEMORY_SINGLE, "SysBench Memory (Single-thread)", benchmark_memory_single, 1); +BENCH_SIMPLE(BENCHMARK_MEMORY_DUAL, "SysBench Memory (Two threads)", benchmark_memory_dual, 1); +BENCH_SIMPLE(BENCHMARK_MEMORY_QUAD, "SysBench Memory (Quad threads)", benchmark_memory_quad, 1); +BENCH_SIMPLE(BENCHMARK_MEMORY_ALL, "SysBench Memory (Multi-thread)", benchmark_memory_all, 1); + +#if !GTK_CHECK_VERSION(3,0,0) +BENCH_CALLBACK(callback_gui, "GPU Drawing", BENCHMARK_GUI, 1); void scan_gui(gboolean reload) { SCAN_START(); @@ -69,37 +76,178 @@ void scan_gui(gboolean reload) } SCAN_END(); } +#endif 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_("CPU Zlib"), "file-roller.png", callback_zlib, scan_zlib, 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}, -#if !GTK_CHECK_VERSION(3,0,0) - {N_("GPU Drawing"), "module.png", callback_gui, scan_gui, MODULE_FLAG_NO_REMOTE}, + [BENCHMARK_BLOWFISH_SINGLE] = + { + N_("CPU Blowfish (Single-thread)"), + "blowfish.png", + callback_benchmark_bfish_single, + scan_benchmark_bfish_single, + MODULE_FLAG_NONE, + }, + [BENCHMARK_BLOWFISH_THREADS] = + { + N_("CPU Blowfish (Multi-thread)"), + "blowfish.png", + callback_benchmark_bfish_threads, + scan_benchmark_bfish_threads, + MODULE_FLAG_NONE, + }, + [BENCHMARK_BLOWFISH_CORES] = + { + N_("CPU Blowfish (Multi-core)"), + "blowfish.png", + callback_benchmark_bfish_cores, + scan_benchmark_bfish_cores, + MODULE_FLAG_NONE, + }, + [BENCHMARK_ZLIB] = + { + N_("CPU Zlib"), + "file-roller.png", + callback_benchmark_zlib, + scan_benchmark_zlib, + MODULE_FLAG_NONE, + }, + [BENCHMARK_CRYPTOHASH] = + { + N_("CPU CryptoHash"), + "cryptohash.png", + callback_benchmark_cryptohash, + scan_benchmark_cryptohash, + MODULE_FLAG_NONE, + }, + [BENCHMARK_FIB] = + { + N_("CPU Fibonacci"), + "nautilus.png", + callback_benchmark_fib, + scan_benchmark_fib, + MODULE_FLAG_NONE, + }, + [BENCHMARK_NQUEENS] = + { + N_("CPU N-Queens"), + "nqueens.png", + callback_benchmark_nqueens, + scan_benchmark_nqueens, + MODULE_FLAG_NONE, + }, + [BENCHMARK_FFT] = + { + N_("FPU FFT"), + "fft.png", + callback_benchmark_fft, + scan_benchmark_fft, + MODULE_FLAG_NONE, + }, + [BENCHMARK_RAYTRACE] = + { + N_("FPU Raytracing (Single-thread)"), + "raytrace.png", + callback_benchmark_raytrace, + scan_benchmark_raytrace, + MODULE_FLAG_NONE, + }, + [BENCHMARK_SBCPU_SINGLE] = + { + N_("SysBench CPU (Single-thread)"), + "processor.png", + callback_benchmark_sbcpu_single, + scan_benchmark_sbcpu_single, + MODULE_FLAG_NONE, + }, + [BENCHMARK_SBCPU_ALL] = + { + N_("SysBench CPU (Multi-thread)"), + "processor.png", + callback_benchmark_sbcpu_all, + scan_benchmark_sbcpu_all, + MODULE_FLAG_NONE, + }, + [BENCHMARK_SBCPU_QUAD] = + { + N_("SysBench CPU (Four threads)"), + "processor.png", + callback_benchmark_sbcpu_quad, + scan_benchmark_sbcpu_quad, + MODULE_FLAG_HIDE, + }, + [BENCHMARK_MEMORY_SINGLE] = + { + N_("SysBench Memory (Single-thread)"), + "memory.png", + callback_benchmark_memory_single, + scan_benchmark_memory_single, + MODULE_FLAG_NONE, + }, + [BENCHMARK_MEMORY_DUAL] = + { + N_("SysBench Memory (Two threads)"), + "memory.png", + callback_benchmark_memory_dual, + scan_benchmark_memory_dual, + MODULE_FLAG_HIDE, + }, + [BENCHMARK_MEMORY_QUAD] = + { + N_("SysBench Memory (Quad threads)"), + "memory.png", + callback_benchmark_memory_quad, + scan_benchmark_memory_quad, + MODULE_FLAG_HIDE, + }, + [BENCHMARK_MEMORY_ALL] = + { + N_("SysBench Memory (Multi-thread)"), + "memory.png", + callback_benchmark_memory_all, + scan_benchmark_memory_all, + MODULE_FLAG_NONE, + }, +#if !GTK_CHECK_VERSION(3, 0, 0) + [BENCHMARK_GUI] = + { + N_("GPU Drawing"), + "module.png", + callback_gui, + scan_gui, + MODULE_FLAG_NO_REMOTE | MODULE_FLAG_HIDE, + }, +#else + [BENCHMARK_GUI] = {"#"}, #endif - {NULL} -}; + {NULL}}; const gchar *hi_note_func(gint entry) { switch (entry) { - case BENCHMARK_CRYPTOHASH: - return _("Results in MiB/second. Higher is better."); + case BENCHMARK_SBCPU_SINGLE: + case BENCHMARK_SBCPU_QUAD: + case BENCHMARK_SBCPU_ALL: + return _("Alexey Kopytov's <i><b>sysbench</b></i> is required.\n" + "Results in events/second. Higher is better."); + + case BENCHMARK_MEMORY_SINGLE: + case BENCHMARK_MEMORY_DUAL: + case BENCHMARK_MEMORY_QUAD: + case BENCHMARK_MEMORY_ALL: + return _("Alexey Kopytov's <i><b>sysbench</b></i> is required.\n" + "Results in MiB/second. Higher is better."); + case BENCHMARK_CRYPTOHASH: + case BENCHMARK_BLOWFISH_SINGLE: + case BENCHMARK_BLOWFISH_THREADS: + case BENCHMARK_BLOWFISH_CORES: case BENCHMARK_ZLIB: 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 _("Results in HIMarks. Higher is better."); } return NULL; diff --git a/modules/benchmark/blowfish.c b/modules/benchmark/blowfish.c index 2aa11a2a..f8d2e14a 100644 --- a/modules/benchmark/blowfish.c +++ b/modules/benchmark/blowfish.c @@ -491,48 +491,3 @@ void Blowfish_Init(BLOWFISH_CTX * ctx, unsigned char *key, int keyLen) } } } - -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) -{ - bench_value r = EMPTY_BENCH_VALUE; - - 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] = r; - g_free(bdata_path); - return; - } - - shell_view_set_enabled(FALSE); - shell_status_update("Performing Blowfish benchmark..."); - - r = benchmark_parallel_for(0, 0, 50000, parallel_blowfish, tmpsrc); - r.result = r.elapsed_time; - - bench_results[BENCHMARK_BLOWFISH] = r; - g_free(bdata_path); - g_free(tmpsrc); -} diff --git a/modules/benchmark/blowfish2.c b/modules/benchmark/blowfish2.c new file mode 100644 index 00000000..7426bef9 --- /dev/null +++ b/modules/benchmark/blowfish2.c @@ -0,0 +1,83 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2017 L. A. F. Pereira <l@tia.mat.br> + * + * 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 or later. + * + * 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 "blowfish.h" + +/* if anything changes in this block, increment revision */ +#define BENCH_REVISION 1 +#define CRUNCH_TIME 7 +#define BENCH_DATA_SIZE 65536 +#define BENCH_DATA_MD5 "c25cf5c889f7bead2ff39788eedae37b" +#define BLOW_KEY "Has my shampoo arrived?" +#define BLOW_KEY_MD5 "6eac709cca51a228bfa70150c9c5a7c4" + +static gpointer bfish_exec(const void *in_data, gint thread_number) +{ + unsigned char key[] = BLOW_KEY; + unsigned char *data = NULL; + unsigned long data_len = BENCH_DATA_SIZE, i = 0; + BLOWFISH_CTX ctx; + + data = malloc(BENCH_DATA_SIZE); + memcpy(data, in_data, BENCH_DATA_SIZE); + + Blowfish_Init(&ctx, key, strlen(key)); + for(i = 0; i < data_len; i += 8) { + Blowfish_Encrypt(&ctx, (unsigned long*)&data[i], (unsigned long*)&data[i+4]); + } + for(i = 0; i < data_len; i += 8) { + Blowfish_Decrypt(&ctx, (unsigned long*)&data[i], (unsigned long*)&data[i+4]); + } + + free(data); + return NULL; +} + +void benchmark_bfish_do(int threads, int entry, const char *status) +{ + bench_value r = EMPTY_BENCH_VALUE; + gchar *test_data = get_test_data(BENCH_DATA_SIZE); + if (!test_data) return; + + shell_view_set_enabled(FALSE); + shell_status_update(status); + + gchar *k = md5_digest_str(BLOW_KEY, strlen(BLOW_KEY)); + if (!SEQ(k, BLOW_KEY_MD5)) + bench_msg("test key has different md5sum: expected %s, actual %s", BLOW_KEY_MD5, k); + gchar *d = md5_digest_str(test_data, BENCH_DATA_SIZE); + if (!SEQ(d, BENCH_DATA_MD5)) + bench_msg("test data has different md5sum: expected %s, actual %s", BENCH_DATA_MD5, d); + + r = benchmark_crunch_for(CRUNCH_TIME, threads, bfish_exec, test_data); + r.result /= 100; + r.revision = BENCH_REVISION; + snprintf(r.extra, 255, "%0.1fs, k:%s, d:%s", (double)CRUNCH_TIME, k, d); + + g_free(test_data); + g_free(k); + g_free(d); + + bench_results[entry] = r; +} + +void benchmark_bfish_threads(void) { benchmark_bfish_do(0, BENCHMARK_BLOWFISH_THREADS, "Performing Blowfish benchmark (multi-thread)..."); } +void benchmark_bfish_single(void) { benchmark_bfish_do(1, BENCHMARK_BLOWFISH_SINGLE, "Performing Blowfish benchmark (single-thread)..."); } +void benchmark_bfish_cores(void) { benchmark_bfish_do(-1, BENCHMARK_BLOWFISH_CORES, "Performing Blowfish benchmark (multi-core)..."); } diff --git a/modules/benchmark/cryptohash.c b/modules/benchmark/cryptohash.c index 6150f3ef..6daef545 100644 --- a/modules/benchmark/cryptohash.c +++ b/modules/benchmark/cryptohash.c @@ -1,10 +1,10 @@ /* - * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * HardInfo - System Information and Benchmark + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,7 +20,14 @@ #include "sha1.h" #include "benchmark.h" -void inline md5_step(char *data, glong srclen) +/* if anything changes in this block, increment revision */ +#define BENCH_REVISION 2 +#define BENCH_DATA_SIZE 65536 +#define CRUNCH_TIME 5 +#define BENCH_DATA_MD5 "c25cf5c889f7bead2ff39788eedae37b" +#define STEPS 250 + +inline void md5_step(char *data, glong srclen) { struct MD5Context ctx; guchar checksum[16]; @@ -30,7 +37,7 @@ void inline md5_step(char *data, glong srclen) MD5Final(checksum, &ctx); } -void inline sha1_step(char *data, glong srclen) +inline void sha1_step(char *data, glong srclen) { SHA1_CTX ctx; guchar checksum[20]; @@ -40,15 +47,15 @@ void inline sha1_step(char *data, glong srclen) SHA1Final(checksum, &ctx); } -static gpointer cryptohash_for(unsigned int start, unsigned int end, void *data, gint thread_number) +static gpointer cryptohash_for(void *in_data, gint thread_number) { unsigned int i; - for (i = start; i <= end; i++) { + for (i = 0;i <= STEPS; i++) { if (i & 1) { - md5_step(data, 65536); + md5_step(in_data, BENCH_DATA_SIZE); } else { - sha1_step(data, 65536); + sha1_step(in_data, BENCH_DATA_SIZE); } } @@ -59,22 +66,24 @@ void benchmark_cryptohash(void) { bench_value r = EMPTY_BENCH_VALUE; - 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; - } + gchar *test_data = get_test_data(BENCH_DATA_SIZE); + if (!test_data) return; shell_view_set_enabled(FALSE); shell_status_update("Running CryptoHash benchmark..."); - r = benchmark_parallel_for(0, 0, 5000, cryptohash_for, tmpsrc); + gchar *d = md5_digest_str(test_data, BENCH_DATA_SIZE); + if (!SEQ(d, BENCH_DATA_MD5)) + bench_msg("test data has different md5sum: expected %s, actual %s", BENCH_DATA_MD5, d); + + r = benchmark_crunch_for(CRUNCH_TIME, 0, cryptohash_for, test_data); + r.revision = BENCH_REVISION; + snprintf(r.extra, 255, "r:%d, d:%s", STEPS, d); + + g_free(test_data); + g_free(d); - g_free(bdata_path); - g_free(tmpsrc); + r.result /= 10; - r.result = 312.0 / r.elapsed_time; //TODO: explain in code comments bench_results[BENCHMARK_CRYPTOHASH] = r; } diff --git a/modules/benchmark/drawing.c b/modules/benchmark/drawing.c index d0905954..e92b9d62 100644 --- a/modules/benchmark/drawing.c +++ b/modules/benchmark/drawing.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/benchmark/fbench.c b/modules/benchmark/fbench.c index b5afc1bc..cf1ff934 100644 --- a/modules/benchmark/fbench.c +++ b/modules/benchmark/fbench.c @@ -277,9 +277,7 @@ static int itercount; /* The iteration counter for the main loop optimise out the loop over the ray tracing code. */ -#ifndef ITERATIONS -#define ITERATIONS 1000 -#endif +#define ITERATIONS 300 static int niter = ITERATIONS; /* Iteration counter */ #if 0 @@ -690,8 +688,6 @@ void fbench() spectral_line[7] = 4340.477; /* G' */ spectral_line[8] = 3968.494; /* H */ - niter = 3000; - /* Load test case into working array */ clear_aperture = 4.0; @@ -701,15 +697,21 @@ void fbench() 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 */ - /* Do main trace in D light */ + paraxial = FALSE; - trace_line(4, clear_aperture / 2.0); - od_sa[paraxial][0] = object_distance; - od_sa[paraxial][1] = axis_slope_angle; - } - paraxial = FALSE; + trace_line(4, clear_aperture / 2.0); + od_sa[0][0] = object_distance; + od_sa[0][1] = axis_slope_angle; + + paraxial = TRUE; + + trace_line(4, clear_aperture / 2.0); + od_sa[1][0] = object_distance; + od_sa[1][1] = axis_slope_angle; + + paraxial = FALSE; /* Trace marginal ray in C */ diff --git a/modules/benchmark/fft.c b/modules/benchmark/fft.c index caa52d3d..503a7aaf 100644 --- a/modules/benchmark/fft.c +++ b/modules/benchmark/fft.c @@ -1,10 +1,10 @@ /* - * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * HardInfo - System Information and Benchmark + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,48 +20,51 @@ #include "benchmark.h" #include "fftbench.h" -static gpointer fft_for(unsigned int start, unsigned int end, void *data, gint thread_number) +/* if anything changes in this block, increment revision */ +#define BENCH_REVISION 2 +#define CRUNCH_TIME 5 + +static gpointer fft_for(void *in_data, gint thread_number) { unsigned int i; - FFTBench **benches = (FFTBench **)data; + FFTBench **benches = (FFTBench **)in_data; FFTBench *fftbench = (FFTBench *)(benches[thread_number]); - for (i = start; i <= end; i++) { - fft_bench_run(fftbench); - } + fft_bench_run(benches[thread_number]); return NULL; } -#define FFT_MAXT 4 - void benchmark_fft(void) { + int cpu_procs, cpu_cores, cpu_threads, cpu_nodes; bench_value r = EMPTY_BENCH_VALUE; int n_cores, i; gchar *temp; - FFTBench **benches; + FFTBench **benches=NULL; shell_view_set_enabled(FALSE); shell_status_update("Running FFT benchmark..."); + cpu_procs_cores_threads_nodes(&cpu_procs, &cpu_cores, &cpu_threads, &cpu_nodes); + /* Pre-allocate all benchmarks */ - benches = g_new0(FFTBench *, FFT_MAXT); - for (i = 0; i < FFT_MAXT; i++) { - benches[i] = fft_bench_new(); - } + benches = g_new0(FFTBench *, cpu_threads); + for (i = 0; i < cpu_threads; i++) {benches[i] = fft_bench_new();} /* Run the benchmark */ - r = benchmark_parallel_for(FFT_MAXT, 0, FFT_MAXT, fft_for, benches); + r = benchmark_crunch_for(CRUNCH_TIME, 0, fft_for, benches); /* Free up the memory */ - for (i = 0; i < FFT_MAXT; i++) { - fft_bench_free(benches[i]); + for (i = 0; i < cpu_threads; i++) { + fft_bench_free(benches[i]); } g_free(benches); - r.result = r.elapsed_time; + r.result /= 100; + + r.revision = BENCH_REVISION; bench_results[BENCHMARK_FFT] = r; } diff --git a/modules/benchmark/fftbench.c b/modules/benchmark/fftbench.c index 89fd5a73..9449cffd 100644 --- a/modules/benchmark/fftbench.c +++ b/modules/benchmark/fftbench.c @@ -59,9 +59,9 @@ static double random_double() return result; } -static const int N = 800; -static const int NM1 = 799; // N - 1 -static const int NP1 = 801; // N + 1 +static const int N = 100; +static const int NM1 = 99; // N - 1 +static const int NP1 = 101; // N + 1 static void lup_decompose(FFTBench *fftbench) { diff --git a/modules/benchmark/fib.c b/modules/benchmark/fib.c index d75ac367..2bec8bed 100644 --- a/modules/benchmark/fib.c +++ b/modules/benchmark/fib.c @@ -1,10 +1,10 @@ /* - * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * HardInfo - System Information and Benchmark + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,6 +18,11 @@ #include "benchmark.h" +/* if anything changes in this block, increment revision */ +#define BENCH_REVISION 2 +#define ANSWER 25 +#define CRUNCH_TIME 5 + gulong fib(gulong n) { if (n == 0) @@ -27,6 +32,14 @@ gulong fib(gulong n) return fib(n - 1) + fib(n - 2); } +static gpointer fib_for(void *in_data, gint thread_number) +{ + fib(ANSWER); + + return NULL; +} + + void benchmark_fib(void) { @@ -34,19 +47,15 @@ benchmark_fib(void) bench_value r = EMPTY_BENCH_VALUE; shell_view_set_enabled(FALSE); - shell_status_update("Calculating the 42nd Fibonacci number..."); - - g_timer_reset(timer); - g_timer_start(timer); + shell_status_update("Calculating Fibonacci number..."); - fib(42); + r = benchmark_crunch_for(CRUNCH_TIME, 0, fib_for, NULL); + //r.threads_used = 1; - g_timer_stop(timer); - r.elapsed_time = g_timer_elapsed(timer, NULL); - g_timer_destroy(timer); + r.result /= 100; - r.threads_used = 1; - r.result = r.elapsed_time; + r.revision = BENCH_REVISION; + snprintf(r.extra, 255, "a:%d", ANSWER); bench_results[BENCHMARK_FIB] = r; } diff --git a/modules/benchmark/guibench.c b/modules/benchmark/guibench.c index b9573278..0faf6b69 100644 --- a/modules/benchmark/guibench.c +++ b/modules/benchmark/guibench.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2009 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -108,7 +108,7 @@ static double test_icons(GtkWindow *window) gc = gdk_gc_new(GDK_DRAWABLE(gdk_window)); timer = g_timer_new(); - pixbufs[0] = icon_cache_get_pixbuf("logo.png"); + pixbufs[0] = icon_cache_get_pixbuf("hardinfo2.png"); pixbufs[1] = icon_cache_get_pixbuf("syncmanager.png"); pixbufs[2] = icon_cache_get_pixbuf("report-large.png"); diff --git a/modules/benchmark/nqueens.c b/modules/benchmark/nqueens.c index 78293abb..6aad7638 100644 --- a/modules/benchmark/nqueens.c +++ b/modules/benchmark/nqueens.c @@ -9,29 +9,30 @@ #include "hardinfo.h" #include "benchmark.h" -#define QUEENS 11 +/* if anything changes in this block, increment revision */ +#define BENCH_REVISION 2 +#define QUEENS 6 +#define CRUNCH_TIME 5 int row[QUEENS]; -bool safe(int x, int y) -{ +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; + if (row[y - i] == x || row[y - i] == x - i || row[y - i] == x + i) + return false; return true; } -int nqueens(int y) -{ +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; + if (safe((row[y - 1] = x), y - 1)) { + if (y < QUEENS) { + nqueens(y + 1); + } else { + break; } } } @@ -39,13 +40,9 @@ int nqueens(int y) return 0; } -static gpointer nqueens_for(unsigned int start, unsigned int end, void *data, gint thread_number) +static gpointer nqueens_for(void *data, gint thread_number) { - unsigned int i; - - for (i = start; i <= end; i++) { - nqueens(0); - } + nqueens(0); return NULL; } @@ -58,9 +55,13 @@ benchmark_nqueens(void) shell_view_set_enabled(FALSE); shell_status_update("Running N-Queens benchmark..."); - r = benchmark_parallel_for(0, 0, 10, nqueens_for, NULL); - r.result = r.elapsed_time; + r = benchmark_crunch_for(CRUNCH_TIME, 0, nqueens_for, NULL); + + r.revision = BENCH_REVISION; + snprintf(r.extra, 255, "q:%d", QUEENS); + r.result /= 25; + bench_results[BENCHMARK_NQUEENS] = r; } diff --git a/modules/benchmark/raytrace.c b/modules/benchmark/raytrace.c index c7963583..bddc3232 100644 --- a/modules/benchmark/raytrace.c +++ b/modules/benchmark/raytrace.c @@ -1,10 +1,10 @@ /* - * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * HardInfo - System Information and Benchmark + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,16 +18,17 @@ #include "benchmark.h" +/* if anything changes in this block, increment revision */ +#define BENCH_REVISION 2 +#define CRUNCH_TIME 5 + void fbench(); /* fbench.c */ -static gpointer -parallel_raytrace(unsigned int start, unsigned int end, gpointer data, gint thread_number) +static gpointer parallel_raytrace(void *in_data, gint thread_number) { unsigned int i; - for (i = start; i <= end; i++) { - fbench(); - } + fbench(); return NULL; } @@ -36,13 +37,20 @@ void benchmark_raytrace(void) { bench_value r = EMPTY_BENCH_VALUE; + gchar *test_data = get_test_data(1000); shell_view_set_enabled(FALSE); shell_status_update("Performing John Walker's FBENCH..."); - r = benchmark_parallel_for(0, 0, 1000, parallel_raytrace, NULL); - r.result = r.elapsed_time; + r = benchmark_crunch_for(CRUNCH_TIME, 1, parallel_raytrace, test_data); + + r.revision = BENCH_REVISION; + snprintf(r.extra, 255, "r:%d", 500);//niter from fbench + + g_free(test_data); + r.result /= 10; + bench_results[BENCHMARK_RAYTRACE] = r; } diff --git a/modules/benchmark/sha1.c b/modules/benchmark/sha1.c index b94ce254..3b213218 100644 --- a/modules/benchmark/sha1.c +++ b/modules/benchmark/sha1.c @@ -47,7 +47,7 @@ A million repetitions of "a" /* Hash a single 512-bit block. This is the core of the algorithm. */ -void SHA1Transform(guint32 state[5], guchar buffer[64]) +void SHA1Transform(guint32 state[20], guchar buffer[64]) { guint32 a, b, c, d, e; typedef union { diff --git a/modules/benchmark/sysbench.c b/modules/benchmark/sysbench.c new file mode 100644 index 00000000..5c45831d --- /dev/null +++ b/modules/benchmark/sysbench.c @@ -0,0 +1,270 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2017 L. A. F. Pereira <l@tia.mat.br> + * Copyright (C) 2019 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, version 2 or later. + * + * 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 "cpu_util.h" + +#define STATMSG "Performing Alexey Kopytov's sysbench memory benchmark" + +/* known to work with: + * sysbench 0.4.12 --> r:4012 + * sysbench 1.0.11 --> r:1000011 + * sysbench 1.0.15 --> r:1000015 + */ + +struct sysbench_ctx { + char *test; + int threads; + int max_time; + char *parms_test; + bench_value r; +}; + +int sysbench_version() { + int ret = -1; + int v1 = 0, v2 = 0, v3 = 0, mc = 0; + gboolean spawned; + gchar *out, *err, *p, *next_nl; + + spawned = g_spawn_command_line_sync("sysbench --version", + &out, &err, NULL, NULL); + if (spawned) { + ret = 0; + p = out; + while(next_nl = strchr(p, '\n')) { + *next_nl = 0; + /* version */ + mc = sscanf(p, "sysbench %d.%d.%d", &v1, &v2, &v3); + if (mc >= 1) { + ret += v1 * 1000000; + ret += v2 * 1000; + ret += v3; + break; + } + p = next_nl + 1; + } + g_free(out); + g_free(err); + } + return ret; +} + +static gboolean sysbench_run(struct sysbench_ctx *ctx, int expecting_version) { + gboolean spawned; + gchar *out, *err, *p, *next_nl; + + int v1 = 0, v2 = 0, v3 = 0, mc = 0; + char *pp = NULL; + + if (!ctx) return FALSE; + if (!ctx->test) return FALSE; + if (!ctx->parms_test) return FALSE; + if (!ctx->threads) ctx->threads = 1; + ctx->r.threads_used = ctx->threads; + if (!ctx->max_time) ctx->max_time = 7; + + gchar *cmd_line = NULL; + snprintf(ctx->r.extra, 255, "--time=%d %s", ctx->max_time, ctx->parms_test); + util_compress_space(ctx->r.extra); + + if (!expecting_version) + expecting_version = sysbench_version(); + if (expecting_version < 1000000) { + /* v0.x.x: sysbench [general-options]... --test=<test-name> [test-options]... command */ + cmd_line = g_strdup_printf("sysbench --num-threads=%d --max-time=%d --test=%s %s run", ctx->threads, ctx->max_time, ctx->test, ctx->parms_test); + } else { + /* v1.x.x: sysbench [options]... [testname] [command] */ + cmd_line = g_strdup_printf("sysbench --threads=%d --time=%d %s %s run", ctx->threads, ctx->max_time, ctx->parms_test, ctx->test); + } + //bench_msg("\ncmd_line: %s", cmd_line); + + spawned = g_spawn_command_line_sync(cmd_line, + &out, &err, NULL, NULL); + g_free(cmd_line); + if (spawned) { + p = out; + while(next_nl = strchr(p, '\n')) { + *next_nl = 0; + + if (strstr(p, "Usage:")) { + /* We're hosed */ + goto sysbench_failed; + } + + /* version */ + mc = sscanf(p, "sysbench %d.%d.%d", &v1, &v2, &v3); + if (mc >= 1) { + ctx->r.revision = 0; + ctx->r.revision += v1 * 1000000; + ctx->r.revision += v2 * 1000; + ctx->r.revision += v3; + } + + /* total_time */ + if (pp = strstr(p, "total time:")) { + pp = strchr(pp, ':') + 1; + ctx->r.elapsed_time = strtof(pp, NULL); + } + + /* result */ + if (SEQ(ctx->test, "memory") ) { + // 57894.30 MiB transferred (5787.59 MiB/sec) + if (pp = strstr(p, " transferred (")) { + pp = strchr(pp, '(') + 1; + ctx->r.result = strtof(pp, NULL); + } + } + if (SEQ(ctx->test, "cpu") ) { + if (ctx->r.revision < 1000000) { + // there is not a nice result line + // to grab in version 0.x... + // total time: 7.0016s + // total number of events: 873 + + /* should already have "total time:" */ + if (pp = strstr(p, " total number of events:")) { + pp = strchr(pp, ':') + 1; + ctx->r.result = strtof(pp, NULL); + ctx->r.result /= ctx->r.elapsed_time; + } + } + if (ctx->r.revision >= 1000000) { + // events per second: 1674.97 + if (pp = strstr(p, " events per second:")) { + pp = strchr(pp, ':') + 1; + ctx->r.result = strtof(pp, NULL); + } + } + } + + p = next_nl + 1; + } + g_free(out); + g_free(err); + } else { + bench_msg("\nfailed to spawn sysbench"); + sleep(5); + } + + if (ctx->r.result == -1) + goto sysbench_failed; + + return spawned; + +sysbench_failed: + bench_msg("\nfailed to configure sysbench"); + g_free(out); + g_free(err); + return 0; +} + +void benchmark_memory_run(int threads, int result_index) { + int cpu_procs, cpu_cores, cpu_threads, cpu_nodes; + + cpu_procs_cores_threads_nodes(&cpu_procs, &cpu_cores, &cpu_threads, &cpu_nodes); + + struct sysbench_ctx ctx = { + .test = "memory", + .threads = threads>0 ? threads : cpu_threads, + .parms_test = "", + .r = EMPTY_BENCH_VALUE}; + + int sbv = sysbench_version(); + if (BENCH_PTR_BITS > 32 && sbv >= 1000011) { + ctx.parms_test = + " --memory-block-size=1K" + " --memory-total-size=100G" + " --memory-scope=global" + " --memory-hugetlb=off" + " --memory-oper=write" + " --memory-access-mode=seq"; + } else { + /* safer set */ + ctx.parms_test = + " --memory-block-size=1K" + " --memory-total-size=3056M" + " --memory-scope=global" + " --memory-hugetlb=off" + " --memory-oper=write" + " --memory-access-mode=seq"; + } + + shell_view_set_enabled(FALSE); + char msg[128] = ""; + snprintf(msg, 128, "%s (threads: %d)", STATMSG, threads); + shell_status_update(msg); + + sysbench_run(&ctx, sbv); + bench_results[result_index] = ctx.r; +} + +void benchmark_memory_single(void) { benchmark_memory_run(1, BENCHMARK_MEMORY_SINGLE); } +void benchmark_memory_dual(void) { benchmark_memory_run(2, BENCHMARK_MEMORY_DUAL); } +void benchmark_memory_quad(void) { benchmark_memory_run(4, BENCHMARK_MEMORY_QUAD); } +void benchmark_memory_all(void) { benchmark_memory_run(0, BENCHMARK_MEMORY_ALL); } + +void benchmark_sbcpu_single(void) { + struct sysbench_ctx ctx = { + .test = "cpu", + .threads = 1, + .parms_test = + "--cpu-max-prime=10000", + .r = EMPTY_BENCH_VALUE}; + + shell_view_set_enabled(FALSE); + shell_status_update(STATMSG " (single thread)..."); + + sysbench_run(&ctx, 0); + bench_results[BENCHMARK_SBCPU_SINGLE] = ctx.r; +} + +void benchmark_sbcpu_all(void) { + int cpu_procs, cpu_cores, cpu_threads, cpu_nodes; + + cpu_procs_cores_threads_nodes(&cpu_procs, &cpu_cores, &cpu_threads, &cpu_nodes); + + struct sysbench_ctx ctx = { + .test = "cpu", + .threads = cpu_threads, + .parms_test = + "--cpu-max-prime=10000", + .r = EMPTY_BENCH_VALUE}; + + shell_view_set_enabled(FALSE); + shell_status_update(STATMSG " (Multi-thread)..."); + + sysbench_run(&ctx, 0); + bench_results[BENCHMARK_SBCPU_ALL] = ctx.r; +} + +void benchmark_sbcpu_quad(void) { + struct sysbench_ctx ctx = { + .test = "cpu", + .threads = 4, + .parms_test = + "--cpu-max-prime=10000", + .r = EMPTY_BENCH_VALUE}; + + shell_view_set_enabled(FALSE); + shell_status_update(STATMSG " (Four thread)..."); + + sysbench_run(&ctx, 0); + bench_results[BENCHMARK_SBCPU_QUAD] = ctx.r; +} diff --git a/modules/benchmark/zlib.c b/modules/benchmark/zlib.c index 2ded59a4..2045969f 100644 --- a/modules/benchmark/zlib.c +++ b/modules/benchmark/zlib.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2017 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2017 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,23 +22,39 @@ #include "benchmark.h" -static gpointer zlib_for(unsigned int start, unsigned int end, void *data, gint thread_number) -{ +/* zip/unzip 256KB blocks for 7 seconds + * result is number of full completions / 100 */ + +/* if anything changes in this block, increment revision */ +#define BENCH_REVISION 3 +#define BENCH_DATA_SIZE 262144 +#define BENCH_DATA_MD5 "3753b649c4fa9ea4576fc8f89a773de2" +#define CRUNCH_TIME 7 +#define VERIFY_RESULT 1 + +static unsigned int zlib_errors = 0; + +static gpointer zlib_for(void *in_data, gint thread_number) { char *compressed; - uLong bound = compressBound(bound); + uLong bound = compressBound(BENCH_DATA_SIZE); unsigned int i; compressed = malloc(bound); if (!compressed) return NULL; - for (i = start; i <= end; i++) { - char uncompressed[65536]; - uLong compressedBound = bound; - uLong destBound = sizeof(uncompressed); + char uncompressed[BENCH_DATA_SIZE]; + uLong compressedBound = bound; + uLong destBound = sizeof(uncompressed); - compress(compressed, &compressedBound, data, 65536); - uncompress(uncompressed, &destBound, compressed, compressedBound); + compress(compressed, &compressedBound, in_data, BENCH_DATA_SIZE); + uncompress(uncompressed, &destBound, compressed, compressedBound); + if (VERIFY_RESULT) { + int cr = memcmp(in_data, uncompressed, BENCH_DATA_SIZE); + if (!!cr) { + zlib_errors++; + bench_msg("zlib error: uncompressed != original"); + } } free(compressed); @@ -50,24 +66,23 @@ void benchmark_zlib(void) { bench_value r = EMPTY_BENCH_VALUE; - 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); + gchar *test_data = get_test_data(BENCH_DATA_SIZE); + if (!test_data) return; - } shell_view_set_enabled(FALSE); shell_status_update("Running Zlib benchmark..."); - r = benchmark_parallel_for(0, 0, 50000, zlib_for, tmpsrc); + gchar *d = md5_digest_str(test_data, BENCH_DATA_SIZE); + if (!SEQ(d, BENCH_DATA_MD5)) + bench_msg("test data has different md5sum: expected %s, actual %s", BENCH_DATA_MD5, d); - g_free(bdata_path); - g_free(tmpsrc); - - //TODO: explain in code comments - gdouble marks = (50000. * 65536.) / (r.elapsed_time * 840205128.); - r.result = marks; + r = benchmark_crunch_for(CRUNCH_TIME, 0, zlib_for, test_data); + r.result /= 100; + r.revision = BENCH_REVISION; + snprintf(r.extra, 255, "zlib %s (built against: %s), d:%s, e:%d", zlib_version, ZLIB_VERSION, d, zlib_errors); bench_results[BENCHMARK_ZLIB] = r; + + g_free(test_data); + g_free(d); } diff --git a/modules/computer.c b/modules/computer.c index ea6762a7..fff8ba36 100644 --- a/modules/computer.c +++ b/modules/computer.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -38,12 +38,16 @@ #include "info.h" +#define THISORUNK(t) ( (t) ? t : _("(Unknown)") ) + /* Callbacks */ gchar *callback_summary(void); gchar *callback_os(void); +gchar *callback_security(void); gchar *callback_modules(void); gchar *callback_boots(void); gchar *callback_locales(void); +gchar *callback_memory_usage(); gchar *callback_fs(void); gchar *callback_display(void); gchar *callback_network(void); @@ -57,10 +61,12 @@ gchar *callback_dev(void); /* Scan callbacks */ void scan_summary(gboolean reload); void scan_os(gboolean reload); +void scan_security(gboolean reload); void scan_modules(gboolean reload); void scan_boots(gboolean reload); void scan_locales(gboolean reload); void scan_fs(gboolean reload); +void scan_memory_usage(gboolean reload); void scan_display(gboolean reload); void scan_network(gboolean reload); void scan_users(gboolean reload); @@ -70,26 +76,46 @@ void scan_env_var(gboolean reload); void scan_dev(gboolean reload); #endif /* GLIB_CHECK_VERSION(2,14,0) */ +enum { + ENTRY_SUMMARY, + ENTRY_OS, + ENTRY_SECURITY, + ENTRY_KMOD, + ENTRY_BOOTS, + ENTRY_LANGUAGES, + ENTRY_MEMORY_USAGE, + ENTRY_FS, + ENTRY_DISPLAY, + ENTRY_ENV, + ENTRY_DEVEL, + ENTRY_USERS, + ENTRY_GROUPS +}; + 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}, + [ENTRY_SUMMARY] = {N_("Summary"), "summary.png", callback_summary, scan_summary, MODULE_FLAG_NONE}, + [ENTRY_OS] = {N_("Operating System"), "os.png", callback_os, scan_os, MODULE_FLAG_NONE}, + [ENTRY_SECURITY] = {N_("Security"), "security.png", callback_security, scan_security, MODULE_FLAG_NONE}, + [ENTRY_KMOD] = {N_("Kernel Modules"), "module.png", callback_modules, scan_modules, MODULE_FLAG_NONE}, + [ENTRY_BOOTS] = {N_("Boots"), "boot.png", callback_boots, scan_boots, MODULE_FLAG_NONE}, + [ENTRY_LANGUAGES] = {N_("Languages"), "language.png", callback_locales, scan_locales, MODULE_FLAG_NONE}, + [ENTRY_MEMORY_USAGE] = {N_("Memory Usage"), "memory.png", callback_memory_usage, scan_memory_usage, MODULE_FLAG_NONE}, + [ENTRY_FS] = {N_("Filesystems"), "dev_removable.png", callback_fs, scan_fs, MODULE_FLAG_NONE}, + [ENTRY_DISPLAY] = {N_("Display"), "monitor.png", callback_display, scan_display, MODULE_FLAG_NONE}, + [ENTRY_ENV] = {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}, + [ENTRY_DEVEL] = {N_("Development"), "devel.png", callback_dev, scan_dev, MODULE_FLAG_NONE}, +#else + [ENTRY_DEVEL] = {N_("Development"), "devel.png", callback_dev, scan_dev, MODULE_FLAG_HIDE}, #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}, + [ENTRY_USERS] = {N_("Users"), "users.png", callback_users, scan_users, MODULE_FLAG_NONE}, + [ENTRY_GROUPS] = {N_("Groups"), "users.png", callback_groups, scan_groups, MODULE_FLAG_NONE}, {NULL}, }; - gchar *module_list = NULL; Computer *computer = NULL; +gchar *meminfo = NULL; gchar *hi_more_info(gchar * entry) { @@ -101,27 +127,42 @@ gchar *hi_more_info(gchar * entry) return g_strdup_printf("[%s]", entry); } +/* a g_str_equal() where either may be null */ +#define g_str_equal0(a,b) (g_strcmp0(a,b) == 0) + gchar *hi_get_field(gchar * field) { + gchar *tag, *label; + key_get_components(field, NULL, &tag, NULL, &label, NULL, TRUE); + gchar *tmp; - if (g_str_equal(field, _("Memory"))) { + if (g_str_equal0(label, _("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"))) { + } else if (g_str_equal0(label, _("Uptime"))) { tmp = computer_get_formatted_uptime(); - } else if (g_str_equal(field, _("Date/Time"))) { + } else if (g_str_equal0(label, _("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"))) { + } else if (g_str_equal0(label, _("Load Average"))) { tmp = computer_get_formatted_loadavg(); - } else if (g_str_equal(field, _("Available entropy in /dev/random"))) { + } else if (g_str_equal0(tag, "entropy")) { tmp = computer_get_entropy_avail(); } else { - tmp = g_strdup_printf("Unknown field: %s", field); + gchar *info = NULL; + if (tag) + info = moreinfo_lookup_with_prefix("DEV", tag); + else if (label) + info = moreinfo_lookup_with_prefix("DEV", label); + + if (info) + tmp = g_strdup(info); + else + tmp = g_strdup_printf("Unknown field: [tag: %s] label: %s", tag ? tag : "(none)", label ? label : "(empty)"); } return tmp; } @@ -141,6 +182,13 @@ void scan_os(gboolean reload) SCAN_END(); } +void scan_security(gboolean reload) +{ + SCAN_START(); + //nothing to do here yet + SCAN_END(); +} + void scan_modules(gboolean reload) { SCAN_START(); @@ -170,9 +218,18 @@ void scan_fs(gboolean reload) SCAN_END(); } +void scan_memory_usage(gboolean reload) +{ + SCAN_START(); + scan_memory_do(); + SCAN_END(); +} + void scan_display(gboolean reload) { SCAN_START(); + if (computer->display) + computer_free_display(computer->display); computer->display = computer_get_display(); SCAN_END(); } @@ -197,16 +254,16 @@ void scan_dev(gboolean reload) { SCAN_START(); - int i; + guint i; struct { gchar *compiler_name; gchar *version_command; gchar *regex; - gboolean stdout; + gboolean read_stdout; } detect_lang[] = { { N_("Scripting Languages"), NULL, FALSE }, { N_("Gambas3 (gbr3)"), "gbr3 --version", "\\d+\\.\\d+\\.\\d+", TRUE }, - { N_("Python"), "python -V", "\\d+\\.\\d+\\.\\d+", FALSE }, + { N_("Python (default)"), "python -V", "\\d+\\.\\d+\\.\\d+", FALSE }, { N_("Python2"), "python2 -V", "\\d+\\.\\d+\\.\\d+", FALSE }, { N_("Python3"), "python3 -V", "\\d+\\.\\d+\\.\\d+", TRUE }, { N_("Perl"), "perl -v", "\\d+\\.\\d+\\.\\d+", TRUE }, @@ -215,26 +272,33 @@ void scan_dev(gboolean reload) { 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_("JavaScript (Node.js)"), "node --version", "(?<=v)(\\d\\.?)+", TRUE }, + { N_("awk"), "awk --version", "GNU Awk \\d+\\.\\d+\\.\\d+", 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_("Gambas3 (gbc3)"), "gbc3 --version", "\\d+\\.\\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_("C♯ (mcs)"), "mcs --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_("Rust"), "rustc --version", "(?<=rustc )(\\d\\.?)+", TRUE }, { N_("Tools"), NULL, FALSE }, { N_("make"), "make --version", "\\d+\\.\\d+", TRUE }, + { N_("ninja"), "ninja --version", "\\d+\\.\\d+\\.\\d+", TRUE }, { N_("GDB"), "gdb --version", "(?<=^GNU gdb ).*", TRUE }, + { N_("LLDB"), "lldb --version", "(?<=lldb version )(\\d\\.?)+", 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}, { N_("Gambas3 IDE"), "gambas3 --version", "\\d+\\.\\d+\\.\\d+", TRUE }, + { N_("Radare2"), "radare2 -v", "(?<=radare2 )(\\d+\\.?)+(-git)?", TRUE }, + { N_("ltrace"), "ltrace --version", "(?<=ltrace version )\\d+\\.\\d+\\.\\d+", TRUE }, + { N_("Powershell"), "pwsh --version", "\\d+\\.\\d+\\.\\d+", TRUE }, }; g_free(dev_list); @@ -254,10 +318,10 @@ void scan_dev(gboolean reload) continue; } - if (detect_lang[i].stdout) { - found = g_spawn_command_line_sync(detect_lang[i].version_command, &output, &ignored, NULL, NULL); + if (detect_lang[i].read_stdout) { + found = hardinfo_spawn_command_line_sync(detect_lang[i].version_command, &output, &ignored, NULL, NULL); } else { - found = g_spawn_command_line_sync(detect_lang[i].version_command, &ignored, &output, NULL, NULL); + found = hardinfo_spawn_command_line_sync(detect_lang[i].version_command, &ignored, &output, NULL, NULL); } g_free(ignored); @@ -293,6 +357,7 @@ gchar *callback_dev(void) { return g_strdup_printf( "[$ShellParam$]\n" + "ViewType=5\n" "ColumnTitle$TextValue=%s\n" /* Program */ "ColumnTitle$Value=%s\n" /* Version */ "ShowColumnHeaders=true\n" @@ -302,6 +367,24 @@ gchar *callback_dev(void) } #endif /* GLIB_CHECK_VERSION(2,14,0) */ +gchar *callback_memory_usage() +{ + extern gchar *lginterval; + return g_strdup_printf("[Memory]\n" + "%s\n" + "[$ShellParam$]\n" + "ViewType=2\n" + "LoadGraphSuffix= kB\n" + "RescanInterval=2000\n" + "ColumnTitle$TextValue=%s\n" + "ColumnTitle$Extra1=%s\n" + "ColumnTitle$Value=%s\n" + "ShowColumnHeaders=true\n" + "%s\n", meminfo, + _("Field"), _("Description"), _("Value"), /* column labels */ + lginterval); +} + static gchar *detect_machine_type(void) { GDir *dir; @@ -315,6 +398,7 @@ static gchar *detect_machine_type(void) if (chassis) { if (strstr(chassis, "Raspberry Pi") != NULL || strstr(chassis, "ODROID") != NULL + || strstr(chassis, "Firefly ROC") != NULL /* FIXME: consider making a table when adding more models */ ) { g_free(chassis); return g_strdup(_("Single-board computer")); @@ -381,7 +465,7 @@ gchar *computer_get_virtualization(void) "/var/log/dmesg", NULL }; - const static struct { + static const struct { gchar *str; gchar *vmtype; } vm_types[] = { @@ -458,9 +542,11 @@ gchar *callback_summary(void) { struct Info *info = info_new(); + info_set_view_type(info, SHELL_VIEW_DETAIL); + info_add_group(info, _("Computer"), - info_field_printf(_("Processor"), "%s", - module_call_method("devices::getProcessorName")), + info_field(_("Processor"), + idle_free(module_call_method("devices::getProcessorNameAndDesc"))), info_field_update(_("Memory"), 1000), info_field_printf(_("Machine Type"), "%s", computer_get_virtualization()), @@ -472,17 +558,19 @@ gchar *callback_summary(void) info_add_group(info, _("Display"), info_field_printf(_("Resolution"), _(/* label for resolution */ "%dx%d pixels"), computer->display->width, computer->display->height), - info_field(_("OpenGL Renderer"), computer->display->ogl_renderer), - info_field(_("X11 Vendor"), computer->display->vendor), + info_field(_("Display Adapter"), + idle_free(module_call_method("devices::getGPUList"))), + info_field(_("OpenGL Renderer"), THISORUNK(computer->display->xi->glx->ogl_renderer)), + info_field(_("Session Display Server"), THISORUNK(computer->display->display_server)), info_field_last()); info_add_computed_group(info, _("Audio Devices"), idle_free(computer_get_alsacards(computer))); - info_add_computed_group(info, _("Input Devices"), + info_add_computed_group_wo_extra(info, _("Input Devices"), idle_free(module_call_method("devices::getInputDevices"))); info_add_computed_group(info, NULL, /* getPrinters provides group headers */ idle_free(module_call_method("devices::getPrinters"))); - info_add_computed_group(info, NULL, /* getStorageDevices provides group headers */ + info_add_computed_group_wo_extra(info, NULL, /* getStorageDevices provides group headers */ idle_free(module_call_method("devices::getStorageDevices"))); return info_flatten(info); @@ -491,27 +579,116 @@ gchar *callback_summary(void) gchar *callback_os(void) { struct Info *info = info_new(); - - info_add_group(info, _("Version"), - info_field(_("Kernel"), computer->os->kernel), + gchar *distro_icon; + gchar *distro; + + info_set_view_type(info, SHELL_VIEW_DETAIL); + + distro_icon = computer->os->distroid + ? idle_free(g_strdup_printf("distros/%s.svg", + computer->os->distroid)) + : NULL; + distro = computer->os->distrocode + ? idle_free(g_strdup_printf("%s (%s)", + computer->os->distro, computer->os->distrocode)) + : computer->os->distro; + + struct InfoGroup *version_group = + info_add_group( + info, _("Version"), info_field(_("Kernel"), computer->os->kernel), + info_field(_("Command Line"), computer->os->kcmdline ?: _("Unknown")), info_field(_("Version"), computer->os->kernel_version), info_field(_("C Library"), computer->os->libc), - info_field(_("Distribution"), computer->os->distro), + info_field(_("Distribution"), distro, + .value_has_vendor = TRUE, + .icon = distro_icon), info_field_last()); + if (computer->os->distro_flavor) { + info_group_add_field(version_group, + info_field(_("Spin/Flavor"), computer->os->distro_flavor->name, + .value_has_vendor = TRUE, + .icon = computer->os->distro_flavor->icon) ); + } + info_add_group(info, _("Current Session"), info_field(_("Computer Name"), computer->os->hostname), info_field(_("User Name"), computer->os->username), info_field(_("Language"), computer->os->language), info_field(_("Home Directory"), computer->os->homedir), + info_field(_("Desktop Environment"), computer->os->desktop), info_field_last()); - info_add_group(info, _("Misc"), - info_field_update(_("Uptime"), 1000), - info_field_update(_("Load Average"), 10000), - info_field_update(_("Available entropy in /dev/random"), 1000), + info_add_group(info, _("Misc"), info_field_update(_("Uptime"), 1000), + info_field_update(_("Load Average"), 10000), + info_field_last()); + + return info_flatten(info); +} + +gchar *callback_security(void) +{ + struct Info *info = info_new(); + + info_set_view_type(info, SHELL_VIEW_DETAIL); + + info_add_group(info, _("HardInfo"), + info_field(_("HardInfo running as"), + (getuid() == 0) ? _("Superuser") : _("User")), + info_field_last()); + + info_add_group( + info, _("Health"), + info_field_update(_("Available entropy in /dev/random"), 1000, .tag = g_strdup("entropy") ), info_field_last()); + info_add_group( + info, _("Hardening Features"), + info_field(_("ASLR"), idle_free(computer_get_aslr())), + info_field(_("dmesg"), idle_free(computer_get_dmesg_status())), + info_field_last()); + + info_add_group( + info, _("Linux Security Modules"), + info_field(_("Modules available"), idle_free(computer_get_lsm())), + info_field(_("SELinux status"), computer_get_selinux()), + info_field_last()); + + GDir *dir = g_dir_open("/sys/devices/system/cpu/vulnerabilities", 0, NULL); + if (dir) { + struct InfoGroup *vulns = + info_add_group(info, _("CPU Vulnerabilities"), info_field_last()); + vulns->sort = INFO_GROUP_SORT_NAME_ASCENDING; + const gchar *vuln; + + while ((vuln = g_dir_read_name(dir))) { + gchar *contents = h_sysfs_read_string( + "/sys/devices/system/cpu/vulnerabilities", vuln); + if (!contents) + continue; + + const gchar *icon = NULL; + if (g_strstr_len(contents, -1, "Not affected") ) + icon = "circle_green_check.svg"; + + if (g_str_has_prefix(contents, "Mitigation:") || + g_str_has_prefix(contents, "mitigation:")) + icon = "circle_yellow_exclaim.svg"; + + if (g_strstr_len(contents, -1, "Vulnerable") || + g_strstr_len(contents, -1, "vulnerable")) + icon = "circle_red_x.svg"; + + info_group_add_fields(vulns, + info_field(g_strdup(vuln), + idle_free(contents), .icon = icon, + .free_name_on_flatten = TRUE), + info_field_last()); + } + + g_dir_close(dir); + } + return info_flatten(info); } @@ -575,27 +752,80 @@ gchar *callback_fs(void) gchar *callback_display(void) { + int n = 0; + gchar *screens_str = strdup(""), *outputs_str = strdup(""); + xinfo *xi = computer->display->xi; + xrr_info *xrr = xi->xrr; + glx_info *glx = xi->glx; + wl_info *wl = computer->display->wl; + struct Info *info = info_new(); - info_add_group(info, _("Display"), - info_field_printf(_("Resolution"), _(/* resolution WxH unit */ "%dx%d pixels"), - computer->display->width, computer->display->height), - info_field(_("Vendor"), computer->display->vendor), - info_field(_("Version"), computer->display->version), - info_field(_("Current Display Name"), computer->display->display_name), + info_set_view_type(info, SHELL_VIEW_DETAIL); + + info_add_group(info, _("Session"), + info_field(_("Type"), THISORUNK(computer->display->session_type)), info_field_last()); - info_add_computed_group(info, _("Monitors"), computer->display->monitors); + info_add_group(info, _("Wayland"), + info_field(_("Current Display Name"), + (wl->display_name) ? (wl->display_name) : _("(Not Available)")), + info_field_last()); - info_add_group(info, _("OpenGL"), - info_field(_("Vendor"), computer->display->ogl_vendor), - info_field(_("Renderer"), computer->display->ogl_renderer), - info_field(_("Version"), computer->display->ogl_version), - info_field(_("Direct Rendering"), - computer->display->dri ? _("Yes") : _("No")), + info_add_group(info, _("X Server"), + info_field(_("Current Display Name"), THISORUNK(xi->display_name) ), + info_field(_("Vendor"), THISORUNK(xi->vendor), .value_has_vendor = TRUE ), + info_field(_("Version"), THISORUNK(xi->version) ), + info_field(_("Release Number"), THISORUNK(xi->release_number) ), info_field_last()); - info_add_computed_group(info, _("Extensions"), computer->display->extensions); + for (n = 0; n < xrr->screen_count; n++) { + gchar *dims = g_strdup_printf(_(/* resolution WxH unit */ "%dx%d pixels"), xrr->screens[n].px_width, xrr->screens[n].px_height); + screens_str = h_strdup_cprintf("Screen %d=%s\n", screens_str, xrr->screens[n].number, dims); + g_free(dims); + } + info_add_computed_group(info, _("Screens"), screens_str); + + for (n = 0; n < xrr->output_count; n++) { + gchar *connection = NULL; + switch (xrr->outputs[n].connected) { + case 0: + connection = _("Disconnected"); + break; + case 1: + connection = _("Connected"); + break; + case -1: + default: + connection = _("Unknown"); + break; + } + gchar *dims = (xrr->outputs[n].screen == -1) + ? g_strdup(_("Unused")) + : g_strdup_printf(_("%dx%d pixels, offset (%d, %d)"), + xrr->outputs[n].px_width, xrr->outputs[n].px_height, + xrr->outputs[n].px_offset_x, xrr->outputs[n].px_offset_y); + + outputs_str = h_strdup_cprintf("%s=%s; %s\n", outputs_str, + xrr->outputs[n].name, connection, dims); + + g_free(dims); + } + info_add_computed_group(info, _("Outputs (XRandR)"), outputs_str); + + info_add_group(info, _("OpenGL (GLX)"), + info_field(_("Vendor"), THISORUNK(glx->ogl_vendor), .value_has_vendor = TRUE ), + info_field(_("Renderer"), THISORUNK(glx->ogl_renderer) ), + info_field(_("Direct Rendering"), + glx->direct_rendering ? _("Yes") : _("No")), + info_field(_("Version (Compatibility)"), THISORUNK(glx->ogl_version) ), + info_field(_("Shading Language Version (Compatibility)"), THISORUNK(glx->ogl_sl_version) ), + info_field(_("Version (Core)"), THISORUNK(glx->ogl_core_version) ), + info_field(_("Shading Language Version (Core)"), THISORUNK(glx->ogl_core_sl_version) ), + info_field(_("Version (ES)"), THISORUNK(glx->ogles_version) ), + info_field(_("Shading Language Version (ES)"), THISORUNK(glx->ogles_sl_version) ), + info_field(_("GLX Version"), THISORUNK(glx->glx_version) ), + info_field_last()); return info_flatten(info); } @@ -641,20 +871,28 @@ gchar *get_ogl_renderer(void) { scan_display(FALSE); - return g_strdup(computer->display->ogl_renderer); + return g_strdup(computer->display->xi->glx->ogl_renderer); } gchar *get_display_summary(void) { scan_display(FALSE); - return g_strdup_printf("%dx%d\n" + gchar *gpu_list = module_call_method("devices::getGPUList"); + + gchar *ret = g_strdup_printf( + "%s\n" + "%dx%d\n" "%s\n" "%s", - computer->display->width, - computer->display->height, - computer->display->ogl_renderer, - computer->display->vendor); + gpu_list, + computer->display->width, computer->display->height, + computer->display->display_server, + (computer->display->xi->glx->ogl_renderer) + ? computer->display->xi->glx->ogl_renderer + : "" ); + g_free(gpu_list); + return ret; } gchar *get_kernel_module_description(gchar *module) @@ -682,16 +920,65 @@ gchar *get_audio_cards(void) return computer_get_alsacards(computer); } -ShellModuleMethod *hi_exported_methods(void) +/* the returned string must stay in kB as it is used + * elsewhere with that expectation */ +gchar *get_memory_total(void) +{ + scan_memory_usage(FALSE); + return moreinfo_lookup ("DEV:MemTotal"); +} + +gchar *memory_devices_get_system_memory_str(); /* in dmi_memory.c */ +gchar *memory_devices_get_system_memory_types_str(); +/* Note 1: moreinfo_lookup() results should not be freed because + * they are pointers into a GHash. + * module_call_method() g_strdup()s it's return value. */ +const gchar *get_memory_desc(void) // [1] const (as to say "don't free") +{ + scan_memory_usage(FALSE); + gchar *avail = g_strdup(moreinfo_lookup("DEV:MemTotal")); // [1] g_strdup() + double k = avail ? (double)strtol(avail, NULL, 10) : 0; + if (k) { + g_free(avail); + avail = NULL; + const char *fmt = _(/*/ <value> <unit> "usable memory" */ "%0.1f %s available to Linux"); + if (k > (2048 * 1024)) + avail = g_strdup_printf(fmt, k / (1024*1024), _("GiB") ); + else if (k > 2048) + avail = g_strdup_printf(fmt, k / 1024, _("MiB") ); + else + avail = g_strdup_printf(fmt, k, _("KiB") ); + } + gchar *mem = memory_devices_get_system_memory_str(); + if (mem) { + gchar *types = memory_devices_get_system_memory_types_str(); + gchar *ret = g_strdup_printf("%s %s\n%s", mem, types, avail ? avail : ""); + g_free(avail); + g_free(mem); + g_free(types); + return (gchar*)idle_free(ret); // [1] idle_free() + } + return (gchar*)idle_free(avail); // [1] idle_free() +} + +static gchar *get_machine_type(void) { - static ShellModuleMethod m[] = { + return computer_get_virtualization(); +} + +const ShellModuleMethod *hi_exported_methods(void) +{ + static const ShellModuleMethod m[] = { {"getOSKernel", get_os_kernel}, {"getOS", get_os}, {"getDisplaySummary", get_display_summary}, {"getOGLRenderer", get_ogl_renderer}, {"getAudioCards", get_audio_cards}, {"getKernelModuleDescription", get_kernel_module_description}, - {NULL} + {"getMemoryTotal", get_memory_total}, + {"getMemoryDesc", get_memory_desc}, + {"getMachineType", get_machine_type}, + {NULL}, }; return m; @@ -721,6 +1008,11 @@ gchar **hi_module_get_dependencies(void) gchar *hi_module_get_summary(void) { + gchar *virt = computer_get_virtualization(); + gchar *machine_type = g_strdup_printf("%s (%s)", + _("Motherboard"), + (char*)idle_free(virt)); + return g_strdup_printf("[%s]\n" "Icon=os.png\n" "Method=computer::getOS\n" @@ -729,7 +1021,7 @@ gchar *hi_module_get_summary(void) "Method=devices::getProcessorNameAndDesc\n" "[%s]\n" "Icon=memory.png\n" - "Method=devices::getMemoryTotal\n" + "Method=computer::getMemoryDesc\n" "[%s]\n" "Icon=module.png\n" "Method=devices::getMotherboard\n" @@ -738,7 +1030,7 @@ gchar *hi_module_get_summary(void) "Method=computer::getDisplaySummary\n" "[%s]\n" "Icon=hdd.png\n" - "Method=devices::getStorageDevices\n" + "Method=devices::getStorageDevicesSimple\n" "[%s]\n" "Icon=printer.png\n" "Method=devices::getPrinters\n" @@ -746,15 +1038,18 @@ gchar *hi_module_get_summary(void) "Icon=audio.png\n" "Method=computer::getAudioCards\n", _("Operating System"), - _("CPU"), _("RAM"), _("Motherboard"), _("Graphics"), + _("Processor"), _("Memory"), (char*)idle_free(machine_type), _("Graphics"), _("Storage"), _("Printers"), _("Audio") ); } void hi_module_deinit(void) { + g_hash_table_destroy(memlabels); + if (computer->os) { g_free(computer->os->kernel); + g_free(computer->os->kcmdline); g_free(computer->os->libc); g_free(computer->os->distrocode); g_free(computer->os->distro); @@ -769,17 +1064,7 @@ void hi_module_deinit(void) 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); - } + computer_free_display(computer->display); if (computer->alsa) { g_slist_free(computer->alsa->cards); @@ -795,18 +1080,45 @@ void hi_module_deinit(void) void hi_module_init(void) { computer = g_new0(Computer, 1); + init_memory_labels(); + kernel_module_icon_init(); } -ModuleAbout *hi_module_get_about(void) +const 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"} - }; + static const ModuleAbout ma = { + .author = "L. A. F. Pereira", + .description = N_("Gathers high-level computer information"), + .version = VERSION, + .license = "GNU GPL version 2 or later.",}; + + return &ma; +} + +static const gchar *hinote_kmod() { + static gchar note[note_max_len] = ""; + gboolean ok = TRUE; + *note = 0; /* clear */ + ok &= note_require_tool("lsmod", note, _("<i><b>lsmod</b></i> is required.")); + return ok ? NULL : g_strstrip(note); /* remove last \n */ +} - return ma; +static const gchar *hinote_display() { + static gchar note[note_max_len] = ""; + gboolean ok = TRUE; + *note = 0; /* clear */ + ok &= note_require_tool("xrandr", note, _("X.org's <i><b>xrandr</b></i> utility provides additional details when available.")); + ok &= note_require_tool("glxinfo", note, _("Mesa's <i><b>glxinfo</b></i> utility is required for OpenGL information.")); + return ok ? NULL : g_strstrip(note); /* remove last \n */ } +const gchar *hi_note_func(gint entry) +{ + if (entry == ENTRY_KMOD) { + return hinote_kmod(); + } + else if (entry == ENTRY_DISPLAY) { + return hinote_display(); + } + return NULL; +} diff --git a/modules/computer/alsa.c b/modules/computer/alsa.c index 00c1fceb..f74d2752 100644 --- a/modules/computer/alsa.c +++ b/modules/computer/alsa.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/computer/boots.c b/modules/computer/boots.c index ba458242..52c122e4 100644 --- a/modules/computer/boots.c +++ b/modules/computer/boots.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,6 +21,8 @@ #include "hardinfo.h" #include "computer.h" +extern void scan_os(gboolean reload); + void scan_boots_real(void) { @@ -35,7 +37,7 @@ scan_boots_real(void) else return; - spawned = g_spawn_command_line_sync("last", + spawned = hardinfo_spawn_command_line_sync("last", &out, &err, NULL, NULL); if (spawned && out != NULL) { p = out; diff --git a/modules/computer/display.c b/modules/computer/display.c index 61eac4eb..98cb7bf7 100644 --- a/modules/computer/display.c +++ b/modules/computer/display.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,131 +21,54 @@ #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)"); +DisplayInfo *computer_get_display(void) { + DisplayInfo *di = g_new0(DisplayInfo, 1); + wl_info *wl = get_walyand_info(); + xinfo *xi = xinfo_get_info(); + xrr_info *xrr = xi->xrr; + glx_info *glx = xi->glx; + + di->width = di->height = 0; + if (xrr->screen_count > 0) { + di->width = xrr->screens[0].px_width; + di->height = xrr->screens[0].px_height; } - -} - -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, ":", 2); - output_lines++; - - 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); - get_str("name of display", di->display_name); - - 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); + di->vendor = xi->vendor; + di->session_type = wl->xdg_session_type; + + if (strcmp(di->session_type, "x11") == 0 ) { + if (xi->nox) { + di->display_server = g_strdup(_("(Unknown)")); + /* assumed x11 previously, because it wasn't set */ + free(wl->xdg_session_type); + di->session_type = wl->xdg_session_type = NULL; + } else if (xi->vendor && xi->version) + di->display_server = g_strdup_printf("%s %s", xi->vendor, xi->version ); + else if (xi->vendor && xi->release_number) + di->display_server = g_strdup_printf("[X11] %s %s", xi->vendor, xi->release_number ); + else + di->display_server = g_strdup("X11"); + } else + if (strcmp(di->session_type, "wayland") == 0 ) { + di->display_server = g_strdup("Wayland"); + } else + if (strcmp(di->session_type, "mir") == 0 ) { + di->display_server = g_strdup("Mir"); + } else { + di->display_server = g_strdup(_("(Unknown)")); } - 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 = ""; - } + di->xi = xi; + di->wl = wl; + return di; } -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; +void computer_free_display(DisplayInfo *di) { + /* fyi: DisplayInfo is in computer.h */ + if (di) { + free(di->display_server); + xinfo_free(di->xi); + wl_free(di->wl); + free(di); } - - get_glx_info(di); - get_x11_info(di); - - return di; } diff --git a/modules/computer/environment.c b/modules/computer/environment.c index dc0fb6f3..2f29c861 100644 --- a/modules/computer/environment.c +++ b/modules/computer/environment.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/computer/filesystem.c b/modules/computer/filesystem.c index 397dc636..e9c84811 100644 --- a/modules/computer/filesystem.c +++ b/modules/computer/filesystem.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -71,6 +71,8 @@ scan_filesystems(void) gchar *strhash; + gboolean rw = strstr(tmp[3], "rw") != NULL; + strreplacechr(tmp[0], "#", '_'); strhash = g_strdup_printf("[%s]\n" "%s=%s\n" @@ -81,7 +83,7 @@ scan_filesystems(void) "%s=%s\n", tmp[0], /* path */ _("Filesystem"), tmp[2], - _("Mounted As"), ( strstr(tmp[3], "rw") != NULL) ? _("Read-Write") : _("Read-Only"), + _("Mounted As"), rw ? _("Read-Write") : _("Read-Only"), _("Mount Point"), tmp[1], _("Size"), strsize, _("Used"), strused, @@ -90,9 +92,10 @@ scan_filesystems(void) 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 = h_strdup_cprintf("$FS%d$%s%s=%.2f %% (%s of %s)|%s\n", fs_list, - count, tmp[0], use_ratio, stravail, strsize, tmp[1]); + count, tmp[0], rw ? "" : "🔒", + use_ratio, stravail, strsize, tmp[1]); g_free(strsize); g_free(stravail); diff --git a/modules/computer/groups.c b/modules/computer/groups.c index 244b8000..9371e211 100644 --- a/modules/computer/groups.c +++ b/modules/computer/groups.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2012 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2012 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/computer/languages.c b/modules/computer/languages.c index d4681839..b2d4910f 100644 --- a/modules/computer/languages.c +++ b/modules/computer/languages.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,113 +22,161 @@ #include "computer.h" #include "cpu_util.h" /* for UNKIFNULL() */ -void -scan_languages(OperatingSystem * os) -{ - FILE *locale; - gchar buf[512], *retval = NULL; - - locale = popen("locale -va && echo", "r"); - if (!locale) - return; - +typedef struct { 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); - - UNKIFNULL(title); - UNKIFNULL(source); - UNKIFNULL(address); - UNKIFNULL(email); - UNKIFNULL(language); - UNKIFNULL(territory); - UNKIFNULL(revision); - UNKIFNULL(date); - UNKIFNULL(codeset); - - /* values may have & */ - title = hardinfo_clean_value(title, 1); - source = hardinfo_clean_value(source, 1); - address = hardinfo_clean_value(address, 1); - email = hardinfo_clean_value(email, 1); - language = hardinfo_clean_value(language, 1); - territory = hardinfo_clean_value(territory, 1); - - currlocale = g_strdup_printf("[%s]\n" - /* Name */ "%s=%s (%s)\n" - /* Source */ "%s=%s\n" - /* Address */ "%s=%s\n" - /* Email */ "%s=%s\n" - /* Language */ "%s=%s\n" - /* Territory */"%s=%s\n" - /* Revision */ "%s=%s\n" - /* Date */ "%s=%s\n" - /* Codeset */ "%s=%s\n", - _("Locale Information"), - _("Name"), name, title, - _("Source"), source, - _("Address"), address, - _("E-mail"), email, - _("Language"), language, - _("Territory"), territory, - _("Revision"), revision, - _("Date"), date, - _("Codeset"), codeset ); - - 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; - } + gchar *title, + *source, + *address, + *email, + *language, + *territory, + *revision, + *date, + *codeset; +} locale_info; + +void locale_info_free(locale_info *s) { + if (s) { + g_free(s->title); + g_free(s->source); + g_free(s->address); + g_free(s->email); + g_free(s->language); + g_free(s->territory); + g_free(s->revision); + g_free(s->date); + g_free(s->codeset); + free(s); } +} - fclose(locale); +/* TODO: use info_* */ +gchar *locale_info_section(locale_info *s) { + gchar *name = g_strdup(s->name); + gchar *title = g_strdup(s->title), + *source = g_strdup(s->source), + *address = g_strdup(s->address), + *email = g_strdup(s->email), + *language = g_strdup(s->language), + *territory = g_strdup(s->territory), + *revision = g_strdup(s->revision), + *date = g_strdup(s->date), + *codeset = g_strdup(s->codeset); + + UNKIFNULL(title); + UNKIFNULL(source); + UNKIFNULL(address); + UNKIFNULL(email); + UNKIFNULL(language); + UNKIFNULL(territory); + UNKIFNULL(revision); + UNKIFNULL(date); + UNKIFNULL(codeset); + + /* values may have & */ + title = hardinfo_clean_value(title, 1); + source = hardinfo_clean_value(source, 1); + address = hardinfo_clean_value(address, 1); + email = hardinfo_clean_value(email, 1); + language = hardinfo_clean_value(language, 1); + territory = hardinfo_clean_value(territory, 1); + + gchar *ret = g_strdup_printf("[%s]\n" + /* Name */ "%s=%s (%s)\n" + /* Source */ "%s=%s\n" + /* Address */ "%s=%s\n" + /* Email */ "%s=%s\n" + /* Language */ "%s=%s\n" + /* Territory */"%s=%s\n" + /* Revision */ "%s=%s\n" + /* Date */ "%s=%s\n" + /* Codeset */ "%s=%s\n", + _("Locale Information"), + _("Name"), name, title, + _("Source"), source, + _("Address"), address, + _("E-mail"), email, + _("Language"), language, + _("Territory"), territory, + _("Revision"), revision, + _("Date"), date, + _("Codeset"), codeset ); + g_free(name); + 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); + return ret; +} - os->languages = retval; +void +scan_languages(OperatingSystem * os) +{ + gboolean spawned; + gchar *out, *err, *p, *next_nl; + + gchar *ret = NULL; + locale_info *curr = NULL; + int last = 0; + + spawned = hardinfo_spawn_command_line_sync("locale -va", + &out, &err, NULL, NULL); + if (spawned) { + ret = g_strdup(""); + p = out; + while(1) { + /* `locale -va` doesn't end the last locale block + * with an \n, which makes this more complicated */ + next_nl = strchr(p, '\n'); + if (next_nl == NULL) + next_nl = strchr(p, 0); + last = (*next_nl == 0) ? 1 : 0; + strend(p, '\n'); + if (strncmp(p, "locale:", 7) == 0) { + curr = g_new0(locale_info, 1); + sscanf(p, "locale: %s", curr->name); + /* TODO: 'directory:' and 'archive:' */ + } else if (strchr(p, '|')) { + do {/* get_str() has a continue in it, + * how fn frustrating that was to figure out */ + gchar **tmp = g_strsplit(p, "|", 2); + tmp[0] = g_strstrip(tmp[0]); + if (tmp[1]) { + tmp[1] = g_strstrip(tmp[1]); + get_str("title", curr->title); + get_str("source", curr->source); + get_str("address", curr->address); + get_str("email", curr->email); + get_str("language", curr->language); + get_str("territory", curr->territory); + get_str("revision", curr->revision); + get_str("date", curr->date); + get_str("codeset", curr->codeset); + } + g_strfreev(tmp); + } while (0); + } else if (strstr(p, "------")) { + /* do nothing */ + } else if (curr) { + /* a blank line is the end of a locale */ + gchar *li_str = locale_info_section(curr); + gchar *clean_title = hardinfo_clean_value(curr->title, 0); /* may contain & */ + ret = h_strdup_cprintf("$%s$%s=%s\n", ret, curr->name, curr->name, clean_title); + moreinfo_add_with_prefix("COMP", g_strdup(curr->name), li_str); /* becomes owned by moreinfo */ + locale_info_free(curr); + curr = NULL; + g_free(clean_title); + } + if (last) break; + p = next_nl + 1; + } + g_free(out); + g_free(err); + } + os->languages = ret; } diff --git a/modules/computer/loadavg.c b/modules/computer/loadavg.c index 7311dbf0..802ae2aa 100644 --- a/modules/computer/loadavg.c +++ b/modules/computer/loadavg.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/computer/memory.c b/modules/computer/memory.c index dc8599c2..994e4040 100644 --- a/modules/computer/memory.c +++ b/modules/computer/memory.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/devmemory.c b/modules/computer/memory_usage.c index 29094dd8..12c62fe7 100644 --- a/modules/devices/devmemory.c +++ b/modules/computer/memory_usage.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +29,12 @@ void scan_memory_do(void) if (offset == -1) { /* gah. linux 2.4 adds three lines of data we don't need in - /proc/meminfo */ + * /proc/meminfo. + * The lines look something like this: + * total: used: free: shared: buffers: cached: + * Mem: 3301101568 1523159040 1777942528 0 3514368 1450356736 + * Swap: 0 0 0 + */ gchar *os_kernel = module_call_method("computer::getOSKernel"); if (os_kernel) { offset = strstr(os_kernel, "Linux 2.4") ? 3 : 0; diff --git a/modules/computer/modules.c b/modules/computer/modules.c index df876e3a..14028362 100644 --- a/modules/computer/modules.c +++ b/modules/computer/modules.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -17,161 +17,384 @@ */ #include <string.h> +#include <sys/utsname.h> +#include <json-glib/json-glib.h> -#include "hardinfo.h" +#include "syncmanager.h" #include "computer.h" #include "cpu_util.h" /* for STRIFNULL() */ +#include "hardinfo.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; \ - } +#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; +static gchar *kernel_modules_dir = NULL; + +enum icons { + ICON_INVALID = 0, + + ICON_AUDIO, + ICON_BLUETOOTH, + ICON_CAMERA_WEB, + ICON_CDROM, + ICON_CRYPTOHASH, + ICON_DEVICES, + ICON_HDD, + ICON_INPUTDEVICES, + ICON_JOYSTICK, + ICON_KEYBOARD, + ICON_MEDIA_FLOPPY, + ICON_MEDIA_REMOVABLE, + ICON_MEMORY, + ICON_MONITOR, + ICON_MOUSE, + ICON_NETWORK, + ICON_NETWORK_CONNECTIONS, + ICON_NETWORK_INTERFACE, + ICON_THERM, + ICON_USB, + ICON_WIRELESS, + + ICON_MAX, +}; + +static const char *icon_table[ICON_MAX] = { + [ICON_AUDIO] = "audio", + [ICON_BLUETOOTH] = "bluetooth", + [ICON_CAMERA_WEB] = "camera-web", + [ICON_CDROM] = "cdrom", + [ICON_CRYPTOHASH] = "cryptohash", + [ICON_DEVICES] = "devices", + [ICON_HDD] = "hdd", + [ICON_INPUTDEVICES] = "inputdevices", + [ICON_JOYSTICK] = "joystick", + [ICON_KEYBOARD] = "keyboard", + [ICON_MEDIA_FLOPPY] = "media-floppy", + [ICON_MEDIA_REMOVABLE] = "media-removable", + [ICON_MEMORY] = "memory", + [ICON_MONITOR] = "monitor", + [ICON_MOUSE] = "mouse", + [ICON_NETWORK] = "network", + [ICON_NETWORK_CONNECTIONS] = "network-connections", + [ICON_NETWORK_INTERFACE] = "network-interface", + [ICON_THERM] = "therm", + [ICON_USB] = "usb", + [ICON_WIRELESS] = "wireless", +}; + +/* Keep this sorted by reverse strlen(dir)! */ +static const struct { + const gchar *dir; + enum icons icon; +} modules_icons[] = { + {"drivers/input/joystick/", ICON_JOYSTICK}, + {"drivers/input/keyboard/", ICON_KEYBOARD}, + {"drivers/media/usb/uvc/", ICON_CAMERA_WEB}, + {"drivers/net/wireless/", ICON_WIRELESS}, + {"drivers/net/ethernet/", ICON_NETWORK_INTERFACE}, + {"drivers/input/mouse/", ICON_MOUSE}, + {"drivers/bluetooth/", ICON_BLUETOOTH}, + {"drivers/media/v4l", ICON_CAMERA_WEB}, + {"arch/x86/crypto/", ICON_CRYPTOHASH}, + {"drivers/crypto/", ICON_CRYPTOHASH}, + {"net/bluetooth/", ICON_BLUETOOTH}, + {"drivers/input/", ICON_INPUTDEVICES}, + {"drivers/cdrom/", ICON_CDROM}, + {"drivers/hwmon/", ICON_THERM}, + {"drivers/iommu/", ICON_MEMORY}, + {"net/wireless/", ICON_WIRELESS}, + {"drivers/nvme/", ICON_HDD}, + {"net/ethernet/", ICON_NETWORK_INTERFACE}, + {"drivers/scsi/", ICON_HDD}, + {"drivers/edac/", ICON_MEMORY}, + {"drivers/hid/", ICON_INPUTDEVICES}, + {"drivers/gpu/", ICON_MONITOR}, + {"drivers/i2c/", ICON_MEMORY}, + {"drivers/ata/", ICON_HDD}, + {"drivers/usb/", ICON_USB}, + {"drivers/pci/", ICON_DEVICES}, + {"drivers/net/", ICON_NETWORK}, + {"drivers/mmc/", ICON_MEDIA_REMOVABLE}, + {"crypto/", ICON_CRYPTOHASH}, + {"sound/", ICON_AUDIO}, + {"net/", ICON_NETWORK_CONNECTIONS}, + {"fs/", ICON_MEDIA_FLOPPY}, + {}, +}; + +static GHashTable *module_icons; -void -scan_modules_do(void) +static void build_icon_table_iter(JsonObject *object, + const gchar *key, + JsonNode *value, + gpointer user_data) { + char *key_copy = g_strdup(key); + char *p; + + for (p = key_copy; *p; p++) { + if (*p == '_') + *p = '-'; + } + + enum icons icon; + const gchar *value_str = json_node_get_string(value); + for (icon = ICON_INVALID; icon < ICON_MAX; icon++) { + const char *icon_name = icon_table[icon]; + + if (!icon_name) + continue; + + if (g_str_equal(value_str, icon_name)) { + g_hash_table_insert(module_icons, + key_copy, GINT_TO_POINTER(icon)); + return; + } + } + + g_free(key_copy); +} + +void kernel_module_icon_init(void) +{ + gchar *icon_json; + + static SyncEntry sync_entry = { + .name = N_("Update kernel module icon table"), + .file_name = "kernel-module-icons.json", + }; + sync_manager_add_entry(&sync_entry); + + icon_json = g_build_filename(g_get_user_config_dir(), + "hardinfo", "kernel-module-icons.json", + NULL); + + module_icons = g_hash_table_new(g_str_hash, g_str_equal); + + if (!g_file_test(icon_json, G_FILE_TEST_EXISTS)) + goto out; + + JsonParser *parser = json_parser_new(); + if (!json_parser_load_from_file(parser, icon_json, NULL)) + goto out_destroy_parser; + + JsonNode *root = json_parser_get_root(parser); + if (json_node_get_node_type(root) != JSON_NODE_OBJECT) + goto out_destroy_parser; + + JsonObject *icons = json_node_get_object(root); + if (!icons) + goto out_destroy_parser; + + json_object_foreach_member(icons, build_icon_table_iter, NULL); + +out_destroy_parser: + g_object_unref(parser); + +out: + g_free(icon_json); +} + +static const gchar* get_module_icon(const char *modname, const char *path) +{ + char *modname_temp = g_strdup(modname); + char *p; + for (p = modname_temp; *p; p++) { + if (*p == '_') + *p = '-'; + } + gpointer icon = g_hash_table_lookup(module_icons, modname_temp); + g_free(modname_temp); + if (icon) + return icon_table[GPOINTER_TO_INT(icon)]; + + if (path == NULL) /* modinfo couldn't find module path */ + return NULL; + + if (kernel_modules_dir == NULL) { + struct utsname utsbuf; + uname(&utsbuf); + kernel_modules_dir = g_strdup_printf("/lib/modules/%s/kernel/", utsbuf.release); + } + + if (!g_str_has_prefix(path, kernel_modules_dir)) + return NULL; + + const gchar *path_no_prefix = path + strlen(kernel_modules_dir); + const size_t path_no_prefix_len = strlen(path_no_prefix); + int i; + + for (i = 0; modules_icons[i].dir; i++) { + if (g_str_has_prefix(path_no_prefix, modules_icons[i].dir)) + return icon_table[modules_icons[i].icon]; + } + + return NULL; +} + +void scan_modules_do(void) { FILE *lsmod; gchar buffer[1024]; gchar *lsmod_path; + gchar *module_icons; + const gchar *icon; - if (!_module_hash_table) { - _module_hash_table = g_hash_table_new(g_str_hash, g_str_equal); - } + if (!_module_hash_table) { _module_hash_table = g_hash_table_new(g_str_hash, g_str_equal); } g_free(module_list); + kernel_modules_dir = NULL; module_list = NULL; + module_icons = NULL; moreinfo_del_with_prefix("COMP:MOD"); lsmod_path = find_program("lsmod"); - if (!lsmod_path) - return; + if (!lsmod_path) return; lsmod = popen(lsmod_path, "r"); if (!lsmod) { g_free(lsmod_path); - return; + return; } - (void)fgets(buffer, 1024, lsmod); /* Discards the first line */ + (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), + gchar *buf, *strmodule, *hashkey; + gchar *author = NULL, *description = NULL, *license = NULL, *deps = NULL, *vermagic = NULL, + *filename = NULL, *srcversion = NULL, *version = NULL, *retpoline = NULL, + *intree = 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); + GET_STR("srcversion", srcversion); /* so "version" doesn't catch */ + GET_STR("version", version); + GET_STR("retpoline", retpoline); + GET_STR("intree", intree); + + 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)); + } 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 : ""); - - STRIFNULL(filename, _("(Not available)") ); - STRIFNULL(description, _("(Not available)") ); - STRIFNULL(vermagic, _("(Not available)") ); - STRIFNULL(author, _("(Not available)") ); - STRIFNULL(license, _("(Not available)") ); - - /* create the module information string */ - strmodule = g_strdup_printf("[%s]\n" - "%s=%s\n" - "%s=%.2f %s\n" - "[%s]\n" - "%s=%s\n" - "%s=%s\n" - "%s=%s\n" - "[%s]\n" - "%s=%s\n" - "%s=%s\n", - _("Module Information"), - _("Path"), filename, - _("Used Memory"), memory / 1024.0, _("KiB"), - _("Description"), - _("Name"), modname, - _("Description"), description, - _("Version Magic"), vermagic, - _("Copyright"), - _("Author"), author, - _("License"), 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); - } + /* append this module to the list of modules */ + module_list = h_strdup_cprintf("$%s$%s=%s\n", module_list, hashkey, modname, + description ? description : ""); + icon = get_module_icon(modname, filename); + module_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", module_icons, hashkey, + modname, icon ? icon: "module"); + + STRIFNULL(filename, _("(Not available)")); + STRIFNULL(description, _("(Not available)")); + STRIFNULL(vermagic, _("(Not available)")); + STRIFNULL(author, _("(Not available)")); + STRIFNULL(license, _("(Not available)")); + STRIFNULL(version, _("(Not available)")); + + gboolean ry = FALSE, ity = FALSE; + if (retpoline && *retpoline == 'Y') ry = TRUE; + if (intree && *intree == 'Y') ity = TRUE; - moreinfo_add_with_prefix("COMP", hashkey, strmodule); - g_free(hashkey); + g_free(retpoline); + g_free(intree); - g_free(license); - g_free(description); - g_free(author); - g_free(vermagic); - g_free(filename); + retpoline = g_strdup(ry ? _("Yes") : _("No")); + intree = g_strdup(ity ? _("Yes") : _("No")); + + /* create the module information string */ + strmodule = g_strdup_printf("[%s]\n" + "%s=%s\n" + "%s=%.2f %s\n" + "[%s]\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "[%s]\n" + "%s=%s\n" + "%s=%s\n", + _("Module Information"), _("Path"), filename, _("Used Memory"), + memory / 1024.0, _("KiB"), _("Description"), _("Name"), modname, + _("Description"), description, _("Version Magic"), vermagic, + _("Version"), version, _("In Linus' Tree"), intree, + _("Retpoline Enabled"), retpoline, _("Copyright"), _("Author"), + author, _("License"), 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); + g_free(srcversion); + g_free(version); + g_free(retpoline); + g_free(intree); } pclose(lsmod); g_free(lsmod_path); + g_free(kernel_modules_dir); + + if (module_list != NULL && module_icons != NULL) { + module_list = h_strdup_cprintf("[$ShellParam$]\n%s", module_list, module_icons); + } + g_free(module_icons); } diff --git a/modules/computer/os.c b/modules/computer/os.c index a8886f64..7648eef3 100644 --- a/modules/computer/os.c +++ b/modules/computer/os.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,6 +21,7 @@ #include <sys/utsname.h> #include "hardinfo.h" #include "computer.h" +#include "distro_flavors.h" static gchar * get_libc_version(void) @@ -46,7 +47,7 @@ get_libc_version(void) gboolean spawned; gchar *out, *err, *p; - spawned = g_spawn_command_line_sync(libs[i].test_cmd, + spawned = hardinfo_spawn_command_line_sync(libs[i].test_cmd, &out, &err, NULL, NULL); if (!spawned) continue; @@ -91,7 +92,7 @@ static gchar *detect_kde_version(void) cmd = "kcontrol --version"; } - spawned = g_spawn_command_line_sync(cmd, &out, NULL, NULL, NULL); + spawned = hardinfo_spawn_command_line_sync(cmd, &out, NULL, NULL, NULL); if (!spawned) return NULL; @@ -106,7 +107,7 @@ detect_gnome_version(void) gchar *out; gboolean spawned; - spawned = g_spawn_command_line_sync( + spawned = hardinfo_spawn_command_line_sync( "gnome-shell --version", &out, NULL, NULL, NULL); if (spawned) { tmp = strstr(idle_free(out), _("GNOME Shell ")); @@ -117,7 +118,7 @@ detect_gnome_version(void) } } - spawned = g_spawn_command_line_sync( + spawned = hardinfo_spawn_command_line_sync( "gnome-about --gnome-version", &out, NULL, NULL, NULL); if (spawned) { tmp = strstr(idle_free(out), _("Version: ")); @@ -131,17 +132,42 @@ detect_gnome_version(void) return NULL; } + static gchar * -detect_window_manager(void) +detect_mate_version(void) { - GdkScreen *screen = gdk_screen_get_default(); - const gchar *windowman; - const gchar *curdesktop; + gchar *tmp; + gchar *out; + gboolean spawned; - if (!screen || !GDK_IS_SCREEN(screen)) - return NULL; + spawned = hardinfo_spawn_command_line_sync( + "mate-about --version", &out, NULL, NULL, NULL); + if (spawned) { + tmp = strstr(idle_free(out), _("MATE Desktop Environment ")); - windowman = gdk_x11_screen_get_window_manager_name(screen); + if (tmp) { + tmp += strlen(_("MATE Desktop Environment ")); + return g_strdup_printf("MATE %s", strend(tmp, '\n')); + } + } + + return NULL; +} + +static gchar * +detect_window_manager(void) +{ + const gchar *curdesktop; + const gchar* windowman; + GdkScreen *screen = gdk_screen_get_default(); + +#if GTK_CHECK_VERSION(3,0,0) + if (GDK_IS_X11_SCREEN(screen)) { +#else + if (screen && GDK_IS_SCREEN(screen)) { +#endif + windowman = gdk_x11_screen_get_window_manager_name(screen); + } else return g_strdup("Not X11"); if (g_str_equal(windowman, "Xfwm4")) return g_strdup("XFCE 4"); @@ -192,6 +218,12 @@ detect_xdg_environment(const gchar *env_var) if (maybe_kde) return maybe_kde; } + if (g_str_equal(tmp, "MATE") || g_str_equal(tmp, "mate")) { + gchar *maybe_mate = detect_mate_version(); + + if (maybe_mate) + return maybe_mate; + } return g_strdup(tmp); } @@ -235,6 +267,44 @@ detect_desktop_environment(void) } gchar * +computer_get_dmesg_status(void) +{ + gchar *out = NULL, *err = NULL; + int ex = 1, result = 0; + hardinfo_spawn_command_line_sync("dmesg", &out, &err, &ex, NULL); + g_free(out); + g_free(err); + result += (getuid() == 0) ? 2 : 0; + result += ex ? 1 : 0; + switch(result) { + case 0: /* readable, user */ + return g_strdup(_("User access allowed")); + case 1: /* unreadable, user */ + return g_strdup(_("User access forbidden")); + case 2: /* readable, root */ + return g_strdup(_("Access allowed (running as superuser)")); + case 3: /* unreadable, root */ + return g_strdup(_("Access forbidden? (running as superuser)")); + } + return g_strdup(_("(Unknown)")); +} + +gchar * +computer_get_aslr(void) +{ + switch (h_sysfs_read_int("/proc/sys/kernel", "randomize_va_space")) { + case 0: + return g_strdup(_("Disabled")); + case 1: + return g_strdup(_("Partially enabled (mmap base+stack+VDSO base)")); + case 2: + return g_strdup(_("Fully enabled (mmap base+stack+VDSO base+heap)")); + default: + return g_strdup(_("Unknown")); + } +} + +gchar * computer_get_entropy_avail(void) { gchar tab_entropy_fstr[][32] = { @@ -281,7 +351,77 @@ computer_get_language(void) return ret; } -static gchar * +static Distro +parse_os_release(void) +{ + gchar *pretty_name = NULL; + gchar *id = NULL; + gchar *codename = NULL; + gchar **split, *contents, **line; + + if (!g_file_get_contents("/usr/lib/os-release", &contents, NULL, NULL)) + return (Distro) {}; + + split = g_strsplit(idle_free(contents), "\n", 0); + if (!split) + return (Distro) {}; + + for (line = split; *line; line++) { + if (!strncmp(*line, "ID=", sizeof("ID=") - 1)) { + id = g_strdup(*line + strlen("ID=")); + } else if (!strncmp(*line, "CODENAME=", sizeof("CODENAME=") - 1)) { + codename = g_strdup(*line + strlen("CODENAME=")); + } else if (!strncmp(*line, "PRETTY_NAME=", sizeof("PRETTY_NAME=") - 1)) { + pretty_name = g_strdup(*line + + strlen("PRETTY_NAME=\"")); + strend(pretty_name, '"'); + } + } + + g_strfreev(split); + + if (pretty_name) + return (Distro) { .distro = pretty_name, .codename = codename, .id = id }; + + g_free(id); + return (Distro) {}; +} + +static Distro +parse_lsb_release(void) +{ + gchar *pretty_name = NULL; + gchar *id = NULL; + gchar *codename = NULL; + gchar **split, *contents, **line; + + if (!hardinfo_spawn_command_line_sync("/usr/bin/lsb_release -di", &contents, NULL, NULL, NULL)) + return (Distro) {}; + + split = g_strsplit(idle_free(contents), "\n", 0); + if (!split) + return (Distro) {}; + + for (line = split; *line; line++) { + if (!strncmp(*line, "Distributor ID:\t", sizeof("Distributor ID:\t") - 1)) { + id = g_utf8_strdown(*line + strlen("Distributor ID:\t"), -1); + } else if (!strncmp(*line, "Codename:\t", sizeof("Codename:\t") - 1)) { + codename = g_utf8_strdown(*line + strlen("Codename:\t"), -1); + } else if (!strncmp(*line, "Description:\t", sizeof("Description:\t") - 1)) { + pretty_name = g_strdup(*line + strlen("Description:\t")); + } + } + + g_strfreev(split); + + if (pretty_name) + return (Distro) { .distro = pretty_name, .codename = codename, .id = id }; + + g_free(id); + return (Distro) {}; +} + +static Distro detect_distro(void) { static const struct { @@ -292,11 +432,11 @@ detect_distro(void) #define DB_PREFIX "/etc/" { DB_PREFIX "arch-release", "arch", "Arch Linux" }, { DB_PREFIX "fatdog-version", "fatdog" }, - { DB_PREFIX "debian_version", "deb" }, + { DB_PREFIX "debian_version", "debian" }, { DB_PREFIX "slackware-version", "slk" }, { DB_PREFIX "mandrake-release", "mdk" }, { DB_PREFIX "mandriva-release", "mdv" }, - { DB_PREFIX "fedora-release", "fdra" }, + { DB_PREFIX "fedora-release", "fedora" }, { DB_PREFIX "coas", "coas" }, { DB_PREFIX "environment.corel", "corel"}, { DB_PREFIX "gentoo-release", "gnt" }, @@ -305,7 +445,6 @@ detect_distro(void) { DB_PREFIX "turbolinux-release", "tl" }, { DB_PREFIX "yellowdog-release", "yd" }, { DB_PREFIX "sabayon-release", "sbn" }, - { DB_PREFIX "arch-release", "arch" }, { DB_PREFIX "enlisy-release", "enlsy" }, { DB_PREFIX "SuSE-release", "suse" }, { DB_PREFIX "sun-release", "sun" }, @@ -324,15 +463,17 @@ detect_distro(void) #undef DB_PREFIX { NULL, NULL } }; + Distro distro; gchar *contents; int i; - if (g_spawn_command_line_sync("lsb_release -d", &contents, NULL, NULL, NULL)) { - gchar *tmp = strstr(idle_free(contents), "Description:\t"); + distro = parse_os_release(); + if (distro.distro) + return distro; - if (tmp) - return g_strdup(tmp + strlen("Description:\t")); - } + distro = parse_lsb_release(); + if (distro.distro) + return distro; for (i = 0; distro_db[i].file; i++) { if (!g_file_get_contents(distro_db[i].file, &contents, NULL, NULL)) @@ -340,23 +481,31 @@ detect_distro(void) if (distro_db[i].override) { g_free(contents); - return g_strdup(distro_db[i].override); + return (Distro) { .distro = g_strdup(distro_db[i].override), + .codename = g_strdup(distro_db[i].codename) }; } - if (g_str_equal(distro_db[i].codename, "deb")) { + if (g_str_equal(distro_db[i].codename, "debian")) { /* HACK: Some Debian systems doesn't include the distribuition * name in /etc/debian_release, so add them here. */ if (isdigit(contents[0]) || contents[0] != 'D') - return g_strdup_printf("Debian GNU/Linux %s", (char*)idle_free(contents)); + return (Distro) { + .distro = g_strdup_printf("Debian GNU/Linux %s", (char*)idle_free(contents)), + .codename = g_strdup(distro_db[i].codename) + }; } - if (g_str_equal(distro_db[i].codename, "fatdog")) - return g_strdup_printf("Fatdog64 [%.10s]", (char*)idle_free(contents)); + if (g_str_equal(distro_db[i].codename, "fatdog")) { + return (Distro) { + .distro = g_strdup_printf("Fatdog64 [%.10s]", (char*)idle_free(contents)), + .codename = g_strdup(distro_db[i].codename) + }; + } - return contents; + return (Distro) { .distro = contents, .codename = g_strdup(distro_db[i].codename) }; } - return g_strdup(_("Unknown")); + return (Distro) { .distro = g_strdup(_("Unknown")) }; } OperatingSystem * @@ -368,13 +517,17 @@ computer_get_os(void) os = g_new0(OperatingSystem, 1); - os->distro = g_strstrip(detect_distro()); + Distro distro = detect_distro(); + os->distro = g_strstrip(distro.distro); + os->distroid = distro.id; + os->distrocode = distro.codename; /* 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->kcmdline = h_sysfs_read_string("/proc", "cmdline"); os->hostname = g_strdup(utsbuf.nodename); os->language = computer_get_language(); os->homedir = g_strdup(g_get_home_dir()); @@ -389,5 +542,41 @@ computer_get_os(void) os->entropy_avail = computer_get_entropy_avail(); + if (g_strcmp0(os->distrocode, "ubuntu") == 0) { + GSList *flavs = ubuntu_flavors_scan(); + if (flavs) { + /* just use the first one */ + os->distro_flavor = (DistroFlavor*)flavs->data; + } + g_slist_free(flavs); + } + return os; } + +const gchar * +computer_get_selinux(void) +{ + int r; + gboolean spawned = hardinfo_spawn_command_line_sync("selinuxenabled", + NULL, NULL, &r, NULL); + + if (!spawned) + return _("Not installed"); + + if (r == 0) + return _("Enabled"); + + return _("Disabled"); +} + +gchar * +computer_get_lsm(void) +{ + gchar *contents; + + if (!g_file_get_contents("/sys/kernel/security/lsm", &contents, NULL, NULL)) + return g_strdup(_("Unknown")); + + return contents; +} diff --git a/modules/computer/ubuntu_flavors.c b/modules/computer/ubuntu_flavors.c new file mode 100644 index 00000000..ac67d665 --- /dev/null +++ b/modules/computer/ubuntu_flavors.c @@ -0,0 +1,90 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2019 L. A. F. Pereira <l@tia.mat.br> + * This file 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, version 2 or later. + * + * 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 "distro_flavors.h" +#include "util_sysobj.h" /* for appfsp() */ + +static const UbuntuFlavor ubuntu_flavors[] = { + { "Vanilla Server", "distros/ubuntu.svg", "https://ubuntu.org", "ubuntu-server" }, + { "Vanilla Desktop", "distros/ubuntu.svg", "https://ubuntu.org", "ubuntu-desktop" }, + { "Xubuntu", "distros/xubuntu.svg", "https://xubuntu.org", "xubuntu-desktop" }, + { "Kubuntu", "distros/kubuntu.png", "https://kubuntu.org", "kubuntu-desktop" }, + { "Lubuntu", "distros/lubuntu.png", "https://lubuntu.me", "lubuntu-desktop" }, /* formerly or also lubuntu.net? */ + { "Ubuntu MATE", "distros/ubuntu-mate.png", "https://ubuntu-mate.org", "ubuntu-mate-desktop" }, + { "Ubuntu Budgie", "distros/ubuntu-budgie.png", "https://ubuntubudgie.org", "ubuntu-budgie-desktop" }, + { "UbuntuKylin (做最有中国味的操作系统)", "distros/ubuntu-kylin.png", "https://www.ubuntukylin.com", "ubuntukylin-desktop" }, + { "UbuntuStudio", "distros/ubuntu-studio.png", "https://ubuntustudio.org", "ubuntustudio-desktop" }, + /* Deprecated flavors */ + { "Ubuntu GNOME", "distros/ubuntu-gnome.png", "https://ubuntugnome.org", "ubuntu-gnome-desktop" }, + // Edubuntu + // Mythbuntu + { NULL } +}; + +static const UbuntuFlavor *_find_flavor(const gchar *pkg) { + int i = 0; + for(; ubuntu_flavors[i].base.name; i++) { + if (SEQ(ubuntu_flavors[i].package, pkg)) + return &ubuntu_flavors[i]; + } + return NULL; +} + +/* items are const; free with g_slist_free() */ +GSList *ubuntu_flavors_scan(void) { + GSList *ret = NULL; + gboolean spawned; + gchar *out, *err, *p, *next_nl; + gint exit_status; + const UbuntuFlavor *f = NULL; + gchar *cmd_line = g_strdup("apt-cache policy"); + int i; + for(i = 0; ubuntu_flavors[i].base.name; i++) { + cmd_line = appfsp(cmd_line, "%s", ubuntu_flavors[i].package); + } + if (!i) + return NULL; + + spawned = hardinfo_spawn_command_line_sync(cmd_line, + &out, &err, &exit_status, NULL); + if (spawned) { + p = out; + while(next_nl = strchr(p, '\n')) { + strend(p, '\n'); + int mc = 0; + char pkg[32] = ""; + if (*p != ' ' && *p != '\t') + mc = sscanf(p, "%31s", pkg); + if (mc == 1) { + strend(pkg, ':'); + f = _find_flavor(pkg); + } else if + (g_strstr_len(p, -1, "Installed:") + && !g_strstr_len(p, -1, "(none)") ) { + ret = g_slist_append(ret, (void*)f); + } + p = next_nl + 1; + } + g_free(out); + g_free(err); + } + g_free(cmd_line); + return ret; +} diff --git a/modules/computer/uptime.c b/modules/computer/uptime.c index 6ef3d250..8aef1530 100644 --- a/modules/computer/uptime.c +++ b/modules/computer/uptime.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/computer/users.c b/modules/computer/users.c index f47320bb..75e24f26 100644 --- a/modules/computer/users.c +++ b/modules/computer/users.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2009 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices.c b/modules/devices.c index 152b6831..574896ee 100644 --- a/modules/devices.c +++ b/modules/devices.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,10 +20,6 @@ #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> @@ -38,9 +34,13 @@ #include "devices.h" #include "dt_util.h" +#include "udisks2_util.h" +#include "storage_util.h" +#include "pci_util.h" gchar *callback_processors(); -gchar *callback_memory(); +gchar *callback_gpu(); +gchar *callback_monitors(); gchar *callback_battery(); gchar *callback_pci(); gchar *callback_sensors(); @@ -48,15 +48,15 @@ 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_dmi_mem(); +gchar *callback_firmware(); gchar *callback_dtree(); gchar *callback_device_resources(); void scan_processors(gboolean reload); -void scan_memory(gboolean reload); +void scan_gpu(gboolean reload); +void scan_monitors(gboolean reload); void scan_battery(gboolean reload); void scan_pci(gboolean reload); void scan_sensors(gboolean reload); @@ -64,50 +64,52 @@ 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_dmi_mem(gboolean reload); +void scan_firmware(gboolean reload); void scan_dtree(gboolean reload); void scan_device_resources(gboolean reload); gboolean root_required_for_resources(void); +gboolean spd_decode_show_hinote(const char**); gchar *hi_more_info(gchar *entry); enum { ENTRY_DTREE, + ENTRY_DMI, ENTRY_PROCESSOR, - ENTRY_MEMORY, + ENTRY_GPU, + ENTRY_MONITORS, + ENTRY_DMI_MEM, ENTRY_PCI, ENTRY_USB, + ENTRY_FW, 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_GPU] = {N_("Graphics Processors"), "devices.png", callback_gpu, scan_gpu, MODULE_FLAG_NONE}, + [ENTRY_MONITORS] = {N_("Monitors"), "monitor.png", callback_monitors, scan_monitors, 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_FW] = {N_("Firmware"), "processor.png", callback_firmware, scan_firmware, 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}, + [ENTRY_DMI] = {N_("System DMI"), "computer.png", callback_dmi, scan_dmi, MODULE_FLAG_NONE}, + [ENTRY_DMI_MEM] = {N_("Memory Devices"), "memory.png", callback_dmi_mem, scan_dmi_mem, 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}, - [ENTRY_DTREE] = {"#"}, + [ENTRY_DTREE] = {N_("Device Tree"), "devices.png", callback_dtree, scan_dtree, MODULE_FLAG_HIDE}, #else - [ENTRY_DMI] = {"#"}, - [ENTRY_SPD] = {"#"}, [ENTRY_DTREE] = {N_("Device Tree"), "devices.png", callback_dtree, scan_dtree, MODULE_FLAG_NONE}, #endif /* x86 or x86_64 */ [ENTRY_RESOURCES] = {N_("Resources"), "resources.png", callback_device_resources, scan_device_resources, MODULE_FLAG_NONE}, @@ -119,13 +121,34 @@ gchar *printer_list = NULL; gchar *printer_icons = NULL; gchar *pci_list = NULL; gchar *input_list = NULL; +gboolean storage_no_nvme = FALSE; gchar *storage_list = NULL; gchar *battery_list = NULL; -gchar *meminfo = NULL; -gchar *lginterval = NULL; + +/* in dmi_memory.c */ +gchar *memory_devices_get_info(); +gboolean memory_devices_hinote(const char **msg); +gchar *memory_devices_info = NULL; + +/* in firmware.c */ +gchar *firmware_get_info(); +gboolean firmware_hinote(const char **msg); +gchar *firmware_info = NULL; + +/* in monitors.c */ +gchar *monitors_get_info(); +gboolean monitors_hinote(const char **msg); +gchar *monitors_info = NULL; #include <vendor.h> +extern gchar *gpu_summary; +const gchar *get_gpu_summary() { + if (gpu_summary == NULL) + scan_gpu(FALSE); + return gpu_summary; +} + static gint proc_cmp_model_name(Processor *a, Processor *b) { return g_strcmp0(a->model_name, b->model_name); } @@ -140,19 +163,27 @@ static gint proc_cmp_max_freq(Processor *a, Processor *b) { gchar *processor_describe_default(GSList * processors) { - int packs, cores, threads; - const gchar *packs_fmt, *cores_fmt, *threads_fmt; + int packs, cores, threads, nodes; + const gchar *packs_fmt, *cores_fmt, *threads_fmt, *nodes_fmt; gchar *ret, *full_fmt; - cpu_procs_cores_threads(&packs, &cores, &threads); + cpu_procs_cores_threads_nodes(&packs, &cores, &threads, &nodes); + + /* NOTE: If this is changed, look at get_cpu_desc() in bench_results.c! */ /* if topology info was available, else fallback to old method */ if (cores > 0) { packs_fmt = ngettext("%d physical processor", "%d physical processors", packs); cores_fmt = ngettext("%d core", "%d cores", cores); threads_fmt = ngettext("%d thread", "%d threads", threads); - full_fmt = g_strdup_printf(_(/*/NP procs; NC cores; NT threads*/ "%s; %s; %s"), packs_fmt, cores_fmt, threads_fmt); - ret = g_strdup_printf(full_fmt, packs, cores, threads); + if (nodes > 1) { + nodes_fmt = ngettext("%d NUMA node", "%d NUMA nodes", nodes); + full_fmt = g_strdup_printf(_(/*/NP procs; NC cores across NN nodes; NT threads*/ "%s; %s across %s; %s"), packs_fmt, cores_fmt, nodes_fmt, threads_fmt); + ret = g_strdup_printf(full_fmt, packs, cores * nodes, nodes, threads); + } else { + full_fmt = g_strdup_printf(_(/*/NP procs; NC cores; NT threads*/ "%s; %s; %s"), packs_fmt, cores_fmt, threads_fmt); + ret = g_strdup_printf(full_fmt, packs, cores, threads); + } g_free(full_fmt); return ret; } else { @@ -246,6 +277,44 @@ gchar *get_processor_name_and_desc(void) return nd; } +gchar *get_storage_devices_simple(void) +{ + scan_storage(FALSE); + + struct Info *info = info_unflatten(storage_list); + if (!info) { + return ""; + } + + guint i, fi; + struct InfoGroup *group; + struct InfoField *field; + gchar *storage_devs = NULL, *tmp; + const gchar *dev_label, *model_wo_tags; + + GRegex *regex; + regex = g_regex_new ("<.*>", 0, 0, NULL); + + for (i = 0; i < info->groups->len; i++) { + group = &g_array_index(info->groups, struct InfoGroup, info->groups->len - 1); + if (!group) + continue; + + info_group_strip_extra(group); + for (fi = 0; fi < group->fields->len; fi++) { + field = &g_array_index(group->fields, struct InfoField, fi); + if (!field->value) + continue; + + tmp = g_regex_replace(regex, field->value, -1, 0, "", 0, NULL); // remove html tags + storage_devs = h_strdup_cprintf("%s\n", storage_devs, g_strchug(tmp)); + g_free(tmp); + } + } + g_free(info); + + return storage_devs; +} gchar *get_storage_devices(void) { @@ -336,59 +405,138 @@ gchar *get_processor_max_frequency(void) } } -gchar *get_pci_device_description(gchar *pci_id) +gchar *get_motherboard(void) { - gchar *description; + gchar *board_name, *board_vendor, *board_version; + gchar *product_name, *product_vendor, *product_version; + gchar *board_part = NULL, *product_part = NULL; + const gchar *tmp; + int b = 0, p = 0; - if (!_pci_devices) { - scan_pci(FALSE); + gchar *ret; + +#if defined(ARCH_x86) || defined(ARCH_x86_64) + scan_dmi(FALSE); + + board_name = dmi_get_str("baseboard-product-name"); + board_version = dmi_get_str("baseboard-version"); + board_vendor = dmi_get_str("baseboard-manufacturer"); + if (board_vendor) { + /* attempt to shorten */ + tmp = vendor_get_shortest_name(board_vendor); + if (tmp && tmp != board_vendor) { + g_free(board_vendor); + board_vendor = g_strdup(tmp); + } } - if ((description = g_hash_table_lookup(_pci_devices, pci_id))) { - return g_strdup(description); + product_name = dmi_get_str("system-product-name"); + product_version = dmi_get_str("system-version"); + product_vendor = dmi_get_str("system-manufacturer"); + if (product_vendor) { + /* attempt to shorten */ + tmp = vendor_get_shortest_name(product_vendor); + if (tmp && tmp != product_vendor) { + g_free(product_vendor); + product_vendor = g_strdup(tmp); + } } - return NULL; -} + if (board_vendor && product_vendor && + strcmp(board_vendor, product_vendor) == 0) { + /* ignore duplicate vendor */ + g_free(product_vendor); + product_vendor = NULL; + } -gchar *get_memory_total(void) -{ - scan_memory(FALSE); - return moreinfo_lookup ("DEV:MemTotal"); -} + if (board_name && product_name && + strcmp(board_name, product_name) == 0) { + /* ignore duplicate name */ + g_free(product_name); + product_name = NULL; + } -gchar *get_motherboard(void) -{ - char *board_name, *board_vendor, *system_version; - char *ret; + if (board_version && product_version && + strcmp(board_version, product_version) == 0) { + /* ignore duplicate version */ + g_free(product_version); + product_version = NULL; + } -#if defined(ARCH_x86) || defined(ARCH_x86_64) - scan_dmi(FALSE); + if (board_name) b += 1; + if (board_vendor) b += 2; + if (board_version) b += 4; + + switch(b) { + case 1: /* only name */ + board_part = g_strdup(board_name); + break; + case 2: /* only vendor */ + board_part = g_strdup(board_vendor); + break; + case 3: /* only name and vendor */ + board_part = g_strdup_printf("%s %s", board_vendor, board_name); + break; + case 4: /* only version? Seems unlikely */ + board_part = g_strdup(board_version); + break; + case 5: /* only name and version? */ + board_part = g_strdup_printf("%s %s", board_name, board_version); + break; + case 6: /* only vendor and version (like lpereira's Thinkpad) */ + board_part = g_strdup_printf("%s %s", board_vendor, board_version); + break; + case 7: /* all */ + board_part = g_strdup_printf("%s %s %s", board_vendor, board_name, board_version); + break; + } - board_name = dmi_get_str("baseboard-product-name"); - if (board_name == NULL) - board_name = dmi_get_str("system-product-name"); + if (product_name) p += 1; + if (product_vendor) p += 2; + if (product_version) p += 4; + + switch(p) { + case 1: /* only name */ + product_part = g_strdup(product_name); + break; + case 2: /* only vendor */ + product_part = g_strdup(product_vendor); + break; + case 3: /* only name and vendor */ + product_part = g_strdup_printf("%s %s", product_vendor, product_name); + break; + case 4: /* only version? Seems unlikely */ + product_part = g_strdup(product_version); + break; + case 5: /* only name and version? */ + product_part = g_strdup_printf("%s %s", product_name, product_version); + break; + case 6: /* only vendor and version? */ + product_part = g_strdup_printf("%s %s", product_vendor, product_version); + break; + case 7: /* all */ + product_part = g_strdup_printf("%s %s %s", product_vendor, product_name, product_version); + break; + } - board_vendor = dmi_get_str("baseboard-manufacturer"); - if (board_vendor == NULL) - board_vendor = dmi_get_str("system-manufacturer"); - - system_version = dmi_get_str("system-version"); - - if (board_name && board_vendor && system_version) - ret = g_strdup_printf("%s / %s (%s)", system_version, board_name, board_vendor); - else if (board_name && board_vendor) - ret = g_strconcat(board_vendor, " ", board_name, NULL); - else if (board_name) - ret = g_strdup(board_name); - else if (board_vendor) - ret = g_strdup(board_vendor); + if (board_part && product_part) { + ret = g_strdup_printf("%s (%s)", board_part, product_part); + g_free(board_part); + g_free(product_part); + } else if (board_part) + ret = board_part; + else if (product_part) + ret = product_part; else ret = g_strdup(_("(Unknown)")); - free(board_name); - free(board_vendor); - free(system_version); + g_free(board_name); + g_free(board_vendor); + g_free(board_version); + g_free(product_name); + g_free(product_vendor); + g_free(product_version); + return ret; #endif @@ -400,22 +548,22 @@ gchar *get_motherboard(void) return g_strdup(_("Unknown")); } -ShellModuleMethod *hi_exported_methods(void) -{ - static ShellModuleMethod m[] = { - {"getProcessorCount", get_processor_count}, - {"getProcessorName", get_processor_name}, - {"getProcessorDesc", get_processor_desc}, - {"getProcessorNameAndDesc", get_processor_name_and_desc}, - {"getProcessorFrequency", get_processor_max_frequency}, - {"getProcessorFrequencyDesc", get_processor_frequency_desc}, - {"getMemoryTotal", get_memory_total}, - {"getStorageDevices", get_storage_devices}, - {"getPrinters", get_printers}, - {"getInputDevices", get_input_devices}, - {"getPCIDeviceDescription", get_pci_device_description}, - {"getMotherboard", get_motherboard}, - {NULL} +const ShellModuleMethod *hi_exported_methods(void) +{ + static const ShellModuleMethod m[] = { + {"getProcessorCount", get_processor_count}, + {"getProcessorName", get_processor_name}, + {"getProcessorDesc", get_processor_desc}, + {"getProcessorNameAndDesc", get_processor_name_and_desc}, + {"getProcessorFrequency", get_processor_max_frequency}, + {"getProcessorFrequencyDesc", get_processor_frequency_desc}, + {"getStorageDevices", get_storage_devices}, + {"getStorageDevicesSimple", get_storage_devices_simple}, + {"getPrinters", get_printers}, + {"getInputDevices", get_input_devices}, + {"getMotherboard", get_motherboard}, + {"getGPUList", get_gpu_summary}, + {NULL}, }; return m; @@ -434,14 +582,12 @@ gchar *hi_more_info(gchar * entry) gchar *hi_get_field(gchar * field) { gchar *info = moreinfo_lookup_with_prefix("DEV", field); - if (info) - return g_strdup(info); + return g_strdup(info); return g_strdup(field); } -#if defined(ARCH_x86) || defined(ARCH_x86_64) void scan_dmi(gboolean reload) { SCAN_START(); @@ -449,13 +595,32 @@ void scan_dmi(gboolean reload) SCAN_END(); } -void scan_spd(gboolean reload) +void scan_dmi_mem(gboolean reload) { SCAN_START(); - scan_spd_do(); + if (memory_devices_info) + g_free(memory_devices_info); + memory_devices_info = memory_devices_get_info(); + SCAN_END(); +} + +void scan_monitors(gboolean reload) +{ + SCAN_START(); + if (monitors_info) + g_free(monitors_info); + monitors_info = monitors_get_info(); + SCAN_END(); +} + +void scan_firmware(gboolean reload) +{ + SCAN_START(); + if (firmware_info) + g_free(firmware_info); + firmware_info = firmware_get_info(); SCAN_END(); } -#endif void scan_dtree(gboolean reload) { @@ -472,17 +637,17 @@ void scan_processors(gboolean reload) SCAN_END(); } -void scan_memory(gboolean reload) +void scan_battery(gboolean reload) { SCAN_START(); - scan_memory_do(); + scan_battery_do(); SCAN_END(); } -void scan_battery(gboolean reload) +void scan_gpu(gboolean reload) { SCAN_START(); - scan_battery_do(); + scan_gpu_do(); SCAN_END(); } @@ -512,9 +677,12 @@ void scan_storage(gboolean reload) SCAN_START(); g_free(storage_list); storage_list = g_strdup(""); - - __scan_ide_devices(); - __scan_scsi_devices(); + storage_no_nvme = FALSE; + if (!__scan_udisks2_devices()) { + storage_no_nvme = TRUE; + __scan_ide_devices(); + __scan_scsi_devices(); + } SCAN_END(); } @@ -537,17 +705,28 @@ gchar *callback_processors() return processor_get_info(processors); } -#if defined(ARCH_x86) || defined(ARCH_x86_64) gchar *callback_dmi() { - return g_strdup(dmi_info); + return g_strdup_printf("%s" + "[$ShellParam$]\n" + "ViewType=5\n", + dmi_info); } -gchar *callback_spd() +gchar *callback_dmi_mem() { - return g_strdup(spd_info); + return g_strdup(memory_devices_info); +} + +gchar *callback_monitors() +{ + return g_strdup(monitors_info); +} + +gchar *callback_firmware() +{ + return g_strdup(firmware_info); } -#endif gchar *callback_dtree() { @@ -556,41 +735,27 @@ gchar *callback_dtree() "ViewType=1\n", dtree_info); } -gchar *callback_memory() -{ - return g_strdup_printf("[Memory]\n" - "%s\n" - "[$ShellParam$]\n" - "ViewType=2\n" - "LoadGraphSuffix= kB\n" - "RescanInterval=2000\n" - "ColumnTitle$TextValue=%s\n" - "ColumnTitle$Extra1=%s\n" - "ColumnTitle$Value=%s\n" - "ShowColumnHeaders=true\n" - "%s\n", meminfo, - _("Field"), _("Description"), _("Value"), /* column labels */ - lginterval); -} - gchar *callback_battery() { return g_strdup_printf("%s\n" "[$ShellParam$]\n" + "ViewType=5\n" "ReloadInterval=4000\n", battery_list); } gchar *callback_pci() { - return g_strdup_printf("[PCI Devices]\n" - "%s" - "[$ShellParam$]\n" "ViewType=1\n", pci_list); + return g_strdup(pci_list); +} + +gchar *callback_gpu() +{ + return g_strdup(gpu_list); } gchar *callback_sensors() { - return g_strdup_printf("[Sensors]\n" - "%s\n" + return g_strdup_printf("%s\n" "[$ShellParam$]\n" "ViewType=2\n" "LoadGraphSuffix=\n" @@ -599,10 +764,13 @@ gchar *callback_sensors() "ColumnTitle$Extra1=%s\n" "ShowColumnHeaders=true\n" "RescanInterval=5000\n" + "%s\n" "%s", sensors, - _("Sensor"), _("Value"), _("Type"), /* column labels */ - lginterval); + _("Sensor"), _("Value"), + SENSORS_GROUP_BY_TYPE ? _("Driver"): _("Type"), + lginterval, + sensor_icons); } gchar *callback_printers() @@ -617,27 +785,37 @@ gchar *callback_printers() gchar *callback_storage() { return g_strdup_printf("%s\n" - "[$ShellParam$]\n" - "ReloadInterval=5000\n" - "ViewType=1\n%s", storage_list, storage_icons); + "[$ShellParam$]\n" + "ReloadInterval=5000\n" + "ColumnTitle$TextValue=%s\n" + "ColumnTitle$Value=%s\n" + "ColumnTitle$Extra1=%s\n" + "ShowColumnHeaders=true\n" + "ViewType=1\n%s", storage_list, _("Device"), _("Size"), _("Model"), 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); + "%s" + "[$ShellParam$]\n" + "ViewType=1\n" + "ColumnTitle$TextValue=%s\n" + "ColumnTitle$Value=%s\n" + "ColumnTitle$Extra1=%s\n" + "ShowColumnHeaders=true\n" + "ReloadInterval=5000\n%s", + input_list, _("Device"), _("Vendor"), _("Type"), + input_icons); } gchar *callback_usb() { return g_strdup_printf("%s" - "[$ShellParam$]\n" - "ViewType=1\n" - "ReloadInterval=5000\n", usb_list); + "[$ShellParam$]\n" + "ViewType=1\n" + "ReloadInterval=5000\n%s", usb_list, usb_icons); + } ModuleEntry *hi_module_get_entries(void) @@ -657,54 +835,68 @@ guchar hi_module_get_weight(void) 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); - } + static SyncEntry entries[] = { + { + .name = N_("Update PCI ID listing"), + .file_name = "pci.ids", + }, + { + .name = N_("Update USB ID listing"), + .file_name = "usb.ids", + }, + { + .name = N_("Update EDID vendor codes"), + .file_name = "edid.ids", + }, + { + .name = N_("Update IEEE OUI vendor codes"), + .file_name = "ieee_oui.ids", + }, + { + .name = N_("Update SD card manufacturer information"), + .file_name = "sdcard.ids", + }, +#ifdef ARCH_x86 + { + .name = N_("Update CPU flags database"), + .file_name = "cpuflags.json", + }, +#endif + }; + guint i; -#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) */ + for (i = 0; i < G_N_ELEMENTS(entries); i++) + sync_manager_add_entry(&entries[i]); - init_memory_labels(); init_cups(); - sensors_init(); + sensor_init(); + udisks2_init(); + +#ifdef ARCH_x86 + void cpuflags_x86_init(void); + cpuflags_x86_init(); +#endif } void hi_module_deinit(void) { moreinfo_del_with_prefix("DEV"); - sensors_shutdown(); - g_hash_table_destroy(memlabels); - g_module_close(cups); + sensor_shutdown(); + storage_shutdown(); + udisks2_shutdown(); + if(cups) g_module_close(cups); } -ModuleAbout *hi_module_get_about(void) +const 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"} + static const ModuleAbout ma = { + .author = "L. A. F. Pereira", + .description = N_("Gathers information about hardware devices"), + .version = VERSION, + .license = "GNU GPL version 2 or later.", }; - return ma; + return &ma; } gchar **hi_module_get_dependencies(void) @@ -716,10 +908,39 @@ gchar **hi_module_get_dependencies(void) const gchar *hi_note_func(gint entry) { + if (entry == ENTRY_PCI + || entry == ENTRY_GPU) { + const gchar *ids = find_pci_ids_file(); + if (!ids) { + return g_strdup(_("A copy of <i><b>pci.ids</b></i> is not available on the system.")); + } + if (ids && strstr(ids, ".min")) { + return g_strdup(_("A full <i><b>pci.ids</b></i> is not available on the system.")); + } + } if (entry == ENTRY_RESOURCES) { if (root_required_for_resources()) { return g_strdup(_("Resource information requires superuser privileges")); } } + else if (entry == ENTRY_STORAGE){ + if (storage_no_nvme) { + return g_strdup( + _("Any NVMe storage devices present are not listed.\n" + "<b><i>udisksd</i></b> is required for NVMe devices.")); + } + } + else if (entry == ENTRY_DMI_MEM){ + const char *msg; + if (memory_devices_hinote(&msg)) { + return msg; + } + } + else if (entry == ENTRY_FW) { + const char *msg; + if (firmware_hinote(&msg)) { + return msg; + } + } return NULL; } diff --git a/modules/devices/alpha/processor.c b/modules/devices/alpha/processor.c index c7862232..0e625316 100644 --- a/modules/devices/alpha/processor.c +++ b/modules/devices/alpha/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/arm/arm_data.c b/modules/devices/arm/arm_data.c index 60e8ea34..aece272f 100644 --- a/modules/devices/arm/arm_data.c +++ b/modules/devices/arm/arm_data.c @@ -82,47 +82,6 @@ static struct { }; 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 */ { 0xd05, "Cortex-A55" }, - /*d */ { 0xd07, "Cortex-A57 MPCore" }, - /*d */ { 0xd08, "Cortex-A72" }, - /*d */ { 0xd09, "Cortex-A73" }, - /*d */ { 0xd0a, "Cortex-A75" }, - { 0, NULL}, -}; - -static struct { char *code; char *name; char *more; } tab_arm_arch[] = { { "7", "AArch32", "AArch32 (ARMv7)" }, @@ -161,37 +120,47 @@ const char *arm_flag_meaning(const char *flag) { 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++; +#include "util_ids.h" + +gchar *arm_ids_file = NULL; + +void find_arm_ids_file() { + if (arm_ids_file) return; + char *file_search_order[] = { + g_build_filename(g_get_user_config_dir(), "hardinfo2", "arm.ids", NULL), + g_build_filename(params.path_data, "arm.ids", NULL), + NULL + }; + int n; + for(n = 0; file_search_order[n]; n++) { + if (!arm_ids_file && !access(file_search_order[n], R_OK)) + arm_ids_file = (gchar*) auto_free_on_exit( file_search_order[n] ); + else + g_free(file_search_order[n]); } - 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; +void arm_part(const char *imp_code, const char *part_code, char **imp, char **part) { + gchar *qpath = NULL; + ids_query_result result = {}; + unsigned int i,p; + + if (!arm_ids_file) + find_arm_ids_file(); + + i = strtol(imp_code, NULL, 0); + p = strtol(part_code, NULL, 0); + qpath = g_strdup_printf("%02x/%03x", i, p); + scan_ids_file(arm_ids_file, qpath, &result, -1); + g_free(qpath); + if (imp) + *imp = result.results[0] + ? g_strdup(result.results[0]) + : NULL; + if (part) + *part = result.results[1] + ? g_strdup(result.results[1]) + : NULL; } const char *arm_arch(const char *cpuinfo_arch_str) { @@ -229,8 +198,7 @@ char *arm_decoded_name(const char *imp, const char *part, const char *var, const * 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); + arm_part(imp, part, &imp_name, &part_desc); arch_name = (char*) arm_arch(arch); if (imp_name || part_desc) { if (arch_name != arch) @@ -251,6 +219,8 @@ char *arm_decoded_name(const char *imp, const char *part, const char *var, const (part_desc) ? part_desc : part, r, p, arch); } + g_free(imp_name); + g_free(part_desc); } else { /* prolly not ARM arch at all */ if (model_name) diff --git a/modules/devices/arm/arm_data.h b/modules/devices/arm/arm_data.h index 63b3c906..0e93d323 100644 --- a/modules/devices/arm/arm_data.h +++ b/modules/devices/arm/arm_data.h @@ -22,13 +22,12 @@ #define _ARMDATA_H_ /* table lookups */ -const char *arm_implementer(const char *code); -const char *arm_part(const char *imp_code, const char *part_code); +void arm_part(const char *imp_code, const char *part_code, char **imp, char **part); const char *arm_arch(const char *cpuinfo_arch_str); const char *arm_arch_more(const char *cpuinfo_arch_str); /* 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 */ + * strdup(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); diff --git a/modules/devices/arm/processor.c b/modules/devices/arm/processor.c index 3bee39f8..9446108d 100644 --- a/modules/devices/arm/processor.c +++ b/modules/devices/arm/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -45,6 +45,7 @@ processor_scan(void) gchar buffer[128]; gchar *rep_pname = NULL; GSList *pi = NULL; + dtr *dt = dtr_new(NULL); cpuinfo = fopen(PROC_CPUINFO, "r"); if (!cpuinfo) @@ -162,6 +163,18 @@ processor_scan(void) else processor->cpu_mhz = 0.0f; + /* Try OPP, although if it exists, it should have been available + * via cpufreq. */ + if (dt && processor->cpu_mhz == 0.0f) { + gchar *dt_cpu_path = g_strdup_printf("/cpus/cpu@%d", processor->id); + dt_opp_range *opp = dtr_get_opp_range(dt, dt_cpu_path); + if (opp) { + processor->cpu_mhz = (double)opp->khz_max / 1000; + g_free(opp); + } + g_free(dt_cpu_path); + } + /* mode */ processor->mode = ARM_A32; if ( processor_has_flag(processor->flags, "pmull") @@ -173,6 +186,7 @@ processor_scan(void) #endif } } + dtr_free(dt); return procs; } @@ -233,7 +247,7 @@ gchar *clocks_summary(GSList * processors) /* create list of all clock references */ for (l = processors; l; l = l->next) { p = (Processor*)l->data; - if (p->cpufreq) { + if (p->cpufreq && p->cpufreq->cpukhz_max > 0) { all_clocks = g_slist_prepend(all_clocks, p->cpufreq); } } @@ -297,10 +311,10 @@ gchar *clocks_summary(GSList * processors) gchar * processor_get_detailed_info(Processor *processor) { - gchar *tmp_flags, *tmp_imp, *tmp_part, *tmp_arch, *tmp_cpufreq, *tmp_topology, *ret; + gchar *tmp_flags, *tmp_imp = NULL, *tmp_part = NULL, + *tmp_arch, *tmp_cpufreq, *tmp_topology, *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); + arm_part(processor->cpu_implementer, processor->cpu_part, &tmp_imp, &tmp_part); tmp_arch = (char*)arm_arch_more(processor->cpu_architecture); tmp_topology = cputopo_section_str(processor->cputopo); @@ -361,9 +375,15 @@ gchar *processor_name(GSList *processors) { char *vendor; char *soc; } dt_compat_searches[] = { - { "brcm,bcm2837", "Broadcom", "BCM2837" }, - { "brcm,bcm2836", "Broadcom", "BCM2836" }, - { "brcm,bcm2835", "Broadcom", "BCM2835" }, + { "brcm,bcm2838", "Broadcom", "BCM2838" }, // RPi 4 + { "brcm,bcm2837", "Broadcom", "BCM2837" }, // RPi 3 + { "brcm,bcm2836", "Broadcom", "BCM2836" }, // RPi 2 + { "brcm,bcm2835", "Broadcom", "BCM2835" }, // RPi 1 + { "rockchip,rk3288", "Rockchip", "RK3288" }, // Asus Tinkerboard + { "rockchip,rk3328", "Rockchip", "RK3328" }, // Firefly Renegade + { "rockchip,rk3399", "Rockchip", "RK3399" }, // Firefly Renegade Elite + { "rockchip,rk32", "Rockchip", "RK32xx-family" }, + { "rockchip,rk33", "Rockchip", "RK33xx-family" }, { "ti,omap5432", "Texas Instruments", "OMAP5432" }, { "ti,omap5430", "Texas Instruments", "OMAP5430" }, { "ti,omap4470", "Texas Instruments", "OMAP4470" }, @@ -395,13 +415,15 @@ gchar *processor_name(GSList *processors) { { "mediatek,mt6732", "MediaTek", "MT6732" }, { "qcom,msm8939", "Qualcomm", "Snapdragon 615"}, { "qcom,msm", "Qualcomm", "Snapdragon-family"}, - { "nvidia,tegra" "nVidia", "Tegra-family" }, - { "bcm,", "Broadcom", UNKSOC }, - { "nvidia," "nVidia", UNKSOC }, - { "rockchip," "Rockchip", UNKSOC }, + { "nvidia,tegra", "nVidia", "Tegra-family" }, + { "brcm,", "Broadcom", UNKSOC }, + { "nvidia,", "nVidia", UNKSOC }, + { "rockchip,", "Rockchip", UNKSOC }, { "ti,", "Texas Instruments", UNKSOC }, { "qcom,", "Qualcom", UNKSOC }, - { "mediatek," "MediaTek", UNKSOC }, + { "mediatek,", "MediaTek", UNKSOC }, + { "amlogic,", "Amlogic", UNKSOC }, + { "allwinner,", "Allwinner", UNKSOC }, { NULL, NULL } }; gchar *ret = NULL; @@ -464,7 +486,7 @@ gchar *processor_get_info(GSList * processors) gchar *meta; /* becomes owned by more_info? no need to free? */ GSList *l; - tmp = g_strdup_printf("$CPU_META$%s=\n", _("SOC/Package Information") ); + tmp = g_strdup_printf("$!CPU_META$%s=\n", _("SOC/Package Information") ); meta = processor_meta(processors); moreinfo_add_with_prefix("DEV", "CPU_META", meta); diff --git a/modules/devices/battery.c b/modules/devices/battery.c index cbcebb12..e356c14a 100644 --- a/modules/devices/battery.c +++ b/modules/devices/battery.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -57,7 +57,7 @@ __scan_battery_apcupsd(void) GHashTable *ups_data; FILE *apcaccess; char buffer[512], *apcaccess_path; - int i; + guint i; apcaccess_path = find_program("apcaccess"); if (apcaccess_path && (apcaccess = popen(apcaccess_path, "r"))) { @@ -82,9 +82,9 @@ __scan_battery_apcupsd(void) battery_list = h_strdup_cprintf("[%s]\n", battery_list, ups_fields[i].key); } else { /* there's a name: adds a line */ + const gchar *name = g_hash_table_lookup(ups_data, ups_fields[i].key); battery_list = h_strdup_cprintf("%s=%s\n", battery_list, - ups_fields[i].name, - g_hash_table_lookup(ups_data, ups_fields[i].key)); + ups_fields[i].name, name); } } @@ -165,12 +165,9 @@ __scan_battery_acpi(void) 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; - } + gchar *tmp = vendor_get_link(manufacturer); + g_free(manufacturer); + manufacturer = tmp; if (g_str_equal(present, "yes")) { if (remaining && capacity) @@ -229,11 +226,11 @@ read_contents(const gchar *base, const gchar *key) return NULL; if (!g_file_get_contents(path, &value, NULL, NULL)) { - free(path); + g_free(path); return NULL; } - free(path); + g_free(path); return g_strchomp(value); } diff --git a/modules/devices/devicetree.c b/modules/devices/devicetree.c index 4f3c85a2..7c798670 100644 --- a/modules/devices/devicetree.c +++ b/modules/devices/devicetree.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -28,6 +28,10 @@ #include "devices.h" #include "cpu_util.h" #include "dt_util.h" +#include "appf.h" + +gchar *dtree_info = NULL; +const char *dtree_mem_str = NULL; /* used by memory devices when nothing else is available */ /* These should really go into CMakeLists.txt */ #if defined(__arm__) @@ -36,8 +40,6 @@ #include "devicetree/pmac_data.c" #endif -gchar *dtree_info = NULL; - static gchar *get_node(dtr *dt, char *np) { gchar *nodes = NULL, *props = NULL, *ret = NULL; gchar *tmp = NULL, *pstr = NULL, *lstr = NULL; @@ -216,13 +218,14 @@ static gchar *get_summary(dtr *dt) { return ret; } -static void mi_add(const char *key, const char *value) { +static void mi_add(const char *key, const char *value, int report_details) { gchar *ckey, *rkey; ckey = hardinfo_clean_label(key, 0); rkey = g_strdup_printf("%s:%s", "DTREE", ckey); - dtree_info = h_strdup_cprintf("$%s$%s=\n", dtree_info, rkey, ckey); + dtree_info = h_strdup_cprintf("$%s%s$%s=\n", dtree_info, + (report_details) ? "!" : "", rkey, ckey); moreinfo_add_with_prefix("DEV", rkey, g_strdup(value)); g_free(ckey); @@ -237,15 +240,14 @@ static void add_keys(dtr *dt, char *np) { GDir *dir; dtr_obj *obj; - /* add self */ - obj = dtr_obj_read(dt, np); - dt_path = dtr_obj_path(obj); - n_info = get_node(dt, dt_path); - mi_add(dt_path, n_info); - dir_path = g_strdup_printf("%s/%s", dtr_base_path(dt), np); dir = g_dir_open(dir_path, 0 , NULL); - if (dir) { + if(!dir){ /* add self */ + obj = dtr_obj_read(dt, np); + dt_path = dtr_obj_path(obj); + n_info = get_node(dt, dt_path); + mi_add(dt_path, n_info, 0); + }else { //dir while((fn = g_dir_read_name(dir)) != NULL) { ftmp = g_strdup_printf("%s/%s", dir_path, fn); if ( g_file_test(ftmp, G_FILE_TEST_IS_DIR) ) { @@ -253,24 +255,25 @@ static void add_keys(dtr *dt, char *np) { ntmp = g_strdup_printf("/%s", fn); else ntmp = g_strdup_printf("%s/%s", np, fn); - add_keys(dt, ntmp); + if(strlen(ntmp)>0) add_keys(dt, ntmp); g_free(ntmp); } g_free(ftmp); } + g_dir_close(dir); } - g_dir_close(dir); + g_free(dir_path); } static char *msg_section(dtr *dt, int dump) { gchar *aslbl = NULL; gchar *messages = dtr_messages(dt); - gchar *ret = g_strdup_printf("[%s]\n", _("Messages")); + gchar *ret = g_strdup_printf("[%s]", _("Messages")); gchar **lines = g_strsplit(messages, "\n", 0); int i = 0; while(lines[i] != NULL) { aslbl = hardinfo_clean_label(lines[i], 0); - ret = appf(ret, "%s=\n", aslbl); + ret = appfnl(ret, "%s=", aslbl); g_free(aslbl); i++; } @@ -289,13 +292,13 @@ void __scan_dtree() gchar *messages = NULL; dtree_info = g_strdup("[Device Tree]\n"); - mi_add("Summary", summary); - mi_add("Maps", maps); + mi_add("Summary", summary, 1); + mi_add("Maps", maps, 0); if(dtr_was_found(dt)) add_keys(dt, "/"); messages = msg_section(dt, 0); - mi_add("Messages", messages); + mi_add("Messages", messages, 0); g_free(summary); g_free(maps); diff --git a/modules/devices/devicetree/pmac_data.c b/modules/devices/devicetree/pmac_data.c index b236aef1..8c5471f0 100644 --- a/modules/devices/devicetree/pmac_data.c +++ b/modules/devices/devicetree/pmac_data.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/devicetree/rpi_data.c b/modules/devices/devicetree/rpi_data.c index d0132e3a..63daa7f3 100644 --- a/modules/devices/devicetree/rpi_data.c +++ b/modules/devices/devicetree/rpi_data.c @@ -1,12 +1,12 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * This file from: 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, version 2. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,48 +21,57 @@ static char unk[] = "(Unknown)"; /* information table from: http://elinux.org/RPi_HardwareHistory */ -static struct { +typedef struct { char *value, *intro, *model, *pcb, *mem, *mfg, *soc; -} rpi_boardinfo[] = { +} RaspberryPiBoard; + +static const RaspberryPiBoard rpi_boardinfo[] = { /* Value Introduction Model Name PCB rev. Memory(spec) Manufacturer SOC(spec) * * Raspberry Pi %s */ { unk, unk, unk, unk, unk, unk, NULL }, - { "Beta", "Q1 2012", "B (Beta)", unk, "256MB", "(Beta board)", NULL }, - { "0002", "Q1 2012", "B", "1.0", "256MB", unk, "BCM2835" }, - { "0003", "Q3 2012", "B (ECN0001)", "1.0", "256MB", "(Fuses mod and D14 removed)", NULL }, - { "0004", "Q3 2012", "B", "2.0", "256MB", "Sony", NULL }, - { "0005", "Q4 2012", "B", "2.0", "256MB", "Qisda", NULL }, - { "0006", "Q4 2012", "B", "2.0", "256MB", "Egoman", NULL }, - { "0007", "Q1 2013", "A", "2.0", "256MB", "Egoman", NULL }, - { "0008", "Q1 2013", "A", "2.0", "256MB", "Sony", NULL }, - { "0009", "Q1 2013", "A", "2.0", "256MB", "Qisda", NULL }, - { "000d", "Q4 2012", "B", "2.0", "512MB", "Egoman", NULL }, - { "000e", "Q4 2012", "B", "2.0", "512MB", "Sony", NULL }, - { "000f", "Q4 2012", "B", "2.0", "512MB", "Qisda", NULL }, - { "0010", "Q3 2014", "B+", "1.0", "512MB", "Sony", NULL }, - { "0011", "Q2 2014", "Compute Module 1", "1.0", "512MB", "Sony", NULL }, - { "0012", "Q4 2014", "A+", "1.1", "256MB", "Sony", NULL }, - { "0013", "Q1 2015", "B+", "1.2", "512MB", unk, NULL }, - { "0014", "Q2 2014", "Compute Module 1", "1.0", "512MB", "Embest", NULL }, - { "0015", unk, "A+", "1.1", "256MB/512MB", "Embest", NULL }, - { "a01040", unk, "2 Model B", "1.0", "1GB", "Sony", "BCM2836" }, - { "a01041", "Q1 2015", "2 Model B", "1.1", "1GB", "Sony", "BCM2836" }, - { "a21041", "Q1 2015", "2 Model B", "1.1", "1GB", "Embest", "BCM2836" }, - { "a22042", "Q3 2016", "2 Model B", "1.2", "1GB", "Embest", "BCM2837" }, /* (with BCM2837) */ - { "900021", "Q3 2016", "A+", "1.1", "512MB", "Sony", NULL }, - { "900032", "Q2 2016?", "B+", "1.2", "512MB", "Sony", NULL }, - { "900092", "Q4 2015", "Zero", "1.2", "512MB", "Sony", NULL }, - { "900093", "Q2 2016", "Zero", "1.3", "512MB", "Sony", NULL }, - { "920093", "Q4 2016?", "Zero", "1.3", "512MB", "Embest", NULL }, - { "9000c1", "Q1 2017", "Zero W", "1.1", "512MB", "Sony", NULL }, - { "a02082", "Q1 2016", "3 Model B", "1.2", "1GB", "Sony", "BCM2837" }, - { "a020a0", "Q1 2017", "Compute Module 3 or CM3 Lite", "1.0", "1GB", "Sony", NULL }, - { "a22082", "Q1 2016", "3 Model B", "1.2", "1GB", "Embest", "BCM2837" }, - { "a32082", "Q4 2016", "3 Model B", "1.2", "1GB", "Sony Japan", NULL }, + { "Beta", "Q1 2012", "B (Beta)", unk, "256 MB", "(Beta board)", NULL }, + { "0002", "Q1 2012", "B", "1.0", "256 MB", unk, "BCM2835" }, + { "0003", "Q3 2012", "B (ECN0001)", "1.0", "256 MB", "(Fuses mod and D14 removed)", NULL }, + { "0004", "Q3 2012", "B", "2.0", "256 MB", "Sony", NULL }, + { "0005", "Q4 2012", "B", "2.0", "256 MB", "Qisda", NULL }, + { "0006", "Q4 2012", "B", "2.0", "256 MB", "Egoman", NULL }, + { "0007", "Q1 2013", "A", "2.0", "256 MB", "Egoman", NULL }, + { "0008", "Q1 2013", "A", "2.0", "256 MB", "Sony", NULL }, + { "0009", "Q1 2013", "A", "2.0", "256 MB", "Qisda", NULL }, + { "000d", "Q4 2012", "B", "2.0", "512 MB", "Egoman", NULL }, + { "000e", "Q4 2012", "B", "2.0", "512 MB", "Sony", NULL }, + { "000f", "Q4 2012", "B", "2.0", "512 MB", "Qisda", NULL }, + { "0010", "Q3 2014", "B+", "1.0", "512 MB", "Sony", NULL }, + { "0011", "Q2 2014", "Compute Module 1", "1.0", "512 MB", "Sony", NULL }, + { "0012", "Q4 2014", "A+", "1.1", "256 MB", "Sony", NULL }, + { "0013", "Q1 2015", "B+", "1.2", "512 MB", unk, NULL }, + { "0014", "Q2 2014", "Compute Module 1", "1.0", "512 MB", "Embest", NULL }, + { "0015", unk, "A+", "1.1", "256 MB/512 MB", "Embest", NULL }, + { "a01040", unk, "2 Model B", "1.0", "1024 MB DDR2", "Sony", "BCM2836" }, + { "a01041", "Q1 2015", "2 Model B", "1.1", "1024 MB DDR2", "Sony", "BCM2836" }, + { "a21041", "Q1 2015", "2 Model B", "1.1", "1024 MB DDR2", "Embest", "BCM2836" }, + { "a22042", "Q3 2016", "2 Model B", "1.2", "1024 MB DDR2", "Embest", "BCM2837" }, /* (with BCM2837) */ + { "900021", "Q3 2016", "A+", "1.1", "512 MB", "Sony", NULL }, + { "900032", "Q2 2016?", "B+", "1.2", "512 MB", "Sony", NULL }, + { "900092", "Q4 2015", "Zero", "1.2", "512 MB", "Sony", NULL }, + { "900093", "Q2 2016", "Zero", "1.3", "512 MB", "Sony", NULL }, + { "920093", "Q4 2016?", "Zero", "1.3", "512 MB", "Embest", NULL }, + { "9000c1", "Q1 2017", "Zero W", "1.1", "512 MB", "Sony", NULL }, + { "a02082", "Q1 2016", "3 Model B", "1.2", "1024 MB DDR2", "Sony", "BCM2837" }, + { "a020a0", "Q1 2017", "Compute Module 3 or CM3 Lite", "1.0", "1024 MB DDR2", "Sony", NULL }, + { "a22082", "Q1 2016", "3 Model B", "1.2", "1024 MB DDR2", "Embest", "BCM2837" }, + { "a32082", "Q4 2016", "3 Model B", "1.2", "1024 MB DDR2", "Sony Japan", NULL }, + { "a020d3", "Q1 2018", "3 Model B+", "1.3", "1024 MB DDR2", "Sony", "BCM2837" }, + { "9020e0", "Q4 2018", "3 Model A+", "1.0", "512 MB DDR2", "Sony", "BCM2837" }, + + { "a03111", "Q2 2019", "4 Model B", "1.0", "1024 MB DDR4", "Sony", "BCM2838" }, + { "b03111", "Q2 2019", "4 Model B", "1.0", "2048 MB DDR4", "Sony", "BCM2838" }, + { "c03111", "Q2 2019", "4 Model B", "1.1", "4096 MB DDR4", "Sony", "BCM2838" }, + { "c03114", "Q2 2020", "4 Model B", "1.4", "8192 MB DDR4", "Sony", "BCM2838" }, + { NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; - /* return number of chars to skip */ static int rpi_ov_check(const char *r_code) { /* sources differ. prefix is either 1000... or just 1... */ @@ -154,7 +163,7 @@ static gchar *rpi_board_details(void) { _("PCB Revision"), rpi_boardinfo[i].pcb, _("Introduction"), rpi_boardinfo[i].intro, _("Manufacturer"), rpi_boardinfo[i].mfg, - _("RCode"), rpi_boardinfo[i].value, + _("RCode"), (rpi_boardinfo[i].value != unk) ? rpi_boardinfo[i].value : revision, _("SOC (spec)"), rpi_boardinfo[i].soc, _("Memory (spec)"), rpi_boardinfo[i].mem, _("Serial Number"), serial, @@ -162,5 +171,9 @@ static gchar *rpi_board_details(void) { g_free(soc); g_free(revision); + + if (rpi_boardinfo[i].mem) + dtree_mem_str = rpi_boardinfo[i].mem; + return ret; } diff --git a/modules/devices/dmi.c b/modules/devices/dmi.c index b25cfe21..34374fbe 100644 --- a/modules/devices/dmi.c +++ b/modules/devices/dmi.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,26 +30,29 @@ struct _DMIInfo { const gchar *name; const gchar *id_str; int group; + gboolean maybe_vendor; }; DMIInfo dmi_info_table[] = { { N_("Product"), NULL, 1 }, { N_("Name"), "system-product-name", 0 }, { N_("Family"), "system-product-family", 0 }, - { N_("Vendor"), "system-manufacturer", 0 }, + { N_("Vendor"), "system-manufacturer", 0, TRUE }, { N_("Version"), "system-version", 0 }, + { N_("Serial Number"), "system-serial-number", 0 }, + { N_("SKU"), "system-sku", 0 }, { N_("BIOS"), NULL, 1 }, { N_("Date"), "bios-release-date", 0 }, - { N_("Vendor"), "bios-vendor", 0 }, + { N_("Vendor"), "bios-vendor", 0, TRUE }, { N_("Version"), "bios-version", 0 }, { N_("Board"), NULL, 1 }, { N_("Name"), "baseboard-product-name", 0 }, - { N_("Vendor"), "baseboard-manufacturer", 0 }, + { N_("Vendor"), "baseboard-manufacturer", 0, TRUE }, { N_("Version"), "baseboard-version", 0 }, { N_("Serial Number"), "baseboard-serial-number", 0 }, { N_("Asset Tag"), "baseboard-asset-tag", 0 }, { N_("Chassis"), NULL, 1 }, - { N_("Vendor"), "chassis-manufacturer", 0 }, + { N_("Vendor"), "chassis-manufacturer", 0, TRUE }, { N_("Type"), "chassis-type", 0 }, { N_("Version"), "chassis-version", 0 }, { N_("Serial Number"), "chassis-serial-number", 0 }, @@ -64,77 +67,102 @@ static void add_to_moreinfo(const char *group, const char *key, char *value) moreinfo_add_with_prefix("DEV", new_key, g_strdup(g_strstrip(value))); } -gboolean dmi_get_info() +gboolean dmi_get_info(void) { - const gchar *group = NULL; - DMIInfo *info; - gboolean dmi_succeeded = FALSE; - gint i; - gchar *value; - - if (dmi_info) { - g_free(dmi_info); - dmi_info = NULL; - } + const gchar *group = NULL; + DMIInfo *info; + gboolean dmi_succeeded = FALSE; + guint i; + gchar *value; + const gchar *vendor; + + 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->group) { - group = info->name; - dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, _(info->name) ); - } else if (group && info->id_str) { - if (strcmp(info->id_str, "chassis-type") == 0) - value = dmi_chassis_type_str(-1, 1); - else - value = dmi_get_str(info->id_str); - - if (value != NULL) { - add_to_moreinfo(group, info->name, value); - - const gchar *url = vendor_get_url(value); - if (url) { - const gchar *vendor = vendor_get_name(value); - dmi_info = h_strdup_cprintf("%s=%s (%s, %s)\n", - dmi_info, - _(info->name), - value, - vendor, url); - } else { - dmi_info = h_strdup_cprintf("%s=%s\n", - dmi_info, - _(info->name), - value); + for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) { + info = &dmi_info_table[i]; + + if (info->group) { + group = info->name; + dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, _(info->name)); + } else if (group && info->id_str) { + int state = 3; + + if (strcmp(info->id_str, "chassis-type") == 0) { + value = dmi_chassis_type_str(-1, 1); + if (value == NULL) + state = (getuid() == 0) ? 0 : 1; + } + else { + switch (dmi_str_status(info->id_str)) { + case 0: + value = NULL; + state = (getuid() == 0) ? 0 : 1; + break; + case -1: + state = 2; + value = dmi_get_str_abs(info->id_str); + break; + case 1: + value = dmi_get_str_abs(info->id_str); + break; + } + } + + switch (state) { + case 0: /* no value, root */ + dmi_info = h_strdup_cprintf("%s=%s\n", dmi_info, _(info->name), + _("(Not available)")); + break; + case 1: /* no value, no root */ + dmi_info = h_strdup_cprintf("%s=%s\n", dmi_info, _(info->name), + _("(Not available; Perhaps try " + "running HardInfo as root.)")); + break; + case 2: /* ignored value */ + if (params.markup_ok) + dmi_info = h_strdup_cprintf("%s=<s>%s</s>\n", dmi_info, + _(info->name), value); + else + dmi_info = h_strdup_cprintf("%s=[X]\"%s\"\n", dmi_info, + _(info->name), value); + break; + case 3: /* good value */ + { + dmi_info = + h_strdup_cprintf("%s%s=%s\n", dmi_info, + info->maybe_vendor ? "$^$" : "", + _(info->name), value); + add_to_moreinfo(group, info->name, value); + dmi_succeeded = TRUE; + break; + } + } } - dmi_succeeded = TRUE; - } else { - dmi_info = h_strdup_cprintf("%s=%s\n", - dmi_info, - _(info->name), - (getuid() == 0) - ? _("(Not available)") - : _("(Not available; Perhaps try running HardInfo as root.)") ); - } } - } - if (!dmi_succeeded) { - g_free(dmi_info); - dmi_info = NULL; - } + if (!dmi_succeeded) { + g_free(dmi_info); + dmi_info = NULL; + } - return dmi_succeeded; + return dmi_succeeded; } -void __scan_dmi() +void __scan_dmi(void) { gboolean dmi_ok; dmi_ok = dmi_get_info(); 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"); + dmi_info = g_strdup_printf("[%s]\n%s=\n", + _("DMI Unavailable"), + (getuid() == 0) + ? _("DMI is not avaliable. Perhaps this platform does not provide DMI.") + : _("DMI is not available; Perhaps try running HardInfo as root.") ); + } } diff --git a/modules/devices/dmi_memory.c b/modules/devices/dmi_memory.c new file mode 100644 index 00000000..eba26c8b --- /dev/null +++ b/modules/devices/dmi_memory.c @@ -0,0 +1,1050 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2019 L. A. F. Pereira <l@tia.mat.br> + * Copyright (C) 2019 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, version 2 or later. + * + * 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 + */ + +#define _GNU_SOURCE + +#include "hardinfo.h" +#include "devices.h" +#include "vendor.h" +#include <inttypes.h> + +extern const char *dtree_mem_str; /* in devicetree.c */ + +/* in monitors.c */ +gchar **get_output_lines(const char *cmd_line); + +#include "util_sysobj.h" /* for appfsp() */ +#define dmi_spd_msg(...) /* fprintf (stderr, __VA_ARGS__) */ + +typedef uint64_t dmi_mem_size; + +#include "spd-decode.c" + +gboolean no_handles = FALSE; +gboolean sketchy_info = FALSE; + +int dmi_ram_types = 0; /* bits using enum RamType */ + +/* strings from dmidecode */ +static const char empty_mem_str[] = "No Module Installed"; +static const char unknown_mfgr_str[] = "<BAD INDEX>"; +static const char mobo_location[] = "System Board Or Motherboard"; +static const char mobo_shorter[] = "Mainboard"; +static const dmi_type dta = 16; /* array */ +static const dmi_type dtm = 17; /* socket */ +static const char mem_icon[] = "memory.png"; +static const char array_icon[] = "devices.png"; +static const char empty_icon[] = "module.png"; + +#define UNKNOWN_MEM_TYPE_STRING _("RAM") +#define UNKIFNULL2(f) ((f) ? f : _("(Unknown)")) +#define UNKIFEMPTY2(f) ((*f) ? f : _("(Unknown)")) +#define STR_IGNORE(str, ignore) if (SEQ(str, ignore)) { *str = 0; null_if_empty(&str); } + +dmi_mem_size dmi_read_memory_str_to_MiB(const char *memstr) { + dmi_mem_size ret = 0, v = 0; + char l[7] = ""; + /* dmidecode units: "bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB" */ + int mc = sscanf(memstr, "%"PRId64" %6s", &v, l); + if (mc == 2) { + if (SEQ(l, "ZB")) ret = v * 1024 * 1024 * 1024 * 1024 * 1024; + else if (SEQ(l, "EB")) ret = v * 1024 * 1024 * 1024 * 1024; + else if (SEQ(l, "PB")) ret = v * 1024 * 1024 * 1024; + else if (SEQ(l, "TB")) ret = v * 1024 * 1024; + else if (SEQ(l, "GB")) ret = v * 1024; + else if (SEQ(l, "MB")) ret = v; + else if (SEQ(l, "kB")) { + /* should never appear */ + if (v % 1024) { dmi_spd_msg("OMG kB!"); } + ret = v / 1024; + } + else if (SEQ(l, "bytes")) { + /* should never appear */ + if (v % 1024) { dmi_spd_msg("OMG bytes!"); } + ret = v / (1024 * 1024); + } + } + return ret; +} + +typedef struct { + dmi_handle array_handle; + gboolean is_main_memory; + gchar *locator; + gchar *use; + gchar *ecc; + int devs; + int devs_populated; + dmi_mem_size size_MiB_max; + dmi_mem_size size_MiB_present; + dmi_mem_size size_MiB_rom; + int ram_types; /* bits using enum RamType */ +} dmi_mem_array; + +dmi_mem_array *dmi_mem_array_new(dmi_handle h) { + dmi_mem_array *s = g_new0(dmi_mem_array, 1); + s->array_handle = h; + s->use = dmidecode_match("Use", &dta, &h); + if (SEQ(s->use, "System Memory")) + s->is_main_memory = TRUE; + s->ecc = dmidecode_match("Error Correction Type", &dta, &h); + s->locator = dmidecode_match("Location", &dta, &h); + if (SEQ(s->locator, mobo_location)) { + g_free(s->locator); + s->locator = g_strdup(mobo_shorter); + s->is_main_memory = TRUE; + } + + gchar *array_max_size = dmidecode_match("Maximum Capacity", &dta, &h); + if (array_max_size) { + s->size_MiB_max = dmi_read_memory_str_to_MiB(array_max_size); + g_free(array_max_size); + } + gchar *array_devs = dmidecode_match("Number Of Devices", &dta, &h); + if (array_devs) { + s->devs = strtol(array_devs, NULL, 10); + g_free(array_devs); + } + return s; +} + +void dmi_mem_array_free(dmi_mem_array* s) { + if (s) { + g_free(s->locator); + g_free(s->use); + g_free(s->ecc); + g_free(s); + } +} + +typedef struct dmi_mem_socket { + dmi_handle handle; + dmi_handle array_handle; + gboolean populated; + gchar *locator; + gchar *full_locator; + gchar *short_locator; + gchar *size_str; + dmi_mem_size size_MiB; + + gboolean is_not_ram; /* maybe is_rom, maybe elsewise, but don't include in RAM total */ + gboolean is_rom; + + gchar *type; + gchar *type_detail; + int ram_type; /* using enum RamType */ + gchar *array_locator; + gchar *bank_locator; + gchar *rank; + gchar *form_factor; + gchar *speed_str; + gchar *configured_clock_str; + gchar *voltage_min_str; + gchar *voltage_max_str; + gchar *voltage_conf_str; + gchar *partno; + gchar *data_width; + gchar *total_width; + gchar *mfgr; + gboolean has_jedec_mfg_id; + int mfgr_bank, mfgr_index; + + const Vendor *vendor; + spd_data *spd; +} dmi_mem_socket; + +typedef struct { + gboolean empty; + GSList *arrays; + GSList *sockets; + GSList *spd; + dmi_mem_size spd_size_MiB; + int spd_ram_types; /* bits using enum RamType */ + + dmi_mem_size system_memory_MiB; + int system_memory_ram_types; /* bits using enum RamType */ + + /* ->short_locator is unique among *sockets */ + gboolean unique_short_locators; +} dmi_mem; + +gboolean null_if_empty(gchar **str) { + if (str && *str) { + gchar *p = *str; + while(p && *p) { + if (isalnum(*p)) + return FALSE; + p++; + } + *str = NULL; + } + return TRUE; +} + +dmi_mem_socket *dmi_mem_socket_new(dmi_handle h) { + dmi_mem_socket *s = g_new0(dmi_mem_socket, 1); + s->handle = h; + s->locator = dmidecode_match("Locator", &dtm, &h); + s->size_str = dmidecode_match("Size", &dtm, &h); + if (s->size_str) + s->size_MiB = dmi_read_memory_str_to_MiB(s->size_str); + + s->bank_locator = dmidecode_match("Bank Locator", &dtm, &h); + STR_IGNORE(s->bank_locator, "Unknown"); + STR_IGNORE(s->bank_locator, "Not Specified"); + null_if_empty(&s->bank_locator); + + gchar *ah = dmidecode_match("Array Handle", &dtm, &h); + STR_IGNORE(ah, "Unknown"); + if (ah) { + s->array_handle = strtol(ah, NULL, 16); + g_free(ah); + s->array_locator = dmidecode_match("Location", &dta, &s->array_handle); + if (SEQ(s->array_locator, mobo_location)) { + g_free(s->array_locator); + s->array_locator = g_strdup(mobo_shorter); + } + } + + gchar *ah_str = g_strdup_printf("0x%"PRIx32, s->array_handle); + gchar *h_str = g_strdup_printf("0x%"PRIx32, s->handle); + s->short_locator = g_strdup_printf("%s \u27A4 %s", + s->array_locator ? s->array_locator : ah_str, + s->locator ? s->locator : h_str); + + if (s->bank_locator) + s->full_locator = g_strdup_printf("%s \u27A4 %s \u27A4 %s", + s->array_locator ? s->array_locator : ah_str, + s->bank_locator, + s->locator ? s->locator : h_str); + else + s->full_locator = g_strdup(s->short_locator); + + g_free(ah_str); + g_free(h_str); + + if (!g_str_has_prefix(s->size_str, empty_mem_str)) { + s->populated = 1; + + s->form_factor = dmidecode_match("Form Factor", &dtm, &h); + s->type = dmidecode_match("Type", &dtm, &h); + STR_IGNORE(s->type, "Unknown"); + if (SEQ(s->type, "Flash") || SEQ(s->type, "ROM")) { + s->is_rom = TRUE; + s->is_not_ram = TRUE; + } else { + if (SEQ(s->type, "DDR")) s->ram_type = DDR_SDRAM; + if (SEQ(s->type, "DDR2")) s->ram_type = DDR2_SDRAM; + if (SEQ(s->type, "DDR3")) s->ram_type = DDR3_SDRAM; + if (SEQ(s->type, "DDR4")) s->ram_type = DDR4_SDRAM; + if (SEQ(s->type, "DRDRAM")) s->ram_type = DIRECT_RAMBUS; + if (SEQ(s->type, "RDRAM")) s->ram_type = RAMBUS; + if (s->ram_type) + dmi_ram_types |= (1 << (s->ram_type-1)); + } + s->type_detail = dmidecode_match("Type Detail", &dtm, &h); + STR_IGNORE(s->type_detail, "None"); + + s->speed_str = dmidecode_match("Speed", &dtm, &h); + s->configured_clock_str = dmidecode_match("Configured Clock Speed", &dtm, &h); + if (!s->configured_clock_str) + s->configured_clock_str = dmidecode_match("Configured Memory Speed", &dtm, &h); + + s->voltage_min_str = dmidecode_match("Minimum Voltage", &dtm, &h); + s->voltage_max_str = dmidecode_match("Maximum Voltage", &dtm, &h); + s->voltage_conf_str = dmidecode_match("Configured Voltage", &dtm, &h); + STR_IGNORE(s->voltage_min_str, "Unknown"); + STR_IGNORE(s->voltage_max_str, "Unknown"); + STR_IGNORE(s->voltage_conf_str, "Unknown"); + + s->partno = dmidecode_match("Part Number", &dtm, &h); + STR_IGNORE(s->partno, "PartNum0"); + STR_IGNORE(s->partno, "PartNum1"); + STR_IGNORE(s->partno, "PartNum2"); + STR_IGNORE(s->partno, "PartNum3"); + null_if_empty(&s->partno); + + s->data_width = dmidecode_match("Data Width", &dtm, &h); + s->total_width = dmidecode_match("Total Width", &dtm, &h); + + s->rank = dmidecode_match("Rank", &dtm, &h); + + s->mfgr = dmidecode_match("Manufacturer", &dtm, &h); + STR_IGNORE(s->mfgr, unknown_mfgr_str); + STR_IGNORE(s->mfgr, "Manufacturer0"); + STR_IGNORE(s->mfgr, "Manufacturer1"); + STR_IGNORE(s->mfgr, "Manufacturer2"); + STR_IGNORE(s->mfgr, "Manufacturer3"); + STR_IGNORE(s->mfgr, "Unknown"); + null_if_empty(&s->mfgr); + + gchar *mfgr_id_str = dmidecode_match("Module Manufacturer ID", &dtm, &h); + STR_IGNORE(mfgr_id_str, "Unknown"); + if (mfgr_id_str) { + static const char dmi_mfg_id_fmt[] = "Bank %d, Hex 0x%02X"; /* from dmidecode.c */ + int mc = sscanf(strstr(mfgr_id_str, "Bank"), dmi_mfg_id_fmt, &s->mfgr_bank, &s->mfgr_index); + if (mc > 0 && !s->mfgr) { + s->has_jedec_mfg_id = TRUE; + s->mfgr = g_strdup(JEDEC_MFG_STR(s->mfgr_bank, s->mfgr_index)); + } + } + + if (s->mfgr && !s->has_jedec_mfg_id && strlen(s->mfgr) == 4) { + /* Some BIOS put the code bytes into the mfgr string + * if they don't know the manufacturer. + * It's not always reliable, but what is lost + * by trying it? */ + if (isxdigit(s->mfgr[0]) + && isxdigit(s->mfgr[1]) + && isxdigit(s->mfgr[2]) + && isxdigit(s->mfgr[3]) ) { + int codes = strtol(s->mfgr, NULL, 16); + char *mstr = NULL; + decode_ddr34_manufacturer(codes >> 8, codes & 0xff, + &mstr, &s->mfgr_bank, &s->mfgr_index); + s->has_jedec_mfg_id = TRUE; + g_free(s->mfgr); + s->mfgr = NULL; + if (mstr) + s->mfgr = g_strdup(mstr); + } + } + + s->vendor = vendor_match(s->mfgr, NULL); + } + return s; +} + +void dmi_mem_socket_free(dmi_mem_socket* s) { + if (s) { + g_free(s->locator); + g_free(s->full_locator); + g_free(s->short_locator); + g_free(s->size_str); + g_free(s->type); + g_free(s->type_detail); + g_free(s->bank_locator); + g_free(s->rank); + g_free(s->array_locator); + g_free(s->form_factor); + g_free(s->speed_str); + g_free(s->configured_clock_str); + g_free(s->voltage_min_str); + g_free(s->voltage_max_str); + g_free(s->voltage_conf_str); + g_free(s->partno); + g_free(s->data_width); + g_free(s->total_width); + g_free(s->mfgr); + + g_free(s); + } +} + +dmi_mem_array *dmi_mem_find_array(dmi_mem *s, unsigned int handle) { + GSList *l = NULL; + for(l = s->arrays; l; l = l->next) { + dmi_mem_array *a = (dmi_mem_array*)l->data; + if (a->array_handle == handle) + return a; + } + return NULL; +} + +static int dmi_spd_match_score(dmi_mem_socket *s, spd_data *e) { + int score = 0; + if (SEQ(s->partno, e->partno)) + score += 20; + if (s->size_MiB == e->size_MiB) + score += 10; + if (s->vendor == e->vendor) + score += 5; + return score; +} + +/* fill in missing from SPD */ +static void dmi_fill_from_spd(dmi_mem_socket *s) { + if (!s->spd) + return; + + if (!s->mfgr && s->spd->vendor_str) { + s->mfgr = g_strdup(s->spd->vendor_str); + s->vendor = s->spd->vendor; + } + if (!s->has_jedec_mfg_id) { + s->mfgr_bank = s->spd->vendor_bank; + s->mfgr_index = s->spd->vendor_index; + s->has_jedec_mfg_id = TRUE; + } + + //Always true - FIXME + //if (!s->partno && s->spd->partno) + s->partno = g_strdup(s->spd->partno); + + if (!s->form_factor && s->spd->form_factor) + s->form_factor = g_strdup(s->spd->form_factor); + + //Always true - FIXME + //if (!s->type_detail && s->spd->type_detail) + s->type_detail = g_strdup(s->spd->type_detail); +} + +static dmi_mem_size size_of_online_memory_blocks() { + gchar *block_size_bytes_str = NULL; + dmi_mem_size block_size_bytes = 0; + dmi_mem_size ret = 0; + + if (g_file_get_contents("/sys/devices/system/memory/block_size_bytes", &block_size_bytes_str, NULL, NULL) ) { + block_size_bytes = strtoll(block_size_bytes_str, NULL, 16); + } + if (!block_size_bytes) + return 0; + + const gchar *f = NULL; + GDir *d = g_dir_open("/sys/devices/system/memory", 0, NULL); + if (!d) return 0; + + while((f = g_dir_read_name(d))) { + gchar *p = g_strdup_printf("/sys/devices/system/memory/%s/online", f); + gchar *ol = NULL; + if (g_file_get_contents(p, &ol, NULL, NULL) ) { + if (1 == strtol(ol, NULL, 0)) { + ret += block_size_bytes; + } + } + g_free(ol); + g_free(p); + } + g_dir_close(d); + return ret; +} + +dmi_mem *dmi_mem_new() { + dmi_mem *m = g_new0(dmi_mem, 1); + + dmi_handle_list *hla = dmidecode_handles(&dta); + if (hla) { + unsigned int i = 0; + for(i = 0; i < hla->count; i++) { + dmi_handle h = hla->handles[i]; + m->arrays = g_slist_append(m->arrays, dmi_mem_array_new(h)); + } + dmi_handle_list_free(hla); + } + + dmi_handle_list *hlm = dmidecode_handles(&dtm); + if (hlm) { + unsigned int i = 0; + for(i = 0; i < hlm->count; i++) { + dmi_handle h = hlm->handles[i]; + m->sockets = g_slist_append(m->sockets, dmi_mem_socket_new(h)); + } + dmi_handle_list_free(hlm); + } + + m->spd = spd_scan(); + + if (!m->sockets && !m->arrays && !m->spd) { + m->empty = 1; + goto dmi_mem_new_last_chance; + } + + GSList *l = NULL, *l2 = NULL; + + /* totals for SPD */ + for(l2 = m->spd; l2; l2 = l2->next) { + spd_data *e = (spd_data*)l2->data; + m->spd_size_MiB += e->size_MiB; + if (e->type) + m->spd_ram_types |= (1 << (e->type-1)); + } + + m->unique_short_locators = TRUE; + for(l = m->sockets; l; l = l->next) { + dmi_mem_socket *s = (dmi_mem_socket*)l->data; + + /* check for duplicate short_locator */ + if (m->unique_short_locators) { + for(l2 = l->next; l2; l2 = l2->next) { + dmi_mem_socket *d = (dmi_mem_socket*)l2->data; + if (SEQ(s->short_locator, d->short_locator)) { + m->unique_short_locators = FALSE; + break; + } + } + } + + /* update array present devices/size */ + dmi_mem_array *a = dmi_mem_find_array(m, s->array_handle); + if (a) { + if (s->is_not_ram) { + if (s->is_rom) + a->size_MiB_rom += s->size_MiB; + } else { + a->size_MiB_present += s->size_MiB; + if (s->populated) + a->devs_populated++; + if (s->ram_type) + a->ram_types |= (1 << (s->ram_type-1)); + } + } + } + + if (m->sockets && m->spd) { + /* attempt to match DMI and SPD data */ + GSList *sock_queue = g_slist_copy(m->sockets); + int loops = g_slist_length(sock_queue) * 4; + while(sock_queue) { + if (loops-- <= 0) break; /* something is wrong, give up */ + spd_data *best = NULL; + int best_score = 0; + dmi_mem_socket *s = (dmi_mem_socket*)sock_queue->data; + /* pop that one off */ + sock_queue = g_slist_delete_link(sock_queue, sock_queue); + if (!s->populated) + continue; + for(l2 = m->spd; l2; l2 = l2->next) { + spd_data *e = (spd_data*)l2->data; + int score = dmi_spd_match_score(s, e); + if (score > best_score) { + if (score > e->match_score) { + best = e; + best_score = score; + } + } + } + if (best) { + if (best->dmi_socket) { + /* displace */ + dmi_mem_socket *old_sock = best->dmi_socket; + old_sock->spd = NULL; + sock_queue = g_slist_append(sock_queue, old_sock); + + best->dmi_socket = s; + best->match_score = best_score; + s->spd = best; + } else { + best->dmi_socket = s; + best->match_score = best_score; + s->spd = best; + } + } + } + + /* fill any missing data in DMI that is + * provided by the matched SPD */ + for(l = m->sockets; l; l = l->next) { + dmi_mem_socket *s = (dmi_mem_socket*)l->data; + dmi_fill_from_spd(s); + } + + } /* end if (m->sockets && m->spd) */ + + /* Look for arrays with "System Memory" use, + * or Mainboard as locator */ + for(l = m->arrays; l; l = l->next) { + dmi_mem_array *a = (dmi_mem_array*)l->data; + if (a->is_main_memory) { + m->system_memory_MiB += a->size_MiB_present; + m->system_memory_ram_types |= a->ram_types; + } + } + + /* If no arrays, then try the SPD total */ + if (!m->system_memory_MiB) { + m->system_memory_MiB = m->spd_size_MiB; + m->system_memory_ram_types |= m->spd_ram_types; + } + +dmi_mem_new_last_chance: + if (m->empty) { + /* reach */ + if (dtree_mem_str) { + int rt = 0; + m->system_memory_MiB = dmi_read_memory_str_to_MiB(dtree_mem_str); + if (strstr(dtree_mem_str, "DDR4")) rt = DDR4_SDRAM; + else if (strstr(dtree_mem_str, "DDR3")) rt = DDR3_SDRAM; + else if (strstr(dtree_mem_str, "DDR2")) rt = DDR2_SDRAM; + else if (strstr(dtree_mem_str, "DDR")) rt = DDR_SDRAM; + else if (strstr(dtree_mem_str, "DRDRAM")) rt = DIRECT_RAMBUS; + else if (strstr(dtree_mem_str, "RDRAM")) rt = RAMBUS; + if (rt) + m->system_memory_ram_types |= (1 << (rt-1)); + } + } + + /* Try to sum the online blocks for a physical memory total */ + if (!m->system_memory_MiB) + m->system_memory_MiB = size_of_online_memory_blocks() / 1024 / 1024; + + return m; +} + +void dmi_mem_free(dmi_mem* s) { + if (s) { + g_slist_free_full(s->arrays, (GDestroyNotify)dmi_mem_array_free); + g_slist_free_full(s->sockets, (GDestroyNotify)dmi_mem_socket_free); + g_slist_free_full(s->spd, (GDestroyNotify)spd_data_free); + g_free(s); + } +} + +gchar *make_spd_section(spd_data *spd) { + gchar *ret = NULL; + if (spd) { + gchar *full_spd = NULL; + switch(spd->type) { + case SDR_SDRAM: + full_spd = decode_sdr_sdram_extra(spd->bytes); + break; + case DDR_SDRAM: + full_spd = decode_ddr_sdram_extra(spd->bytes); + break; + case DDR2_SDRAM: + full_spd = decode_ddr2_sdram_extra(spd->bytes); + break; + case DDR3_SDRAM: + full_spd = decode_ddr3_sdram_extra(spd->bytes); + break; + case DDR4_SDRAM: + full_spd = decode_ddr4_sdram_extra(spd->bytes, spd->spd_size); + break; + default: + DEBUG("blug for type: %d %s\n", spd->type, ram_types[spd->type]); + } + gchar *size_str = NULL; + if (!spd->size_MiB) + size_str = g_strdup(_("(Unknown)")); + else + size_str = g_strdup_printf("%"PRId64" %s", spd->size_MiB, _("MiB") ); + + gchar *mfg_date_str = NULL; + if (spd->year) + mfg_date_str = g_strdup_printf("%d / %d", spd->week, spd->year); + + ret = g_strdup_printf("[%s]\n" + "%s=%s (%s)%s\n" + "%s=%d.%d\n" + "%s=%s\n" + "%s=%s\n" + "$^$%s=[%02x%02x] %s\n" /* module vendor */ + "$^$%s=[%02x%02x] %s\n" /* dram vendor */ + "%s=%s\n" /* part */ + "%s=%s\n" /* size */ + "%s=%s\n" /* mfg date */ + "%s", + _("Serial Presence Detect (SPD)"), + _("Source"), spd->dev, spd->spd_driver, + (spd->type == DDR4_SDRAM && strcmp(spd->spd_driver, "ee1004") != 0) ? problem_marker() : "", + _("SPD Revision"), spd->spd_rev_major, spd->spd_rev_minor, + _("Form Factor"), UNKIFNULL2(spd->form_factor), + _("Type"), UNKIFEMPTY2(spd->type_detail), + _("Module Vendor"), spd->vendor_bank, spd->vendor_index, + UNKIFNULL2(spd->vendor_str), + _("DRAM Vendor"), spd->dram_vendor_bank, spd->dram_vendor_index, + UNKIFNULL2(spd->dram_vendor_str), + _("Part Number"), UNKIFEMPTY2(spd->partno), + _("Size"), size_str, + _("Manufacturing Date (Week / Year)"), UNKIFNULL2(mfg_date_str), + full_spd ? full_spd : "" + ); + g_free(full_spd); + g_free(size_str); + g_free(mfg_date_str); + } + return ret; +} + +static gchar *tag_make_safe_inplace(gchar *tag) { + if (!tag) + return tag; + if (!g_utf8_validate(tag, -1, NULL)) + return tag; //TODO: reconsider + gchar *p = tag, *pd = tag; + while(*p) { + gchar *np = g_utf8_next_char(p); + gunichar c = g_utf8_get_char_validated(p, -1); + int l = g_unichar_to_utf8(c, NULL); + if (l == 1 && g_unichar_isalnum(c)) { + g_unichar_to_utf8(c, pd); + } else { + *pd = '_'; + } + p = np; + pd++; + } + return tag; +} + +gchar *memory_devices_get_info() { + gchar *icons = g_strdup(""); + gchar *ret = g_strdup_printf("[%s]\n", _("Memory Device List")); + GSList *l = NULL; + sketchy_info = FALSE; + gchar tag_prefix[] = "DEV"; + + dmi_mem *mem = dmi_mem_new(); + + /* Arrays */ + for(l = mem->arrays; l; l = l->next) { + dmi_mem_array *a = (dmi_mem_array*)l->data; + gchar *tag = g_strdup_printf("%s", a->locator); + gchar *size_str = NULL, *rom_size_str = NULL; + + tag_make_safe_inplace(tag); + + if (a->size_MiB_max > 1024 && (a->size_MiB_max % 1024 == 0) + && a->size_MiB_present > 1024 && (a->size_MiB_present % 1024 == 0) ) + size_str = g_strdup_printf("%"PRId64" / %"PRId64" %s", a->size_MiB_present / 1024, a->size_MiB_max / 1024, _("GiB")); + else + size_str = g_strdup_printf("%"PRId64" / %"PRId64" %s", a->size_MiB_present, a->size_MiB_max, _("MiB")); + + if (a->size_MiB_max < a->size_MiB_present) { + sketchy_info = TRUE; + size_str = h_strdup_cprintf(" %s", size_str, problem_marker()); + } + + if (a->size_MiB_rom > 1024 && (a->size_MiB_rom % 1024 == 0)) + rom_size_str = g_strdup_printf("%"PRId64" %s", a->size_MiB_rom / 1024, _("GiB")); + else + rom_size_str = g_strdup_printf("%"PRId64" %s", a->size_MiB_rom, _("MiB")); + + gchar *types_str = NULL; + int i; + for(i = 1; i < N_RAM_TYPES; i++) { + int bit = 1 << (i-1); + if (a->ram_types & bit) + types_str = appfsp(types_str, "%s", GET_RAM_TYPE_STR(i)); + } + + gchar *details = g_strdup_printf("[%s]\n" + "%s=0x%"PRIx32"\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%d / %d\n" + "%s=[0x%x] %s\n" + "%s=%s\n", + _("Memory Array"), + _("DMI Handle"), a->array_handle, + _("Locator"), a->locator ? a->locator : ".", + _("Use"), UNKIFNULL2(a->use), + _("Error Correction Type"), UNKIFNULL2(a->ecc), + _("Size (Present / Max)"), size_str, + _("Devices (Populated / Sockets)"), a->devs_populated, a->devs, + _("Types Present"), a->ram_types, UNKIFNULL2(types_str), + _("ROM Size"), rom_size_str + ); + moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */ + ret = h_strdup_cprintf("$!%s$%s=%s|%s\n", + ret, + tag, a->locator, UNKIFNULL2(types_str), size_str + ); + icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, array_icon); + g_free(tag); + g_free(size_str); + g_free(rom_size_str); + g_free(types_str); + } + + /* Sockets */ + for(l = mem->sockets; l; l = l->next) { + dmi_mem_socket *s = (dmi_mem_socket*)l->data; + gchar *tag = g_strdup_printf("%s", s->full_locator); + tag_make_safe_inplace(tag); + + if (s->populated) { + gchar *size_str = NULL; + if (!s->size_str) + size_str = g_strdup(_("(Unknown)")); + else if (!s->size_MiB) + size_str = g_strdup(s->size_str); + else + size_str = g_strdup_printf("%"PRId64" %s", s->size_MiB, _("MiB") ); + + gchar *spd = s->spd ? make_spd_section(s->spd) : NULL; + + gchar *details = g_strdup_printf("[%s]\n" + "%s=0x%"PRIx32", 0x%"PRIx32"\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s / %s\n" + "$^$%s=[%02x%02x] %s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s / %s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s", /* spd */ + _("Memory Socket"), + _("DMI Handles (Array, Socket)"), s->array_handle, s->handle, + _("Locator"), s->full_locator, + _("Bank Locator"), UNKIFNULL2(s->bank_locator), + _("Form Factor"), UNKIFNULL2(s->form_factor), + _("Type"), UNKIFNULL2(s->type), UNKIFNULL2(s->type_detail), + _("Vendor"), + s->mfgr_bank, s->mfgr_index, UNKIFNULL2(s->mfgr), + _("Part Number"), UNKIFNULL2(s->partno), + _("Size"), size_str, + _("Rated Speed"), UNKIFNULL2(s->speed_str), + _("Configured Speed"), UNKIFNULL2(s->configured_clock_str), + _("Data Width/Total Width"), UNKIFNULL2(s->data_width), UNKIFNULL2(s->total_width), + _("Rank"), UNKIFNULL2(s->rank), + _("Minimum Voltage"), UNKIFNULL2(s->voltage_min_str), + _("Maximum Voltage"), UNKIFNULL2(s->voltage_max_str), + _("Configured Voltage"), UNKIFNULL2(s->voltage_conf_str), + spd ? spd : "" + ); + g_free(spd); + moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */ + gchar *mfgr = s->mfgr ? vendor_match_tag(s->mfgr, params.fmt_opts) : NULL; + ret = h_strdup_cprintf("$!%s$%s=%s|%s|%s\n", + ret, + tag, + mem->unique_short_locators ? s->short_locator : s->full_locator, + UNKIFNULL2(s->partno), size_str, UNKIFNULL2(mfgr) + ); + icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, mem_icon); + g_free(size_str); + g_free(mfgr); + } else { + gchar *details = g_strdup_printf("[%s]\n" + "%s=0x%"PRIx32", 0x%"PRIx32"\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n", + _("Memory Socket"), + _("DMI Handles (Array, Socket)"), s->array_handle, s->handle, + _("Locator"), s->full_locator, + _("Bank Locator"), UNKIFNULL2(s->bank_locator), + _("Size"), _("(Empty)") + ); + moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */ + ret = h_strdup_cprintf("$%s$%s=|%s\n", + ret, + tag, + mem->unique_short_locators ? s->short_locator : s->full_locator, + _("(Empty)") + ); + icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, empty_icon); + } + g_free(tag); + } + + /* No DMI Array, show SPD totals */ + if (!mem->arrays && mem->spd) { + gchar *key = g_strdup("SPD:*"); + gchar *tag = g_strdup(key); + tag_make_safe_inplace(tag); + gchar *types_str = NULL; + gchar *size_str = NULL; + + if (mem->spd_size_MiB > 1024 && (mem->spd_size_MiB % 1024 == 0) ) + size_str = g_strdup_printf("%"PRId64" %s", mem->spd_size_MiB / 1024, _("GiB")); + else + size_str = g_strdup_printf("%"PRId64" %s", mem->spd_size_MiB, _("MiB")); + + int i; + for(i = 1; i < N_RAM_TYPES; i++) { + int bit = 1 << (i-1); + if (mem->spd_ram_types & bit) + types_str = appfsp(types_str, "%s", GET_RAM_TYPE_STR(i)); + } + + gchar *details = g_strdup_printf("[%s]\n" + "%s=%s\n" + "%s=%d\n" + "%s=[0x%x] %s\n", + _("Serial Presence Detect (SPD) Summary"), + _("Size"), size_str, + _("Devices"), g_slist_length(mem->spd), + _("Types Present"), mem->spd_ram_types, UNKIFNULL2(types_str) + ); + moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */ + ret = h_strdup_cprintf("$!%s$%s=%s|%s\n", + ret, + tag, key, UNKIFNULL2(types_str), size_str + ); + icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, array_icon); + g_free(key); + g_free(tag); + g_free(size_str); + g_free(types_str); + } + + /* Unmatched SPD */ + for(l = mem->spd; l; l = l->next) { + spd_data *s = (spd_data*)l->data; + if (s->dmi_socket) continue; /* claimed by DMI */ + gchar *key = g_strdup_printf("SPD:%s", s->dev); + gchar *tag = g_strdup(key); + tag_make_safe_inplace(tag); + + gchar *vendor_str = NULL; + if (s->vendor) { + vendor_str = vendor_get_link_from_vendor(s->vendor); + } + gchar *size_str = NULL; + if (!s->size_MiB) + size_str = g_strdup(_("(Unknown)")); + else + size_str = g_strdup_printf("%"PRId64" %s", s->size_MiB, _("MiB") ); + + gchar *details = make_spd_section(s); + + moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */ + const gchar *mfgr = s->vendor_str ? vendor_get_shortest_name(s->vendor_str) : NULL; + ret = h_strdup_cprintf("$!%s$%s%s=%s|%s|%s\n", + ret, + tag, key, problem_marker(), UNKIFEMPTY2(s->partno), size_str, UNKIFNULL2(mfgr) + ); + icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, mem_icon); + g_free(vendor_str); + g_free(size_str); + g_free(key); + g_free(tag); + } + + no_handles = FALSE; + if(mem->empty) { + no_handles = TRUE; + g_free(ret); + ret = g_strdup_printf("[%s]\n%s=%s\n" "[$ShellParam$]\nViewType=0\n", + _("Memory Device List"), _("Result"), + (getuid() == 0) + ? _("(Not available)") + : _("(Not available; Perhaps try running HardInfo as root.)") ); + } else { + ret = h_strdup_cprintf( + "[$ShellParam$]\nViewType=1\n" + "ColumnTitle$TextValue=%s\n" /* Locator */ + "ColumnTitle$Extra1=%s\n" /* Size */ + "ColumnTitle$Extra2=%s\n" /* Vendor */ + "ColumnTitle$Value=%s\n" /* Part */ + "ShowColumnHeaders=true\n" + "%s", + ret, + _("Locator"), + _("Size"), + _("Vendor"), + _("Part"), + icons + ); + } + + g_free(icons); + dmi_mem_free(mem); + return ret; +} + +gchar *memory_devices_get_system_memory_types_str() { + gchar *ret = NULL, *types_str = NULL; + int i, rtypes; + + dmi_mem *lmem = dmi_mem_new(); + rtypes = lmem->system_memory_ram_types; + dmi_mem_free(lmem); + + for(i = 1; i < N_RAM_TYPES; i++) { + int bit = 1 << (i-1); + if (rtypes & bit) + types_str = appfsp(types_str, "%s", GET_RAM_TYPE_STR(i)); + } + + if (types_str) + ret = g_strdup(types_str); + else + ret = g_strdup(UNKNOWN_MEM_TYPE_STRING); + g_free(types_str); + return ret; +} + +uint64_t memory_devices_get_system_memory_MiB() { + dmi_mem *mem = dmi_mem_new(); + int ret = (int)mem->system_memory_MiB; + dmi_mem_free(mem); + return ret; +} + +gchar *memory_devices_get_system_memory_str() { + gchar *ret = NULL; + dmi_mem_size m = memory_devices_get_system_memory_MiB(); + if (m) { + if (m > 1024 && (m % 1024 == 0) ) + ret = g_strdup_printf("%"PRId64" %s", m/1024, _("GiB")); + else + ret = g_strdup_printf("%"PRId64" %s", m, _("MiB")); + } + return ret; +} + +static gchar note_state[note_max_len] = ""; + +gboolean memory_devices_hinote(const char **msg) { + gchar *want_dmi = _(" <b><i>dmidecode</i></b> utility available"); + gchar *want_root = _(" ... <i>and</i> HardInfo running with superuser privileges"); + gchar *want_at24 = _(" <b><i>at24</i></b> (or eeprom) module loaded (for SDR, DDR, DDR2, DDR3)"); + gchar *want_ee1004 = _(" ... <i>or</i> <b><i>ee1004</i></b> module loaded <b>and configured!</b> (for DDR4)"); + + gboolean has_root = (getuid() == 0); + gboolean has_dmi = !no_handles; + gboolean has_at24eep = g_file_test("/sys/bus/i2c/drivers/at24", G_FILE_TEST_IS_DIR) || + g_file_test("/sys/bus/i2c/drivers/eeprom", G_FILE_TEST_IS_DIR); + gboolean has_ee1004 = g_file_test("/sys/bus/i2c/drivers/ee1004", G_FILE_TEST_IS_DIR); + + *note_state = 0; /* clear */ + note_printf(note_state, "%s\n", _("Memory information requires <b>one or both</b> of the following:")); + note_print(note_state, "<tt>1. </tt>"); + note_cond_bullet(has_dmi, note_state, want_dmi); + note_print(note_state, "<tt> </tt>"); + note_cond_bullet(has_root, note_state, want_root); + note_print(note_state, "<tt>2. </tt>"); + note_cond_bullet(has_at24eep, note_state, want_at24); + note_print(note_state, "<tt> </tt>"); + note_cond_bullet(has_ee1004, note_state, want_ee1004); + g_strstrip(note_state); /* remove last \n */ + + gboolean ddr3_ee1004 = ((dmi_ram_types & (1<<(DDR3_SDRAM-1))) && has_ee1004); + + gboolean best_state = FALSE; + if (has_dmi && has_root && + ((has_at24eep && !spd_ddr4_partial_data) + || (has_ee1004 && !ddr3_ee1004) ) ) + best_state = TRUE; + + if (!best_state) { + *msg = note_state; + return TRUE; + } + + if (sketchy_info) { + *msg = g_strdup( + _("\"More often than not, information contained in the DMI tables is inaccurate,\n" + "incomplete or simply wrong.\" -<i><b>dmidecode</b></i> manual page")); + return TRUE; + } + + return FALSE; +} diff --git a/modules/devices/e2k/processor.c b/modules/devices/e2k/processor.c new file mode 100644 index 00000000..74476853 --- /dev/null +++ b/modules/devices/e2k/processor.c @@ -0,0 +1,420 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2020 EntityFX <artem.solopiy@gmail.com> and MCST Elbrus Team + * modified by Boris Afonot <boris.afonot@gmail.com> (2022) + * 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 "cpu_util.h" + +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, + C_("cache-type", cache->type), + cache->ways_of_associativity, + cache->number_of_sets, + cache->size); + } + + return result; +} + +/* This is not used directly, but creates translatable strings for + * the type string returned from /sys/.../cache */ +static const char* cache_types[] = { + NC_("cache-type", /*/cache type, as appears in: Level 1 (Data)*/ "Data"), + NC_("cache-type", /*/cache type, as appears in: Level 1 (Instruction)*/ "Instruction"), + NC_("cache-type", /*/cache type, as appears in: Level 2 (Unified)*/ "Unified") +}; + +static void __cache_obtain_info(Processor *processor) +{ + ProcessorCache *cache; + gchar *endpoint, *entry, *index; + gchar *uref = NULL; + 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); + + /* unique cache references: id is nice, but share_cpu_list can be + * used if it is not available. */ + entry = g_strconcat(index, "id", NULL); + uref = h_sysfs_read_string(endpoint, entry); + g_free(entry); + if (uref != NULL && *uref != 0 ) + cache->uid = atoi(uref); + else + cache->uid = -1; + g_free(uref); + entry = g_strconcat(index, "shared_cpu_list", NULL); + cache->shared_cpu_list = h_sysfs_read_string(endpoint, entry); + g_free(entry); + + /* reacharound */ + entry = g_strconcat(index, "../../topology/physical_package_id", NULL); + cache->phy_sock = h_sysfs_read_int(endpoint, entry); + g_free(entry); + + g_free(index); + + processor->cache = g_slist_append(processor->cache, cache); + } + +fail: + g_free(endpoint); +} + +#define cmp_cache_test(f) if (a->f < b->f) return -1; if (a->f > b->f) return 1; + +static gint cmp_cache(ProcessorCache *a, ProcessorCache *b) { + gint i = 0; + cmp_cache_test(phy_sock); + i = g_strcmp0(a->type, b->type); if (i!=0) return i; + cmp_cache_test(level); + cmp_cache_test(size); + cmp_cache_test(uid); /* uid is unique among caches with the same (type, level) */ + if (a->uid == -1) { + /* if id wasn't available, use shared_cpu_list as a unique ref */ + i = g_strcmp0(a->shared_cpu_list, b->shared_cpu_list); if (i!=0) + return i; + } + return 0; +} + +static gint cmp_cache_ignore_id(ProcessorCache *a, ProcessorCache *b) { + gint i = 0; + cmp_cache_test(phy_sock); + i = g_strcmp0(a->type, b->type); if (i!=0) return i; + cmp_cache_test(level); + cmp_cache_test(size); + return 0; +} + +gchar *caches_summary(GSList * processors) +{ + gchar *ret = g_strdup_printf("[%s]\n", _("Caches")); + GSList *all_cache = NULL, *uniq_cache = NULL; + GSList *tmp, *l; + Processor *p; + ProcessorCache *c, *cur = NULL; + gint cur_count = 0, i = 0; + + /* create list of all cache references */ + for (l = processors; l; l = l->next) { + p = (Processor*)l->data; + if (p->cache) { + tmp = g_slist_copy(p->cache); + if (all_cache) { + all_cache = g_slist_concat(all_cache, tmp); + } else { + all_cache = tmp; + } + } + } + + if (g_slist_length(all_cache) == 0) { + ret = h_strdup_cprintf("%s=\n", ret, _("(Not Available)") ); + g_slist_free(all_cache); + return ret; + } + + /* ignore duplicate references */ + all_cache = g_slist_sort(all_cache, (GCompareFunc)cmp_cache); + for (l = all_cache; l; l = l->next) { + c = (ProcessorCache*)l->data; + if (!cur) { + cur = c; + } else { + if (cmp_cache(cur, c) != 0) { + uniq_cache = g_slist_prepend(uniq_cache, cur); + cur = c; + } + } + } + uniq_cache = g_slist_prepend(uniq_cache, cur); + uniq_cache = g_slist_reverse(uniq_cache); + cur = 0, cur_count = 0; + + /* count and list caches */ + for (l = uniq_cache; l; l = l->next) { + c = (ProcessorCache*)l->data; + if (!cur) { + cur = c; + cur_count = 1; + } else { + if (cmp_cache_ignore_id(cur, c) != 0) { + ret = h_strdup_cprintf(_("Level %d (%s)#%d=%dx %dKB (%dKB), %d-way set-associative, %d sets\n"), + ret, + cur->level, + C_("cache-type", cur->type), + cur->phy_sock, + cur_count, + cur->size, + cur->size * cur_count, + cur->ways_of_associativity, + cur->number_of_sets); + cur = c; + cur_count = 1; + } else { + cur_count++; + } + } + } + ret = h_strdup_cprintf(_("Level %d (%s)#%d=%dx %dKB (%dKB), %d-way set-associative, %d sets\n"), + ret, + cur->level, + C_("cache-type", cur->type), + cur->phy_sock, + cur_count, + cur->size, + cur->size * cur_count, + cur->ways_of_associativity, + cur->number_of_sets); + + g_slist_free(all_cache); + g_slist_free(uniq_cache); + return ret; +} + +static gchar *processor_get_full_name(const gchar *model_name) +{ + if(g_strcmp0(model_name ,"E2S") == 0) + return "Elbrus-4C"; + else if(g_strcmp0(model_name ,"E1C+") == 0) + return "Elbrus-1C+"; + else if(g_strcmp0(model_name ,"E2C+DSP") == 0) + return "Elbrus-2C+"; + else if(g_strcmp0(model_name ,"E8C") == 0) + return "Elbrus-8C"; + else if(g_strcmp0(model_name ,"E8C2") == 0) + return "Elbrus-8CB"; + else if(g_strcmp0(model_name ,"E12C") == 0) + return "Elbrus-12C"; + else if(g_strcmp0(model_name ,"E16C") == 0) + return "Elbrus-16C"; + else if(g_strcmp0(model_name ,"E2C3") == 0) + return "Elbrus-2C3"; + else + return (gchar *)model_name; +} + +GSList *processor_scan(void) +{ + GSList *procs = NULL, *l = NULL; + Processor *processor = NULL; + FILE *cpuinfo; + gchar buffer[1024]; + + cpuinfo = fopen(PROC_CPUINFO, "r"); + if (!cpuinfo) + return NULL; + + while (fgets(buffer, 1024, 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) { + if (g_str_has_prefix(tmp[0], "model name")) { + const gchar *model_name = processor_get_full_name(tmp[1]); + processor->model_name = g_strdup(model_name); + g_strfreev(tmp); + continue; + } + + get_str("vendor_id", processor->vendor_id); + get_int("cpu family", processor->family); + get_int("model", processor->model); + get_int("revision", processor->revision); + + get_float("cpu MHz", processor->cpu_mhz); + get_float("bogomips", processor->bogomips); + } + + //populate processor structure + g_strfreev(tmp); + } + + //appent to the list + if (processor) + procs = g_slist_append(procs, processor); + + for (l = procs; l; l = l->next) { + processor = (Processor *) l->data; + __cache_obtain_info(processor); + } + + fclose(cpuinfo); + + return procs; +} + +gchar *processor_name(GSList * processors) { + return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { + return processor_describe_default(processors); +} + +gchar * +processor_get_detailed_info(Processor *processor) +{ + gchar *ret; + gchar *cache_info; + cache_info = __cache_get_info_as_string(processor); + + ret = g_strdup_printf("[%s]\n" + "$^$%s=%s\n" /* name */ + "$^$%s=%s\n" /* vendor */ + "%s=%d\n" /* family */ + "%s=%d\n" /* model */ + "%s=%d\n" /* revision */ + "%s=%.2f %s\n" /* frequency */ + "%s=%.2f\n" /* bogomips */ + "%s=%s\n" /* byte order */ + "[%s]\n" /* cache */ + "%s\n", + _("Processor"), + _("Name"), processor->model_name, + _("Vendor"), processor->vendor_id, + _("Family"), processor->family, + _("Model"), processor->model, + _("Revision"), processor->revision, + _("Frequency"), processor->cpu_mhz, _("MHz"), + _("BogoMips"), processor->bogomips, + _("Byte Order"), byte_order_str(), + _("Cache"), cache_info + ); + g_free(cache_info); + return ret; +} + +//prepare processor info for all cpus +gchar *processor_get_info(GSList * processors) +{ + Processor *processor; + + gchar *ret, *tmp, *hashkey; + GSList *l; + + tmp = g_strdup(""); + + for (l = processors; l; l = l->next) { + processor = (Processor *) l->data; + gchar *model_name = g_strdup_printf("MCST %s", processor->model_name); + + /* change vendor id of 8CB processor for correct parse from vendor.ids */ + if (!g_strcmp0(processor->vendor_id, "E8C")) { + gchar *orig_vendor_id = processor->vendor_id; + processor->vendor_id = g_strdup_printf("%s-SWTX", orig_vendor_id); + free(orig_vendor_id); + } + + const Vendor *v = vendor_match(processor->vendor_id, NULL); + if (v) + tag_vendor(&model_name, 0, v->name_short ? v->name_short : v->name, v->ansi_color, params.fmt_opts); + + tmp = g_strdup_printf("%s$CPU%d$cpu%d=%.2f %s|%s\n", + tmp, processor->id, + processor->id, + processor->cpu_mhz, _("MHz"), + model_name); + + 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" + "ColumnTitle$TextValue=%s\n" + "ColumnTitle$Value=%s\n" + "ColumnTitle$Extra1=%s\n" + "ShowColumnHeaders=true\n" + "[Processors]\n" + "%s", _("Device"), _("Frequency"), _("Model"), tmp); + g_free(tmp); + + return ret; +} diff --git a/modules/devices/firmware.c b/modules/devices/firmware.c new file mode 100644 index 00000000..ea6ce532 --- /dev/null +++ b/modules/devices/firmware.c @@ -0,0 +1,261 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2019 L. A. F. Pereira <l@tia.mat.br> + * Copyright (C) 2019 Burt P. <pburt0@gmail.com> + * Copyright (C) 2020 Ondrej Čerman + * + * 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 or later. + * + * 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 <inttypes.h> +#include <gio/gio.h> +#include "util_sysobj.h" /* for SEQ() and appf() */ + +#define fw_msg(msg, ...) fprintf (stderr, "[%s] " msg "\n", __FUNCTION__, ##__VA_ARGS__) /**/ + +#define FWUPT_INTERFACE "org.freedesktop.fwupd" + +gboolean fail_no_fwupd = TRUE; + +char *decode_flags(guint64 flags) { + /* https://github.com/hughsie/fwupd/blob/master/libfwupd/fwupd-enums.{h,c} */ + static const struct { guint64 b; char *flag, *def; } flag_defs[] = { + { (1u << 0), "internal", N_("Device cannot be removed easily") }, + { (1u << 1), "updatable", N_("Device is updatable in this or any other mode") }, + { (1u << 2), "only-offline", N_("Update can only be done from offline mode") }, + { (1u << 3), "require-ac", N_("Requires AC power") }, + { (1u << 4), "locked", N_("Is locked and can be unlocked") }, + { (1u << 5), "supported", N_("Is found in current metadata") }, + { (1u << 6), "needs-bootloader", N_("Requires a bootloader mode to be manually enabled by the user") }, + { (1u << 7), "registered", N_("Has been registered with other plugins") }, + { (1u << 8), "needs-reboot", N_("Requires a reboot to apply firmware or to reload hardware") }, + { (1u << 17), "needs-shutdown", N_("Requires system shutdown to apply firmware") }, + { (1u << 9), "reported", N_("Has been reported to a metadata server") }, + { (1u << 10), "notified", N_("User has been notified") }, + { (1u << 11), "use-runtime-version", N_("Always use the runtime version rather than the bootloader") }, + { (1u << 12), "install-parent-first", N_("Install composite firmware on the parent before the child") }, + { (1u << 13), "is-bootloader", N_("Is currently in bootloader mode") }, + { (1u << 14), "wait-for-replug", N_("The hardware is waiting to be replugged") }, + { (1u << 15), "ignore-validation", N_("Ignore validation safety checks when flashing this device") }, + { (1u << 18), "another-write-required", N_("Requires the update to be retried with a new plugin") }, + { (1u << 19), "no-auto-instance-ids", N_("Do not add instance IDs from the device baseclass") }, + { (1u << 20), "needs-activation", N_("Device update needs to be separately activated") }, + { (1u << 21), "ensure-semver", N_("Ensure the version is a valid semantic version, e.g. numbers separated with dots") }, + { (1u << 16), "trusted", N_("Extra metadata can be exposed about this device") }, + { 0, NULL } + }; + + gchar *flag_list = g_strdup(""); + + int i; + for (i = 0; flag_defs[i].flag; i++) { + if (flags & flag_defs[i].b) + flag_list = appfnl(flag_list, "[%s] %s", flag_defs[i].flag, flag_defs[i].def); + } + return flag_list; +} + +const char *find_translation(const char *str) { + /* TODO: https://github.com/hughsie/fwupd/blob/master/src/README.md */ + static const char *translatable[] = { + N_("DeviceId"), N_("Guid"), N_("Summary"), N_("Plugin"), N_("Flags"), + N_("Vendor"), N_("VendorId"), N_("Version"), N_("VersionBootloader"), + N_("Icon"), N_("InstallDuration"), N_("Created"), + NULL + }; + int i; + if (!str) return NULL; + for (i = 0; translatable[i]; i++) { + if (SEQ(str, translatable[i])) + return _(translatable[i]); + } + return str; +}; + +/* map lvfs icon names to hardinfo icon names */ +const char *find_icon(const char *lvfs_name) { + /* icon names found by looking for fu_device_add_icon () + * in the fwupd source. */ + static const + struct { char *lvfs, *hi; } imap[] = { + { "applications-internet", "dns.png" }, + { "audio-card", "audio.png" }, + { "computer", "computer.png" }, + { "drive-harddisk", "hdd.png" }, + { "input-gaming", "joystick.png" }, + { "input-tablet", NULL }, + { "network-modem", "wireless.png" }, + { "preferences-desktop-keyboard", "keyboard.png" }, + { "thunderbolt", NULL }, + { "touchpad-disabled", NULL }, + /* default */ + { NULL, "memory.png" } /* a device with firmware maybe */ + }; + unsigned int i = 0; + for(; imap[i].lvfs; i++) { + if (SEQ(imap[i].lvfs, lvfs_name) && imap[i].hi) + return imap[i].hi; + } + return imap[i].hi; +} + +gchar *fwupdmgr_get_devices_info() { + struct Info *info = info_new(); + struct InfoGroup *this_group = NULL; + gboolean has_vendor_field = FALSE; + gboolean updatable = FALSE; + const Vendor *gv = NULL; + int gc = 0; + + GDBusConnection *conn; + GDBusProxy *proxy; + GVariant *devices, *value; + GVariantIter *deviter, *dictiter, *iter; + const gchar *key, *tmpstr; + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); + if (!conn) + return g_strdup(""); + + proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL, + FWUPT_INTERFACE, "/", FWUPT_INTERFACE, + NULL, NULL); + if (!proxy) { + g_object_unref(conn); + return g_strdup(""); + } + + fail_no_fwupd = FALSE; + devices = g_dbus_proxy_call_sync(proxy, "GetDevices", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); + + if (devices) { + g_variant_get(devices, "(aa{sv})", &deviter); + while(g_variant_iter_loop(deviter, "a{sv}", &dictiter)){ + + this_group = info_add_group(info, _("Unknown"), info_field_last()); + this_group->sort = INFO_GROUP_SORT_NAME_DESCENDING; + has_vendor_field = FALSE; + updatable = FALSE; + gv = NULL; + + while (g_variant_iter_loop(dictiter, "{&sv}", &key, &value)) { + if (SEQ(key, "Name")) { + tmpstr = g_variant_get_string(value, NULL); + this_group->name = hardinfo_clean_grpname(tmpstr, 0); + gv = vendor_match(tmpstr, NULL); + } else if (SEQ(key, "Vendor")) { + has_vendor_field = TRUE; + tmpstr = g_variant_get_string(value, NULL); + + const Vendor* v = vendor_match(tmpstr, NULL); + if (v) { + info_group_add_field(this_group, + info_field(_("Vendor"), v->name, + .value_has_vendor = TRUE, + .free_value_on_flatten = FALSE) ); + } else { + info_group_add_field(this_group, + info_field(_("Vendor"), g_strdup(tmpstr), + .free_value_on_flatten = TRUE) ); + } + } else if (SEQ(key, "Icon")) { + g_variant_get(value, "as", &iter); + while (g_variant_iter_loop(iter, "s", &tmpstr)) { + info_group_add_field(this_group, + info_field(_("Icon"), g_strdup(tmpstr), + .free_value_on_flatten = TRUE, + .icon = g_strdup(find_icon(tmpstr)) ) ); + } + } else if (SEQ(key, "Guid")) { + g_variant_get(value, "as", &iter); + while (g_variant_iter_loop(iter, "s", &tmpstr)) { + info_group_add_field(this_group, + info_field(_("Guid"), g_strdup(tmpstr), + .tag = g_strdup_printf("guid%d", gc++), + .free_value_on_flatten = TRUE) ); + } + g_variant_iter_free(iter); + } else if (SEQ(key, "Created")) { + guint64 created = g_variant_get_uint64(value); + GDateTime *dt = g_date_time_new_from_unix_local(created); + if (dt) { + info_group_add_field(this_group, + info_field(_("Created"), g_date_time_format(dt, "%x"), + .free_value_on_flatten = TRUE) ); + g_date_time_unref(dt); + } + } else if (SEQ(key, "Flags")) { + guint64 flags = g_variant_get_uint64(value); + updatable = (gboolean)(flags & (1u << 1)); + info_group_add_field(this_group, + info_field(_("Flags"), decode_flags(flags), + .free_value_on_flatten = TRUE) ); + } else { + if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + info_group_add_field(this_group, + info_field(find_translation(key), + g_variant_dup_string(value, NULL), + .free_value_on_flatten = TRUE) ); + } + } + } + + if (gv && !has_vendor_field) { + info_group_add_field(this_group, + info_field(_("Vendor"), gv->name, + .value_has_vendor = TRUE, + .free_value_on_flatten = FALSE) ); + } + + // hide devices that are not updatable + if (!updatable) { + info_remove_group(info, info->groups->len - 1); + } + } + g_variant_iter_free(deviter); + g_variant_unref(devices); + } + + g_object_unref(proxy); + g_object_unref(conn); + + gchar *ret = NULL; + if (info->groups->len) { + info_set_view_type(info, SHELL_VIEW_DETAIL); + //fw_msg("flatten..."); + ret = info_flatten(info); + //fw_msg("ret: %s", ret); + } else { + ret = g_strdup_printf("[%s]\n%s=%s\n" "[$ShellParam$]\nViewType=0\n", + _("Firmware List"), + _("Result"), _("(Not available)") ); + } + return ret; +} + +gchar *firmware_get_info() { + return fwupdmgr_get_devices_info(); +} + +gboolean firmware_hinote(const char **msg) { + if (fail_no_fwupd) { + *msg = g_strdup( + _("Requires the <i><b>fwupd</b></i> daemon.")); + return TRUE; + } + return FALSE; +} diff --git a/modules/devices/gpu.c b/modules/devices/gpu.c new file mode 100644 index 00000000..96520161 --- /dev/null +++ b/modules/devices/gpu.c @@ -0,0 +1,291 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2017 L. A. F. Pereira <l@tia.mat.br> + * This file + * Copyright (C) 2018 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, version 2 or later. + * + * 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" +#include "gpu_util.h" + +gchar *gpu_list = NULL; +gchar *gpu_summary = NULL; + +void gpu_summary_add(const char *gpu_name) { + if (strlen(gpu_summary) == 0) { + /* first one */ + gpu_summary = h_strdup_cprintf("%s", gpu_summary, gpu_name); + } else { + /* additional */ + gpu_summary = h_strdup_cprintf(" + %s", gpu_summary, gpu_name); + } +} + +#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)"); + +static void _gpu_pci_dev(gpud* gpu) { + pcid *p = gpu->pci_dev; + gchar *str; + gchar *vendor, *svendor, *product, *sproduct; + gchar *name, *key; + gchar *drm_path = NULL; + + gboolean vendor_is_svendor = (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id); + + vendor = UNKIFNULL_AC(p->vendor_id_str); + svendor = UNKIFNULL_AC(p->sub_vendor_id_str); + product = UNKIFNULL_AC(p->device_id_str); + sproduct = UNKIFNULL_AC(p->sub_device_id_str); + if (gpu->drm_dev) + drm_path = g_strdup_printf("/dev/dri/%s", gpu->drm_dev); + else + drm_path = g_strdup(_("(Unknown)")); + + gchar *ven_tag = vendor_match_tag(p->vendor_id_str, params.fmt_opts); + gchar *sven_tag = vendor_match_tag(p->sub_vendor_id_str, params.fmt_opts); + if (ven_tag) { + if (sven_tag && !vendor_is_svendor) { + name = g_strdup_printf("%s %s %s", sven_tag, ven_tag, product); + } else { + name = g_strdup_printf("%s %s", ven_tag, product); + } + } else { + name = g_strdup_printf("%s %s", vendor, product); + } + g_free(ven_tag); + g_free(sven_tag); + + key = g_strdup_printf("GPU%s", gpu->id); + + gpu_summary_add((gpu->nice_name) ? gpu->nice_name : name); + gpu_list = h_strdup_cprintf("$!%s$%s=%s\n", gpu_list, key, gpu->id, name); + + gchar *vendor_device_str; + if (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id) { + vendor_device_str = g_strdup_printf( + /* Vendor */ "$^$%s=[%04x] %s\n" + /* Device */ "%s=[%04x] %s\n", + _("Vendor"), p->vendor_id, vendor, + _("Device"), p->device_id, product); + } else { + vendor_device_str = g_strdup_printf( + /* Vendor */ "$^$%s=[%04x] %s\n" + /* Device */ "%s=[%04x] %s\n" + /* Sub-device vendor */ "$^$%s=[%04x] %s\n" + /* Sub-device */ "%s=[%04x] %s\n", + _("Vendor"), p->vendor_id, vendor, + _("Device"), p->device_id, product, + _("SVendor"), p->sub_vendor_id, svendor, + _("SDevice"), p->sub_device_id, sproduct); + } + + gchar *pcie_str; + if (p->pcie_width_curr) { + pcie_str = g_strdup_printf("[%s]\n" + /* Width (max) */ "%s=x%u\n" + /* Speed (max) */ "%s=%0.1f %s\n", + _("PCI Express"), + _("Maximum Link Width"), p->pcie_width_max, + _("Maximum Link Speed"), p->pcie_speed_max, _("GT/s") ); + } else + pcie_str = strdup(""); + + gchar *nv_str; + if (gpu->nv_info) { + nv_str = g_strdup_printf("[%s]\n" + /* model */ "%s=%s\n" + /* bios */ "%s=%s\n" + /* uuid */ "%s=%s\n", + _("NVIDIA"), + _("Model"), gpu->nv_info->model, + _("BIOS Version"), gpu->nv_info->bios_version, + _("UUID"), gpu->nv_info->uuid ); + } else + nv_str = strdup(""); + + gchar *freq = g_strdup(_("(Unknown)")); + if (gpu->khz_max > 0) { + if (gpu->khz_min > 0 && gpu->khz_min != gpu->khz_max) + freq = g_strdup_printf("%0.2f-%0.2f %s", (double) gpu->khz_min / 1000, (double) gpu->khz_max / 1000, _("MHz")); + else + freq = g_strdup_printf("%0.2f %s", (double) gpu->khz_max / 1000, _("MHz")); + } + + gchar *mem_freq = g_strdup(_("(Unknown)")); + if (gpu->mem_khz_max > 0) { + if (gpu->mem_khz_min > 0 && gpu->mem_khz_min != gpu->mem_khz_max) + mem_freq = g_strdup_printf("%0.2f-%0.2f %s", (double) gpu->mem_khz_min / 1000, (double) gpu->mem_khz_max / 1000, _("MHz")); + else + mem_freq = g_strdup_printf("%0.2f %s", (double) gpu->mem_khz_max / 1000, _("MHz")); + } + + str = g_strdup_printf("[%s]\n" + /* Location */ "%s=%s\n" + /* DRM Dev */ "%s=%s\n" + /* Class */ "%s=[%04x] %s\n" + "%s" + /* Revision */ "%s=%02x\n" + "[%s]\n" + /* Core freq */ "%s=%s\n" + /* Mem freq */ "%s=%s\n" + /* NV */ "%s" + /* PCIe */ "%s" + "[%s]\n" + /* Driver */ "%s=%s\n" + /* Modules */ "%s=%s\n", + _("Device Information"), + _("Location"), gpu->location, + _("DRM Device"), drm_path, + _("Class"), p->class, p->class_str, + vendor_device_str, + _("Revision"), p->revision, + _("Clocks"), + _("Core"), freq, + _("Memory"), mem_freq, + nv_str, + pcie_str, + _("Driver"), + _("In Use"), (p->driver) ? p->driver : _("(Unknown)"), + _("Kernel Modules"), (p->driver_list) ? p->driver_list : _("(Unknown)") + ); + + moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */ + + g_free(drm_path); + g_free(pcie_str); + g_free(nv_str); + g_free(vendor_device_str); + g_free(name); + g_free(key); +} + +int _dt_soc_gpu(gpud *gpu) { + static char UNKSOC[] = "(Unknown)"; /* don't translate this */ + gchar *vendor = gpu->vendor_str; + gchar *device = gpu->device_str; + if (vendor == NULL) vendor = UNKSOC; + if (device == NULL) device = UNKSOC; + gchar *freq = g_strdup(_("(Unknown)")); + if (gpu->khz_max > 0) { + if (gpu->khz_min > 0) + freq = g_strdup_printf("%0.2f-%0.2f %s", (double) gpu->khz_min / 1000, (double) gpu->khz_max / 1000, _("MHz")); + else + freq = g_strdup_printf("%0.2f %s", (double) gpu->khz_max / 1000, _("MHz")); + } + gchar *key = g_strdup(gpu->id); + + gchar *name = NULL; + gchar *vtag = vendor_match_tag(gpu->vendor_str, params.fmt_opts); + if (vtag) { + name = g_strdup_printf("%s %s", vtag, device); + } else { + name = (vendor == UNKSOC && device == UNKSOC) + ? g_strdup(_("Unknown integrated GPU")) + : g_strdup_printf("%s %s", vendor, device); + } + g_free(vtag); + + gchar *opp_str; + if (gpu->dt_opp) { + static const char *freq_src[] = { + N_("clock-frequency property"), + N_("Operating Points (OPPv1)"), + N_("Operating Points (OPPv2)"), + }; + opp_str = g_strdup_printf("[%s]\n" + /* MinFreq */ "%s=%d %s\n" + /* MaxFreq */ "%s=%d %s\n" + /* Latency */ "%s=%d %s\n" + /* Source */ "%s=%s\n", + _("Frequency Scaling"), + _("Minimum"), gpu->dt_opp->khz_min, _("kHz"), + _("Maximum"), gpu->dt_opp->khz_max, _("kHz"), + _("Transition Latency"), gpu->dt_opp->clock_latency_ns, _("ns"), + _("Source"), _(freq_src[gpu->dt_opp->version]) ); + } else + opp_str = strdup(""); + + gpu_summary_add((gpu->nice_name) ? gpu->nice_name : name); + gpu_list = h_strdup_cprintf("$!%s$%s=%s\n", gpu_list, key, key, name); + gchar *str = g_strdup_printf("[%s]\n" + /* Location */ "%s=%s\n" + /* Vendor */ "$^$%s=%s\n" + /* Device */ "%s=%s\n" + "[%s]\n" + /* Freq */ "%s=%s\n" + /* opp-v2 */ "%s" + "[%s]\n" + /* Path */ "%s=%s\n" + /* Compat */ "%s=%s\n" + /* Status */ "%s=%s\n" + /* Name */ "%s=%s\n", + _("Device Information"), + _("Location"), gpu->location, + _("Vendor"), vendor, + _("Device"), device, + _("Clocks"), + _("Core"), freq, + opp_str, + _("Device Tree Node"), + _("Path"), gpu->dt_path, + _("Compatible"), gpu->dt_compat, + _("Status"), gpu->dt_status, + _("Name"), gpu->dt_name + ); + moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */ + g_free(freq); + g_free(opp_str); + return 1; +} + +void scan_gpu_do(void) { + if (gpu_summary) + g_free(gpu_summary); + if (gpu_list) { + moreinfo_del_with_prefix("DEV:GPU"); + g_free(gpu_list); + } + gpu_summary = strdup(""); + gpu_list = g_strdup_printf("[%s]\n", _("GPUs")); + + gpud *gpus = gpu_get_device_list(); + gpud *curr = gpus; + + int c = gpud_list_count(gpus); + + if (c > 0) { + while(curr) { + if (curr->pci_dev) { + _gpu_pci_dev(curr); + } + if (curr->dt_compat) { + _dt_soc_gpu(curr); + } + curr=curr->next; + } + } + gpud_list_free(gpus); + + if (c) + gpu_list = g_strconcat(gpu_list, "[$ShellParam$]\n", "ViewType=1\n", NULL); + else { + /* NO GPU? */ + gpu_list = g_strconcat(gpu_list, _("No GPU devices found"), "=\n", NULL); + } +} diff --git a/modules/devices/ia64/processor.c b/modules/devices/ia64/processor.c index c4d06a71..f31813bc 100644 --- a/modules/devices/ia64/processor.c +++ b/modules/devices/ia64/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/inputdevices.c b/modules/devices/inputdevices.c index cf1728a9..301641d4 100644 --- a/modules/devices/inputdevices.c +++ b/modules/devices/inputdevices.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,6 +20,7 @@ #include "hardinfo.h" #include "devices.h" +#include "usb_util.h" gchar *input_icons = NULL; @@ -27,113 +28,143 @@ static struct { char *name; char *icon; } input_devices[] = { + { NULL, "module.png" }, // UNKNOWN { "Keyboard", "keyboard.png" }, { "Joystick", "joystick.png" }, { "Mouse", "mouse.png" }, - { "Speaker", "audio.png" }, - { "Unknown", "module.png" }, + { "Speaker", "audio.png" }, + { "Audio", "audio.png" } }; +// source: https://elixir.bootlin.com/linux/v5.9/source/include/uapi/linux/input.h#L251 +static const gchar *bus_types[] = { + NULL, "PCI", "ISA PnP", "USB", // 0x0 - 0x3 + "HIL", "Bluetooth", "Virtual", NULL, // 0x4 - 0x7 + NULL, NULL, NULL, NULL, // 0x8 - 0xB + NULL, NULL, NULL, NULL, // 0xC - 0xF + "ISA", "i8042", "XT Keyboard bus", "RS232", // 0x10 - 0x13 + "Game port", "Parallel port", "Amiga bus", "ADB", // 0x14 - 0x17 + "I²C", "HOST", "GSC", "Atari bus", // 0x18 - 0x1B + "SPI", "RMI", "CEC", "Intel ISHTP" // 0x1C - 0x1F +}; + +#define UNKWNIFNULL(f) ((f) ? f : _("(Unknown)")) +#define EMPTYIFNULL(f) ((f) ? f : "") + void __scan_input_devices(void) { FILE *dev; gchar buffer[1024]; + vendor_list vl = NULL; gchar *tmp, *name = NULL, *phys = NULL; + gchar *vendor_str = NULL, *product_str = NULL, *vendor_tags = NULL; gint bus = 0, vendor = 0, product = 0, version = 0; + const gchar *bus_str = NULL; int d = 0, n = 0; dev = fopen("/proc/bus/input/devices", "r"); if (!dev) - return; + return; if (input_list) { moreinfo_del_with_prefix("DEV:INP"); - g_free(input_list); - g_free(input_icons); + 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); - - const gchar *v_url = (gchar*)vendor_get_url(name); - const gchar *v_name = (gchar*)vendor_get_name(name); - gchar *v_str = NULL; - if (v_url != NULL) - v_str = g_strdup_printf("[0x%x] %s (%s)", vendor, v_name, v_url); - else - v_str = g_strdup_printf("0x%x", vendor); - v_str = hardinfo_clean_value(v_str, 1); - name = hardinfo_clean_value(name, 1); - - gchar *strhash = g_strdup_printf("[%s]\n" - /* Name */ "%s=%s\n" - /* Type */ "%s=%s\n" - /* Bus */ "%s=0x%x\n" - /* Vendor */ "%s=%s\n" - /* Product */"%s=0x%x\n" - /* Version */"%s=0x%x\n", - _("Device Information"), - _("Name"), name, - _("Type"), input_devices[d].name, - _("Bus"), bus, - _("Vendor"), v_str, - _("Product"), product, - _("Version"), version ); - - if (phys && phys[1] != 0) { - strhash = h_strdup_cprintf("%s=%s\n", strhash, _("Connected to"), phys); + 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 = 1; //INPUT_KEYBOARD; + else if (strstr(tmp, "js")) + d = 2; //INPUT_JOYSTICK; + else if (strstr(tmp, "mouse")) + d = 3; //INPUT_MOUSE; + else + d = 0; //INPUT_UNKNOWN; + break; + case '\n': + if (name && strstr(name, "PC Speaker")) { + d = 4; // INPUT_PCSPKR + } + if (d == 0 && g_strcmp0(phys, "ALSA")) { + d = 5; // INPUT_AUDIO + } + + if (vendor > 0 && product > 0 && g_str_has_prefix(phys, "usb-")) { + usb_lookup_ids_vendor_product_str(vendor, product, &vendor_str, &product_str); + } + + if (bus >= 0 && (guint)bus < sizeof(bus_types) / sizeof(gchar*)) { + bus_str = bus_types[bus]; + } + + vl = vendor_list_remove_duplicates_deep(vendors_match(name, vendor_str, NULL)); + vendor_tags = vendor_list_ribbon(vl, params.fmt_opts); + + tmp = g_strdup_printf("INP%d", ++n); + input_list = h_strdup_cprintf("$%s$%s=%s|%s\n", + input_list, + tmp, name, EMPTYIFNULL(vendor_tags), + EMPTYIFNULL(input_devices[d].name)); + input_icons = h_strdup_cprintf("Icon$%s$%s=%s\n", + input_icons, + tmp, name, + input_devices[d].icon); + + gchar *strhash = g_strdup_printf("[%s]\n" + /* Name */ "$^$%s=%s\n" + /* Type */ "%s=%s\n" + /* Bus */ "%s=[0x%x] %s\n" + /* Vendor */ "$^$%s=[0x%x] %s\n" + /* Product */"%s=[0x%x] %s\n" + /* Version */"%s=0x%x\n", + _("Device Information"), + _("Name"), name, + _("Type"), UNKWNIFNULL(input_devices[d].name), + _("Bus"), bus, UNKWNIFNULL(bus_str), + _("Vendor"), vendor, UNKWNIFNULL(vendor_str), + _("Product"), product, UNKWNIFNULL(product_str), + _("Version"), version ); + + if (phys && phys[1] != 0) { + strhash = h_strdup_cprintf("%s=%s\n", strhash, _("Connected to"), phys); + } + + if (phys && strstr(phys, "ir")) { + strhash = h_strdup_cprintf("%s=%s\n", strhash, _("InfraRed port"), _("Yes") ); + } + + moreinfo_add_with_prefix("DEV", tmp, strhash); + g_free(tmp); + g_free(phys); + g_free(name); + g_free(vendor_str); + g_free(vendor_tags); + g_free(product_str); + bus_str = NULL; + vendor_str = NULL; + product_str = NULL; + vendor_tags = NULL; } - - if (phys && strstr(phys, "ir")) { - strhash = h_strdup_cprintf("%s=%s\n", strhash, _("InfraRed port"), _("Yes") ); - } - - moreinfo_add_with_prefix("DEV", tmp, strhash); - g_free(tmp); - g_free(v_str); - g_free(phys); - g_free(name); - } } fclose(dev); diff --git a/modules/devices/loongarch64/processor.c b/modules/devices/loongarch64/processor.c new file mode 100644 index 00000000..08f3645e --- /dev/null +++ b/modules/devices/loongarch64/processor.c @@ -0,0 +1,90 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> + * + * 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 or later. + * + * 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 "cpu_util.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->vendor_id); + get_str("CPU Family", processor->family); + get_str("Model Name", processor->model_name); + get_int("CPU Revision", processor->revision); + get_float("CPU MHz", processor->cpu_mhz); + get_float("BogoMIPS", processor->bogomips); + get_str("Features", processor->features); + } + g_strfreev(tmp); + } + + fclose(cpuinfo); + + return g_slist_append(NULL, processor); +} + +gchar *processor_name(GSList * processors) { + return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { + return processor_describe_default(processors); +} + +gchar * +processor_get_info(GSList *processors) +{ + Processor *processor = (Processor *)processors->data; + + return g_strdup_printf("[%s]\n" + "%s=%s\n" /* vendor */ + "%s=%s\n" /* family */ + "%s=%s\n" /* name */ + "%s=%d\n" /* revision */ + "%s=%.2f %s\n" /* frequency */ + "%s=%.2f\n" /* bogoMIPS */ + "%s=%s\n" /* features */ + "%s=%s\n", /* byte order */ + _("Processor"), + _("System Type"), processor->vendor_id, + _("Family"), processor->family, + _("Model"), processor->model_name, + _("Revision"), processor->revision, + _("Frequency"), processor->cpu_mhz, _("MHz"), + _("BogoMIPS"), processor->bogomips, + _("Features"), processor->features, + _("Byte Order"), byte_order_str() + ); +} diff --git a/modules/devices/m68k/processor.c b/modules/devices/m68k/processor.c index e030732a..a9d71835 100644 --- a/modules/devices/m68k/processor.c +++ b/modules/devices/m68k/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/mips/processor.c b/modules/devices/mips/processor.c index b31af7dd..112a3c3b 100644 --- a/modules/devices/mips/processor.c +++ b/modules/devices/mips/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/monitors.c b/modules/devices/monitors.c new file mode 100644 index 00000000..02fb1d67 --- /dev/null +++ b/modules/devices/monitors.c @@ -0,0 +1,515 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2019 L. A. F. Pereira <l@tia.mat.br> + * Copyright (C) 2019 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, version 2 or later. + * + * 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 "devices.h" +#include "util_sysobj.h" +#include "util_edid.h" +#include "util_ids.h" + +static const char monitor_icon[] = "monitor.png"; + +#define UNKIFNULL2(f) ((f) ? f : _("(Unknown)")) +#define UNKIFEMPTY2(f) ((*f) ? f : _("(Unknown)")) +#define UNSPECIFNULL2(f) ((f) ? f : _("(Unspecified)")) + +gboolean no_monitors = FALSE; + +gchar *edid_ids_file = NULL; +gchar *ieee_oui_ids_file = NULL; + +void find_edid_ids_file() { + if (edid_ids_file) return; + char *file_search_order[] = { + g_build_filename(g_get_user_config_dir(), "hardinfo2", "edid.ids", NULL), + g_build_filename(params.path_data, "edid.ids", NULL), + NULL + }; + int n; + for(n = 0; file_search_order[n]; n++) { + if (!edid_ids_file && !access(file_search_order[n], R_OK)) + edid_ids_file = file_search_order[n]; + else + g_free(file_search_order[n]); + } + auto_free(edid_ids_file); +} + +void find_ieee_oui_ids_file() { + if (ieee_oui_ids_file) return; + char *file_search_order[] = { + g_build_filename(g_get_user_config_dir(), "hardinfo2", "ieee_oui.ids", NULL), + g_build_filename(params.path_data, "ieee_oui.ids", NULL), + NULL + }; + int n; + for(n = 0; file_search_order[n]; n++) { + if (!ieee_oui_ids_file && !access(file_search_order[n], R_OK)) + ieee_oui_ids_file = file_search_order[n]; + else + g_free(file_search_order[n]); + } + auto_free(ieee_oui_ids_file); +} + +typedef struct { + gchar *drm_path; + gchar *drm_connection; + gchar *drm_status; + gchar *drm_enabled; + edid *e; + gchar *_vstr; /* use monitor_vendor_str() */ +} monitor; +#define monitor_new() g_new0(monitor, 1) + +monitor *monitor_new_from_sysfs(const gchar *sysfs_edid_file) { + gchar *edid_bin = NULL; + gsize edid_len = 0; + if (!sysfs_edid_file || !*sysfs_edid_file) return NULL; + monitor *m = monitor_new(); + m->drm_path = g_path_get_dirname(sysfs_edid_file); + m->drm_connection = g_path_get_basename(m->drm_path); + gchar *drm_enabled_file = g_strdup_printf("%s/%s", m->drm_path, "enabled"); + gchar *drm_status_file = g_strdup_printf("%s/%s", m->drm_path, "status"); + g_file_get_contents(drm_enabled_file, &m->drm_enabled, NULL, NULL); + if (m->drm_enabled) g_strstrip(m->drm_enabled); + g_file_get_contents(drm_status_file, &m->drm_status, NULL, NULL); + if (m->drm_status) g_strstrip(m->drm_status); + g_file_get_contents(sysfs_edid_file, &edid_bin, &edid_len, NULL); + if (edid_len) + m->e = edid_new(edid_bin, edid_len); + g_free(drm_enabled_file); + g_free(drm_status_file); + return m; +} + +void monitor_free(monitor *m) { + if (m) { + g_free(m->_vstr); + g_free(m->drm_connection); + edid_free(m->e); + g_free(m); + } +} + +gchar *monitor_vendor_str(monitor *m, gboolean include_value, gboolean link_name) { + if (!m || !m->e) return NULL; + edid_ven ven = m->e->ven; + gchar v[20] = "", t[4] = ""; + ids_query_result result;// = {}; + + memset(&result,0,sizeof(ids_query_result)); + if (ven.type == VEN_TYPE_PNP) { + strcpy(v, ven.pnp); + strcpy(t, "PNP"); + } else if (ven.type == VEN_TYPE_OUI) { + strcpy(v, ven.oui_str); + strcpy(t, "OUI"); + } + + if (!m->_vstr) { + if (ven.type == VEN_TYPE_PNP) { + if (!edid_ids_file) + find_edid_ids_file(); + scan_ids_file(edid_ids_file, v, &result, -1); + if (result.results[0]) + m->_vstr = g_strdup(result.results[0]); + } else if (ven.type == VEN_TYPE_OUI) { + if (!ieee_oui_ids_file) + find_ieee_oui_ids_file(); + scan_ids_file(ieee_oui_ids_file, v, &result, -1); + if (result.results[0]) + m->_vstr = g_strdup(result.results[0]); + } + } + + gchar *ret = NULL; + if (include_value) + ret = g_strdup_printf("[%s:%s]", t, v); + if (m->_vstr) { + if (link_name) { + gchar *lv = vendor_get_link(m->_vstr); + ret = appfsp(ret, "%s", lv); + g_free(lv); + } else + ret = appfsp(ret, "%s", m->_vstr); + } else if (!include_value && ven.type == VEN_TYPE_PNP) { + ret = appfsp(ret, "%s", ven.pnp); + } else + ret = appfsp(ret, "%s", _("(Unknown)")); + return ret; +} + +gchar *monitor_name(monitor *m, gboolean include_vendor) { + if (!m) return NULL; + gchar *desc = NULL; + edid *e = m->e; + if (!e) + return g_strdup(_("(Unknown)")); + + if (include_vendor) { + if (e->ven.type != VEN_TYPE_INVALID) { + gchar *vstr = monitor_vendor_str(m, FALSE, FALSE); + gchar *vtag = vendor_match_tag(vstr, params.fmt_opts); + desc = appfsp(desc, "%s", vtag ? vtag : vstr); + g_free(vstr); + g_free(vtag); + } else + desc = appfsp(desc, "%s", "Unknown"); + } + + if (e->img_max.diag_in) + desc = appfsp(desc, "%s", e->img_max.class_inch); + + if (e->name) + desc = appfsp(desc, "%s", e->name); + else + desc = appfsp(desc, "%s %s", e->a_or_d ? "Digital" : "Analog", "Display"); + + return desc; +} + +gchar **get_output_lines(const char *cmd_line) { + gboolean spawned; + gchar *out, *err; + gchar **ret = NULL; + + spawned = g_spawn_command_line_sync(cmd_line, + &out, &err, NULL, NULL); + if (spawned) { + ret = g_strsplit(out, "\n", -1); + g_free(out); + g_free(err); + } + return ret; +} + +static gchar *tag_make_safe_inplace(gchar *tag) { + if (!tag) + return tag; + if (!g_utf8_validate(tag, -1, NULL)) + return tag; //TODO: reconsider + gchar *p = tag, *pd = tag; + while(*p) { + gchar *np = g_utf8_next_char(p); + gunichar c = g_utf8_get_char_validated(p, -1); + int l = g_unichar_to_utf8(c, NULL); + if (l == 1 && g_unichar_isalnum(c)) { + g_unichar_to_utf8(c, pd); + } else { + *pd = '_'; + } + p = np; + pd++; + } + return tag; +} + +static gchar *make_edid_section(monitor *m) { + int i; + edid *e = m->e; + if (e->len) { + gchar *vstr = monitor_vendor_str(m, TRUE, FALSE); + + gchar *dom = NULL; + if (!e->dom.is_model_year && e->dom.week && e->dom.year) + dom = g_strdup_printf(_("Week %d of %d"), e->dom.week, e->dom.year); + else if (e->dom.year) + dom = g_strdup_printf("%d", e->dom.year); + + gchar *bpcc = NULL; + if (e->bpc) + bpcc = g_strdup_printf("%d", e->bpc); + + int aok = e->checksum_ok; + if (e->ext_blocks_fail) aok = 0; + gchar *csum = aok ? _("Ok") : _("Fail"); + + gchar *iface; + if (e->interface && e->di.exists) { + gchar *tmp = g_strdup_printf("[%x] %s\n[DI-EXT:%x] %s", + e->interface, _(edid_interface(e->interface)), + e->di.interface, _(edid_di_interface(e->di.interface)) ); + iface = gg_key_file_parse_string_as_value(tmp, '|'); + g_free(tmp); + } else if (e->di.exists) { + iface = g_strdup_printf("[DI-EXT:%x] %s", + e->di.interface, _(edid_di_interface(e->di.interface)) ); + } else { + iface = g_strdup_printf("[%x] %s", + e->interface, + e->interface ? _(edid_interface(e->interface)) : _("(Unspecified)") ); + } + + gchar *d_list, *ext_list, *dtd_list, *cea_list, + *etb_list, *std_list, *svd_list, *sad_list, + *didt_list, *did_string_list; + + etb_list = NULL; + for(i = 0; i < e->etb_count; i++) { + char *desc = edid_output_describe(&e->etbs[i]); + etb_list = appfnl(etb_list, "etb%d=%s", i, desc); + g_free(desc); + } + if (!etb_list) etb_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + std_list = NULL; + for(i = 0; i < e->std_count; i++) { + char *desc = edid_output_describe(&e->stds[i].out); + std_list = appfnl(std_list, "std%d=%s", i, desc); + g_free(desc); + } + if (!std_list) std_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + d_list = NULL; + for(i = 0; i < 4; i++) { + char *desc = edid_base_descriptor_describe(&e->d[i]); + d_list = appfnl(d_list, "descriptor%d=%s", i, desc); + g_free(desc); + } + if (!d_list) d_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + ext_list = NULL; + for(i = 0; i < e->ext_blocks; i++) { + int type = e->u8[(i+1)*128]; + int version = e->u8[(i+1)*128 + 1]; + ext_list = appfnl(ext_list, "ext%d = ([%02x:v%02x] %s) %s", i, + type, version, _(edid_ext_block_type(type)), + e->ext_ok[i] ? "ok" : "fail" + ); + } + if (!ext_list) ext_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + dtd_list = NULL; + for(i = 0; i < e->dtd_count; i++) { + char *desc = edid_dtd_describe(&e->dtds[i], 0); + dtd_list = appfnl(dtd_list, "dtd%d = %s", i, desc); + free(desc); + } + if (!dtd_list) dtd_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + cea_list = NULL; + for(i = 0; i < e->cea_block_count; i++) { + char *desc = edid_cea_block_describe(&e->cea_blocks[i]); + cea_list = appfnl(cea_list, "cea_block%d = %s", i, desc); + } + if (!cea_list) cea_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + svd_list = NULL; + for(i = 0; i < e->svd_count; i++) { + char *desc = edid_output_describe(&e->svds[i].out); + svd_list = appfnl(svd_list, "svd%d=%s", i, desc); + g_free(desc); + } + if (!svd_list) svd_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + sad_list = NULL; + for(i = 0; i < e->sad_count; i++) { + char *desc = edid_cea_audio_describe(&e->sads[i]); + sad_list = appfnl(sad_list, "sad%d=%s", i, desc); + g_free(desc); + } + if (!sad_list) sad_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + didt_list = NULL; + for(i = 0; i < e->didt_count; i++) { + char *desc = edid_output_describe(&e->didts[i]); + didt_list = appfnl(didt_list, "didt%d=%s", i, desc); + g_free(desc); + } + if (!didt_list) didt_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + did_string_list = NULL; + for(i = 0; i < e->did_string_count; i++) { + did_string_list = appfnl(did_string_list, "did_string%d=%s", i, e->did_strings[i].str); + } + if (!did_string_list) did_string_list = g_strdup_printf("%s=\n", _("(Empty List)")); + + gchar *speakers = NULL; + if (e->speaker_alloc_bits) { + gchar *spk_tmp = edid_cea_speaker_allocation_describe(e->speaker_alloc_bits, 0); + speakers = gg_key_file_parse_string_as_value(spk_tmp, '|'); + g_free(spk_tmp); + } else + speakers = g_strdup(_("(Unspecified)")); + + gchar *hex = edid_dump_hex(e, 0, 1); + gchar *hex_esc = gg_key_file_parse_string_as_value(hex, '|'); + g_free(hex); + if (params.markup_ok) + hex = g_strdup_printf("<tt>%s</tt>", hex_esc); + else + hex = g_strdup(hex_esc); + g_free(hex_esc); + + gchar *ret = g_strdup_printf( + /* extending "Connection" section */ + "%s=%s\n" /* sig type */ + "%s=%s\n" /* interface */ + "%s=%s\n" /* bpcc */ + "%s=%s\n" /* speakers */ + "[%s]\n" + "%s=%s\n" /* base out */ + "%s=%s\n" /* ext out */ + "[%s]\n" + "$^$%s=%s\n" /* vendor */ + "%s=%s\n" /* name */ + "%s=[%04x-%08x] %u-%u\n" /* model, n_serial */ + "%s=%s\n" /* serial */ + "%s=%s\n" /* dom */ + "[%s]\n" + "%s=%d %s\n" /* size */ + "%s=%d.%d\n" /* version */ + "%s=%d\n" /* ext block */ + "%s=%s\n" /* ext to */ + "%s=%s %s\n" /* checksum */ + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s\n" + "[%s]\n%s=%s\n" + , + _("Signal Type"), e->a_or_d ? _("Digital") : _("Analog"), + _("Interface"), iface, + _("Bits per Color Channel"), UNSPECIFNULL2(bpcc), + _("Speaker Allocation"), speakers, + _("Output (Max)"), + edid_output_src(e->img.src), edid_output_describe(&e->img), + edid_output_src(e->img_max.src), edid_output_describe(&e->img_max), + _("EDID Device"), + _("Vendor"), vstr, + _("Name"), e->name, + _("Model"), e->product, e->n_serial, e->product, e->n_serial, + _("Serial"), UNKIFNULL2(e->serial), + _("Manufacture Date"), UNKIFNULL2(dom), + _("EDID Meta"), + _("Data Size"), e->len, _("bytes"), + _("Version"), (int)e->ver_major, (int)e->ver_minor, + _("Extension Blocks"), e->ext_blocks, + _("Extended to"), e->std ? _(edid_standard(e->std)) : _("(None)"), + _("Checksum"), csum, aok ? "" : problem_marker(), + _("EDID Descriptors"), d_list, + _("Detailed Timing Descriptors (DTD)"), dtd_list, + _("Established Timings Bitmap (ETB)"), etb_list, + _("Standard Timings (STD)"), std_list, + _("E-EDID Extension Blocks"), ext_list, + _("EIA/CEA-861 Data Blocks"), cea_list, + _("EIA/CEA-861 Short Audio Descriptors"), sad_list, + _("EIA/CEA-861 Short Video Descriptors"), svd_list, + _("DisplayID Timings"), didt_list, + _("DisplayID Strings"), did_string_list, + _("Hex Dump"), _("Data"), hex + ); + g_free(bpcc); + g_free(dom); + + g_free(d_list); + g_free(ext_list); + g_free(etb_list); + g_free(std_list); + g_free(dtd_list); + g_free(cea_list); + g_free(sad_list); + g_free(svd_list); + g_free(didt_list); + g_free(did_string_list); + g_free(iface); + g_free(vstr); + g_free(hex); + //printf("ret: %s\n", ret); + return ret; + } else + return g_strdup(""); +} + +gchar *monitors_get_info() { + gchar *icons = g_strdup(""); + gchar *ret = g_strdup_printf("[%s]\n", _("Monitors")); + gchar tag_prefix[] = "DEV"; + + gchar **edid_files = get_output_lines("find /sys/devices -name edid"); + //gchar **edid_files = get_output_lines("find /home/pburt/github/verbose-spork/junk/testing/.testing/edid2/ -name edid.*"); + int i, found = 0; + for(i = 0; edid_files[i]; i++) { + monitor *m = monitor_new_from_sysfs(edid_files[i]); + //if (m && m->e->std < STD_DISPLAYID) continue; + //if (m && !m->e->interface) continue; + //if (m && m->e->interface != 1) continue; + if (m && !SEQ(m->drm_status, "disconnected")) { + gchar *tag = g_strdup_printf("%d-%s", found, m->drm_connection); + tag_make_safe_inplace(tag); + gchar *desc = monitor_name(m, TRUE); + gchar *edid_section = NULL; + edid *e = m->e; + if (e && e->checksum_ok) + edid_section = make_edid_section(m); + + gchar *details = g_strdup_printf("[%s]\n" + "%s=%s\n" + "%s=%s %s\n" + "%s\n", + _("Connection"), + _("DRM"), m->drm_connection, + _("Status"), m->drm_status, m->drm_enabled, + edid_section ? edid_section : "" + ); + moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */ + ret = h_strdup_cprintf("$!%s$%s=%s\n", + ret, tag, m->drm_connection, desc); + icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, monitor_icon); + g_free(desc); + g_free(edid_section); + found++; + } + monitor_free(m); + } + g_strfreev(edid_files); + + no_monitors = FALSE; + if(!found) { + no_monitors = TRUE; + g_free(ret); + ret = g_strdup_printf("[%s]\n%s=%s\n" "[$ShellParam$]\nViewType=0\n", + _("Monitors"), _("Result"), _("(Empty)") ); + } else { + ret = h_strdup_cprintf( + "[$ShellParam$]\nViewType=1\n" + "ColumnTitle$TextValue=%s\n" /* DRM connection */ + "ColumnTitle$Value=%s\n" /* Name */ + "ShowColumnHeaders=true\n" + "%s", + ret, + _("Connection"), + _("Name"), + icons + ); + } + + return ret; +} + +gboolean monitors_hinote(const char **msg) { + PARAM_NOT_UNUSED(msg); + return FALSE; +} diff --git a/modules/devices/parisc/processor.c b/modules/devices/parisc/processor.c index 9ca38d12..c749bc5a 100644 --- a/modules/devices/parisc/processor.c +++ b/modules/devices/parisc/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/pci.c b/modules/devices/pci.c index c1965a63..859fa339 100644 --- a/modules/devices/pci.c +++ b/modules/devices/pci.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,239 +16,185 @@ * 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) +#include "pci_util.h" + +#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)"); + +static const struct { + const gchar *icon; + uint32_t class; +} class2icon[] = { + { .class = 0x0200, .icon = "network-interface.png" }, + { .class = 0x0c03, .icon = "usb.png" }, + { .class = 0x0403, .icon = "audio.png" }, + { .class = 0x0805, .icon = "usbfldisk.png" }, + { .class = 0x0d11, .icon = "bluetooth.png" }, + { .class = 0x0703, .icon = "modem.png" }, + { .class = 0x01, .icon = "hdd.png" }, + { .class = 0x02, .icon = "network.png" }, + { .class = 0x03, .icon = "monitor.png" }, + { .class = 0x05, .icon = "memory.png" }, + { .class = 0x07, .icon = "network-connections.png" }, + { .class = 0x09, .icon = "inputdevices.png" }, + { .class = 0x10, .icon = "cryptohash.png" }, +}; + +static const gchar *find_icon_for_class(uint32_t class) { - 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; + guint i; + + for (i = 0; i < G_N_ELEMENTS(class2icon); i++) { + if (class2icon[i].class <= 0xff) { + if ((class & 0xff00) == class2icon[i].class << 8) + return class2icon[i].icon; + } else if (class == class2icon[i].class) { + return class2icon[i].icon; + } + } - if ((lspci_path = find_program("lspci")) == NULL) { - goto pci_error; + return "devices.png"; +} + +static gchar *_pci_dev(const pcid *p, gchar *icons) { + gchar *str; + const gchar *class, *vendor, *svendor, *product, *sproduct, *lproduct; + gchar *name, *key; + + gboolean device_is_sdevice = (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id); + + class = UNKIFNULL_AC(p->class_str); + vendor = UNKIFNULL_AC(p->vendor_id_str); + svendor = UNKIFNULL_AC(p->sub_vendor_id_str); + product = UNKIFNULL_AC(p->device_id_str); + sproduct = UNKIFNULL_AC(p->sub_device_id_str); + lproduct = p->device_id_str ? p->device_id_str : p->class_str; + lproduct = UNKIFNULL_AC(lproduct); + + gchar *ven_tag = vendor_match_tag(p->vendor_id_str, params.fmt_opts); + gchar *sven_tag = vendor_match_tag(p->sub_vendor_id_str, params.fmt_opts); + if (ven_tag) { + if (sven_tag && p->vendor_id != p->sub_vendor_id) { + name = g_strdup_printf("%s %s %s", sven_tag, ven_tag, lproduct); + } else { + name = g_strdup_printf("%s %s", ven_tag, lproduct); + } } else { - command_line = g_strdup_printf("%s -v", lspci_path); + name = g_strdup_printf("%s %s", vendor, lproduct); } + g_free(ven_tag); + g_free(sven_tag); - if (!_pci_devices) { - _pci_devices = g_hash_table_new(g_str_hash, g_str_equal); - } + key = g_strdup_printf("PCI%04x:%02x:%02x.%01x", p->domain, p->bus, p->device, p->function); - 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; - } + pci_list = h_strdup_cprintf("$%s$%04x:%02x:%02x.%01x=%s\n", pci_list, key, p->domain, p->bus, p->device, p->function, name); + icons = h_strdup_cprintf("Icon$%s$%04x:%02x:%02x.%01x=%s\n", icons, key, p->domain, p->bus, p->device, p->function, find_icon_for_class(p->class)); + + gchar *vendor_device_str; + if (device_is_sdevice) { + vendor_device_str = g_strdup_printf( + /* Vendor */ "$^$%s=[%04x] %s\n" + /* Device */ "%s=[%04x] %s\n", + _("Vendor"), p->vendor_id, vendor, + _("Device"), p->device_id, product); } 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); - } + vendor_device_str = g_strdup_printf( + /* Vendor */ "$^$%s=[%04x] %s\n" + /* Device */ "%s=[%04x] %s\n" + /* Sub-device vendor */ "$^$%s=[%04x] %s\n" + /* Sub-device */ "%s=[%04x] %s\n", + _("Vendor"), p->vendor_id, vendor, + _("Device"), p->device_id, product, + _("SVendor"), p->sub_vendor_id, svendor, + _("SDevice"), p->sub_device_id, sproduct); } - 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("%s=%d\n", strdevice, _("IRQ"), irq); - if (freq) - strdevice = h_strdup_cprintf("%s=%d %s\n", strdevice, _("Frequency"), freq, _("MHz") ); - if (latency) - strdevice = h_strdup_cprintf("%s=%d\n", strdevice, _("Latency"), latency); - - strdevice = h_strdup_cprintf("%s=%s\n", strdevice, _("Bus Master"), bus_master ? _("Yes") : _("No") ); - } else if (!strncmp(buf, "Kernel modules", 14)) { - WALK_UNTIL(' '); - WALK_UNTIL(':'); - buf++; - - strdevice = h_strdup_cprintf("%s=%s\n", strdevice, _("Kernel modules"), 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(_("%s=%s (%s)\n"), - strdevice, - _("OEM Vendor"), - 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("%s#%d=%d%cB (%s%s)\n", - strdevice, _("Memory"), ++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("%s#%d=0x%x - 0x%x\n", - strdevice, _("I/O ports at"), ++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("[%s]\n" - /* Name */ "%s=%s\n" - /* Class */ "%s=%s\n" - /* Domain */ "%s=%d\n" - /* Bus, device, function */ - "%s=%d, %d, %d\n", - _("Device Information"), - _("Name"), name, - _("Class"), category, - _("Domain"), domain, - _("Bus, device, function"), - bus, device, function); - - const gchar *url = vendor_get_url(name); - if (url) { - strdevice = h_strdup_cprintf("%s=%s (%s)\n", - strdevice, - _("Vendor"), - 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++; - } + gchar *pcie_str; + if (p->pcie_width_curr) { + pcie_str = g_strdup_printf("[%s]\n" + /* Width */ "%s=x%u\n" + /* Width (max) */ "%s=x%u\n" + /* Speed */ "%s=%0.1f %s\n" + /* Speed (max) */ "%s=%0.1f %s\n", + _("PCI Express"), + _("Link Width"), p->pcie_width_curr, + _("Maximum Link Width"), p->pcie_width_max, + _("Link Speed"), p->pcie_speed_curr, _("GT/s"), + _("Maximum Link Speed"), p->pcie_speed_max, _("GT/s") ); + } else + pcie_str = strdup(""); + + str = g_strdup_printf("[%s]\n" + /* Class */ "%s=[%04x] %s\n" + "%s" + /* Revision */ "%s=%02x\n" + /* PCIE? */ "%s" + "[%s]\n" + /* Driver */ "%s=%s\n" + /* Modules */ "%s=%s\n" + "[%s]\n" + /* Domain */ "%s=%04x\n" + /* Bus */ "%s=%02x\n" + /* Device */ "%s=%02x\n" + /* Function */ "%s=%01x\n", + _("Device Information"), + _("Class"), p->class, class, + vendor_device_str, + _("Revision"), p->revision, + pcie_str, + _("Driver"), + _("In Use"), (p->driver) ? p->driver : _("(Unknown)"), + _("Kernel Modules"), (p->driver_list) ? p->driver_list : _("(Unknown)"), + _("Connection"), + _("Domain"), p->domain, + _("Bus"), p->bus, + _("Device"), p->device, + _("Function"), p->function + ); + + g_free(pcie_str); + + moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */ + + g_free(vendor_device_str); + g_free(name); + g_free(key); + + return icons; +} + +void scan_pci_do(void) { + + if (pci_list) { + moreinfo_del_with_prefix("DEV:PCI"); + g_free(pci_list); + } + pci_list = g_strdup_printf("[%s]\n", _("PCI Devices")); + + gchar *pci_icons = g_strdup(""); + + pcid_list list = pci_get_device_list(0,0); + list = g_slist_sort(list, (GCompareFunc)pcid_cmp_by_addy); + GSList *l = list; + + int c = 0; + while(l) { + pcid *curr = (pcid*)l->data; + pci_icons = _pci_dev(curr, pci_icons); + c++; + l=l->next; } + pcid_list_free(list); - if (pclose(lspci)) { -pci_error: - /* error (no pci, perhaps?) */ + if (c) { + pci_list = g_strconcat(pci_list, "[$ShellParam$]\n", "ViewType=1\n", pci_icons, NULL); + } else { + /* NO PCI? */ 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); + g_free(pci_icons); } diff --git a/modules/devices/ppc/processor.c b/modules/devices/ppc/processor.c index 3360a136..12c575a6 100644 --- a/modules/devices/ppc/processor.c +++ b/modules/devices/ppc/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/printers.c b/modules/devices/printers.c index 77b52a43..fb9389ac 100644 --- a/modules/devices/printers.c +++ b/modules/devices/printers.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,6 +16,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef _XOPEN_SOURCE + #define _XOPEN_SOURCE +#endif + #include <stdio.h> #include <stdlib.h> #include <time.h> @@ -33,7 +37,7 @@ struct _CUPSDest { char *name, *instance; int is_default; int num_options; - CUPSOption *options; + CUPSOption *options; }; static int (*cups_dests_get) (CUPSDest **dests) = NULL; @@ -49,13 +53,13 @@ init_cups(void) 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; + break; } - + if (!cups) { cups_init = FALSE; return; @@ -63,11 +67,11 @@ init_cups(void) if (!g_module_symbol(cups, "cupsGetDests", (gpointer) & cups_dests_get) || !g_module_symbol(cups, "cupsFreeDests", (gpointer) & cups_dests_free)) { - g_module_close(cups); + if(cups) g_module_close(cups); cups_init = FALSE; } } - + cups_init = TRUE; } @@ -76,7 +80,7 @@ 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) @@ -121,7 +125,7 @@ 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); @@ -144,29 +148,30 @@ gchar *__cups_callback_boolean(gchar *value) const struct { char *key, *name; gchar *(*callback)(gchar *value); + gboolean maybe_vendor; } cups_fields[] = { { "Printer Information", NULL, NULL }, { "printer-info", "Destination Name", NULL }, - { "printer-make-and-model", "Make and Model", NULL }, - + { "printer-make-and-model", "Make and Model", NULL, TRUE }, + { "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 }, @@ -176,7 +181,7 @@ const struct { void scan_printers_do(void) { - int num_dests, i, j; + guint num_dests, j, i; CUPSDest *dests; gchar *prn_id, *prn_moreinfo; @@ -185,7 +190,7 @@ scan_printers_do(void) if (!cups_init) { init_cups(); - + printer_icons = g_strdup(""); printer_list = g_strdup(_("[Printers]\n" "No suitable CUPS library found=")); @@ -201,22 +206,22 @@ scan_printers_do(void) 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++) { + + for (j = 0; (int)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, + prn_id, dests[i].name, - dests[i].is_default ? "<i>Default</i>" : ""); + dests[i].is_default ? ((params.markup_ok) ? "<i>Default</i>" : "(Default)") : ""); printer_icons = h_strdup_cprintf("\nIcon$%s$%s=printer.png", printer_icons, prn_id, @@ -230,9 +235,9 @@ scan_printers_do(void) 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 { @@ -243,21 +248,22 @@ scan_printers_do(void) temp = g_strdup(_("Unknown")); } } - - prn_moreinfo = h_strdup_cprintf("%s=%s\n", + + prn_moreinfo = h_strdup_cprintf("%s%s=%s\n", prn_moreinfo, + cups_fields[j].maybe_vendor ? "$^$" : "", 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" diff --git a/modules/devices/resources.c b/modules/devices/resources.c index 15cb8f21..c9d1ccb5 100644 --- a/modules/devices/resources.c +++ b/modules/devices/resources.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -37,21 +37,27 @@ static gchar *_resource_obtain_name(gchar *name) 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) { + if (params.markup_ok) return g_strdup_printf("<b><small>PCI</small></b> %s", (gchar *)idle_free(temp)); + else + return g_strdup_printf("PCI %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) { + if (params.markup_ok) return g_strdup_printf("<b><small>Module</small></b> %s", (gchar *)idle_free(temp)); + else + return g_strdup_printf("Module %s", (gchar *)idle_free(temp)); } } - + return g_strdup(name); } #else @@ -66,7 +72,7 @@ void scan_device_resources(gboolean reload) SCAN_START(); FILE *io; gchar buffer[256]; - gint i; + guint i; gint zero_to_zero_addr = 0; struct { @@ -77,10 +83,10 @@ void scan_device_resources(gboolean reload) { "/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); @@ -92,8 +98,12 @@ void scan_device_resources(gboolean reload) if (strstr(temp[0], "0000-0000")) zero_to_zero_addr++; - _resources = h_strdup_cprintf("<tt>%s</tt>=%s\n", _resources, - temp[0], name); + if (params.markup_ok) + _resources = h_strdup_cprintf("<tt>%s</tt>=%s\n", _resources, + temp[0], name); + else + _resources = h_strdup_cprintf(">%s=%s\n", _resources, + temp[0], name); g_strfreev(temp); g_free(name); diff --git a/modules/devices/riscv/processor.c b/modules/devices/riscv/processor.c index afddf89d..f2e51c91 100644 --- a/modules/devices/riscv/processor.c +++ b/modules/devices/riscv/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/riscv/riscv_data.c b/modules/devices/riscv/riscv_data.c index 4ae68ef4..917e8e06 100644 --- a/modules/devices/riscv/riscv_data.c +++ b/modules/devices/riscv/riscv_data.c @@ -93,7 +93,7 @@ const char *riscv_ext_meaning(const char *ext) { /* see RISC-V spec 2.2: Chapter 22: ISA Subset Naming Conventions */ -/* Spec says case-insensitve, but I prefer single-letter extensions +/* Spec says case-insensitive, but I prefer single-letter extensions * capped and version string (like "2p1") with a lowercase p. */ #define RV_FIX_CASE(fstr,vo) \ p = fstr; while (*p != 0 && *p != ':') { if (!vo) *p = toupper(*p); p++; } \ diff --git a/modules/devices/s390/processor.c b/modules/devices/s390/processor.c index cf45c33c..e4f2b303 100644 --- a/modules/devices/s390/processor.c +++ b/modules/devices/s390/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/sensors.c b/modules/devices/sensors.c index c9d78ff7..095f0bc4 100644 --- a/modules/devices/sensors.c +++ b/modules/devices/sensors.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,12 +22,21 @@ #include "expr.h" #include "hardinfo.h" #include "socket.h" +#include "udisks2_util.h" + +#if defined(HAS_LIBSENSORS) && HAS_LIBSENSORS +#include <sensors/sensors.h> +#endif gchar *sensors = NULL; +gchar *sensor_icons = NULL; GHashTable *sensor_compute = NULL; GHashTable *sensor_labels = NULL; +gboolean hwmon_first_run = TRUE; + +static gchar *last_group = NULL; -static void read_sensor_labels(gchar *driver) { +static void read_sensor_labels(gchar *devname) { FILE *conf; gchar buf[256], *line, *p; gboolean lock = FALSE; @@ -55,14 +64,14 @@ static void read_sensor_labels(gchar *driver) { continue; } else if (lock && strstr(line, "label")) { /* label lines */ gchar **names = g_strsplit(strstr(line, "label") + 5, " ", 0); - gchar *name = NULL, *value = NULL; + gchar *key = NULL, *value = NULL; for (i = 0; names[i]; i++) { if (names[i][0] == '\0') continue; - if (!name) - name = g_strdup(names[i]); + if (!key) + key = g_strdup_printf("%s/%s", devname, names[i]); else if (!value) value = g_strdup(names[i]); else @@ -70,7 +79,7 @@ static void read_sensor_labels(gchar *driver) { } remove_quotes(value); - g_hash_table_insert(sensor_labels, name, value); + g_hash_table_insert(sensor_labels, key, g_strstrip(value)); g_strfreev(names); } else if (lock && strstr(line, "ignore")) { /* ignore lines */ @@ -80,19 +89,18 @@ static void read_sensor_labels(gchar *driver) { while (*p == ' ') p++; - g_hash_table_insert(sensor_labels, g_strdup(p), "ignore"); + g_hash_table_insert(sensor_labels, g_strdup_printf("%s/%s", devname, p), "ignore"); } else if (lock && strstr(line, "compute")) { /* compute lines */ + strend(line, ','); gchar **formulas = g_strsplit(strstr(line, "compute") + 7, " ", 0); - gchar *name = NULL, *formula = NULL; + gchar *key = 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]); + if (!key) + key = g_strdup_printf("%s/%s", devname, formulas[i]); else if (!formula) formula = g_strdup(formulas[i]); else @@ -100,7 +108,7 @@ static void read_sensor_labels(gchar *driver) { } g_strfreev(formulas); - g_hash_table_insert(sensor_compute, name, + g_hash_table_insert(sensor_compute, key, math_string_to_postfix(formula)); } else if (g_str_has_prefix(line, "chip")) { /* chip lines (delimiter) */ @@ -110,7 +118,7 @@ static void read_sensor_labels(gchar *driver) { for (i = 1; chips[i]; i++) { strend(chips[i], '*'); - if (g_str_has_prefix(chips[i] + 1, driver)) { + if (g_str_has_prefix(chips[i] + 1, devname)) { lock = TRUE; break; } @@ -128,36 +136,59 @@ static void read_sensor_labels(gchar *driver) { static void add_sensor(const char *type, const char *sensor, - const char *driver, + const char *parent, double value, - const char *unit) { + const char *unit, + const char *icon) { char key[64]; - sensors = h_strdup_cprintf("%s/%s=%.2f%s|%s\n", sensors, - driver, sensor, value, unit, type); + snprintf(key, sizeof(key), "%s/%s", parent, sensor); + + if (SENSORS_GROUP_BY_TYPE) { + // group by type + if (g_strcmp0(last_group, type) != 0) { + sensors = h_strdup_cprintf("[%s]\n", sensors, type); + g_free(last_group); + last_group = g_strdup(type); + } + sensors = h_strdup_cprintf("$%s$%s=%.2f%s|%s\n", sensors, + key, sensor, value, unit, parent); + } + else { + // group by device source / driver + if (g_strcmp0(last_group, parent) != 0) { + sensors = h_strdup_cprintf("[%s]\n", sensors, parent); + g_free(last_group); + last_group = g_strdup(parent); + } + sensors = h_strdup_cprintf("$%s$%s=%.2f%s|%s\n", sensors, + key, sensor, value, unit, type); + } + + if (icon != NULL) { + sensor_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", sensor_icons, + key, sensor, icon); + } - snprintf(key, sizeof(key), "%s/%s", driver, sensor); moreinfo_add_with_prefix("DEV", key, g_strdup_printf("%.2f%s", value, unit)); lginterval = h_strdup_cprintf("UpdateInterval$%s=1000\n", lginterval, key); } -static gchar *get_sensor_label(gchar *sensor) { +static gchar *get_sensor_label_from_conf(gchar *key) { gchar *ret; + ret = g_hash_table_lookup(sensor_labels, key); - ret = g_hash_table_lookup(sensor_labels, sensor); - if (!ret) - ret = g_strdup(sensor); - else - ret = g_strdup(ret); + if (ret) + return g_strdup(ret); - return ret; + return NULL; } -static float adjust_sensor(gchar *name, float value) { +static float adjust_sensor(gchar *key, float value) { GSList *postfix; - postfix = g_hash_table_lookup(sensor_compute, name); + postfix = g_hash_table_lookup(sensor_compute, key); if (!postfix) return value; @@ -168,79 +199,137 @@ 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; +static char *determine_devname_for_hwmon_path(char *path) { + char *tmp, *devname = NULL; + + // device name + tmp = g_strdup_printf("%s/name", path); + g_file_get_contents(tmp, &devname, NULL, NULL); + g_free(tmp); + if (devname) + return g_strstrip(devname); + // fallback: driver name (from driver link) tmp = g_strdup_printf("%s/device/driver", path); - driver = g_file_read_link(tmp, NULL); + devname = g_file_read_link(tmp, NULL); g_free(tmp); - if (driver) { - tmp = g_path_get_basename(driver); - g_free(driver); - driver = tmp; - } else { + if (!devname) { + // fallback: device folder name (from device link) tmp = g_strdup_printf("%s/device", path); - driver = g_file_read_link(tmp, NULL); + devname = 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); + if (devname) { + tmp = g_path_get_basename(devname); + g_free(devname); + return tmp; } - return driver; + return g_strdup("unknown"); } struct HwmonSensor { const char *friendly_name; - const char *path_format; + const char *value_file_regex; + const char *value_path_format; + const char *label_path_format; const char *key_format; const char *unit; const float adjust_ratio; - const int begin_at; + const char *icon; }; static const struct HwmonSensor hwmon_sensors[] = { { - "Fan", + "Fan Speed", + "^fan([0-9]+)_input$", "%s/fan%d_input", + "%s/fan%d_label", "fan%d", - "RPM", + " RPM", 1.0, - 1 + "fan" }, { "Temperature", + "^temp([0-9]+)_input$", "%s/temp%d_input", + "%s/temp%d_label", "temp%d", "\302\260C", 1000.0, - 1 + "therm" }, { "Voltage", + "^in([0-9]+)_input$", "%s/in%d_input", + "%s/in%d_label", "in%d", "V", 1000.0, - 0 + "bolt" + }, + { + "Current", + "^curr([0-9]+)_input$", + "%s/curr%d_input", + "%s/curr%d_label", + "curr%d", + " A", + 1000.0, + "bolt" + }, + { + "Power", + "^power([0-9]+)_input$", + "%s/power%d_input", + "%s/power%d_label", + "power%d", + " W", + 1000000.0, + "bolt" + }, + { + "CPU Voltage", + "^cpu([0-9]+)_vid$", + "%s/cpu%d_vid", + NULL, + "cpu%d_vid", + " V", + 1000.0, + "bolt" }, { } }; static const char *hwmon_prefix[] = {"device", "", NULL}; +static gboolean read_raw_hwmon_value(gchar *path_hwmon, const gchar *item_path_format, int item_id, gchar **result){ + gchar *full_path; + gboolean file_result; + + if (item_path_format == NULL) + return FALSE; + + full_path = g_strdup_printf(item_path_format, path_hwmon, item_id); + file_result = g_file_get_contents(full_path, result, NULL, NULL); + + g_free(full_path); + + return file_result; +} + static void read_sensors_hwmon(void) { - int hwmon, count; - gchar *path_hwmon, *path_sensor, *tmp, *driver, *name, *mon; - const char **prefix; + int hwmon, count, min, max; + gchar *path_hwmon, *tmp, *devname, *name, *mon, *key; + const char **prefix, *entry; + GDir *dir; + GRegex *regex; + GMatchInfo *match_info; + GError *err = NULL; for (prefix = hwmon_prefix; *prefix; prefix++) { hwmon = 0; @@ -248,56 +337,92 @@ static void read_sensors_hwmon(void) { 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); + devname = determine_devname_for_hwmon_path(path_hwmon); + DEBUG("hwmon%d has device=%s", hwmon, devname); + if (hwmon_first_run) { + read_sensor_labels(devname); } + dir = g_dir_open(path_hwmon, 0, NULL); + if (!dir) + continue; + for (sensor = hwmon_sensors; sensor->friendly_name; sensor++) { DEBUG("current sensor type=%s", sensor->friendly_name); + regex = g_regex_new (sensor->value_file_regex, 0, 0, &err); + if (err != NULL){ + g_free(err); + err = NULL; + continue; + } - 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; + g_dir_rewind(dir); + min = 999; + max = -1; + + while ((entry = g_dir_read_name(dir))) { + g_regex_match(regex, entry, 0, &match_info); + if (g_match_info_matches(match_info)) { + tmp = g_match_info_fetch(match_info, 1); + count = atoi(tmp); + g_free (tmp); + + if (count < min){ + min = count; + } + if (count > max){ + max = count; + } + } + g_match_info_free(match_info); + } + g_regex_unref(regex); + + for (count = min; count <= max; count++) { + if (!read_raw_hwmon_value(path_hwmon, sensor->value_path_format, count, &tmp)) { + continue; } mon = g_strdup_printf(sensor->key_format, count); - name = get_sensor_label(mon); + key = g_strdup_printf("%s/%s", devname, mon); + name = get_sensor_label_from_conf(key); + if (name == NULL){ + if (read_raw_hwmon_value(path_hwmon, sensor->label_path_format, count, &name)){ + name = g_strchomp(name); + } + else{ + name = g_strdup(mon); + } + } + if (!g_str_equal(name, "ignore")) { - float adjusted = adjust_sensor(mon, + float adjusted = adjust_sensor(key, atof(tmp) / sensor->adjust_ratio); add_sensor(sensor->friendly_name, name, - driver, + devname, adjusted, - sensor->unit); + sensor->unit, + sensor->icon); } g_free(tmp); g_free(mon); + g_free(key); g_free(name); - g_free(path_sensor); } } + g_dir_close(dir); g_free(path_hwmon); - g_free(driver); + g_free(devname); path_hwmon = get_sensor_path(++hwmon, *prefix); } - g_free(path_hwmon); } + hwmon_first_run = FALSE; } static void read_sensors_acpi(void) { @@ -323,7 +448,8 @@ static void read_sensors_acpi(void) { entry, "ACPI Thermal Zone", temperature, - "\302\260C"); + "\302\260C", + "therm"); } } @@ -332,6 +458,78 @@ static void read_sensors_acpi(void) { } } +// Sensors for Apple PowerPC devices using Windfarm driver. +struct WindfarmSensorType { + const char *type; + const char *icon; + const char *file_regex; + const char *unit; + gboolean with_decimal_p; +}; +static const struct WindfarmSensorType windfarm_sensor_types[] = { + {"Fan", "fan", "^[a-z-]+-fan(-[0-9]+)?$", " RPM", FALSE}, + {"Temperature", "therm", "^[a-z-]+-temp(-[0-9]+)?$", "\302\260C", TRUE}, + {"Power", "bolt", "^[a-z-]+-power(-[0-9]+)?$", " W", TRUE}, + {"Current", "bolt", "^[a-z-]+-current(-[0-9]+)?$", " A", TRUE}, + {"Voltage", "bolt", "^[a-z-]+-voltage(-[0-9]+)?$", " V", TRUE}, + { } +}; +static void read_sensors_windfarm(void) +{ + const gchar *path_wf = "/sys/devices/platform/windfarm.0"; + GDir *wf; + gchar *tmp = NULL; + gint v1, v2; + double value; + + wf = g_dir_open(path_wf, 0, NULL); + if (wf) { + GRegex *regex; + GError *err = NULL; + const gchar *entry; + const struct WindfarmSensorType *sensor; + + for (sensor = windfarm_sensor_types; sensor->type; sensor++) { + DEBUG("current windfarm sensor type=%s", sensor->type); + regex = g_regex_new(sensor->file_regex, 0, 0, &err); + if (err != NULL) { + g_free(err); + err = NULL; + continue; + } + + g_dir_rewind(wf); + + while ((entry = g_dir_read_name(wf))) { + if (g_regex_match(regex, entry, 0, NULL)) { + gchar *path = g_strdup_printf("%s/%s", path_wf, entry); + if (g_file_get_contents(path, &tmp, NULL, NULL)) { + + if (sensor->with_decimal_p) { + // format source + // https://elixir.free-electrons.com/linux/v5.14/source/drivers/macintosh/windfarm_core.c#L301 + sscanf(tmp, "%d.%03d", &v1, &v2); + value = v1 + (v2 / 1000.0); + } else { + value = (double)atoi(tmp); + } + g_free(tmp); + + tmp = g_strdup(entry); + add_sensor(sensor->type, g_strdelimit(tmp, "-", ' '), + "windfarm", value, sensor->unit, + sensor->icon); + g_free(tmp); + } + g_free(path); + } + } + g_regex_unref(regex); + } + g_dir_close(wf); + } +} + static void read_sensors_sys_thermal(void) { const gchar *path_tz = "/sys/class/thermal"; @@ -355,7 +553,8 @@ static void read_sensors_sys_thermal(void) { entry, "thermal", temperature / 1000.0, - "\302\260C"); + "\302\260C", + "therm"); g_free(contents); } @@ -379,7 +578,8 @@ static void read_sensors_omnibook(void) { "CPU", "omnibook", temperature, - "\302\260C\n"); + "\302\260C", + "therm"); g_free(contents); } @@ -401,7 +601,7 @@ static void read_sensors_hddtemp(void) { gchar **disks; int i; - disks = g_strsplit(buffer, "\n", 0); + disks = g_strsplit(buffer, "||", 0); for (i = 0; disks[i]; i++) { gchar **fields = g_strsplit(disks[i] + 1, "|", 5); @@ -412,12 +612,13 @@ static void read_sensors_hddtemp(void) { * 3 -> C */ const gchar *unit = strcmp(fields[3], "C") - ? "\302\260C" : "\302\260F"; - add_sensor("Hard Drive", + ? "\302\260F" : "\302\260C"; + add_sensor("Drive Temperature", fields[1], "hddtemp", atoi(fields[2]), - unit); + unit, + "therm"); g_strfreev(fields); } @@ -426,28 +627,144 @@ static void read_sensors_hddtemp(void) { } } +static void read_sensors_udisks2(void) { + GSList *node; + GSList *temps; + udiskt *disk; + + temps = get_udisks2_temps(); + if (temps == NULL) + return; + + for (node = temps; node != NULL; node = node->next) { + disk = (udiskt *)node->data; + add_sensor("Drive Temperature", + disk->drive, + "udisks2", + disk->temperature, + "\302\260C", + "therm"); + udiskt_free(disk); + } + g_slist_free(temps); +} + +#if HAS_LIBSENSORS +static const struct libsensors_feature_type { + const char *type_name; + const char *icon; + const char *unit; + sensors_subfeature_type input; +} libsensors_feature_types[SENSORS_FEATURE_MAX] = { + [SENSORS_FEATURE_FAN] = {"Fan", "fan", "RPM", + SENSORS_SUBFEATURE_FAN_INPUT}, + [SENSORS_FEATURE_TEMP] = {"Temperature", "therm", "\302\260C", + SENSORS_SUBFEATURE_TEMP_INPUT}, + [SENSORS_FEATURE_POWER] = {"Power", "bolt", "W", + SENSORS_SUBFEATURE_POWER_INPUT}, + [SENSORS_FEATURE_CURR] = {"Current", "bolt", "A", + SENSORS_SUBFEATURE_CURR_INPUT}, + [SENSORS_FEATURE_IN] = {"Voltage", "bolt", "V", + SENSORS_SUBFEATURE_IN_INPUT}, + [SENSORS_FEATURE_VID] = {"CPU Voltage", "bolt", "V", + SENSORS_SUBFEATURE_VID}, +}; +static gboolean libsensors_initialized; + +static int read_sensors_libsensors(void) { + char chip_name_buf[512]; + const sensors_chip_name *name; + int chip_nr = 0; + int added_sensors = 0; + + if (!libsensors_initialized) + return 0; + + while ((name = sensors_get_detected_chips(NULL, &chip_nr))) { + const struct sensors_feature *feat; + int feat_nr = 0; + + sensors_snprintf_chip_name(chip_name_buf, 512, name); + + while ((feat = sensors_get_features(name, &feat_nr))) { + const struct libsensors_feature_type *feat_descr; + const struct sensors_subfeature *subfeat; + double value; + + feat_descr = &libsensors_feature_types[feat->type]; + if (!feat_descr->type_name) + continue; + + subfeat = sensors_get_subfeature(name, feat, feat_descr->input); + if (!subfeat) + continue; + + if (!sensors_get_value(name, subfeat->number, &value)) { + char *label = sensors_get_label(name, feat); + gchar *label_with_chip = g_strdup_printf("%s (%s)", label, chip_name_buf); + + add_sensor(feat_descr->type_name, + label_with_chip, + "libsensors", + value, + feat_descr->unit, + feat_descr->icon); + + free(label_with_chip); + free(label); + + added_sensors++; + } + } + } + + return added_sensors; +} +#else +static int read_sensors_libsensors(void) +{ + return 0; +} +#endif + void scan_sensors_do(void) { g_free(sensors); + g_free(sensor_icons); + g_free(last_group); + last_group = NULL; sensors = g_strdup(""); + sensor_icons = g_strdup(""); g_free(lginterval); lginterval = g_strdup(""); - read_sensors_hwmon(); - read_sensors_acpi(); - read_sensors_sys_thermal(); - read_sensors_omnibook(); + if (read_sensors_libsensors() == 0) { + read_sensors_hwmon(); + read_sensors_acpi(); + read_sensors_sys_thermal(); + read_sensors_omnibook(); + } + + read_sensors_windfarm(); read_sensors_hddtemp(); - /* FIXME: Add support for ibm acpi and more sensors */ + read_sensors_udisks2(); } -void sensors_init(void) { +void sensor_init(void) { +#if HAS_LIBSENSORS + libsensors_initialized = sensors_init(NULL) == 0; +#endif + 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) { +void sensor_shutdown(void) { +#if HAS_LIBSENSORS + sensors_cleanup(); +#endif + 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 index 9da2f9b0..a5ce3e0a 100644 --- a/modules/devices/sh/processor.c +++ b/modules/devices/sh/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/sparc/processor.c b/modules/devices/sparc/processor.c index 32c7aa94..76f4b0e0 100644 --- a/modules/devices/sparc/processor.c +++ b/modules/devices/sparc/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/devices/spd-decode.c b/modules/devices/spd-decode.c index 2db4895b..511504b2 100644 --- a/modules/devices/spd-decode.c +++ b/modules/devices/spd-decode.c @@ -1,6 +1,8 @@ /* - * spd-decode.c - * Copyright (c) 2010 Leandro A. F. Pereira + * spd-decode.c, spd-vendors.c + * Copyright (c) 2010 L. A. F. Pereira + * modified by Ondrej Čerman (2019) + * modified by Burt P. (2019) * * Based on decode-dimms.pl * Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com> @@ -27,602 +29,91 @@ #include <stdio.h> #include <sys/stat.h> -#include "hardinfo.h" #include "devices.h" +#include "hardinfo.h" + +gboolean spd_no_driver = FALSE; +gboolean spd_no_support = FALSE; +gboolean spd_ddr4_partial_data = FALSE; +int spd_ram_types = 0; /* bits using enum RamType */ typedef enum { - UNKNOWN, - DIRECT_RAMBUS, - RAMBUS, - FPM_DRAM, - EDO, - PIPELINED_NIBBLE, - SDR_SDRAM, - MULTIPLEXED_ROM, - DDR_SGRAM, - DDR_SDRAM, - DDR2_SDRAM, - DDR3_SDRAM + UNKNOWN = 0, + DIRECT_RAMBUS = 1, + RAMBUS = 2, + FPM_DRAM = 3, + EDO = 4, + PIPELINED_NIBBLE = 5, + SDR_SDRAM = 6, + MULTIPLEXED_ROM = 7, + DDR_SGRAM = 8, + DDR_SDRAM = 9, + DDR2_SDRAM = 10, + DDR3_SDRAM = 11, + DDR4_SDRAM = 12, + N_RAM_TYPES = 13 } 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 *ram_types[] = {"Unknown", "Direct Rambus", "Rambus", "FPM DRAM", + "EDO", "Pipelined Nibble", "SDR SDRAM", "Multiplexed ROM", + "DDR SGRAM", "DDR SDRAM", "DDR2 SDRAM", "DDR3 SDRAM", + "DDR4 SDRAM"}; +#define GET_RAM_TYPE_STR(rt) (ram_types[(rt < N_RAM_TYPES) ? rt : 0]) -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" -}; +#include "spd-vendors.c" -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", -}; +struct dmi_mem_socket; +typedef struct { + unsigned char bytes[512]; + char dev[32]; /* %1d-%04d\0 */ + const char *spd_driver; + int spd_size; -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" -}; + RamType type; -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" -}; + int vendor_bank; + int vendor_index; + const char *vendor_str; + const Vendor *vendor; -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" -}; + int dram_vendor_bank; + int dram_vendor_index; + const char *dram_vendor_str; + const Vendor *dram_vendor; -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" -}; + char partno[32]; + const char *form_factor; + char type_detail[256]; -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." -}; + dmi_mem_size size_MiB; -static const char **vendors[7] = { vendors1, vendors2, vendors3, vendors4, vendors5, vendors6, - vendors7 -}; + int spd_rev_major; // bytes[1] >> 4 + int spd_rev_minor; // bytes[1] & 0xf + + int week, year; + + gboolean ddr4_no_ee1004; + + struct dmi_mem_socket *dmi_socket; + int match_score; +} spd_data; + +#define spd_data_new() g_new0(spd_data, 1) +void spd_data_free(spd_data *s) { g_free(s); } /* * 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) -{ +static int spd_written(unsigned char *bytes, int len) { do { - if (*bytes == 0x00 || *bytes == 0xFF) - return 1; + if (*bytes == 0x00 || *bytes == 0xFF) return 1; } while (--len && bytes++); return 0; } -static int parity(int value) -{ +static int parity(int value) { value ^= value >> 16; value ^= value >> 8; value ^= value >> 4; @@ -631,235 +122,152 @@ static int parity(int value) return (0x6996 >> value) & 1; } -static void decode_sdr_module_size(unsigned char *bytes, int *size) -{ - int i, k = 0; +static void decode_sdr_module_size(unsigned char *bytes, dmi_mem_size *size) { + unsigned short i, k = 0; i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17; - if (bytes[5] <= 8 && bytes[17] <= 8) { - k = bytes[5] * bytes[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; - } + if (size) { *size = (dmi_mem_size)k * (unsigned short)(1 << i); } } else { - if (size) { - *size = -1; - } + if (size) { *size = -1; } } } -static void decode_sdr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras) -{ +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; - } + if (bytes[18] & 1 << j) { cas[i++] = j + 1; } } - ctime = (bytes[9] >> 4 + bytes[9] & 0xf) * 0.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]; - } + 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) -{ +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; + 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"; + /* printf("%d\n", bytes[3]); */ + temp = NULL; } - if (bits) { - *bits = temp; - } + if (bits) { *bits = temp; } } -static void decode_sdr_module_col_address_bits(unsigned char *bytes, char **bits) -{ +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; + 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"; + /*printf("%d\n", bytes[4]); */ + temp = NULL; } - if (bits) { - *bits = temp; - } + 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_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) -{ +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]; - } + 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) -{ +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"; + 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 = NULL; } - if (signal_levels) { - *signal_levels = temp; - } + if (signal_levels) { *signal_levels = temp; } } -static void decode_sdr_module_configuration_type(unsigned char *bytes, char **module_config_type) -{ +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"; + case 0: temp = "No parity"; break; + case 1: temp = "Parity"; break; + case 2: temp = "ECC"; break; + default: temp = NULL; } - if (module_config_type) { - *module_config_type = temp; - } + if (module_config_type) { *module_config_type = temp; } } -static void decode_sdr_module_refresh_type(unsigned char *bytes, char **refresh_type) -{ +static void decode_sdr_module_refresh_type(unsigned char *bytes, char **refresh_type) { char *temp; if (bytes[12] & 0x80) { - temp = "Self refreshing"; + temp = "Self refreshing"; } else { - temp = "Not self refreshing"; + temp = "Not self refreshing"; } - if (refresh_type) { - *refresh_type = temp; - } + if (refresh_type) { *refresh_type = temp; } } -static void decode_sdr_module_refresh_rate(unsigned char *bytes, char **refresh_rate) -{ +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"; + 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 = NULL; } - if (refresh_rate) { - *refresh_rate = temp; + if (refresh_rate) { *refresh_rate = temp; } +} + +static void decode_sdr_module_detail(unsigned char *bytes, char *type_detail) { + bytes = bytes; /* silence unused warning */ + if (type_detail) { + snprintf(type_detail, 255, "SDR"); } } -static gchar *decode_sdr_sdram(unsigned char *bytes, int *size) -{ +static gchar *decode_sdr_sdram_extra(unsigned char *bytes) { 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); @@ -882,29 +290,30 @@ static gchar *decode_sdr_sdram(unsigned char *bytes, int *size) - 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); + /* expected to continue an [SPD] section */ + return g_strdup_printf("%s=%s\n" + "%s=%s\n" + "%s=%d\n" + "%s=%d bits\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s (%s)\n" + "[%s]\n" + "tCL=%.2f\n" + "tRCD=%.2f\n" + "tRP=%.2f\n" + "tRAS=%.2f\n", + _("Row address bits"), row_address_bits ? row_address_bits : _("(Unknown)"), + _("Column address bits"), col_address_bits ? col_address_bits : _("(Unknown)"), + _("Number of rows"), rows, + _("Data width"), data_width, + _("Interface signal levels"), signal_level ? signal_level : _("(Unknown)"), + _("Configuration type"), module_config_type ? module_config_type : _("(Unknown)"), + _("Refresh"), refresh_type, refresh_rate ? refresh_rate : _("Unknown"), + _("Timings"), tcl, trcd, trp, tras); } -static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pcclk) -{ +static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pcclk) { float temp, clk; int tbits, pc; @@ -912,601 +321,952 @@ static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pc clk = 2 * (1000 / temp); tbits = (bytes[7] * 256) + bytes[6]; - if (bytes[11] == 2 || bytes[11] == 1) { - tbits -= 8; - } + if (bytes[11] == 2 || bytes[11] == 1) { tbits -= 8; } pc = clk * tbits / 8; - if (pc % 100 > 50) { - pc += 100; - } + if (pc % 100 > 50) { pc += 100; } pc -= pc % 100; - if (ddrclk) - *ddrclk = (int) clk; + if (ddrclk) *ddrclk = (int)clk; - if (pcclk) - *pcclk = pc; + if (pcclk) *pcclk = pc; } -static void decode_ddr_module_size(unsigned char *bytes, int *size) -{ - int i, k; +static void decode_ddr_module_size(unsigned char *bytes, dmi_mem_size *size) { + unsigned short 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; - } + if (size) { *size = (dmi_mem_size)k * (unsigned short)(1 << i); } } else { - if (size) { - *size = -1; - } + if (size) { *size = -1; } } } -static void *decode_ddr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras) -{ +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; - } + 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); + *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); + *trp = (bytes[27] >> 2) + ((bytes[27] & 3) * 0.25); + *trp = ceil(*trp / ctime); } if (tras) { - *tras = bytes[30]; - *tras = ceil(*tras / ctime); + *tras = bytes[30]; + *tras = ceil(*tras / ctime); } - if (tcl) { - *tcl = highest_cas; - } + if (tcl) { *tcl = highest_cas; } } -static gchar *decode_ddr_sdram(unsigned char *bytes, int *size) -{ +static void decode_ddr_module_detail(unsigned char *bytes, char *type_detail) { float ddr_clock; - float tcl, trcd, trp, tras; int pc_speed; + if (type_detail) { + decode_ddr_module_speed(bytes, &ddr_clock, &pc_speed); + snprintf(type_detail, 255, "DDR-%.0f (PC-%d)", ddr_clock, pc_speed); + } +} + +static gchar *decode_ddr_sdram_extra(unsigned char *bytes) { + float tcl, trcd, trp, tras; - 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); + return g_strdup_printf("[%s]\n" + "tCL=%.2f\n" + "tRCD=%.2f\n" + "tRP=%.2f\n" + "tRAS=%.2f\n", + _("Timings"), tcl, trcd, trp, tras); } -static float decode_ddr2_module_ctime(unsigned char byte) -{ +static float decode_ddr2_module_ctime(unsigned char byte) { float ctime; ctime = (byte >> 4); byte &= 0xf; if (byte <= 9) { - ctime += byte * 0.1; + ctime += byte * 0.1; } else if (byte == 10) { - ctime += 0.25; + ctime += 0.25; } else if (byte == 11) { - ctime += 0.33; + ctime += 0.33; } else if (byte == 12) { - ctime += 0.66; + ctime += 0.66; } else if (byte == 13) { - ctime += 0.75; + ctime += 0.75; } return ctime; } -static void decode_ddr2_module_speed(unsigned char *bytes, float *ddr_clock, int *pc2_speed) -{ +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; - } + 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; - } + 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; +static void decode_ddr2_module_size(unsigned char *bytes, dmi_mem_size *size) { + unsigned short 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); - } + if (size) { *size = (dmi_mem_size)k * (unsigned short)(1 << i); } } else { - if (*size) { - *size = 0; - } + 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; - } +static void decode_ddr2_module_type(unsigned char *bytes, const char **type) { + switch (bytes[20]) { + case 0x01: *type = "RDIMM (Registered DIMM)"; break; + case 0x02: *type = "UDIMM (Unbuffered DIMM)"; break; + case 0x04: *type = "SO-DIMM (Small Outline DIMM)"; break; + case 0x06: *type = "72b-SO-CDIMM (Small Outline Clocked DIMM, 72-bit data bus)"; break; + case 0x07: *type = "72b-SO-RDIMM (Small Outline Registered DIMM, 72-bit data bus)"; break; + case 0x08: *type = "Micro-DIMM"; break; + case 0x10: *type = "Mini-RDIMM (Mini Registered DIMM)"; break; + case 0x20: *type = "Mini-UDIMM (Mini Unbuffered DIMM)"; break; + default: *type = NULL; } +} - ctime = decode_ddr2_module_ctime(bytes[9]); +static void decode_ddr2_module_timings(float ctime, unsigned char *bytes, float *trcd, float *trp, float *tras) { - if (trcd) { - *trcd = ceil(((bytes[29] >> 2) + ((bytes[29] & 3) * 0.25)) / ctime); - } + 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 (trp) { *trp = ceil(((bytes[27] >> 2) + ((bytes[27] & 3) * 0.25)) / ctime); } - if (tras) { - *tras = ceil(bytes[30] / ctime); + if (tras) { *tras = ceil(bytes[30] / ctime); } +} + +static gboolean decode_ddr2_module_ctime_for_casx(int casx_minus, unsigned char *bytes, float *ctime, float *tcl){ + int highest_cas, i, bytei; + float ctimev = 0; + + switch (casx_minus){ + case 0: + bytei = 9; + break; + case 1: + bytei = 23; + break; + case 2: + bytei = 25; + break; + default: + return FALSE; } - if (tcl) { - *tcl = highest_cas; + for (i = 0; i < 7; i++) { + if (bytes[18] & (1 << i)) { highest_cas = i; } } + + if ((bytes[18] & (1 << (highest_cas-casx_minus))) == 0) + return FALSE; + + ctimev = decode_ddr2_module_ctime(bytes[bytei]); + if (ctimev == 0) + return FALSE; + + if (tcl) { *tcl = highest_cas-casx_minus; } + if (ctime) { *ctime = ctimev; } + + return TRUE; } -static gchar *decode_ddr2_sdram(unsigned char *bytes, int *size) -{ +static void decode_ddr2_module_detail(unsigned char *bytes, char *type_detail) { float ddr_clock; - float trcd, trp, tras, tcl; int pc2_speed; + if (type_detail) { + decode_ddr2_module_speed(bytes, &ddr_clock, &pc2_speed); + snprintf(type_detail, 255, "DDR2-%.0f (PC2-%d)", ddr_clock, 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 gchar *decode_ddr2_sdram_extra(unsigned char *bytes) { + float trcd, trp, tras, ctime, tcl; + const char* voltage; + gchar *out; + int i; + + switch(bytes[8]){ + case 0x0: + voltage = "TTL/5 V tolerant"; + break; + case 0x1: + voltage = "LVTTL"; + break; + case 0x2: + voltage = "HSTL 1.5 V"; + break; + case 0x3: + voltage = "SSTL 3.3 V"; + break; + case 0x4: + voltage = "SSTL 2.5 V"; + break; + case 0x5: + voltage = "SSTL 1.8 V"; + break; + default: + voltage = _("(Unknown)"); + } + + /* expected to continue an [SPD] section */ + out = g_strdup_printf("%s=%s\n" + "[%s]\n", + _("Voltage"), voltage, + _("JEDEC Timings")); + + for (i = 0; i <= 2; i++) { + if (!decode_ddr2_module_ctime_for_casx(i, bytes, &ctime, &tcl)) + break; + decode_ddr2_module_timings(ctime, bytes, &trcd, &trp, &tras); + out = h_strdup_cprintf("DDR2-%d=%.0f-%.0f-%.0f-%.0f\n", + out, + (int)(2 * (1000 / ctime)), tcl, trcd, trp, tras); + } + + return out; } -static void decode_ddr3_module_speed(unsigned char *bytes, float *ddr_clock, int *pc3_speed) -{ +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; + 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 1: tbits = 16; break; + case 4: tbits = 32; break; case 3: - case 0xb: - tbits = 64; - break; + 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; - } + 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_size(unsigned char *bytes, dmi_mem_size *size) { + unsigned int sdr_capacity = 256 << (bytes[4] & 0xF); + unsigned int sdr_width = 4 << (bytes[7] & 0x7); + unsigned int bus_width = 8 << (bytes[8] & 0x7); + unsigned int ranks = 1 + ((bytes[7] >> 3) & 0x7); + + *size = (dmi_mem_size)sdr_capacity / 8 * bus_width / sdr_width * ranks; } -static void decode_ddr3_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras, float *tcl) -{ +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; + float taa; - if (bytes[10] == 1 && bytes[11] == 8) - mtb = 0.125; - if (bytes[10] == 1 && bytes[11] == 15) - mtb = 0.0625; + if (bytes[10] == 1 && bytes[11] == 8) mtb = 0.125; + if (bytes[10] == 1 && bytes[11] == 15) mtb = 0.0625; ctime = mtb * bytes[12]; + taa = bytes[16] * mtb; - 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 (trcd) { *trcd = bytes[18] * mtb; } - if (trp) { - *trp = bytes[20] * mtb; - } + if (trp) { *trp = bytes[20] * mtb; } - if (tras) { - *tras = (bytes[22] + bytes[21] & 0xf) * mtb; - } + if (tras) { *tras = (bytes[22] + (bytes[21] & 0xf)) * mtb; } - if (tcl) { - *tcl = highest_cas; - } + if (tcl) { *tcl = ceil(taa/ctime); } } -static void decode_ddr3_module_type(unsigned char *bytes, const char **type) -{ +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"; + 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 = NULL; } } -static gchar *decode_ddr3_sdram(unsigned char *bytes, int *size) -{ +static void decode_ddr3_module_detail(unsigned char *bytes, char *type_detail) { float ddr_clock; - float trcd, trp, tras, tcl; int pc3_speed; - const char *type; + if (type_detail) { + decode_ddr3_module_speed(bytes, &ddr_clock, &pc3_speed); + snprintf(type_detail, 255, "DDR3-%.0f (PC3-%d)", ddr_clock, pc3_speed); + } +} + +static gchar *decode_ddr3_sdram_extra(unsigned char *bytes) { + float trcd, trp, tras, tcl; - 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); + + int ranks = 1 + ((bytes[7] >> 3) & 0x7); + int pins = 4 << (bytes[7] & 0x7); + int die_count = (bytes[33] >> 4) & 0x7; + int ts = !!(bytes[32] & 0x80); + + /* expected to continue an [SPD] section */ + return g_strdup_printf("%s=%d\n" + "%s=%d\n" + "%s=%d %s\n" + "%s=[%02x] %s\n" + "%s=%s%s%s\n" + "%s=" + "%s%s%s%s%s%s%s%s" + "%s%s%s%s%s%s%s\n" + "[%s]\n" + "tCL=%.0f\n" + "tRCD=%.3fns\n" + "tRP=%.3fns\n" + "tRAS=%.3fns\n", + _("Ranks"), ranks, + _("IO Pins per Chip"), pins, + _("Die count"), die_count, die_count ? "" : _("(Unspecified)"), + _("Thermal Sensor"), bytes[32], ts ? _("Present") : _("Not present"), + _("Supported Voltages"), + (bytes[6] & 4) ? "1.25V " : "", + (bytes[6] & 2) ? "1.35V " : "", + (bytes[6] & 1) ? "" : "1.5V", + _("Supported CAS Latencies"), + (bytes[15] & 0x40) ? "18 " : "", + (bytes[15] & 0x20) ? "17 " : "", + (bytes[15] & 0x10) ? "16 " : "", + (bytes[15] & 0x08) ? "15 " : "", + (bytes[15] & 0x04) ? "14 " : "", + (bytes[15] & 0x02) ? "13 " : "", + (bytes[15] & 0x01) ? "12 " : "", + (bytes[14] & 0x80) ? "11 " : "", + (bytes[14] & 0x40) ? "10 " : "", + (bytes[14] & 0x20) ? "9 " : "", + (bytes[14] & 0x10) ? "8 " : "", + (bytes[14] & 0x08) ? "7 " : "", + (bytes[14] & 0x04) ? "6 " : "", + (bytes[14] & 0x02) ? "5 " : "", + (bytes[14] & 0x01) ? "4" : "", + _("Timings"), tcl, trcd, trp, tras + ); } -static void decode_ddr3_part_number(unsigned char *bytes, char *part_number) -{ +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'; + 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"; +static void decode_ddr34_manufacturer(unsigned char count, unsigned char code, char **manufacturer, int *bank, int *index) { + if (!manufacturer) return; + + if (code == 0x00 || code == 0xFF) { + *manufacturer = NULL; + return; + } + + if (parity(count) != 1 || parity(code) != 1) { + *manufacturer = _("Invalid"); + return; + } - end: - if (manufacturer) { - *manufacturer = out; + *bank = count & 0x7f; + *index = code & 0x7f; + if (*bank >= VENDORS_BANKS) { + *manufacturer = NULL; + return; } + + *manufacturer = (char *)JEDEC_MFG_STR(*bank, *index - 1); +} + +static void decode_ddr3_manufacturer(unsigned char *bytes, char **manufacturer, int *bank, int *index) { + decode_ddr34_manufacturer(bytes[117], bytes[118], (char **) manufacturer, bank, index); } -static void decode_module_manufacturer(unsigned char *bytes, char **manufacturer) -{ +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; + out = "Undefined"; + goto end; } - do { - ai++; - } while ((--len && (*bytes++ == 0x7f))); + do { ai++; } while ((--len && (*bytes++ == 0x7f))); first = *--bytes; if (ai == 0) { - out = "Invalid"; - goto end; + out = "Invalid"; + goto end; } if (parity(first) != 1) { - out = "Invalid"; - goto end; + out = "Invalid"; + goto end; } - out = (char *) vendors[ai - 1][(first & 0x7f) - 1]; + out = (char*)JEDEC_MFG_STR(ai - 1, (first & 0x7f) - 1); - end: - if (manufacturer) { - *manufacturer = out; - } +end: + if (manufacturer) { *manufacturer = out; } } -static void decode_module_part_number(unsigned char *bytes, char *part_number) -{ +static void decode_module_part_number(unsigned char *bytes, char *part_number) { if (part_number) { - bytes += 8 + 64; + bytes += 8 + 64; + + while (*++bytes && *bytes >= 32 && *bytes < 127) { *part_number++ = *bytes; } + *part_number = '\0'; + } +} + +static char *print_spd_timings(int speed, float cas, float trcd, float trp, float tras, + float ctime) { + return g_strdup_printf("DDR4-%d=%.0f-%.0f-%.0f-%.0f\n", speed, cas, ceil(trcd / ctime - 0.025), + ceil(trp / ctime - 0.025), ceil(tras / ctime - 0.025)); +} + +static void decode_ddr4_module_type(unsigned char *bytes, const char **type) { + switch (bytes[3]) { + case 0x01: *type = "RDIMM (Registered DIMM)"; break; + case 0x02: *type = "UDIMM (Unbuffered DIMM)"; break; + case 0x03: *type = "SODIMM (Small Outline Unbuffered DIMM)"; break; + case 0x04: *type = "LRDIMM (Load-Reduced DIMM)"; break; + case 0x05: *type = "Mini-RDIMM (Mini Registered DIMM)"; break; + case 0x06: *type = "Mini-UDIMM (Mini Unbuffered DIMM)"; break; + case 0x08: *type = "72b-SO-RDIMM (Small Outline Registered DIMM, 72-bit data bus)"; break; + case 0x09: *type = "72b-SO-UDIMM (Small Outline Unbuffered DIMM, 72-bit data bus)"; break; + case 0x0c: *type = "16b-SO-UDIMM (Small Outline Unbuffered DIMM, 16-bit data bus)"; break; + case 0x0d: *type = "32b-SO-UDIMM (Small Outline Unbuffered DIMM, 32-bit data bus)"; break; + default: *type = NULL; + } +} + +static float ddr4_mtb_ftb_calc(unsigned char b1, signed char b2) { + float mtb = 0.125; + float ftb = 0.001; + return b1 * mtb + b2 * ftb; +} + +static void decode_ddr4_module_speed(unsigned char *bytes, float *ddr_clock, int *pc4_speed) { + float ctime; + float ddrclk; + int tbits, pcclk; + + ctime = ddr4_mtb_ftb_calc(bytes[18], bytes[125]); + ddrclk = 2 * (1000 / ctime); + tbits = 8 << (bytes[13] & 7); + + pcclk = ddrclk * tbits / 8; + pcclk -= pcclk % 100; + + if (ddr_clock) { *ddr_clock = (int)ddrclk; } + if (pc4_speed) { *pc4_speed = pcclk; } +} + +static void decode_ddr4_module_spd_timings(unsigned char *bytes, float speed, char **str) { + float ctime, ctime_max, pctime, taa, trcd, trp, tras; + int pcas, best_cas, base_cas, ci, i, j; + unsigned char cas_support[] = {bytes[20], bytes[21], bytes[22], bytes[23] & 0x1f}; + float possible_ctimes[] = {15 / 24.0, 15 / 22.0, 15 / 20.0, 15 / 18.0, + 15 / 16.0, 15 / 14.0, 15 / 12.0}; + + base_cas = bytes[23] & 0x80 ? 23 : 7; + + ctime = ddr4_mtb_ftb_calc(bytes[18], bytes[125]); + ctime_max = ddr4_mtb_ftb_calc(bytes[19], bytes[124]); + + taa = ddr4_mtb_ftb_calc(bytes[24], bytes[123]); + trcd = ddr4_mtb_ftb_calc(bytes[25], bytes[122]); + trp = ddr4_mtb_ftb_calc(bytes[26], bytes[121]); + tras = (((bytes[27] & 0x0f) << 8) + bytes[28]) * 0.125; + + *str = print_spd_timings((int)speed, ceil(taa / ctime - 0.025), trcd, trp, tras, ctime); + + for (ci = 0; ci < 7; ci++) { + best_cas = 0; + pctime = possible_ctimes[ci]; + + for (i = 3; i >= 0; i--) { + for (j = 7; j >= 0; j--) { + if ((cas_support[i] & (1 << j)) != 0) { + pcas = base_cas + 8 * i + j; + if (ceil(taa / pctime) - 0.025 <= pcas) { best_cas = pcas; } + } + } + } + + if (best_cas > 0 && pctime <= ctime_max && pctime >= ctime) { + *str = h_strdup_cprintf( + "%s\n", *str, + print_spd_timings((int)(2000.0 / pctime), best_cas, trcd, trp, tras, pctime)); + } + } +} + +static void decode_ddr4_module_size(unsigned char *bytes, dmi_mem_size *size) { + int sdrcap = 256 << (bytes[4] & 15); + int buswidth = 8 << (bytes[13] & 7); + int sdrwidth = 4 << (bytes[12] & 7); + int signal_loading = bytes[6] & 3; + int lranks_per_dimm = ((bytes[12] >> 3) & 7) + 1; + + if (signal_loading == 2) lranks_per_dimm *= ((bytes[6] >> 4) & 7) + 1; + + *size = (dmi_mem_size)sdrcap / 8 * buswidth / sdrwidth * lranks_per_dimm; +} + + +static void decode_ddr234_module_date(unsigned char weekb, unsigned char yearb, int *week, int *year) { + if (yearb == 0x0 || yearb == 0xff || + weekb == 0x0 || weekb == 0xff) { + return; + } + *week = (weekb>>4) & 0xf; + *week *= 10; + *week += weekb & 0xf; + *year = (yearb>>4) & 0xf; + *year *= 10; + *year += yearb & 0xf; + *year += 2000; +} + +static void decode_ddr2_module_date(unsigned char *bytes, int *week, int *year) { + decode_ddr234_module_date(bytes[94], bytes[93], week, year); +} - while (*bytes++ && *bytes >= 32 && *bytes < 127) { - *part_number++ = *bytes; - } - *part_number = '\0'; +static void decode_ddr3_module_date(unsigned char *bytes, int *week, int *year) { + decode_ddr234_module_date(bytes[121], bytes[120], week, year); +} + +static void decode_ddr4_module_date(unsigned char *bytes, int spd_size, int *week, int *year) { + if (spd_size < 324) + return; + decode_ddr234_module_date(bytes[324], bytes[323], week, year); +} + +static void decode_ddr3_dram_manufacturer(unsigned char *bytes, + char **manufacturer, int *bank, int *index) { + decode_ddr34_manufacturer(bytes[94], bytes[95], (char **) manufacturer, bank, index); +} + +static void decode_ddr4_dram_manufacturer(unsigned char *bytes, int spd_size, + char **manufacturer, int *bank, int *index) { + if (spd_size < 351) { + *manufacturer = NULL; + return; + } + + decode_ddr34_manufacturer(bytes[350], bytes[351], (char **) manufacturer, bank, index); +} + +static void detect_ddr4_xmp(unsigned char *bytes, int spd_size, int *majv, int *minv) { + if (spd_size < 387) + return; + + *majv = 0; *minv = 0; + + if (bytes[384] != 0x0c || bytes[385] != 0x4a) // XMP magic number + return; + + if (majv) + *majv = bytes[387] >> 4; + if (minv) + *minv = bytes[387] & 0xf; +} + +static void decode_ddr4_xmp(unsigned char *bytes, int spd_size, char **str) { + float ctime; + float ddrclk, taa, trcd, trp, tras; + + if (spd_size < 405) + return; + + ctime = ddr4_mtb_ftb_calc(bytes[396], bytes[431]); + ddrclk = 2 * (1000 / ctime); + taa = ddr4_mtb_ftb_calc(bytes[401], bytes[430]); + trcd = ddr4_mtb_ftb_calc(bytes[402], bytes[429]); + trp = ddr4_mtb_ftb_calc(bytes[403], bytes[428]); + tras = (((bytes[404] & 0x0f) << 8) + bytes[405]) * 0.125; + + *str = g_strdup_printf("[%s]\n" + "%s=DDR4 %d MHz\n" + "%s=%d.%d V\n" + "[%s]\n" + "%s", + _("XMP Profile"), + _("Speed"), (int) ddrclk, + _("Voltage"), bytes[393] >> 7, bytes[393] & 0x7f, + _("XMP Timings"), + print_spd_timings((int) ddrclk, ceil(taa/ctime - 0.025), trcd, trp, tras, ctime)); +} + +static void decode_ddr4_module_detail(unsigned char *bytes, char *type_detail) { + float ddr_clock; + int pc4_speed; + if (type_detail) { + decode_ddr4_module_speed(bytes, &ddr_clock, &pc4_speed); + snprintf(type_detail, 255, "DDR4-%.0f (PC4-%d)", ddr_clock, pc4_speed); + } +} + +static gchar *decode_ddr4_sdram_extra(unsigned char *bytes, int spd_size) { + float ddr_clock; + int pc4_speed, xmp_majv = -1, xmp_minv = -1; + char *speed_timings = NULL, *xmp_profile = NULL, *xmp = NULL, *manf_date = NULL; + static gchar *out; + + decode_ddr4_module_speed(bytes, &ddr_clock, &pc4_speed); + decode_ddr4_module_spd_timings(bytes, ddr_clock, &speed_timings); + detect_ddr4_xmp(bytes, spd_size, &xmp_majv, &xmp_minv); + + if (xmp_majv == -1 && xmp_minv == -1) { + xmp = NULL; + } + else if (xmp_majv <= 0 && xmp_minv <= 0) { + xmp = g_strdup(_("No")); + } + else { + xmp = g_strdup_printf("%s (revision %d.%d)", _("Yes"), xmp_majv, xmp_minv); + if (xmp_majv == 2 && xmp_minv == 0) + decode_ddr4_xmp(bytes, spd_size, &xmp_profile); + } + + /* expected to continue an [SPD] section */ + out = g_strdup_printf("%s=%s\n" + "%s=%s\n" + "[%s]\n" + "%s\n" + "%s", + _("Voltage"), bytes[11] & 0x01 ? "1.2 V": _("(Unknown)"), + _("XMP"), xmp ? xmp : _("(Unknown)"), + _("JEDEC Timings"), speed_timings, + xmp_profile ? xmp_profile: ""); + + g_free(speed_timings); + g_free(manf_date); + g_free(xmp); + g_free(xmp_profile); + + return out; +} + +static void decode_ddr4_part_number(unsigned char *bytes, int spd_size, char *part_number) { + int i; + if (!part_number) return; + + if (spd_size < 348) { + *part_number++ = '\0'; + return; } + + for (i = 329; i <= 348; i++) + *part_number++ = bytes[i]; + *part_number = '\0'; +} + +static void decode_ddr4_module_manufacturer(unsigned char *bytes, int spd_size, + char **manufacturer, int *bank, int *index) { + if (spd_size < 321) { + *manufacturer = NULL; + return; + } + + decode_ddr34_manufacturer(bytes[320], bytes[321], manufacturer, bank, index); } -static int decode_ram_type(unsigned char *bytes) -{ +static int decode_ram_type(unsigned char *bytes) { if (bytes[0] < 4) { - switch (bytes[2]) { - case 1: - return DIRECT_RAMBUS; - case 17: - return RAMBUS; - } + 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; - } + 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; + case 12: return DDR4_SDRAM; + } } return UNKNOWN; } -static void read_spd(char *spd_path, int offset, size_t size, int use_sysfs, unsigned char *bytes_out) -{ +static int read_spd(char *spd_path, int offset, size_t size, int use_sysfs, + unsigned char *bytes_out) { + int data_size = 0; if (use_sysfs) { - FILE *spd; - gchar *temp_path; + 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); - } + temp_path = g_strdup_printf("%s/eeprom", spd_path); + if ((spd = fopen(temp_path, "rb"))) { + fseek(spd, offset, SEEK_SET); + data_size = fread(bytes_out, 1, size, spd); + fclose(spd); + } - g_free(temp_path); + g_free(temp_path); } else { - int i; + int i; - for (i = 0; i <= 3; i++) { - FILE *spd; - char *temp_path; + 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); - } + temp_path = g_strdup_printf("%s/%02x", spd_path, offset + i * 16); + if ((spd = fopen(temp_path, "rb"))) { + data_size += fread(bytes_out + i * 16, 1, 16, spd); + fclose(spd); + } - g_free(temp_path); - } + g_free(temp_path); + } } + + return data_size; } -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); +static GSList *decode_dimms2(GSList *eeprom_list, const gchar *driver, gboolean use_sysfs, int max_size) { + GSList *eeprom, *dimm_list = NULL; + int count = 0; + int spd_size = 0; + unsigned char bytes[512] = {0}; + spd_data *s = NULL; + + for (eeprom = eeprom_list; eeprom; eeprom = eeprom->next, count++) { + gchar *spd_path = (gchar*)eeprom->data; + s = NULL; + + RamType ram_type; + + memset(bytes, 0, 512); /* clear */ + spd_size = read_spd(spd_path, 0, max_size, use_sysfs, bytes); + ram_type = decode_ram_type(bytes); + + switch (ram_type) { + case SDR_SDRAM: + s = spd_data_new(); + memcpy(s->bytes, bytes, 512); + decode_module_part_number(bytes, s->partno); + decode_module_manufacturer(bytes + 64, (char**)&s->vendor_str); + decode_sdr_module_size(bytes, &s->size_MiB); + decode_sdr_module_detail(bytes, s->type_detail); + break; + case DDR_SDRAM: + s = spd_data_new(); + memcpy(s->bytes, bytes, 512); + decode_module_part_number(bytes, s->partno); + decode_module_manufacturer(bytes + 64, (char**)&s->vendor_str); + decode_ddr_module_size(bytes, &s->size_MiB); + decode_ddr_module_detail(bytes, s->type_detail); + break; + case DDR2_SDRAM: + s = spd_data_new(); + memcpy(s->bytes, bytes, 512); + decode_module_part_number(bytes, s->partno); + decode_module_manufacturer(bytes + 64, (char**)&s->vendor_str); + decode_ddr2_module_size(bytes, &s->size_MiB); + decode_ddr2_module_detail(bytes, s->type_detail); + decode_ddr2_module_type(bytes, &s->form_factor); + decode_ddr2_module_date(bytes, &s->week, &s->year); + break; + case DDR3_SDRAM: + s = spd_data_new(); + memcpy(s->bytes, bytes, 512); + decode_ddr3_part_number(bytes, s->partno); + decode_ddr3_manufacturer(bytes, (char**)&s->vendor_str, + &s->vendor_bank, &s->vendor_index); + decode_ddr3_dram_manufacturer(bytes, (char**)&s->dram_vendor_str, + &s->dram_vendor_bank, &s->dram_vendor_index); + decode_ddr3_module_size(bytes, &s->size_MiB); + decode_ddr3_module_type(bytes, &s->form_factor); + decode_ddr3_module_detail(bytes, s->type_detail); + decode_ddr3_module_date(bytes, &s->week, &s->year); + break; + case DDR4_SDRAM: + s = spd_data_new(); + memcpy(s->bytes, bytes, 512); + decode_ddr4_part_number(bytes, spd_size, s->partno); + decode_ddr4_module_manufacturer(bytes, spd_size, (char**)&s->vendor_str, + &s->vendor_bank, &s->vendor_index); + decode_ddr4_dram_manufacturer(bytes, spd_size, (char**)&s->dram_vendor_str, + &s->dram_vendor_bank, &s->dram_vendor_index); + decode_ddr4_module_size(bytes, &s->size_MiB); + decode_ddr4_module_type(bytes, &s->form_factor); + decode_ddr4_module_detail(bytes, s->type_detail); + decode_ddr4_module_date(bytes, spd_size, &s->week, &s->year); + s->ddr4_no_ee1004 = s->ddr4_no_ee1004 || (spd_size < 512); + spd_ddr4_partial_data = spd_ddr4_partial_data || s->ddr4_no_ee1004; + break; + case UNKNOWN: + break; + default: + DEBUG("Unsupported EEPROM type: %s for %s\n", GET_RAM_TYPE_STR(ram_type), spd_path); continue; + if (ram_type) { + /* some kind of RAM that we can't decode, but exists */ + s = spd_data_new(); + memcpy(s->bytes, bytes, 512); + } + } + + if (s) { + strncpy(s->dev, g_basename(spd_path), 31); + s->spd_driver = driver; + s->spd_size = spd_size; + s->type = ram_type; + spd_ram_types |= (1 << (ram_type-1)); + switch (ram_type) { + case SDR_SDRAM: + case DDR_SDRAM: + case DDR2_SDRAM: + s->spd_rev_major = bytes[62] >> 4; + s->spd_rev_minor = bytes[62] & 0xf; + break; + case DDR3_SDRAM: + case DDR4_SDRAM: + s->spd_rev_major = bytes[1] >> 4; + s->spd_rev_minor = bytes[1] & 0xf; + break; + } + s->vendor = vendor_match(s->vendor_str, NULL); + s->dram_vendor = vendor_match(s->dram_vendor_str, NULL); + dimm_list = g_slist_append(dimm_list, s); + } } - return g_string_free(output, FALSE); + return dimm_list; } -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); - } +struct SpdDriver { + const char *driver; + const char *dir_path; + const gint max_size; + const gboolean use_sysfs; + const char *spd_name; +}; - 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; +static const struct SpdDriver spd_drivers[] = { + { "ee1004", "/sys/bus/i2c/drivers/ee1004", 512, TRUE, "ee1004"}, + { "at24", "/sys/bus/i2c/drivers/at24" , 256, TRUE, "spd"}, + { "eeprom", "/sys/bus/i2c/drivers/eeprom", 256, TRUE, "eeprom"}, + { "eeprom-proc", "/proc/sys/dev/sensors" , 256, FALSE, NULL}, + { NULL } +}; + +GSList *spd_scan() { + GDir *dir = NULL; + GSList *eeprom_list = NULL, *dimm_list = NULL; + gchar *dimm_list_entry, *dir_entry, *name_file, *name; + const struct SpdDriver *driver; + gboolean driver_found = FALSE; + gboolean is_spd = FALSE; + + spd_ddr4_partial_data = FALSE; + spd_no_driver = FALSE; + spd_no_support = FALSE; + + for (driver = spd_drivers; driver->dir_path; driver++) { + if (g_file_test(driver->dir_path, G_FILE_TEST_EXISTS)) { + dir = g_dir_open(driver->dir_path, 0, NULL); + if (!dir) continue; + + driver_found = TRUE; + while ((dir_entry = (char *)g_dir_read_name(dir))) { + is_spd = FALSE; + + if (driver->use_sysfs) { + name_file = NULL; + name = NULL; + + if (isdigit(dir_entry[0])) { + name_file = g_build_filename(driver->dir_path, dir_entry, "name", NULL); + g_file_get_contents(name_file, &name, NULL, NULL); + + is_spd = g_strcmp0(name, driver->spd_name); + + g_free(name_file); + g_free(name); + } + } + else { + is_spd = g_str_has_prefix(dir_entry, "eeprom-"); + } + + if (is_spd){ + dimm_list_entry = g_strdup_printf("%s/%s", driver->dir_path, dir_entry); + eeprom_list = g_slist_prepend(eeprom_list, dimm_list_entry); + } + } + + g_dir_close(dir); + + if (eeprom_list) { + dimm_list = decode_dimms2(eeprom_list, driver->driver, driver->use_sysfs, driver->max_size); + g_slist_free(eeprom_list); + eeprom_list = NULL; + } + if (dimm_list) break; + } } - 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)); - } + if (!driver_found) { + if (!g_file_test("/sys/module/eeprom", G_FILE_TEST_EXISTS) && + !g_file_test("/sys/module/at24", G_FILE_TEST_EXISTS)) { + spd_no_driver = TRUE; /* trigger hinote for no eeprom driver */ + } else { + spd_no_support = TRUE; /* trigger hinote for unsupported system */ + } } - 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("[%s]\n" - "%s\n" - "[$ShellParam$]\n" - "ViewType=1\n" - "ColumnTitle$TextValue=%s\n" /* Bank */ - "ColumnTitle$Extra1=%s\n" /* Size */ - "ColumnTitle$Extra2=%s\n" /* Manufacturer */ - "ColumnTitle$Value=%s\n" /* Model */ - "ShowColumnHeaders=true\n", - _("SPD"), list, - _("Bank"), _("Size"), _("Manufacturer"), _("Model") ); - g_free(list); + return dimm_list; } diff --git a/modules/devices/spd-vendors.c b/modules/devices/spd-vendors.c new file mode 100644 index 00000000..80b2a6a4 --- /dev/null +++ b/modules/devices/spd-vendors.c @@ -0,0 +1,292 @@ +/* + * spd-decode.c, spd-vendors.c + * Copyright (c) 2010 L. A. F. Pereira + * modified by Ondrej Čerman (2019) + * modified by Burt P. (2019) + * + * 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. + */ + +/* from decode-dimms, in the i2c-tools package: + * https://github.com/angeloc/i2c-tools/blob/master/eeprom/decode-dimms + * + * STANDARD MANUFACTURERS IDENTIFICATION CODEs + * as defined in JEP106 + * + * As of: 28 June 2019 + * + */ + +#define VENDORS_BANKS 8 +#define VENDORS_ITEMS 128 +#define JEDEC_MFG_STR(b,i) ( (b >= 0 && b < VENDORS_BANKS && i < VENDORS_ITEMS) ? vendors[(b)][(i)] : NULL ) +static const char* vendors[VENDORS_BANKS][VENDORS_ITEMS] = +{ +{"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", + "SK Hynix (former 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", "Oracle Corporation (former Sun Microsystems)", "Silicon Storage Technology", "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", + "Integrated 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", "Numonyx Corporation (former Level One Communication)"}, +{"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"}, +{"Camintonn Corporation", "ISOA Incorporated", "Agate Semiconductor", "ADMtek Incorporated", + "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies", "Ardent Technologies", + "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies", "WorkX AG (Wichman)", + "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 SA (former 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"}, +{"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 - Ultron AG (former Memorysolution GmbH)", "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", + "Scaleo Chip (former 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"}, +{"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", "Scaleo Chip (former 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", "Parker Vision, Inc. (former 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 Electronics (former 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"}, +{"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", "Terra Semiconductor Inc. (former 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"}, +{"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.", "Andes Technology Corporation", "Coronis Systems", + "Achronix Semiconductor", "Siano Mobile Silicon Ltd.", "Semtech Corporation", "Pixelworks Inc.", + "Gaisler Research AB", "Teranetics", "Toppan Printing Co. Ltd.", "Kingxcon", + "Silicon Integrated Systems", "I-O Data Device, Inc.", "NDS Americas Inc.", "Solomon Systech Limited", + "On Demand Microelectronics", "Amicus Wireless Inc.", "SMARDTV SNC", "Comsys Communication Ltd.", + "Movidia Ltd.", "Javad GNSS, Inc.", "Montage Technology Group", "Trident Microsystems", "Super Talent", + "Optichron, Inc.", "Future Waves UK Ltd.", "SiBEAM, Inc.", "Inicore, Inc.", "Virident Systems", + "M2000, Inc.", "ZeroG Wireless, Inc.", "Gingle Technology Co. Ltd.", "Space Micro Inc.", "Wilocity", + "Novafora, Inc.", "iKoa Corporation", "ASint Technology", "Ramtron", "Plato Networks Inc.", + "IPtronics AS", "Infinite-Memories", "Parade Technologies Inc.", "Dune Networks", + "GigaDevice Semiconductor", "Modu Ltd.", "CEITEC", "Northrop Grumman", "XRONET Corporation", + "Sicon Semiconductor AB", "Atla Electronics Co. Ltd.", "TOPRAM Technology", "Silego Technology Inc.", + "Kinglife", "Ability Industries Ltd.", "Silicon Power Computer & Communications", + "Augusta Technology, Inc.", "Nantronics Semiconductors", "Hilscher Gesellschaft", "Quixant Ltd.", + "Percello Ltd.", "NextIO Inc.", "Scanimetrics Inc.", "FS-Semi Company Ltd.", "Infinera Corporation", + "SandForce Inc.", "Lexar Media", "Teradyne Inc.", "Memory Exchange Corp.", "Suzhou Smartek Electronics", + "Avantium Corporation", "ATP Electronics Inc.", "Valens Semiconductor Ltd", "Agate Logic, Inc.", + "Netronome", "Zenverge, Inc.", "N-trig Ltd", "SanMax Technologies Inc.", "Contour Semiconductor Inc.", + "TwinMOS", "Silicon Systems, Inc.", "V-Color Technology Inc.", "Certicom Corporation", "JSC ICC Milandr", + "PhotoFast Global Inc.", "InnoDisk Corporation", "Muscle Power", "Energy Micro", "Innofidei", + "CopperGate Communications", "Holtek Semiconductor Inc.", "Myson Century, Inc.", "FIDELIX", + "Red Digital Cinema", "Densbits Technology", "Zempro", "MoSys", "Provigent", "Triad Semiconductor, Inc."}, +{"Siklu Communication Ltd.", "A Force Manufacturing Ltd.", "Strontium", "Abilis Systems", "Siglead, Inc.", + "Ubicom, Inc.", "Unifosa Corporation", "Stretch, Inc.", "Lantiq Deutschland GmbH", "Visipro", + "EKMemory", "Microelectronics Institute ZTE", "Cognovo Ltd.", "Carry Technology Co. Ltd.", "Nokia", + "King Tiger Technology", "Sierra Wireless", "HT Micron", "Albatron Technology Co. Ltd.", + "Leica Geosystems AG", "BroadLight", "AEXEA", "ClariPhy Communications, Inc.", "Green Plug", + "Design Art Networks", "Mach Xtreme Technology Ltd.", "ATO Solutions Co. Ltd.", "Ramsta", + "Greenliant Systems, Ltd.", "Teikon", "Antec Hadron", "NavCom Technology, Inc.", + "Shanghai Fudan Microelectronics", "Calxeda, Inc.", "JSC EDC Electronics", "Kandit Technology Co. Ltd.", + "Ramos Technology", "Goldenmars Technology", "XeL Technology Inc.", "Newzone Corporation", + "ShenZhen MercyPower Tech", "Nanjing Yihuo Technology", "Nethra Imaging Inc.", "SiTel Semiconductor BV", + "SolidGear Corporation", "Topower Computer Ind Co Ltd.", "Wilocity", "Profichip GmbH", + "Gerad Technologies", "Ritek Corporation", "Gomos Technology Limited", "Memoright Corporation", + "D-Broad, Inc.", "HiSilicon Technologies", "Syndiant Inc.", "Enverv Inc.", "Cognex", + "Xinnova Technology Inc.", "Ultron AG", "Concord Idea Corporation", "AIM Corporation", + "Lifetime Memory Products", "Ramsway", "Recore Systems BV", "Haotian Jinshibo Science Tech", + "Being Advanced Memory", "Adesto Technologies", "Giantec Semiconductor, Inc.", "HMD Electronics AG", + "Gloway International (HK)", "Kingcore", "Anucell Technology Holding", + "Accord Software & Systems Pvt. Ltd.", "Active-Semi Inc.", "Denso Corporation", "TLSI Inc.", + "Shenzhen Daling Electronic Co. Ltd.", "Mustang", "Orca Systems", "Passif Semiconductor", + "GigaDevice Semiconductor (Beijing) Inc.", "Memphis Electronic", "Beckhoff Automation GmbH", + "Harmony Semiconductor Corp (former ProPlus Design Solutions)", "Air Computers SRL", "TMT Memory", + "Eorex Corporation", "Xingtera", "Netsol", "Bestdon Technology Co. Ltd.", "Baysand Inc.", + "Uroad Technology Co. Ltd. (former Triple Grow Industrial Ltd.)", "Wilk Elektronik S.A.", + "AAI", "Harman", "Berg Microelectronics Inc.", "ASSIA, Inc.", "Visiontek Products LLC", + "OCMEMORY", "Welink Solution Inc.", "Shark Gaming", "Avalanche Technology", + "R&D Center ELVEES OJSC", "KingboMars Technology Co. Ltd.", + "High Bridge Solutions Industria Eletronica", "Transcend Technology Co. Ltd.", + "Everspin Technologies", "Hon-Hai Precision", "Smart Storage Systems", "Toumaz Group", + "Zentel Electronics Corporation", "Panram International Corporation", + "Silicon Space Technology"} +}; diff --git a/modules/devices/storage.c b/modules/devices/storage.c index 0c393682..bbf9b195 100644 --- a/modules/devices/storage.c +++ b/modules/devices/storage.c @@ -1,10 +1,11 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> + * modified by Ondrej Čerman (2019-2021) * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,12 +21,464 @@ #include "hardinfo.h" #include "devices.h" +#include "udisks2_util.h" +#include "storage_util.h" + +#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)"); gchar *storage_icons = NULL; +gchar *nvme_pci_sections(pcid *p) { + const gchar *vendor, *svendor, *product, *sproduct; + + if (!p) return NULL; + + vendor = UNKIFNULL_AC(p->vendor_id_str); + svendor = UNKIFNULL_AC(p->sub_vendor_id_str); + product = UNKIFNULL_AC(p->device_id_str); + sproduct = UNKIFNULL_AC(p->sub_device_id_str); + + gchar *vendor_device_str; + if (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id) { + vendor_device_str = g_strdup_printf("[%s]\n" + /* Vendor */ "$^$%s=[%04x] %s\n" + /* Device */ "%s=[%04x] %s\n", + _("NVMe Controller"), + _("Vendor"), p->vendor_id, vendor, + _("Device"), p->device_id, product); + } else { + vendor_device_str = g_strdup_printf("[%s]\n" + /* Vendor */ "$^$%s=[%04x] %s\n" + /* Device */ "%s=[%04x] %s\n" + /* Sub-device vendor */ "$^$%s=[%04x] %s\n" + /* Sub-device */ "%s=[%04x] %s\n", + _("NVMe Controller"), + _("Vendor"), p->vendor_id, vendor, + _("Device"), p->device_id, product, + _("SVendor"), p->sub_vendor_id, svendor, + _("SDevice"), p->sub_device_id, sproduct); + } + + gchar *pcie_str; + if (p->pcie_width_curr) { + pcie_str = g_strdup_printf("[%s]\n" + /* Addy */ "%s=PCI/%s\n" + /* Width (max) */ "%s=x%u\n" + /* Speed (max) */ "%s=%0.1f %s\n", + _("PCI Express"), + _("Location"), p->slot_str, + _("Maximum Link Width"), p->pcie_width_max, + _("Maximum Link Speed"), p->pcie_speed_max, _("GT/s") ); + } else + pcie_str = strdup(""); + + gchar *ret = g_strdup_printf("%s%s", vendor_device_str, pcie_str); + g_free(vendor_device_str); + g_free(pcie_str); + return ret; +} + +gboolean __scan_udisks2_devices(void) { + GSList *node, *drives; + u2driveext *ext; + udiskd *disk; + udiskp *part; + udisksa *attrib; + gchar *udisks2_storage_list = NULL, *features = NULL, *moreinfo = NULL; + gchar *devid, *size, *tmp = NULL, *media_comp = NULL, *ven_tag = NULL; + const gchar *url, *media_label, *alabel, *icon, *media_curr = NULL; + int n = 0, i, j, m; + + // http://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.Drive.html#gdbus-property-org-freedesktop-UDisks2-Drive.MediaCompatibility + static struct { + char *media; + char *label; + char *icon; + } media_info[] = { + { "thumb", "Thumb-drive", "usbfldisk" }, + { "flash", "Flash Card", "usbfldisk" }, + { "flash_cf", "CompactFlash", "usbfldisk" }, + { "flash_ms", "MemoryStick", "usbfldisk" }, + { "flash_sm", "SmartMedia", "usbfldisk" }, + { "flash_sd", "SD", "usbfldisk" }, + { "flash_sdhc", "SDHC", "usbfldisk" }, + { "flash_sdxc", "SDXC", "usbfldisk" }, + { "flash_mmc", "MMC", "usbfldisk" }, + { "floppy", "Floppy Disk", "media-floppy" }, + { "floppy_zip", "Zip Disk", "media-floppy" }, + { "floppy_jaz", "Jaz Disk", "media-floppy" }, + { "optical", "Optical Disc", "cdrom" }, + { "optical_cd", "CD-ROM", "cdrom" }, + { "optical_cd_r", "CD-R", "cdrom" }, + { "optical_cd_rw", "CD-RW", "cdrom" }, + { "optical_dvd", "DVD-ROM", "cdrom" }, + { "optical_dvd_r", "DVD-R", "cdrom" }, + { "optical_dvd_rw", "DVD-RW", "cdrom" }, + { "optical_dvd_ram", "DVD-RAM", "cdrom" }, + { "optical_dvd_plus_r", "DVD+R" , "cdrom" }, + { "optical_dvd_plus_rw", "DVD+RW" , "cdrom" }, + { "optical_dvd_plus_r_dl", "DVD+R DL", "cdrom" }, + { "optical_dvd_plus_rw_dl", "DVD+RW DL", "cdrom" }, + { "optical_bd", "BD-ROM", "cdrom" }, + { "optical_bd_r", "BD-R", "cdrom" }, + { "optical_bd_re", "BD-RE", "cdrom" }, + { "optical_hddvd", "HD DVD-ROM", "cdrom" }, + { "optical_hddvd_r", "HD DVD-R", "cdrom" }, + { "optical_hddvd_rw", "HD DVD-RW", "cdrom" }, + { "optical_mo", "MO Disc", "cdrom" }, + { "optical_mrw", "MRW Media", "cdrom" }, + { "optical_mrw_w", "MRW Media (write)", "cdrom" }, + { NULL, NULL } + }; + + struct { + char *identifier; + char *label; + } smart_attrib_info[] = { + { "raw-read-error-rate", _("Read Error Rate" ) }, + { "throughput-performance", _("Throughput Performance") }, + { "spin-up-time", _("Spin-Up Time") }, + { "start-stop-count", _("Start/Stop Count") }, + { "reallocated-sector-count", _("Reallocated Sector Count") }, + { "read-channel-margin", _("Read Channel Margin") }, + { "seek-error-rate", _("Seek Error Rate") }, + { "seek-time-performance", _("Seek Timer Performance") }, + { "power-on-hours", _("Power-On Hours") }, + { "spin-retry-count", _("Spin Retry Count") }, + { "calibration-retry-count", _("Calibration Retry Count") }, + { "power-cycle-count", _("Power Cycle Count") }, + { "read-soft-error-rate", _("Soft Read Error Rate") }, + { "runtime-bad-block-total", _("Runtime Bad Block") }, + { "end-to-end-error", _("End-to-End error") }, + { "reported-uncorrect", _("Reported Uncorrectable Errors") }, + { "command-timeout", _("Command Timeout") }, + { "high-fly-writes", _("High Fly Writes") }, + { "airflow-temperature-celsius", _("Airflow Temperature") }, + { "g-sense-error-rate", _("G-sense Error Rate") }, + { "power-off-retract-count", _("Power-off Retract Count") }, + { "load-cycle-count", _("Load Cycle Count") }, + { "temperature-celsius-2", _("Temperature") }, + { "hardware-ecc-recovered", _("Hardware ECC Recovered") }, + { "reallocated-event-count", _("Reallocation Event Count") }, + { "current-pending-sector", _("Current Pending Sector Count") }, + { "offline-uncorrectable", _("Uncorrectable Sector Count") }, + { "udma-crc-error-count", _("UltraDMA CRC Error Count") }, + { "multi-zone-error-rate", _("Multi-Zone Error Rate") }, + { "soft-read-error-rate", _("Soft Read Error Rate") }, + { "run-out-cancel", _("Run Out Cancel") }, + { "flying-height", _("Flying Height") }, + { "spin-high-current", _("Spin High Current") }, + { "spin-buzz", _("Spin Buzz") }, + { "offline-seek-performance", _("Offline Seek Performance") }, + { "disk-shift", _("Disk Shift") }, + { "g-sense-error-rate-2", _("G-Sense Error Rate") }, + { "loaded-hours", _("Loaded Hours") }, + { "load-retry-count", _("Load/Unload Retry Count") }, + { "load-friction", _("Load Friction") }, + { "load-cycle-count-2", _("Load/Unload Cycle Count") }, + { "load-in-time", _("Load-in time") }, + { "torq-amp-count", _("Torque Amplification Count") }, + { "power-off-retract-count-2", _("Power-Off Retract Count") }, + { "head-amplitude", _("GMR Head Amplitude") }, + { "temperature-celsius", _("Temperature") }, + { "endurance-remaining", _("Endurance Remaining") }, + { "power-on-seconds-2", _("Power-On Hours") }, + { "good-block-rate", _("Good Block Rate") }, + { "head-flying-hours", _("Head Flying Hours") }, + { "read-error-retry-rate", _("Read Error Retry Rate") }, + { "total-lbas-written", _("Total LBAs Written") }, + { "total-lbas-read", _("Total LBAs Read") }, + { "wear-leveling-count", _("Wear leveling Count") }, + { "used-reserved-blocks-total", _("Total Used Reserved Block Count") }, + { "program-fail-count-total", _("Total Program Fail Count") }, + { "erase-fail-count-total", _("Total Erase Fail Count") }, + { "available-reserved-space", _("Available Reserved Space") }, + { "program-fail-count", _("Program Fail Count") }, + { "erase-fail-count", _("Erase Fail Count") }, + { "ta-increase-count", _("TA Counter Increased") }, + { "unused-reserved-blocks", _("Total Unused Reserved Block Count") }, + { NULL, NULL } + }; + + moreinfo_del_with_prefix("DEV:UDISKS"); + udisks2_storage_list = g_strdup(_("\n[UDisks2]\n")); + + drives = get_udisks2_drives_ext(); + for (node = drives; node != NULL; node = node->next) { + ext = (u2driveext *)node->data; + disk = ext->d; + devid = g_strdup_printf("UDISKS%d", n++); + + icon = NULL; + + media_curr = disk->media; + if (disk->media){ + for (j = 0; media_info[j].media != NULL; j++) { + if (g_strcmp0(disk->media, media_info[j].media) == 0) { + media_curr = media_info[j].label; + break; + } + } + } + + if (disk->media_compatibility){ + for (i = 0; disk->media_compatibility[i] != NULL; i++){ + media_label = disk->media_compatibility[i]; + + for (j = 0; media_info[j].media != NULL; j++) { + if (g_strcmp0(disk->media_compatibility[i], media_info[j].media) == 0) { + media_label = media_info[j].label; + if (icon == NULL) + icon = media_info[j].icon; + break; + } + } + + if (media_comp == NULL){ + media_comp = g_strdup(media_label); + } + else{ + media_comp = h_strdup_cprintf(", %s", media_comp, media_label); + } + } + } + if (icon == NULL && disk->ejectable && g_strcmp0(disk->connection_bus, "usb") == 0) { + icon = "usbfldisk"; + } + if (icon == NULL){ + icon = "hdd"; + } + + size = size_human_readable((gfloat) disk->size); + ven_tag = vendor_list_ribbon(ext->vendors, params.fmt_opts); + + udisks2_storage_list = h_strdup_cprintf("$%s$%s=%s|%s %s\n", udisks2_storage_list, devid, disk->block_dev, size, ven_tag ? ven_tag : "", disk->model); + storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, disk->model, icon); + features = h_strdup_cprintf("%s", features, disk->removable ? _("Removable"): _("Fixed")); + + if (disk->ejectable) { + features = h_strdup_cprintf(", %s", features, _("Ejectable")); + } + if (disk->smart_supported) { + features = h_strdup_cprintf(", %s", features, _("Self-monitoring (S.M.A.R.T.)")); + } + if (disk->pm_supported) { + features = h_strdup_cprintf(", %s", features, _("Power Management")); + } + if (disk->apm_supported) { + features = h_strdup_cprintf(", %s", features, _("Advanced Power Management")); + } + if (disk->aam_supported) { + features = h_strdup_cprintf(", %s", features, _("Automatic Acoustic Management")); + } + + moreinfo = g_strdup_printf(_("[Drive Information]\n" + "Model=%s\n"), + disk->model); + + if (disk->vendor && *disk->vendor) { + moreinfo = h_strdup_cprintf("$^$%s=%s\n", + moreinfo, + _("Vendor"), disk->vendor); + } + + moreinfo = h_strdup_cprintf(_("Revision=%s\n" + "Block Device=%s\n" + "Serial=%s\n" + "Size=%s\n" + "Features=%s\n"), + moreinfo, + disk->revision, + disk->block_dev, + disk->serial, + size, + features); + g_free(size); + g_free(ven_tag); + + if (disk->rotation_rate > 0) { + moreinfo = h_strdup_cprintf(_("Rotation Rate=%d RPM\n"), moreinfo, disk->rotation_rate); + } + if (media_comp || media_curr) { + moreinfo = h_strdup_cprintf(_("Media=%s\n" + "Media compatibility=%s\n"), + moreinfo, + media_curr ? media_curr : _("(None)"), + media_comp ? media_comp : _("(Unknown)")); + } + if (disk->connection_bus && strlen(disk->connection_bus) > 0) { + moreinfo = h_strdup_cprintf(_("Connection bus=%s\n"), moreinfo, disk->connection_bus); + } + + tmp = NULL; + if (disk->wwid) { + m = strlen(disk->wwid); + if (m > 2 && m % 2 == 0){ + for (j = 4; j < m; j = j + 2) { + tmp = h_strdup_cprintf("%s%c%c", tmp, j > 4 ? "-": "", disk->wwid[j], disk->wwid[j+1]); + } + } + moreinfo = h_strdup_cprintf("%s=%s\n", moreinfo, + g_str_has_prefix(disk->wwid, "nna.") ? _("WWN"): + (g_str_has_prefix(disk->wwid, "eui.") ? _("EUI "): "Unknown ID"), + tmp); + g_free(tmp); + } + else{ + moreinfo = h_strdup_cprintf("%s=%s\n", moreinfo, _("WWN / EUI"), _("(None)")); + } + + if (ext->wwid_oui.oui) { + moreinfo = h_strdup_cprintf(_("$^$%s=[%s] %s\n"), + moreinfo, + _("IEEE OUI"), ext->wwid_oui.oui, + ext->wwid_oui.vendor ? + ext->wwid_oui.vendor : _("(Unknown)")); + } + + if (ext->nvme_controller) { + gchar *nvme = nvme_pci_sections(ext->nvme_controller); + if (nvme) + moreinfo = h_strdup_cprintf("%s", moreinfo, nvme); + g_free(nvme); + } + if (disk->smart_enabled) { + moreinfo = h_strdup_cprintf(_("[Self-monitoring (S.M.A.R.T.)]\n" + "Status=%s\n" + "Bad Sectors=%" G_GINT64_FORMAT "\n" + "Power on time=%" G_GUINT64_FORMAT " days %" G_GUINT64_FORMAT " hours\n" + "Temperature=%d°C\n"), + moreinfo, + disk->smart_failing ? _("Failing"): _("OK"), + disk->smart_bad_sectors, + disk->smart_poweron/(60*60*24), (disk->smart_poweron/60/60) % 24, + disk->smart_temperature); + + if (disk->smart_attributes != NULL) { + moreinfo = h_strdup_cprintf(_("[S.M.A.R.T. Attributes]\n" + "Attribute=<tt>Value / Normalized / Worst / Threshold</tt>\n"), + moreinfo); + + attrib = disk->smart_attributes; + + while (attrib != NULL){ + tmp = g_strdup(""); + + switch (attrib->interpreted_unit){ + case UDSK_INTPVAL_SKIP: + tmp = h_strdup_cprintf("-", tmp); + break; + case UDSK_INTPVAL_MILISECONDS: + tmp = h_strdup_cprintf("%" G_GINT64_FORMAT " ms", tmp, attrib->interpreted); + break; + case UDSK_INTPVAL_HOURS: + tmp = h_strdup_cprintf("%" G_GINT64_FORMAT " h", tmp, attrib->interpreted); + break; + case UDSK_INTPVAL_CELSIUS: + tmp = h_strdup_cprintf("%" G_GINT64_FORMAT "°C", tmp, attrib->interpreted); + break; + case UDSK_INTPVAL_SECTORS: + tmp = h_strdup_cprintf(ngettext("%" G_GINT64_FORMAT " sector", + "%" G_GINT64_FORMAT " sectors", attrib->interpreted), + tmp, attrib->interpreted); + break; + case UDSK_INTPVAL_DIMENSIONLESS: + default: + tmp = h_strdup_cprintf("%" G_GINT64_FORMAT, tmp, attrib->interpreted); + break; + } + + // pad spaces to next col + j = g_utf8_strlen(tmp, -1); + if (j < 13) tmp = h_strdup_cprintf("%*c", tmp, 13 - j, ' '); + + if (attrib->value != -1) + tmp = h_strdup_cprintf("%-13d", tmp, attrib->value); + else + tmp = h_strdup_cprintf("%-13s", tmp, "???"); + + if (attrib->worst != -1) + tmp = h_strdup_cprintf("%-8d", tmp, attrib->worst); + else + tmp = h_strdup_cprintf("%-8s", tmp, "???"); + + if (attrib->threshold != -1) + tmp = h_strdup_cprintf("%d", tmp, attrib->threshold); + else + tmp = h_strdup_cprintf("???", tmp); + + + alabel = attrib->identifier; + for (i = 0; smart_attrib_info[i].identifier != NULL; i++) { + if (g_strcmp0(attrib->identifier, smart_attrib_info[i].identifier) == 0) { + alabel = smart_attrib_info[i].label; + break; + } + } + + moreinfo = h_strdup_cprintf(_("(%d) %s=<tt>%s</tt>\n"), + moreinfo, + attrib->id, alabel, tmp); + g_free(tmp); + attrib = attrib->next; + } + } + } + if (disk->partition_table || disk->partitions) { + moreinfo = h_strdup_cprintf(_("[Partition table]\n" + "Type=%s\n"), + moreinfo, + disk->partition_table ? disk->partition_table : _("(Unknown)")); + + if (disk->partitions != NULL) { + part = disk->partitions; + while (part != NULL){ + + tmp = size_human_readable((gfloat) part->size); + if (part->label) { + tmp = h_strdup_cprintf(" - %s", tmp, part->label); + } + if (part->type && part->version) { + tmp = h_strdup_cprintf(" (%s %s)", tmp, part->type, part->version); + } + else if (part->type) { + tmp = h_strdup_cprintf(" (%s)", tmp, part->type); + } + moreinfo = h_strdup_cprintf(_("Partition %s=%s\n"), + moreinfo, + part->block, tmp); + g_free(tmp); + part = part->next; + } + } + } + + moreinfo_add_with_prefix("DEV", devid, moreinfo); + g_free(devid); + g_free(features); + g_free(media_comp); + media_comp = NULL; + + features = NULL; + moreinfo = NULL; + devid = NULL; + + u2driveext_free(ext); + } + g_slist_free(drives); + + if (n) { + storage_list = h_strconcat(storage_list, udisks2_storage_list, NULL); + g_free(udisks2_storage_list); + return TRUE; + } + + g_free(udisks2_storage_list); + return FALSE; +} + /* SCSI support by Pascal F.Martin <pascalmartin@earthlink.net> */ -void -__scan_scsi_devices(void) +void __scan_scsi_devices(void) { FILE *proc_scsi; gchar buffer[256], *buf; @@ -40,12 +493,16 @@ __scan_scsi_devices(void) /* 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"))) { + int otype = 0; + if (proc_scsi = fopen("/proc/scsi/scsi", "r")) { + otype = 1; + } else if (proc_scsi = popen("lsscsi -c", "r")) { + otype = 2; + } + + if (otype) { while (fgets(buffer, 256, proc_scsi)) { buf = g_strstrip(buffer); if (!strncmp(buf, "Host: scsi", 10)) { @@ -104,23 +561,15 @@ __scan_scsi_devices(void) } gchar *devid = g_strdup_printf("SCSI%d", n); - scsi_storage_list = h_strdup_cprintf("$%s$%s=\n", scsi_storage_list, devid, model); + scsi_storage_list = h_strdup_cprintf("$%s$scsi%d=|%s\n", scsi_storage_list, devid, scsi_controller, 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("$^$%s=%s\n", + strhash, + _("Vendor"), model); strhash = h_strdup_cprintf(_("Type=%s\n" "Revision=%s\n" @@ -135,6 +584,7 @@ __scan_scsi_devices(void) scsi_channel, scsi_id, scsi_lun); + moreinfo_add_with_prefix("DEV", devid, strhash); g_free(devid); @@ -145,7 +595,10 @@ __scan_scsi_devices(void) scsi_controller = scsi_channel = scsi_id = scsi_lun = 0; } } - fclose(proc_scsi); + if (otype == 1) + fclose(proc_scsi); + else if (otype == 2) + pclose(proc_scsi); } if (n) { @@ -157,7 +610,8 @@ __scan_scsi_devices(void) void __scan_ide_devices(void) { FILE *proc_ide; - gchar *device, iface, *model, *media, *pgeometry = NULL, *lgeometry = NULL; + gchar *device, *model, *media, *pgeometry = NULL, *lgeometry = NULL; + gchar iface; gint n = 0, i = 0, cache, nn = 0; gchar *capab = NULL, *speed = NULL, *driver = NULL, *ide_storage_list; @@ -305,7 +759,7 @@ void __scan_ide_devices(void) gchar *devid = g_strdup_printf("IDE%d", n); - ide_storage_list = h_strdup_cprintf("$%s$%s=\n", ide_storage_list, devid, model); + ide_storage_list = h_strdup_cprintf("$%s$hd%c=|%s\n", ide_storage_list, devid, iface, model); storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, model, g_str_equal(media, "cdrom") ? "cdrom" : "hdd"); @@ -313,13 +767,8 @@ void __scan_ide_devices(void) 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("$^$%s=%s\n", + strhash, _("Vendor"), model); strhash = h_strdup_cprintf(_("Device Name=hd%c\n" "Media=%s\n" "Cache=%dkb\n"), strhash, iface, media, cache); diff --git a/modules/devices/usb.c b/modules/devices/usb.c index 9366c7ce..c6a5ab39 100644 --- a/modules/devices/usb.c +++ b/modules/devices/usb.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,422 +15,210 @@ * 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 "cpu_util.h" #include "hardinfo.h" #include "devices.h" +#include "usb_util.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_printf("%d %s", 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(_(/*/%.2f is version*/ "USB %.2f Hub"), version); - } else { - product = g_strdup_printf(_("Unknown USB %.2f Device (class %d)"), version, classid); +gchar *usb_icons = NULL; + +#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)") +#define IARR_END -2 +#define IARR_ANY -1 + +static struct { + int class; + char *icon; +} usb_class_icons[] = { + { 0x1, "audio"}, /* Audio */ + { 0x2, "modem"}, /* Communications and CDC Control */ + { 0x3, "inputdevices"}, /* HID (Human Interface Device) */ + { 0x6, "camera-photo"}, /* Still Imaging */ + { 0x7, "printer"}, /* Printer */ + { 0x8, "media-removable"}, /* Mass storage */ + { 0x9, "usb"}, /* Hub */ + { 0xe, "camera-web"}, /* Video */ + {IARR_END, NULL} +}; + +static struct { + int class, subclass, protocol; + char *icon; +} usb_type_icons[] = { + { 0x2, 0x6, IARR_ANY, "network-interface"}, /* Ethernet Networking Control Model */ + { 0x3, 0x1, 0x1, "keyboard"}, /* Keyboard */ + { 0x3, 0x1, 0x2, "mouse"}, /* Mouse */ + {0xe0, 0x1, 0x1, "bluetooth"}, /* Bluetooth Programming Interface */ + {IARR_END, IARR_END, IARR_END, NULL}, +}; + +static const char* get_class_icon(int class){ + int i = 0; + while (usb_class_icons[i].class != IARR_END) { + if (usb_class_icons[i].class == class) { + return usb_class_icons[i].icon; } + i++; } - - const gchar *v_url = vendor_get_url(manufacturer); - const gchar *v_name = vendor_get_name(manufacturer); - gchar *v_str; - if (v_url != NULL) { - v_str = g_strdup_printf("%s (%s)", v_name, v_url); - } else { - v_str = g_strdup_printf("%s", manufacturer); - } - - tmp = g_strdup_printf("USB%d", n); - usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product); - - strhash = g_strdup_printf("[%s]\n" - /* Product */ "%s=%s\n" - /* Manufacturer */ "%s=%s\n" - /* Speed */ "%s=%.2f %s\n" - /* Max Current */ "%s=%s\n" - "[%s]\n" - /* USB Version */ "%s=%.2f\n" - /* Class */ "%s=0x%x\n" - /* Vendor */ "%s=0x%x\n" - /* Product ID */ "%s=0x%x\n" - /* Bus */ "%s=%d\n", - _("Device Information"), - _("Product"), product, - _("Manufacturer"), v_str, - _("Speed"), speed, _("Mbit/s"), - _("Max Current"), mxpwr, - _("Misc"), - _("USB Version"), version, - _("Class"), classid, - _("Vendor ID"), vendor, - _("Product ID"), prodid, - _("Bus"), bus); - - moreinfo_add_with_prefix("DEV", tmp, strhash); - g_free(tmp); - g_free(v_str); - g_free(manufacturer); - g_free(product); - g_free(mxpwr); + return NULL; } -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_printf("[%s]\n", _("USB Devices")); - - while ((filename = (gchar *) g_dir_read_name(sysfs))) { - gchar *endpoint = - g_build_filename(sysfs_path, filename, "device", NULL); - gchar *temp; +static const char* get_usbif_icon(const usbi *usbif) { + int i = 0; + while (usb_type_icons[i].class != IARR_END) { + if (usb_type_icons[i].class == usbif->if_class && usb_type_icons[i].subclass == usbif->if_subclass && + (usb_type_icons[i].protocol == IARR_ANY || usb_type_icons[i].protocol == usbif->if_protocol)) { - 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); + return usb_type_icons[i].icon; + } + i++; } - g_dir_close(sysfs); - - return usb_device_number > 0; + return get_class_icon(usbif->if_class); } -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; +static const char* get_usbdev_icon(const usbd *u) { + const char * icon = NULL; + usbi *curr_if; - if (usb_list) { - moreinfo_del_with_prefix("DEV:USB"); - g_free(usb_list); + curr_if = u->if_list; + while (icon == NULL && curr_if != NULL){ + icon = get_usbif_icon(curr_if); + curr_if = curr_if->next; } - usb_list = g_strdup_printf("[%s]\n", _("USB Devices")); - - 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); - - EMPIFNULL(manuf); - const gchar *v_url = vendor_get_url(manuf); - const gchar *v_name = vendor_get_name(manuf); - gchar *v_str = NULL; - if (strlen(manuf)) { - if (v_url != NULL) - v_str = g_strdup_printf("%s (%s)", v_name, v_url); - else - v_str = g_strdup_printf("%s", manuf); - } - UNKIFNULL(v_str); - UNKIFNULL(product); - - gchar *strhash = g_strdup_printf("[%s]\n" "%s=%s\n" "%s=%s\n", - _("Device Information"), - _("Product"), product, - _("Manufacturer"), v_str); - - strhash = h_strdup_cprintf("[%s #%d]\n" - /* Speed */ "%s=%.2f %s\n" - /* Max Current */ "%s=%s\n" - "[%s]\n" - /* USB Version */ "%s=%.2f\n" - /* Revision */ "%s=%.2f\n" - /* Class */ "%s=0x%x\n" - /* Vendor */ "%s=0x%x\n" - /* Product ID */ "%s=0x%x\n" - /* Bus */ "%s=%d\n" - /* Level */ "%s=%d\n", - strhash, - _("Port"), port, - _("Speed"), speed, _("Mbit/s"), - _("Max Current"), mxpwr, - _("Misc"), - _("USB Version"), ver, - _("Revision"), rev, - _("Class"), classid, - _("Vendor ID"), vendor, - _("Product ID"), prodid, - _("Bus"), bus, - _("Level"), level); - - moreinfo_add_with_prefix("DEV", tmp, strhash); - g_free(v_str); - g_free(tmp); - } - - g_free(manuf); - g_free(product); - manuf = NULL; - product = NULL; - port = classid = 0; - } + if (icon == NULL){ + icon = get_class_icon(u->dev_class); } - fclose(dev); - - return n > 0; + return icon; } - -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); - - const gchar *v_url = vendor_get_url(vendor); - const gchar *v_name = vendor_get_name(vendor); - gchar *v_str; - if (v_url != NULL) { - v_str = g_strdup_printf("%s (%s)", v_name, v_url); +static void _usb_dev(const usbd *u) { + gchar *name, *key, *label, *str, *speed; + gchar *product, *vendor, *manufacturer, *device; /* don't free */ + gchar *interfaces = strdup(""); + usbi *i; + const char* icon; + + vendor = UNKIFNULL_AC(u->vendor); + product = UNKIFNULL_AC(u->product); + manufacturer = UNKIFNULL_AC(u->manufacturer); + device = UNKIFNULL_AC(u->device); + + if (u->vendors) { + gchar *ribbon = vendor_list_ribbon(u->vendors, params.fmt_opts); + name = g_strdup_printf("%s %s", ribbon, u->product? product: device); } else { - v_str = g_strdup_printf("%s", g_strstrip(vendor) ); + name = g_strdup_printf("%s %s", u->vendor? vendor: manufacturer, u->product? product: device); + } + key = g_strdup_printf("USB%03d:%03d:%03d", u->bus, u->dev, 0); + label = g_strdup_printf("%03d:%03d", u->bus, u->dev); + icon = get_usbdev_icon(u); + + usb_list = h_strdup_cprintf("$%s$%s=%s\n", usb_list, key, label, name); + usb_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", usb_icons, key, label, icon ? icon: "usb"); + + if (u->if_list != NULL) { + i = u->if_list; + while (i != NULL){ + interfaces = h_strdup_cprintf("[%s %d %s]\n" + /* Class */ "%s=[%d] %s\n" + /* Sub-class */ "%s=[%d] %s\n" + /* Protocol */ "%s=[%d] %s\n" + /* Driver */ "%s=%s\n", + interfaces, + _("Interface"), i->if_number, i->if_label? i->if_label: "", + _("Class"), i->if_class, UNKIFNULL_AC(i->if_class_str), + _("Sub-class"), i->if_subclass, UNKIFNULL_AC(i->if_subclass_str), + _("Protocol"), i->if_protocol, UNKIFNULL_AC(i->if_protocol_str), + _("Driver"), UNKIFNULL_AC(i->driver) + ); + i = i->next; + } } - if (max_power != NULL) { - int mA = atoi(g_strstrip(max_power)); - gchar *trent_steel = g_strdup_printf("%d %s", mA, _("mA")); - g_free(max_power); - max_power = trent_steel; + if (u->speed_mbs > 0){ + speed = g_strdup_printf("%d %s", u->speed_mbs, _("Mb/s")); + } + else{ + speed = g_strdup(_("Unknown")); } - UNKIFNULL(product); - UNKIFNULL(v_str); - UNKIFNULL(max_power); - UNKIFNULL(version); - UNKIFNULL(dev_class); - - strhash = g_strdup_printf("[%s]\n" - /* Product */ "%s=%s\n" - /* Manufacturer */ "%s=%s\n" - /* Max Current */ "%s=%s\n" - "[%s]\n" + str = g_strdup_printf("[%s]\n" + /* Product */ "%s=[0x%04x] %s\n" + /* Vendor */ "$^$%s=[0x%04x] %s\n" + /* Device */ "%s=%s\n" + /* Manufacturer */ "$^$%s=%s\n" + /* Max Current */ "%s=%d %s\n" /* USB Version */ "%s=%s\n" - /* Class */ "%s=%s\n" - /* Vendor ID */ "%s=0x%x\n" - /* Product ID */ "%s=0x%x\n" - /* Bus */ "%s=%d\n", + /* Speed */ "%s=%s\n" + /* Class */ "%s=[%d] %s\n" + /* Sub-class */ "%s=[%d] %s\n" + /* Protocol */ "%s=[%d] %s\n" + /* Dev Version */ "%s=%s\n" + /* Serial */ "%s=%s\n" + "[%s]\n" + /* Bus */ "%s=%03d\n" + /* Device */ "%s=%03d\n" + /* Interfaces */ "%s", _("Device Information"), - _("Product"), g_strstrip(product), - _("Vendor"), v_str, - _("Max Current"), g_strstrip(max_power), - _("Misc"), - _("USB Version"), g_strstrip(version), - _("Class"), g_strstrip(dev_class), - _("Vendor ID"), vendor_id, - _("Product ID"), product_id, - _("Bus"), bus); - - moreinfo_add_with_prefix("DEV", tmp, strhash); - g_free(v_str); - g_free(vendor); - g_free(product); - g_free(max_power); - g_free(dev_class); - g_free(version); - g_free(tmp); + _("Product"), u->product_id, product, + _("Vendor"), u->vendor_id, vendor, + _("Device"), device, + _("Manufacturer"), manufacturer, + _("Max Current"), u->max_curr_ma, _("mA"), + _("USB Version"), u->usb_version, + _("Speed"), speed, + _("Class"), u->dev_class, UNKIFNULL_AC(u->dev_class_str), + _("Sub-class"), u->dev_subclass, UNKIFNULL_AC(u->dev_subclass_str), + _("Protocol"), u->dev_protocol, UNKIFNULL_AC(u->dev_protocol_str), + _("Device Version"), UNKIFNULL_AC(u->device_version), + _("Serial Number"), UNKIFNULL_AC(u->serial), + _("Connection"), + _("Bus"), u->bus, + _("Device"), u->dev, + interfaces + ); + + moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */ + + g_free(speed); g_free(name); + g_free(key); + g_free(label); + g_free(interfaces); } -gboolean __scan_usb_lsusb(void) -{ - static gchar *lsusb_path = NULL; - int usb_device_number = 0; - FILE *lsusb; - FILE *temp_lsusb; - char buffer[512], *temp; +void __scan_usb(void) { + usbd *list = usb_get_device_list(); + usbd *curr = list; - 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); - g_free(temp); - 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); + int c = usbd_list_count(list); if (usb_list) { - moreinfo_del_with_prefix("DEV:USB"); + moreinfo_del_with_prefix("DEV:USB"); g_free(usb_list); } + if (usb_icons){ + g_free(usb_icons); + usb_icons = NULL; + } usb_list = g_strdup_printf("[%s]\n", _("USB Devices")); - 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); + if (c > 0) { + while(curr) { + _usb_dev(curr); + curr=curr->next; } - } - - fclose(temp_lsusb); - return usb_device_number > 0; -} - -void __scan_usb(void) -{ - if (!__scan_usb_procfs()) { - if (!__scan_usb_sysfs()) { - __scan_usb_lsusb(); - } + usbd_list_free(list); + } else { + /* No USB? */ + usb_list = g_strconcat(usb_list, _("No USB devices found."), "=\n", NULL); } } diff --git a/modules/devices/x86/processor.c b/modules/devices/x86/processor.c index f1c2b6e9..4141f051 100644 --- a/modules/devices/x86/processor.c +++ b/modules/devices/x86/processor.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,7 +19,7 @@ #include "hardinfo.h" #include "devices.h" #include "cpu_util.h" - +#include "nice_name.h" #include "x86_data.h" #include "x86_data.c" @@ -275,7 +275,7 @@ gchar *clocks_summary(GSList * processors) /* create list of all clock references */ for (l = processors; l; l = l->next) { p = (Processor*)l->data; - if (p->cpufreq) { + if (p->cpufreq && p->cpufreq->cpukhz_max > 0) { all_clocks = g_slist_prepend(all_clocks, p->cpufreq); } } @@ -448,14 +448,15 @@ gchar *caches_summary(GSList * processors) return ret; } -#define PROC_SCAN_READ_BUFFER_SIZE 896 +#define PROC_SCAN_READ_BUFFER_SIZE 1024 GSList *processor_scan(void) { GSList *procs = NULL, *l = NULL; Processor *processor = NULL; FILE *cpuinfo; - gchar buffer[PROC_SCAN_READ_BUFFER_SIZE]; + gchar *buffer; + buffer = g_malloc(PROC_SCAN_READ_BUFFER_SIZE); cpuinfo = fopen(PROC_CPUINFO, "r"); if (!cpuinfo) return NULL; @@ -513,6 +514,7 @@ GSList *processor_scan(void) } fclose(cpuinfo); + g_free(buffer); /* finish last */ if (processor) @@ -567,6 +569,8 @@ GSList *processor_scan(void) if (processor->cpufreq->cpukhz_max) processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000; + + nice_name_x86_cpuid_model_string(processor->model_name); } return procs; @@ -584,7 +588,7 @@ gchar *processor_get_capabilities_from_flags(gchar *strflags, gchar *lookup_pref old = flags; while (flags[j]) { - if ( sscanf(flags[j], "[%d]", &i) ) { + if ( sscanf(flags[j], "[%d]", &i)==1 ) { /* Some flags are indexes, like [13], and that looks like * a new section to hardinfo shell */ tmp = h_strdup_cprintf("(%s%d)=\n", tmp, @@ -624,7 +628,7 @@ gchar *processor_get_detailed_info(Processor * processor) ret = g_strdup_printf("[%s]\n" "%s=%s\n" "%s=%d, %d, %d (%s)\n" /* family, model, stepping (decoded name) */ - "%s=%s\n" /* vendor */ + "$^$%s=%s\n" /* vendor */ "%s=%s\n" /* microcode */ "[%s]\n" /* configuration */ "%s=%d %s\n" /* cache size (from cpuinfo) */ @@ -648,7 +652,7 @@ gchar *processor_get_detailed_info(Processor * processor) processor->model, processor->stepping, processor->strmodel, - _("Vendor"), vendor_get_name(processor->vendor_id), + _("Vendor"), processor->vendor_id, _("Microcode Version"), processor->microcode, _("Configuration"), _("Cache Size"), processor->cache_size, _("kb"), @@ -678,12 +682,62 @@ gchar *processor_describe(GSList * processors) { return processor_describe_default(processors); } +gchar *dmi_socket_info() { + gchar *ret; + dmi_type dt = 4; + guint i; + dmi_handle_list *hl = dmidecode_handles(&dt); + + if (!hl) { + ret = g_strdup_printf("[%s]\n%s=%s\n", + _("Socket Information"), _("Result"), + (getuid() == 0) + ? _("(Not available)") + : _("(Not available; Perhaps try running HardInfo as root.)") ); + } else { + ret = g_strdup(""); + for(i = 0; i < hl->count; i++) { + dmi_handle h = hl->handles[i]; + gchar *upgrade = dmidecode_match("Upgrade", &dt, &h); + gchar *socket = dmidecode_match("Socket Designation", &dt, &h); + gchar *bus_clock_str = dmidecode_match("External Clock", &dt, &h); + gchar *voltage_str = dmidecode_match("Voltage", &dt, &h); + gchar *max_speed_str = dmidecode_match("Max Speed", &dt, &h); + + ret = h_strdup_cprintf("[%s (%d) %s]\n" + "%s=0x%x\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n" + "%s=%s\n", + ret, + _("CPU Socket"), i, socket, + _("DMI Handle"), h, + _("Type"), upgrade, + _("Voltage"), voltage_str, + _("External Clock"), bus_clock_str, + _("Max Frequency"), max_speed_str + ); + g_free(upgrade); + g_free(socket); + g_free(bus_clock_str); + g_free(voltage_str); + g_free(max_speed_str); + } + + dmi_handle_list_free(hl); + } + + return ret; +} + gchar *processor_meta(GSList * processors) { gchar *meta_cpu_name = processor_name(processors); gchar *meta_cpu_desc = processor_describe(processors); gchar *meta_freq_desc = processor_frequency_desc(processors); gchar *meta_clocks = clocks_summary(processors); gchar *meta_caches = caches_summary(processors); + gchar *meta_dmi = dmi_socket_info(); gchar *ret = NULL; UNKIFNULL(meta_cpu_desc); ret = g_strdup_printf("[%s]\n" @@ -691,13 +745,15 @@ gchar *processor_meta(GSList * processors) { "%s=%s\n" "%s=%s\n" "%s" + "%s" "%s", _("Package Information"), _("Name"), meta_cpu_name, _("Topology"), meta_cpu_desc, _("Logical CPU Config"), meta_freq_desc, meta_clocks, - meta_caches); + meta_caches, + meta_dmi); g_free(meta_cpu_desc); g_free(meta_freq_desc); g_free(meta_clocks); @@ -711,8 +767,9 @@ gchar *processor_get_info(GSList * processors) gchar *ret, *tmp, *hashkey; gchar *meta; /* becomes owned by more_info? no need to free? */ GSList *l; + gchar *icons=g_strdup(""); - tmp = g_strdup_printf("$CPU_META$%s=\n", _("Package Information") ); + tmp = g_strdup_printf("$!CPU_META$%s=|Summary\n", "all"); meta = processor_meta(processors); moreinfo_add_with_prefix("DEV", "CPU_META", meta); @@ -720,27 +777,46 @@ gchar *processor_get_info(GSList * processors) for (l = processors; l; l = l->next) { processor = (Processor *) l->data; - tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s|%d:%d|%d\n", + gchar *model_name = g_strdup(processor->model_name); + const Vendor *v = vendor_match(processor->vendor_id, NULL); + if (v) + tag_vendor(&model_name, 0, v->name_short ? v->name_short : v->name, v->ansi_color, params.fmt_opts); + + // bp: not convinced it looks good, but here's how it would be done... + //icons = h_strdup_cprintf("Icon$CPU%d$cpu%d=processor.png\n", icons, processor->id, processor->id); + + tmp = g_strdup_printf("%s$CPU%d$cpu%d=%.2f %s|%s|%d:%d\n", tmp, processor->id, - processor->model_name, + processor->id, processor->cpu_mhz, _("MHz"), + model_name, processor->cputopo->socket_id, - processor->cputopo->core_id, - processor->cputopo->id ); + processor->cputopo->core_id); hashkey = g_strdup_printf("CPU%d", processor->id); moreinfo_add_with_prefix("DEV", hashkey, processor_get_detailed_info(processor)); g_free(hashkey); + g_free(model_name); } ret = g_strdup_printf("[$ShellParam$]\n" "ViewType=1\n" + "ColumnTitle$TextValue=%s\n" + "ColumnTitle$Value=%s\n" "ColumnTitle$Extra1=%s\n" "ColumnTitle$Extra2=%s\n" + "ShowColumnHeaders=true\n" + "%s" "[Processors]\n" - "%s", _("Socket:Core"), _("Thread" /*TODO: +s*/), tmp); + "%s", _("Device"), _("Frequency"), _("Model"), _("Socket:Core"), icons, tmp); g_free(tmp); + g_free(icons); + + // now here's something fun... + struct Info *i = info_unflatten(ret); + g_free(ret); + ret = info_flatten(i); return ret; } diff --git a/modules/devices/x86/x86_data.c b/modules/devices/x86/x86_data.c index c052f4e1..f56e8668 100644 --- a/modules/devices/x86/x86_data.c +++ b/modules/devices/x86/x86_data.c @@ -18,6 +18,7 @@ * */ +#include <json-glib/json-glib.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -35,9 +36,13 @@ * https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/arch/x86/include/asm/cpufeatures.h?id=refs/tags/v4.9 * hardinfo: modules/devices/x86/processor.c */ -static struct { - char *name, *meaning; -} tab_flag_meaning[] = { + +struct flag_to_meaning { + char *name; + char *meaning; +}; + +static const struct flag_to_meaning builtin_tab_flag_meaning[] = { /* Intel-defined CPU features, CPUID level 0x00000001 (edx) * See also Wikipedia and table 2-27 in Intel Advanced Vector Extensions Programming Reference */ { "fpu", NC_("x86-flag", /*/flag:fpu*/ "Onboard FPU (floating point support)") }, @@ -282,6 +287,8 @@ static struct { { "bug:cpu_meltdown", NC_("x86-flag", /*/bug:cpu_insecure & bug:cpu_meltdown*/ "CPU is affected by meltdown attack and needs kernel page table isolation") }, { "bug:spectre_v1", NC_("x86-flag", /*/bug:spectre_v1*/ "CPU is affected by Spectre variant 1 attack with conditional branches") }, { "bug:spectre_v2", NC_("x86-flag", /*/bug:spectre_v2*/ "CPU is affected by Spectre variant 2 attack with indirect branches") }, + { "bug:spec_store_bypass", NC_("x86-flag", /*/bug:spec_store_bypass*/ "CPU is affected by speculative store bypass attack") }, + { "bug:l1tf", NC_("x86-flag", /*/bug:l1tf*/ "CPU is affected by L1 Terminal Fault") }, /* power management * ... from arch/x86/kernel/cpu/powerflags.h */ { "pm:ts", NC_("x86-flag", /*/flag:pm:ts*/ "temperature sensor") }, @@ -299,32 +306,77 @@ static struct { { NULL, NULL}, }; +static struct flag_to_meaning *tab_flag_meaning; + static char all_flags[4096] = ""; -#define APPEND_FLAG(f) strcat(all_flags, f); strcat(all_flags, " "); -const char *x86_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; +static void build_meaning_table_iter(JsonObject *object, + const gchar *member_name, + JsonNode *member_node, + gpointer user_data) +{ + int *i = user_data; + + tab_flag_meaning[*i] = (struct flag_to_meaning) { + .name = g_strdup(member_name), + .meaning = g_strdup(json_node_get_string(member_node)), + }; + + (*i)++; } -const char *x86_flag_meaning(const char *flag) { +void cpuflags_x86_init(void) +{ + gchar *flag_json = g_build_filename(g_get_user_config_dir(), "hardinfo2", + "cpuflags.json", NULL); + gboolean use_builtin_table = TRUE; + + if (!g_file_test(flag_json, G_FILE_TEST_EXISTS)) + goto use_builtin_table; + + JsonParser *parser = json_parser_new(); + if (!json_parser_load_from_file(parser, flag_json, NULL)) + goto use_builtin_table_with_json; + + JsonNode *root = json_parser_get_root(parser); + if (json_node_get_node_type(root) != JSON_NODE_OBJECT) + goto use_builtin_table_with_json; + + JsonObject *x86_flags = + json_object_get_object_member(json_node_get_object(root), "x86"); + if (!x86_flags) + goto use_builtin_table_with_json; + + tab_flag_meaning = + g_new(struct flag_to_meaning, json_object_get_size(x86_flags) + 1); int i = 0; - if (flag) - while(tab_flag_meaning[i].name != NULL) { + json_object_foreach_member(x86_flags, build_meaning_table_iter, &i); + tab_flag_meaning[i] = (struct flag_to_meaning){NULL, NULL}; + use_builtin_table = FALSE; + +use_builtin_table_with_json: + g_object_unref(parser); +use_builtin_table: + g_free(flag_json); + + if (use_builtin_table) + tab_flag_meaning = (struct flag_to_meaning *)builtin_tab_flag_meaning; +} + +const char *x86_flag_meaning(const char *flag) { + int i; + + if (!flag) + return NULL; + + for (i = 0; tab_flag_meaning[i].name; i++) { if (strcmp(tab_flag_meaning[i].name, flag) == 0) { if (tab_flag_meaning[i].meaning != NULL) return C_("x86-flag", tab_flag_meaning[i].meaning); else return NULL; } - i++; } + return NULL; } diff --git a/modules/network.c b/modules/network.c index f27a159a..4b65e0aa 100644 --- a/modules/network.c +++ b/modules/network.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,6 +27,8 @@ #include <sys/stat.h> #include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include <netdb.h> #include <hardinfo.h> @@ -106,8 +108,13 @@ void scan_statistics(gboolean reload) gchar *tmp = buffer; while (*tmp && isspace(*tmp)) tmp++; - - __statistics = h_strdup_cprintf("<b> </b>#%d=%s\n", + /* the bolded-space/dot used here is a hardinfo shell hack */ + if (params.markup_ok) + __statistics = h_strdup_cprintf("<b> </b>#%d=%s\n", + __statistics, + line++, tmp); + else + __statistics = h_strdup_cprintf(">#%d=%s\n", __statistics, line++, tmp); } @@ -154,7 +161,6 @@ void scan_dns(gboolean reload) __nameservers = h_strdup_cprintf("%s=%s\n", __nameservers, ip, hbuf); - } shell_status_pulse(); @@ -427,15 +433,15 @@ void hi_module_deinit(void) g_free(__connections); } -ModuleAbout *hi_module_get_about(void) +const 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"} + static const ModuleAbout ma = { + .author = "L. A. F. Pereira", + .description = + N_("Gathers information about this computer's network connection"), + .version = VERSION, + .license = "GNU GPL version 2 or later.", }; - return ma; + return &ma; } diff --git a/modules/network/net.c b/modules/network/net.c index a75cf8b6..9a5cb5f1 100644 --- a/modules/network/net.c +++ b/modules/network/net.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -146,7 +146,7 @@ void get_wireless_info(int fd, NetInfo *netinfo) if (ioctl(fd, SIOCGIWMODE, &wi_req) < 0) { netinfo->wi_mode = 0; } else { - if (wi_req.u.mode >= 0 && wi_req.u.mode < 6) { + if (wi_req.u.mode < 6) { netinfo->wi_mode = wi_req.u.mode; } else { netinfo->wi_mode = 6; diff --git a/modules/network/nfs.c b/modules/network/nfs.c index 54bbfe0e..67095f92 100644 --- a/modules/network/nfs.c +++ b/modules/network/nfs.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2009 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/modules/network/samba.c b/modules/network/samba.c index 7e8dc46c..e14742ea 100644 --- a/modules/network/samba.c +++ b/modules/network/samba.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2009 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -57,7 +57,7 @@ scan_samba_usershares(void) gchar *usershare, *cmdline; gsize length; - spawned = g_spawn_command_line_sync("net usershare list", + spawned = hardinfo_spawn_command_line_sync("net usershare list", &out, &err, &status, NULL); if (spawned && status == 0 && out != NULL) { @@ -66,7 +66,7 @@ scan_samba_usershares(void) while(next_nl = strchr(p, '\n')) { cmdline = g_strdup_printf("net usershare info '%s'", strend(p, '\n')); - if (g_spawn_command_line_sync(cmdline, + if (hardinfo_spawn_command_line_sync(cmdline, &usershare, NULL, NULL, NULL)) { length = strlen(usershare); scan_samba_from_string(usershare, length); @@ -74,7 +74,6 @@ scan_samba_usershares(void) } g_free(cmdline); - shell_status_pulse(); p = next_nl + 1; } g_free(out); @@ -105,8 +104,6 @@ scan_samba_from_string(gchar *str, gsize length) 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", |