/* * HardInfo - Displays System Information * Copyright (C) 2003-2007 Leandro A. F. Pereira * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __USE_XOPEN #define __USE_XOPEN #endif /* __USE_XOPEN */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE #endif /* _XOPEN_SOURCE */ #include #include #include #include #include #include #include #include #include #include "devices.h" gchar *callback_processors(); gchar *callback_memory(); gchar *callback_battery(); gchar *callback_pci(); gchar *callback_sensors(); gchar *callback_printers(); gchar *callback_storage(); gchar *callback_input(); gchar *callback_usb(); #if defined(ARCH_x86) || defined(ARCH_x86_64) gchar *callback_dmi(); gchar *callback_spd(); #endif gchar *callback_device_resources(); void scan_processors(gboolean reload); void scan_memory(gboolean reload); void scan_battery(gboolean reload); void scan_pci(gboolean reload); void scan_sensors(gboolean reload); void scan_printers(gboolean reload); void scan_storage(gboolean reload); void scan_input(gboolean reload); void scan_usb(gboolean reload); #if defined(ARCH_x86) || defined(ARCH_x86_64) void scan_dmi(gboolean reload); void scan_spd(gboolean reload); #endif void scan_device_resources(gboolean reload); gboolean root_required_for_resources(void); gchar *hi_more_info(gchar *entry); enum { ENTRY_PROCESSOR, ENTRY_MEMORY, ENTRY_PCI, ENTRY_USB, ENTRY_PRINTERS, ENTRY_BATTERY, ENTRY_SENSORS, ENTRY_INPUT, ENTRY_STORAGE, ENTRY_DMI, ENTRY_SPD, ENTRY_RESOURCES }; static ModuleEntry entries[] = { [ENTRY_PROCESSOR] = {N_("Processor"), "processor.png", callback_processors, scan_processors, MODULE_FLAG_NONE}, [ENTRY_MEMORY] = {N_("Memory"), "memory.png", callback_memory, scan_memory, MODULE_FLAG_NONE}, [ENTRY_PCI] = {N_("PCI Devices"), "devices.png", callback_pci, scan_pci, MODULE_FLAG_NONE}, [ENTRY_USB] = {N_("USB Devices"), "usb.png", callback_usb, scan_usb, MODULE_FLAG_NONE}, [ENTRY_PRINTERS] = {N_("Printers"), "printer.png", callback_printers, scan_printers, MODULE_FLAG_NONE}, [ENTRY_BATTERY] = {N_("Battery"), "battery.png", callback_battery, scan_battery, MODULE_FLAG_NONE}, [ENTRY_SENSORS] = {N_("Sensors"), "therm.png", callback_sensors, scan_sensors, MODULE_FLAG_NONE}, [ENTRY_INPUT] = {N_("Input Devices"), "inputdevices.png", callback_input, scan_input, MODULE_FLAG_NONE}, [ENTRY_STORAGE] = {N_("Storage"), "hdd.png", callback_storage, scan_storage, MODULE_FLAG_NONE}, #if defined(ARCH_x86) || defined(ARCH_x86_64) [ENTRY_DMI] = {N_("DMI"), "computer.png", callback_dmi, scan_dmi, MODULE_FLAG_NONE}, [ENTRY_SPD] = {N_("Memory SPD"), "memory.png", callback_spd, scan_spd, MODULE_FLAG_NONE}, #endif /* x86 or x86_64 */ [ENTRY_RESOURCES] = {N_("Resources"), "resources.png", callback_device_resources, scan_device_resources, MODULE_FLAG_NONE}, {NULL} }; static GSList *processors = NULL; gchar *printer_list = NULL; gchar *printer_icons = NULL; gchar *pci_list = NULL; gchar *input_list = NULL; gchar *storage_list = NULL; gchar *battery_list = NULL; gchar *meminfo = NULL; gchar *lginterval = NULL; #include gchar *get_processor_name(void) { scan_processors(FALSE); Processor *p = (Processor *) processors->data; if (g_slist_length(processors) > 1) { return idle_free(g_strdup_printf("%dx %s", g_slist_length(processors), p->model_name)); } else { return p->model_name; } } gchar *get_storage_devices(void) { scan_storage(FALSE); return storage_list; } gchar *get_printers(void) { scan_printers(FALSE); return printer_list; } gchar *get_input_devices(void) { scan_input(FALSE); return input_list; } gchar *get_processor_count(void) { scan_processors(FALSE); return g_strdup_printf("%d", g_slist_length(processors)); } gchar *get_processor_frequency(void) { Processor *p; scan_processors(FALSE); p = (Processor *)processors->data; if (p->cpu_mhz == 0.0f) { return g_strdup(N_("Unknown")); } else { return g_strdup_printf("%.0f", p->cpu_mhz); } } gchar *get_pci_device_description(gchar *pci_id) { gchar *description; if (!_pci_devices) { scan_pci(FALSE); } if ((description = g_hash_table_lookup(_pci_devices, pci_id))) { return g_strdup(description); } return NULL; } gchar *get_memory_total(void) { scan_memory(FALSE); return moreinfo_lookup ("DEV:Total Memory"); //hi_more_info(N_("Total Memory")); } /* information table from: http://elinux.org/RPi_HardwareHistory */ static struct { char *value, *intro, *model, *pcb, *mem, *mfg; } rpi_boardinfo[] = { /* Value Introduction Model Name PCB rev. Memory Manufacturer * * Raspberry Pi %s */ { "Beta", "Q1 2012", "B (Beta)", "?", "256MB", "(Beta board)" }, { "0002", "Q1 2012", "B", "1.0", "256MB", "?" }, { "0003", "Q3 2012", "B (ECN0001)", "1.0", "256MB", "(Fuses mod and D14 removed)" }, { "0004", "Q3 2012", "B", "2.0", "256MB", "Sony" }, { "0005", "Q4 2012", "B", "2.0", "256MB", "Qisda" }, { "0006", "Q4 2012", "B", "2.0", "256MB", "Egoman" }, { "0007", "Q1 2013", "A", "2.0", "256MB", "Egoman" }, { "0008", "Q1 2013", "A", "2.0", "256MB", "Sony" }, { "0009", "Q1 2013", "A", "2.0", "256MB", "Qisda" }, { "000d", "Q4 2012", "B", "2.0", "512MB", "Egoman" }, { "000e", "Q4 2012", "B", "2.0", "512MB", "Sony" }, { "000f", "Q4 2012", "B", "2.0", "512MB", "Qisda" }, { "0010", "Q3 2014", "B+", "1.0", "512MB", "Sony" }, { "0011", "Q2 2014", "Compute Module 1", "1.0", "512MB", "Sony" }, { "0012", "Q4 2014", "A+", "1.1", "256MB", "Sony" }, { "0013", "Q1 2015", "B+", "1.2", "512MB", "?" }, { "0014", "Q2 2014", "Compute Module 1", "1.0", "512MB", "Embest" }, { "0015", "?", "A+", "1.1", "256MB/512MB", "Embest" }, { "a01040", "Unknown", "2 Model B", "1.0", "1GB", "Sony" }, { "a01041", "Q1 2015", "2 Model B", "1.1", "1GB", "Sony" }, { "a21041", "Q1 2015", "2 Model B", "1.1", "1GB", "Embest" }, { "a22042", "Q3 2016", "2 Model B", "1.2", "1GB", "Embest" }, /* (with BCM2837) */ { "900021", "Q3 2016", "A+", "1.1", "512MB", "Sony" }, { "900032", "Q2 2016?", "B+", "1.2", "512MB", "Sony" }, { "900092", "Q4 2015", "Zero", "1.2", "512MB", "Sony" }, { "900093", "Q2 2016", "Zero", "1.3", "512MB", "Sony" }, { "920093", "Q4 2016?", "Zero", "1.3", "512MB", "Embest" }, { "9000c1", "Q1 2017", "Zero W", "1.1", "512MB", "Sony" }, { "a02082", "Q1 2016", "3 Model B", "1.2", "1GB", "Sony" }, { "a020a0", "Q1 2017", "Compute Module 3 or CM3 Lite", "1.0", "1GB", "Sony" }, { "a22082", "Q1 2016", "3 Model B", "1.2", "1GB", "Embest" }, { "a32082", "Q4 2016", "3 Model B", "1.2", "1GB", "Sony Japan" }, { NULL, NULL, NULL, NULL, NULL, NULL } }; static gchar *rpi_get_boardname(void) { int i = 0, c = 0; gchar *ret = NULL; gchar *soc = NULL; gchar *revision = NULL; int overvolt = 0; FILE *cpuinfo; gchar buffer[128]; cpuinfo = fopen("/proc/cpuinfo", "r"); if (!cpuinfo) return NULL; while (fgets(buffer, 128, cpuinfo)) { gchar **tmp = g_strsplit(buffer, ":", 2); tmp[0] = g_strstrip(tmp[0]); tmp[1] = g_strstrip(tmp[1]); get_str("Revision", revision); get_str("Hardware", soc); } fclose(cpuinfo); if (revision == NULL || soc == NULL) { g_free(soc); g_free(revision); return NULL; } if (g_str_has_prefix(revision, "1000")) overvolt = 1; while (rpi_boardinfo[i].value != NULL) { if (overvolt) /* +4 to ignore the 1000 prefix */ c = g_strcmp0(revision+4, rpi_boardinfo[i].value); else c = g_strcmp0(revision, rpi_boardinfo[i].value); if (c == 0) { ret = g_strdup_printf("Raspberry Pi %s (%s) pcb-rev:%s soc:%s mem:%s mfg-by:%s%s", rpi_boardinfo[i].model, rpi_boardinfo[i].intro, rpi_boardinfo[i].pcb, soc, rpi_boardinfo[i].mem, rpi_boardinfo[i].mfg, (overvolt) ? " (over-volted)" : "" ); break; } i++; } g_free(soc); g_free(revision); return ret; } gchar *get_motherboard(void) { char *board_name, *board_vendor; #if defined(ARCH_x86) || defined(ARCH_x86_64) scan_dmi(FALSE); board_name = moreinfo_lookup("DEV:DMI:Board:Name"); board_vendor = moreinfo_lookup("DEV:DMI:Board:Vendor"); if (board_name && board_vendor && *board_name && *board_vendor) return g_strconcat(board_vendor, " ", board_name, NULL); else if (board_name && *board_name) return g_strconcat(board_name, _(" (vendor unknown)"), NULL); else if (board_vendor && *board_vendor) return g_strconcat(board_vendor, _(" (model unknown)"), NULL); #else /* use device tree "model" */ if (g_file_get_contents("/proc/device-tree/model", &board_vendor, NULL, NULL)) { /* if a raspberry pi, try and get a more detailed name */ if (g_str_has_prefix(board_vendor, "Raspberry Pi")) { board_name = rpi_get_boardname(); if (board_name != NULL) { g_free(board_vendor); return board_name; } } return board_vendor; } #endif return g_strdup(_("Unknown")); } ShellModuleMethod *hi_exported_methods(void) { static ShellModuleMethod m[] = { {"getProcessorCount", get_processor_count}, {"getProcessorName", get_processor_name}, {"getProcessorFrequency", get_processor_frequency}, {"getMemoryTotal", get_memory_total}, {"getStorageDevices", get_storage_devices}, {"getPrinters", get_printers}, {"getInputDevices", get_input_devices}, {"getPCIDeviceDescription", get_pci_device_description}, {"getMotherboard", get_motherboard}, {NULL} }; return m; } gchar *hi_more_info(gchar * entry) { gchar *info = moreinfo_lookup_with_prefix("DEV", entry); if (info) return g_strdup(info); return g_strdup("?"); } gchar *hi_get_field(gchar * field) { gchar *info = moreinfo_lookup_with_prefix("DEV", field); if (info) return g_strdup(info); return g_strdup(field); } #if defined(ARCH_x86) || defined(ARCH_x86_64) void scan_dmi(gboolean reload) { SCAN_START(); __scan_dmi(); SCAN_END(); } void scan_spd(gboolean reload) { SCAN_START(); scan_spd_do(); SCAN_END(); } #endif void scan_processors(gboolean reload) { SCAN_START(); if (!processors) processors = processor_scan(); SCAN_END(); } void scan_memory(gboolean reload) { SCAN_START(); scan_memory_do(); SCAN_END(); } void scan_battery(gboolean reload) { SCAN_START(); scan_battery_do(); SCAN_END(); } void scan_pci(gboolean reload) { SCAN_START(); scan_pci_do(); SCAN_END(); } void scan_sensors(gboolean reload) { SCAN_START(); scan_sensors_do(); SCAN_END(); } void scan_printers(gboolean reload) { SCAN_START(); scan_printers_do(); SCAN_END(); } void scan_storage(gboolean reload) { SCAN_START(); g_free(storage_list); storage_list = g_strdup(""); __scan_ide_devices(); __scan_scsi_devices(); SCAN_END(); } void scan_input(gboolean reload) { SCAN_START(); __scan_input_devices(); SCAN_END(); } void scan_usb(gboolean reload) { SCAN_START(); __scan_usb(); SCAN_END(); } gchar *callback_processors() { return processor_get_info(processors); } #if defined(ARCH_x86) || defined(ARCH_x86_64) gchar *callback_dmi() { return g_strdup(dmi_info); } gchar *callback_spd() { return g_strdup(spd_info); } #endif gchar *callback_memory() { return g_strdup_printf("[Memory]\n" "%s\n" "[$ShellParam$]\n" "ViewType=2\n" "LoadGraphSuffix= kB\n" "RescanInterval=2000\n" "%s\n", meminfo, lginterval); } gchar *callback_battery() { return g_strdup_printf("%s\n" "[$ShellParam$]\n" "ReloadInterval=4000\n", battery_list); } gchar *callback_pci() { return g_strdup_printf("[PCI Devices]\n" "%s" "[$ShellParam$]\n" "ViewType=1\n", pci_list); } gchar *callback_sensors() { return g_strdup_printf("[$ShellParam$]\n" "ReloadInterval=5000\n" "%s", sensors); } gchar *callback_printers() { return g_strdup_printf("%s\n" "[$ShellParam$]\n" "ViewType=1\n" "ReloadInterval=5000\n" "%s", printer_list, printer_icons); } gchar *callback_storage() { return g_strdup_printf("%s\n" "[$ShellParam$]\n" "ReloadInterval=5000\n" "ViewType=1\n%s", storage_list, storage_icons); } gchar *callback_input() { return g_strdup_printf("[Input Devices]\n" "%s" "[$ShellParam$]\n" "ViewType=1\n" "ReloadInterval=5000\n%s", input_list, input_icons); } gchar *callback_usb() { return g_strdup_printf("%s" "[$ShellParam$]\n" "ViewType=1\n" "ReloadInterval=5000\n", usb_list); } ModuleEntry *hi_module_get_entries(void) { return entries; } gchar *hi_module_get_name(void) { return g_strdup(_("Devices")); } guchar hi_module_get_weight(void) { return 85; } void hi_module_init(void) { if (!g_file_test("/usr/share/misc/pci.ids", G_FILE_TEST_EXISTS)) { static SyncEntry se = { .fancy_name = N_("Update PCI ID listing"), .name = "GetPCIIds", .save_to = "pci.ids", .get_data = NULL }; sync_manager_add_entry(&se); } #if defined(ARCH_x86) || defined(ARCH_x86_64) { static SyncEntry se = { .fancy_name = N_("Update CPU feature database"), .name = "RecvCPUFlags", .save_to = "cpuflags.conf", .get_data = NULL }; sync_manager_add_entry(&se); } #endif /* defined(ARCH_x86) */ init_memory_labels(); init_cups(); sensors_init(); } void hi_module_deinit(void) { moreinfo_del_with_prefix("DEV"); sensors_shutdown(); g_hash_table_destroy(memlabels); g_module_close(cups); } ModuleAbout *hi_module_get_about(void) { static ModuleAbout ma[] = { { .author = "Leandro A. F. Pereira", .description = N_("Gathers information about hardware devices"), .version = VERSION, .license = "GNU GPL version 2"} }; return ma; } gchar **hi_module_get_dependencies(void) { static gchar *deps[] = { "computer.so", NULL }; return deps; } const gchar *hi_note_func(gint entry) { if (entry == ENTRY_RESOURCES) { if (root_required_for_resources()) { return g_strdup_printf(_("Resource information requires superuser privileges")); } } return NULL; }