aboutsummaryrefslogtreecommitdiff
path: root/arch/linux/common
diff options
context:
space:
mode:
authorLeandro A. F. Pereira <leandro@hardinfo.org>2010-05-03 09:27:26 -0300
committerLeandro A. F. Pereira <leandro@hardinfo.org>2010-05-03 21:08:06 -0300
commit9273c075a2f993c5154614b70233d8f74515c851 (patch)
treeeb72a8c58e6bc8f4ca3b739d28fbecc269c0052d /arch/linux/common
parent9a50155ec3e27aa6cedf3f118196f1947c769a29 (diff)
Move files from hardinfo2 to root.
Diffstat (limited to 'arch/linux/common')
-rw-r--r--arch/linux/common/alsa.h68
-rw-r--r--arch/linux/common/battery.h303
-rw-r--r--arch/linux/common/boots.h60
-rw-r--r--arch/linux/common/devmemory.h100
-rw-r--r--arch/linux/common/dmi.h198
-rw-r--r--arch/linux/common/filesystem.h108
-rw-r--r--arch/linux/common/inputdevices.h139
-rw-r--r--arch/linux/common/loadavg.h47
-rw-r--r--arch/linux/common/memory.h56
-rw-r--r--arch/linux/common/modules.h169
-rw-r--r--arch/linux/common/net.h448
-rw-r--r--arch/linux/common/nfs.h55
-rw-r--r--arch/linux/common/os.h215
-rw-r--r--arch/linux/common/pci.h240
-rw-r--r--arch/linux/common/resources.h103
-rw-r--r--arch/linux/common/samba.h119
-rw-r--r--arch/linux/common/sensors.h376
-rw-r--r--arch/linux/common/storage.h372
-rw-r--r--arch/linux/common/uptime.h74
-rw-r--r--arch/linux/common/usb.h343
20 files changed, 3593 insertions, 0 deletions
diff --git a/arch/linux/common/alsa.h b/arch/linux/common/alsa.h
new file mode 100644
index 00000000..1a156c2e
--- /dev/null
+++ b/arch/linux/common/alsa.h
@@ -0,0 +1,68 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+gchar *
+computer_get_alsacards(Computer * computer)
+{
+ GSList *p;
+ gchar *tmp = g_strdup("[Audio Devices]\n");
+ gint n = 0;
+
+ if (computer->alsa) {
+ for (p = computer->alsa->cards; p; p = p->next) {
+ AlsaCard *ac = (AlsaCard *) p->data;
+
+ tmp = h_strdup_cprintf("Audio Adapter#%d=%s\n",
+ tmp, ++n, ac->friendly_name);
+ }
+ }
+
+ return tmp;
+}
+
+static AlsaInfo *
+computer_get_alsainfo(void)
+{
+ AlsaInfo *ai;
+ AlsaCard *ac;
+ FILE *cards;
+ gchar buffer[128];
+
+ cards = fopen("/proc/asound/cards", "r");
+ if (!cards)
+ return NULL;
+
+ ai = g_new0(AlsaInfo, 1);
+
+ while (fgets(buffer, 128, cards)) {
+ gchar **tmp;
+
+ ac = g_new0(AlsaCard, 1);
+
+ tmp = g_strsplit(buffer, ":", 0);
+
+ ac->friendly_name = g_strdup(tmp[1]);
+ ai->cards = g_slist_append(ai->cards, ac);
+
+ g_strfreev(tmp);
+ (void)fgets(buffer, 128, cards); /* skip next line */
+ }
+ fclose(cards);
+
+ return ai;
+}
diff --git a/arch/linux/common/battery.h b/arch/linux/common/battery.h
new file mode 100644
index 00000000..5161422a
--- /dev/null
+++ b/arch/linux/common/battery.h
@@ -0,0 +1,303 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <time.h>
+
+const struct {
+ gchar *key, *name;
+} ups_fields[] = {
+ { "UPS Status", NULL },
+ { "STATUS", "Status" },
+ { "TIMELEFT", "Time Left" },
+ { "LINEV", "Line Voltage" },
+ { "LOADPCT", "Load Percent" },
+
+ { "UPS Battery Information", NULL },
+ { "BATTV", "Battery Voltage" },
+ { "BCHARGE", "Battery Charge" },
+ { "BATTDATE", "Battery Date" },
+
+ { "UPS Information", NULL },
+ { "APCMODEL", "Model" },
+ { "FIRMWARE", "Firmware Version" },
+ { "SERIALNO", "Serial Number" },
+ { "UPSMODE", "UPS Mode" },
+ { "CABLE", "Cable" },
+ { "UPSNAME", "UPS Name" },
+
+ { "UPS Nominal Values", NULL },
+ { "NOMINV", "Voltage" },
+ { "NOMBATTV", "Battery Voltage" },
+ { "NOMPOWER", "Power" }
+};
+
+
+static void
+__scan_battery_apcupsd(void)
+{
+ GHashTable *ups_data;
+ FILE *apcaccess;
+ char buffer[512], *apcaccess_path;
+ int i;
+
+ apcaccess_path = find_program("apcaccess");
+
+ if ((apcaccess = popen(apcaccess_path, "r"))) {
+ /* first line isn't important */
+ if (fgets(buffer, 512, apcaccess)) {
+ /* allocate the key, value hash table */
+ ups_data = g_hash_table_new(g_str_hash, g_str_equal);
+
+ /* read up all the apcaccess' output, saving it in the key, value hash table */
+ while (fgets(buffer, 512, apcaccess)) {
+ buffer[9] = '\0';
+
+ g_hash_table_insert(ups_data,
+ g_strdup(g_strstrip(buffer)),
+ g_strdup(g_strstrip(buffer + 10)));
+ }
+
+ /* builds the ups info string, respecting the field order as found in ups_fields */
+ for (i = 0; i < G_N_ELEMENTS(ups_fields); i++) {
+ if (!ups_fields[i].name) {
+ /* there's no name: make a group with the key as its name */
+ battery_list = h_strdup_cprintf("[%s]\n", battery_list, ups_fields[i].key);
+ } else {
+ /* there's a name: adds a line */
+ battery_list = h_strdup_cprintf("%s=%s\n", battery_list,
+ ups_fields[i].name,
+ g_hash_table_lookup(ups_data, ups_fields[i].key));
+ }
+ }
+
+ g_hash_table_destroy(ups_data);
+ }
+
+ pclose(apcaccess);
+ }
+
+ g_free(apcaccess_path);
+}
+
+static void
+__scan_battery_acpi(void)
+{
+ gchar *acpi_path;
+
+ gchar *present = NULL;
+ gchar *capacity = NULL;
+ gchar *technology = NULL;
+ gchar *voltage = NULL;
+ gchar *model = NULL, *serial = NULL, *type = NULL;
+ gchar *state = NULL, *rate = NULL;
+ gchar *remaining = NULL;
+ gchar *manufacturer = NULL;
+
+ acpi_path = g_strdup("/proc/acpi/battery");
+ if (g_file_test(acpi_path, G_FILE_TEST_EXISTS)) {
+ GDir *acpi;
+
+ if ((acpi = g_dir_open(acpi_path, 0, NULL))) {
+ const gchar *entry;
+
+ while ((entry = g_dir_read_name(acpi))) {
+ gchar *path = g_strdup_printf("%s/%s/info", acpi_path, entry);
+ FILE *f;
+ gchar buffer[256];
+ gdouble charge_rate = 1.0;
+
+ f = fopen(path, "r");
+ g_free(path);
+
+ if (!f)
+ goto cleanup;
+
+ while (fgets(buffer, 256, f)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ GET_STR("present", present);
+ GET_STR("design capacity", capacity);
+ GET_STR("battery technology", technology);
+ GET_STR("design voltage", voltage);
+ GET_STR("model number", model);
+ GET_STR("serial number", serial);
+ GET_STR("battery type", type);
+ GET_STR("OEM info", manufacturer);
+
+ g_strfreev(tmp);
+ }
+ fclose(f);
+
+ path = g_strdup_printf("%s/%s/state", acpi_path, entry);
+ f = fopen(path, "r");
+ g_free(path);
+
+ if (!f)
+ goto cleanup;
+
+ while (fgets(buffer, 256, f)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ GET_STR("charging state", state);
+ GET_STR("present rate", rate);
+ GET_STR("remaining capacity", remaining);
+
+ g_strfreev(tmp);
+ }
+
+ fclose(f);
+
+ const gchar *url = vendor_get_url(manufacturer);
+ if (url) {
+ char *tmp = g_strdup_printf("%s (%s)", vendor_get_name(manufacturer), url);
+ g_free(manufacturer);
+ manufacturer = tmp;
+ }
+
+ if (g_str_equal(present, "yes")) {
+ charge_rate = atof(remaining) / atof(capacity);
+
+ battery_list = h_strdup_cprintf("\n[Battery: %s]\n"
+ "State=%s (load: %s)\n"
+ "Capacity=%s / %s (%.2f%%)\n"
+ "Battery Technology=%s (%s)\n"
+ "Manufacturer=%s\n"
+ "Model Number=%s\n"
+ "Serial Number=%s\n",
+ battery_list,
+ entry,
+ state, rate,
+ remaining, capacity, charge_rate * 100.0,
+ technology, type,
+ manufacturer,
+ model,
+ serial);
+ }
+
+ cleanup:
+ g_free(present);
+ g_free(capacity);
+ g_free(technology);
+ g_free(type);
+ g_free(model);
+ g_free(serial);
+ g_free(state);
+ g_free(remaining);
+ g_free(rate);
+ g_free(manufacturer);
+
+ present = capacity = technology = type = \
+ model = serial = state = remaining = rate = NULL;
+ }
+
+ g_dir_close(acpi);
+ }
+ }
+
+ g_free(acpi_path);
+}
+
+static void
+__scan_battery_apm(void)
+{
+ FILE *procapm;
+ static char *sremaining = NULL, *stotal = NULL;
+ static unsigned int last_time = 0;
+ static int percentage = 0;
+ const char *ac_status[] = { "Battery",
+ "AC Power",
+ "Charging" };
+ int ac_bat;
+ char apm_bios_ver[16], apm_drv_ver[16];
+ char trash[10];
+
+ if ((procapm = fopen("/proc/apm", "r"))) {
+ int old_percentage = percentage;
+
+ (void)fscanf(procapm, "%s %s %s 0x%x %s %s %d%%",
+ apm_drv_ver, apm_bios_ver, trash,
+ &ac_bat, trash, trash, &percentage);
+ fclose(procapm);
+
+ if (last_time == 0) {
+ last_time = time(NULL);
+ sremaining = stotal = NULL;
+ }
+
+ if (old_percentage - percentage > 0) {
+ if (sremaining && stotal) {
+ g_free(sremaining);
+ g_free(stotal);
+ }
+
+ int secs_remaining = (time(NULL) - last_time) * percentage /
+ (old_percentage - percentage);
+ sremaining = seconds_to_string(secs_remaining);
+ stotal = seconds_to_string((secs_remaining * 100) / percentage);
+
+ last_time = time(NULL);
+ }
+ } else {
+ return;
+ }
+
+ if (stotal && sremaining) {
+ battery_list = h_strdup_cprintf("\n[Battery (APM)]\n"
+ "Charge=%d%%\n"
+ "Remaining Charge=%s of %s\n"
+ "Using=%s\n"
+ "APM driver version=%s\n"
+ "APM BIOS version=%s\n",
+ battery_list,
+ percentage,
+ sremaining, stotal,
+ ac_status[ac_bat],
+ apm_drv_ver, apm_bios_ver);
+ } else {
+ battery_list = h_strdup_cprintf("\n[Battery (APM)]\n"
+ "Charge=%d%%\n"
+ "Using=%s\n"
+ "APM driver version=%s\n"
+ "APM BIOS version=%s\n",
+ battery_list,
+ percentage,
+ ac_status[ac_bat],
+ apm_drv_ver, apm_bios_ver);
+
+ }
+}
+
+static void
+__scan_battery(void)
+{
+ if (battery_list) {
+ g_free(battery_list);
+ }
+ battery_list = g_strdup("");
+
+ __scan_battery_acpi();
+ __scan_battery_apm();
+ __scan_battery_apcupsd();
+
+ if (*battery_list == '\0') {
+ g_free(battery_list);
+
+ battery_list = g_strdup("[No batteries]\n"
+ "No batteries found on this system=\n");
+ }
+}
diff --git a/arch/linux/common/boots.h b/arch/linux/common/boots.h
new file mode 100644
index 00000000..8a3c11fa
--- /dev/null
+++ b/arch/linux/common/boots.h
@@ -0,0 +1,60 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+void
+scan_boots_real(void)
+{
+ FILE *last;
+ char buffer[256];
+
+ scan_os(FALSE);
+
+ if (!computer->os->boots)
+ computer->os->boots = g_strdup("[Boots]\n");
+ else
+ return;
+
+ last = popen("last", "r");
+ if (last) {
+ while (fgets(buffer, 256, last)) {
+ if (strstr(buffer, "system boot")) {
+ gchar **tmp, *buf = buffer;
+
+ strend(buffer, '\n');
+
+ while (*buf) {
+ if (*buf == ' ' && *(buf + 1) == ' ') {
+ strcpy(buf, buf + 1);
+
+ buf--;
+ } else {
+ buf++;
+ }
+ }
+
+ tmp = g_strsplit(buffer, " ", 0);
+ computer->os->boots = h_strdup_cprintf("\n%s %s %s %s=%s|%s",
+ computer->os->boots,
+ tmp[4], tmp[5], tmp[6], tmp[7], tmp[3], tmp[8]);
+ g_strfreev(tmp);
+ }
+ }
+
+ pclose(last);
+ }
+}
diff --git a/arch/linux/common/devmemory.h b/arch/linux/common/devmemory.h
new file mode 100644
index 00000000..e3921cdd
--- /dev/null
+++ b/arch/linux/common/devmemory.h
@@ -0,0 +1,100 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static GHashTable *memlabels;
+
+static void __scan_memory()
+{
+ gchar **keys, *tmp;
+ static gint offset = -1;
+ gint i;
+
+ if (offset == -1) {
+ /* gah. linux 2.4 adds three lines of data we don't need in
+ /proc/meminfo */
+ gchar *os_kernel = module_call_method("computer::getOSKernel");
+ offset = strstr(os_kernel, "Linux 2.4") ? 3 : 0;
+ g_free(os_kernel);
+ }
+
+ g_file_get_contents("/proc/meminfo", &meminfo, NULL, NULL);
+
+ keys = g_strsplit(meminfo, "\n", 0);
+
+ g_free(meminfo);
+ g_free(lginterval);
+
+ meminfo = g_strdup("");
+ lginterval = g_strdup("");
+
+ for (i = offset; keys[i]; i++) {
+ gchar **newkeys = g_strsplit(keys[i], ":", 0);
+
+ if (!newkeys[0]) {
+ g_strfreev(newkeys);
+ break;
+ }
+
+ g_strstrip(newkeys[1]);
+
+ if ((tmp = g_hash_table_lookup(memlabels, newkeys[0]))) {
+ g_free(newkeys[0]);
+ newkeys[0] = g_strdup(tmp);
+ }
+
+ g_hash_table_replace(moreinfo, g_strdup(newkeys[0]), g_strdup(newkeys[1]));
+
+ tmp = g_strconcat(meminfo, newkeys[0], "=", newkeys[1], "\n", NULL);
+ g_free(meminfo);
+ meminfo = tmp;
+
+ tmp = g_strconcat(lginterval,
+ "UpdateInterval$", newkeys[0], "=1000\n", NULL);
+ g_free(lginterval);
+ lginterval = tmp;
+
+ g_strfreev(newkeys);
+ }
+ g_strfreev(keys);
+}
+
+static void __init_memory_labels(void)
+{
+ static struct {
+ char *proc_label;
+ char *real_label;
+ } proc2real[] = {
+ { "MemTotal", "Total Memory" },
+ { "MemFree", "Free Memory" },
+ { "SwapCached", "Cached Swap" },
+ { "HighTotal", "High Memory" },
+ { "HighFree", "Free High Memory" },
+ { "LowTotal", "Low Memory" },
+ { "LowFree", "Free Low Memory" },
+ { "SwapTotal", "Virtual Memory" },
+ { "SwapFree", "Free Virtual Memory" },
+ { NULL },
+ };
+ gint i;
+
+ memlabels = g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (i = 0; proc2real[i].proc_label; i++) {
+ g_hash_table_insert(memlabels, proc2real[i].proc_label, proc2real[i].real_label);
+ }
+}
diff --git a/arch/linux/common/dmi.h b/arch/linux/common/dmi.h
new file mode 100644
index 00000000..6d35b25a
--- /dev/null
+++ b/arch/linux/common/dmi.h
@@ -0,0 +1,198 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * DMI support based on patch by Stewart Adam <s.adam@diffingo.com>
+ */
+#include <unistd.h>
+#include <sys/types.h>
+
+typedef struct _DMIInfo DMIInfo;
+
+struct _DMIInfo {
+ const gchar *name;
+ const gchar *file; /* for sysfs */
+ const gchar *param; /* for dmidecode */
+};
+
+DMIInfo dmi_info_table[] = {
+ { "$BIOS", NULL, NULL },
+ { "Date", "/sys/class/dmi/id/bios_date", "bios-release-date" },
+ { "Vendor", "/sys/class/dmi/id/bios_vendor", "bios-vendor" },
+ { "Version", "/sys/class/dmi/id/bios_version", "bios-version" },
+ { "$Board", NULL, NULL },
+ { "Name", "/sys/class/dmi/id/board_name", "baseboard-product-name" },
+ { "Vendor", "/sys/class/dmi/id/board_vendor", "baseboard-manufacturer" },
+};
+
+static gchar *dmi_info = NULL;
+
+gboolean dmi_get_info_dmidecode()
+{
+ FILE *dmi_pipe;
+ gchar buffer[256];
+ DMIInfo *info;
+ gboolean dmi_failed = FALSE;
+ gint i;
+
+ if (dmi_info) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) {
+ info = &dmi_info_table[i];
+
+ if (*(info->name) == '$') {
+ dmi_info = h_strdup_cprintf("[%s]\n", dmi_info,
+ (info->name) + 1);
+ } else {
+ gchar *temp;
+
+ if (!info->param)
+ continue;
+
+ temp = g_strconcat("dmidecode -s ", info->param, NULL);
+ if ((dmi_pipe = popen(temp, "r"))) {
+ g_free(temp);
+
+ (void)fgets(buffer, 256, dmi_pipe);
+ if (pclose(dmi_pipe)) {
+ dmi_failed = TRUE;
+ break;
+ }
+
+ const gchar *url = vendor_get_url(buffer);
+ if (url) {
+ const gchar *vendor = vendor_get_name(buffer);
+ if (g_strstr_len(vendor, -1, g_strstrip(buffer)) ||
+ g_strstr_len(g_strstrip(buffer), -1, vendor)) {
+ dmi_info = h_strdup_cprintf("%s=%s (%s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ url);
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s (%s, %s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ vendor, url);
+ }
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s\n",
+ dmi_info,
+ info->name,
+ buffer);
+ }
+ } else {
+ g_free(temp);
+ dmi_failed = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (dmi_failed) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ return !dmi_failed;
+}
+
+gboolean dmi_get_info_sys()
+{
+ FILE *dmi_file;
+ gchar buffer[256];
+ DMIInfo *info;
+ gboolean dmi_failed = FALSE;
+ gint i;
+
+ if (dmi_info) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) {
+ info = &dmi_info_table[i];
+
+ if (*(info->name) == '$') {
+ dmi_info = h_strdup_cprintf("[%s]\n", dmi_info,
+ (info->name) + 1);
+ } else {
+ if (!info->file)
+ continue;
+
+ if ((dmi_file = fopen(info->file, "r"))) {
+ (void)fgets(buffer, 256, dmi_file);
+ fclose(dmi_file);
+
+ const gchar *url = vendor_get_url(buffer);
+ if (url) {
+ const gchar *vendor = vendor_get_name(buffer);
+ if (g_strstr_len(vendor, -1, g_strstrip(buffer)) ||
+ g_strstr_len(g_strstrip(buffer), -1, vendor)) {
+ dmi_info = h_strdup_cprintf("%s=%s (%s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ url);
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s (%s, %s)\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer),
+ vendor, url);
+ }
+ } else {
+ dmi_info = h_strdup_cprintf("%s=%s\n",
+ dmi_info,
+ info->name,
+ g_strstrip(buffer));
+ }
+ } else {
+ dmi_failed = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (dmi_failed) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
+
+ return !dmi_failed;
+}
+
+void __scan_dmi()
+{
+ gboolean dmi_ok;
+
+ dmi_ok = dmi_get_info_sys();
+
+ if (!dmi_ok) {
+ dmi_ok = dmi_get_info_dmidecode();
+ }
+
+ if (!dmi_ok) {
+ dmi_info = g_strdup("[No DMI information]\n"
+ "There was an error retrieving the information.=\n"
+ "Please try running HardInfo as root.=\n");
+ }
+}
diff --git a/arch/linux/common/filesystem.h b/arch/linux/common/filesystem.h
new file mode 100644
index 00000000..48cbbd51
--- /dev/null
+++ b/arch/linux/common/filesystem.h
@@ -0,0 +1,108 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Some code from xfce4-mount-plugin, version 0.4.3
+ * Copyright (C) 2005 Jean-Baptiste jb_dul@yahoo.com
+ * Distributed under the terms of GNU GPL 2.
+ */
+#include <sys/vfs.h>
+
+static gchar *fs_list = NULL;
+
+static gboolean
+remove_filesystem_entries(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "FS");
+}
+
+static void
+scan_filesystems(void)
+{
+ FILE *mtab;
+ gchar buf[1024];
+ struct statfs sfs;
+ int count = 0;
+
+ g_free(fs_list);
+ fs_list = g_strdup("");
+ g_hash_table_foreach_remove(moreinfo, remove_filesystem_entries, NULL);
+
+ mtab = fopen("/etc/mtab", "r");
+ if (!mtab)
+ return;
+
+ while (fgets(buf, 1024, mtab)) {
+ gfloat size, used, avail;
+ gchar **tmp;
+
+ tmp = g_strsplit(buf, " ", 0);
+ if (!statfs(tmp[1], &sfs)) {
+ gfloat use_ratio;
+
+ size = (float) sfs.f_bsize * (float) sfs.f_blocks;
+ avail = (float) sfs.f_bsize * (float) sfs.f_bavail;
+ used = size - avail;
+
+ if (size == 0.0f) {
+ continue;
+ }
+
+ if (avail == 0.0f) {
+ use_ratio = 100.0f;
+ } else {
+ use_ratio = 100.0f * (used / size);
+ }
+
+ gchar *strsize = size_human_readable(size),
+ *stravail = size_human_readable(avail),
+ *strused = size_human_readable(used);
+
+ gchar *strhash;
+ if ((strhash = g_hash_table_lookup(moreinfo, tmp[0]))) {
+ g_hash_table_remove(moreinfo, tmp[0]);
+ g_free(strhash);
+ }
+
+ strreplacechr(tmp[0], "#", '_');
+
+ strhash = g_strdup_printf("[%s]\n"
+ "Filesystem=%s\n"
+ "Mounted As=%s\n"
+ "Mount Point=%s\n"
+ "Size=%s\n"
+ "Used=%s\n"
+ "Available=%s\n",
+ tmp[0],
+ tmp[2],
+ strstr(tmp[3], "rw") ? "Read-Write" :
+ "Read-Only", tmp[1], strsize, strused,
+ stravail);
+ g_hash_table_insert(moreinfo, g_strdup_printf("FS%d", ++count), strhash);
+
+ fs_list = h_strdup_cprintf("$FS%d$%s=%.2f %% (%s of %s)|%s\n",
+ fs_list,
+ count, tmp[0], use_ratio, stravail, strsize, tmp[1]);
+
+ g_free(strsize);
+ g_free(stravail);
+ g_free(strused);
+ }
+ g_strfreev(tmp);
+ }
+
+ fclose(mtab);
+}
diff --git a/arch/linux/common/inputdevices.h b/arch/linux/common/inputdevices.h
new file mode 100644
index 00000000..20e4289c
--- /dev/null
+++ b/arch/linux/common/inputdevices.h
@@ -0,0 +1,139 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static gchar *input_icons = NULL;
+
+static gboolean
+remove_input_devices(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "INP");
+}
+
+static struct {
+ char *name;
+ char *icon;
+} input_devices[] = {
+ { "Keyboard", "keyboard.png" },
+ { "Joystick", "joystick.png" },
+ { "Mouse", "mouse.png" },
+ { "Speaker", "audio.png" },
+ { "Unknown", "module.png" },
+};
+
+void
+__scan_input_devices(void)
+{
+ FILE *dev;
+ gchar buffer[128];
+ gchar *tmp, *name = NULL, *phys = NULL;
+ gint bus, vendor, product, version;
+ int d = 0, n = 0;
+
+ dev = fopen("/proc/bus/input/devices", "r");
+ if (!dev)
+ return;
+
+ if (input_list) {
+ g_hash_table_foreach_remove(moreinfo, remove_input_devices, NULL);
+ g_free(input_list);
+ g_free(input_icons);
+ }
+ input_list = g_strdup("");
+ input_icons = g_strdup("");
+
+ while (fgets(buffer, 128, dev)) {
+ tmp = buffer;
+
+ switch (*tmp) {
+ case 'N':
+ name = g_strdup(tmp + strlen("N: Name="));
+ 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 (strstr(name, "PC Speaker")) {
+ d = 3; // INPUT_PCSPKR
+ }
+
+ tmp = g_strdup_printf("INP%d", ++n);
+ input_list = h_strdup_cprintf("$%s$%s=\n",
+ input_list,
+ tmp, name);
+ input_icons = h_strdup_cprintf("Icon$%s$%s=%s\n",
+ input_icons,
+ tmp, name,
+ input_devices[d].icon);
+ gchar *strhash = g_strdup_printf("[Device Information]\n"
+ "Name=%s\n"
+ "Type=%s\n"
+ "Bus=0x%x\n",
+ name,
+ input_devices[d].name,
+ bus);
+
+ const gchar *url = vendor_get_url(name);
+ if (url) {
+ strhash = h_strdup_cprintf("Vendor=%s (%s)\n",
+ strhash,
+ vendor_get_name(name),
+ url);
+ } else {
+ strhash = h_strdup_cprintf("Vendor=%x\n",
+ strhash,
+ vendor);
+ }
+
+ strhash = h_strdup_cprintf("Product=0x%x\n"
+ "Version=0x%x\n",
+ strhash, product, version);
+
+ if (phys[1] != 0) {
+ strhash = h_strdup_cprintf("Connected to=%s\n",
+ strhash, phys);
+ }
+
+ if (strstr(phys,"ir")) {
+ strhash = h_strdup_cprintf("InfraRed port=yes\n",
+ strhash);
+ }
+
+ g_hash_table_insert(moreinfo, tmp, strhash);
+
+ g_free(phys);
+ g_free(name);
+ }
+ }
+
+ fclose(dev);
+}
diff --git a/arch/linux/common/loadavg.h b/arch/linux/common/loadavg.h
new file mode 100644
index 00000000..ce2d8775
--- /dev/null
+++ b/arch/linux/common/loadavg.h
@@ -0,0 +1,47 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static LoadInfo *
+computer_get_loadinfo(void)
+{
+ LoadInfo *li = g_new0(LoadInfo, 1);
+ FILE *procloadavg;
+
+ procloadavg = fopen("/proc/loadavg", "r");
+ (void)fscanf(procloadavg, "%f %f %f", &(li->load1), &(li->load5),
+ &(li->load15));
+ fclose(procloadavg);
+
+ return li;
+}
+
+static gchar *
+computer_get_formatted_loadavg()
+{
+ LoadInfo *li;
+ gchar *tmp;
+
+ li = computer_get_loadinfo();
+
+ tmp =
+ g_strdup_printf("%.2f, %.2f, %.2f", li->load1, li->load5,
+ li->load15);
+
+ g_free(li);
+ return tmp;
+}
diff --git a/arch/linux/common/memory.h b/arch/linux/common/memory.h
new file mode 100644
index 00000000..c87359b9
--- /dev/null
+++ b/arch/linux/common/memory.h
@@ -0,0 +1,56 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static MemoryInfo *
+computer_get_memory(void)
+{
+ MemoryInfo *mi;
+ FILE *procmem;
+ gchar buffer[128];
+
+ procmem = fopen("/proc/meminfo", "r");
+ if (!procmem)
+ return NULL;
+ mi = g_new0(MemoryInfo, 1);
+
+ while (fgets(buffer, 128, procmem)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ get_int("MemTotal", mi->total);
+ get_int("MemFree", mi->free);
+ get_int("Cached", mi->cached);
+
+ g_strfreev(tmp);
+ }
+ fclose(procmem);
+
+ mi->used = mi->total - mi->free;
+
+ mi->total /= 1000;
+ mi->cached /= 1000;
+ mi->used /= 1000;
+ mi->free /= 1000;
+
+ mi->used -= mi->cached;
+ mi->ratio = 1 - (gdouble) mi->used / mi->total;
+
+ return mi;
+}
diff --git a/arch/linux/common/modules.h b/arch/linux/common/modules.h
new file mode 100644
index 00000000..78fb9de3
--- /dev/null
+++ b/arch/linux/common/modules.h
@@ -0,0 +1,169 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#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; \
+ }
+
+static gboolean
+remove_module_devices(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "MOD");
+}
+
+static GHashTable *_module_hash_table = NULL;
+
+static void
+scan_modules_do(void)
+{
+ FILE *lsmod;
+ gchar buffer[1024];
+ gchar *lsmod_path;
+
+ if (!_module_hash_table) {
+ _module_hash_table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ if (module_list) {
+ g_free(module_list);
+ }
+
+ module_list = NULL;
+ g_hash_table_foreach_remove(moreinfo, remove_module_devices, NULL);
+
+ lsmod_path = find_program("lsmod");
+ lsmod = popen(lsmod_path, "r");
+ if (!lsmod) {
+ g_free(lsmod_path);
+ return;
+ }
+
+ (void)fgets(buffer, 1024, lsmod); /* Discards the first line */
+
+ while (fgets(buffer, 1024, lsmod)) {
+ gchar *buf, *strmodule, *hashkey;
+ gchar *author = NULL,
+ *description = NULL,
+ *license = NULL,
+ *deps = NULL, *vermagic = NULL, *filename = NULL, modname[64];
+ FILE *modi;
+ glong memory;
+
+ shell_status_pulse();
+
+ buf = buffer;
+
+ sscanf(buf, "%s %ld", modname, &memory);
+
+ hashkey = g_strdup_printf("MOD%s", modname);
+ buf = g_strdup_printf("/sbin/modinfo %s 2>/dev/null", modname);
+
+ modi = popen(buf, "r");
+ while (fgets(buffer, 1024, modi)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+
+ GET_STR("author", author);
+ GET_STR("description", description);
+ GET_STR("license", license);
+ GET_STR("depends", deps);
+ GET_STR("vermagic", vermagic);
+ GET_STR("filename", filename);
+
+ g_strfreev(tmp);
+ }
+ pclose(modi);
+ g_free(buf);
+
+ /* old modutils includes quotes in some strings; strip them */
+ /*remove_quotes(modname);
+ remove_quotes(description);
+ remove_quotes(vermagic);
+ remove_quotes(author);
+ remove_quotes(license); */
+
+ /* old modutils displays <none> when there's no value for a
+ given field; this is not desirable in the module name
+ display, so change it to an empty string */
+ if (description && g_str_equal(description, "&lt;none&gt;")) {
+ g_free(description);
+ description = g_strdup("");
+
+ g_hash_table_insert(_module_hash_table,
+ g_strdup(modname),
+ g_strdup_printf("Kernel module (%s)", modname));
+ } else {
+ g_hash_table_insert(_module_hash_table,
+ g_strdup(modname),
+ g_strdup(description));
+ }
+
+ /* append this module to the list of modules */
+ module_list = h_strdup_cprintf("$%s$%s=%s\n",
+ module_list,
+ hashkey,
+ modname,
+ description ? description : "");
+
+#define NONE_IF_NULL(var) (var) ? (var) : "N/A"
+
+ /* create the module information string */
+ strmodule = g_strdup_printf("[Module Information]\n"
+ "Path=%s\n"
+ "Used Memory=%.2fKiB\n"
+ "[Description]\n"
+ "Name=%s\n"
+ "Description=%s\n"
+ "Version Magic=%s\n"
+ "[Copyright]\n"
+ "Author=%s\n"
+ "License=%s\n",
+ NONE_IF_NULL(filename),
+ memory / 1024.0,
+ modname,
+ NONE_IF_NULL(description),
+ NONE_IF_NULL(vermagic),
+ NONE_IF_NULL(author),
+ NONE_IF_NULL(license));
+
+ /* if there are dependencies, append them to that string */
+ if (deps && strlen(deps)) {
+ gchar **tmp = g_strsplit(deps, ",", 0);
+
+ strmodule = h_strconcat(strmodule,
+ "\n[Dependencies]\n",
+ g_strjoinv("=\n", tmp),
+ "=\n", NULL);
+ g_strfreev(tmp);
+ g_free(deps);
+ }
+
+ g_hash_table_insert(moreinfo, hashkey, strmodule);
+
+ g_free(license);
+ g_free(description);
+ g_free(author);
+ g_free(vermagic);
+ g_free(filename);
+ }
+ pclose(lsmod);
+
+ g_free(lsmod_path);
+}
diff --git a/arch/linux/common/net.h b/arch/linux/common/net.h
new file mode 100644
index 00000000..c3224321
--- /dev/null
+++ b/arch/linux/common/net.h
@@ -0,0 +1,448 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * Wireless Extension Example
+ * http://www.krugle.org/examples/p-OZYzuisV6gyQIaTu/iwconfig.c
+ */
+static gchar *network_interfaces = NULL, *network_icons = NULL;
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <linux/sockios.h>
+
+#include <arpa/inet.h>
+
+#ifdef HAS_LINUX_WE
+#include <linux/if.h>
+#include <linux/wireless.h>
+#else
+#include <net/if.h>
+#endif /* HAS_LINUX_WE */
+
+typedef struct _NetInfo NetInfo;
+struct _NetInfo {
+ char name[16];
+ int mtu;
+ unsigned char mac[8];
+ char ip[16];
+ char mask[16];
+ char broadcast[16];
+
+#ifdef HAS_LINUX_WE
+ char wi_essid[IW_ESSID_MAX_SIZE + 1];
+ int wi_rate;
+ int wi_mode, wi_status;
+ gboolean wi_has_txpower;
+ struct iw_param wi_txpower;
+ int wi_quality_level, wi_signal_level, wi_noise_level;
+ gboolean is_wireless;
+#endif
+};
+
+#ifdef HAS_LINUX_WE
+const gchar *wi_operation_modes[] = { "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Unknown" };
+
+void get_wireless_info(int fd, NetInfo *netinfo)
+{
+ FILE *wrls;
+ char wbuf[256];
+ struct iwreq wi_req;
+ int r, trash;
+
+ netinfo->is_wireless = FALSE;
+
+ if ((wrls = fopen("/proc/net/wireless", "r"))) {
+ while (fgets(wbuf, 256, wrls)) {
+ if (strchr(wbuf, ':') && strstr(wbuf, netinfo->name)) {
+ gchar *buf1 = wbuf;
+
+ netinfo->is_wireless = TRUE;
+
+ buf1 = strchr(buf1, ':') + 1;
+
+ if (strstr(buf1, ".")) {
+ sscanf(buf1, "%d %d. %d %d %d %d %d %d %d %d",
+ &(netinfo->wi_status),
+ &(netinfo->wi_quality_level),
+ &(netinfo->wi_signal_level),
+ &(netinfo->wi_noise_level),
+ &trash, &trash, &trash, &trash, &trash, &trash);
+ } else {
+ sscanf(buf1, "%d %d %d %d %d %d %d %d %d %d",
+ &(netinfo->wi_status),
+ &(netinfo->wi_quality_level),
+ &(netinfo->wi_signal_level),
+ &(netinfo->wi_noise_level),
+ &trash, &trash, &trash, &trash, &trash,
+ &trash);
+ }
+
+ break;
+ }
+ }
+ fclose(wrls);
+ }
+
+ if (!netinfo->is_wireless)
+ return;
+
+ strncpy(wi_req.ifr_name, netinfo->name, 16);
+
+ /* obtain essid */
+ wi_req.u.essid.pointer = netinfo->wi_essid;
+ wi_req.u.essid.length = IW_ESSID_MAX_SIZE + 1;
+ wi_req.u.essid.flags = 0;
+
+ if ((r = ioctl(fd, SIOCGIWESSID, &wi_req) < 0)) {
+ strcpy(netinfo->wi_essid, "");
+ } else {
+ netinfo->wi_essid[wi_req.u.essid.length] = '\0';
+ }
+
+ /* obtain bit rate */
+ if ((r = ioctl(fd, SIOCGIWRATE, &wi_req) < 0)) {
+ netinfo->wi_rate = 0;
+ } else {
+ netinfo->wi_rate = wi_req.u.bitrate.value;
+ }
+
+ /* obtain operation mode */
+ if ((r = ioctl(fd, SIOCGIWMODE, &wi_req) < 0)) {
+ netinfo->wi_mode = 0;
+ } else {
+ if (wi_req.u.mode >= 0 && wi_req.u.mode < 6) {
+ netinfo->wi_mode = wi_req.u.mode;
+ } else {
+ netinfo->wi_mode = 6;
+ }
+ }
+
+#if WIRELESS_EXT >= 10
+ /* obtain txpower */
+ if ((r = ioctl(fd, SIOCGIWTXPOW, &wi_req) < 0)) {
+ netinfo->wi_has_txpower = FALSE;
+ } else {
+ netinfo->wi_has_txpower = TRUE;
+
+ memcpy(&netinfo->wi_txpower, &wi_req.u.txpower, sizeof(struct iw_param));
+ }
+#else
+ netinfo->wi_has_txpower = FALSE;
+#endif /* WIRELESS_EXT >= 10 */
+}
+#endif /* HAS_LINUX_WE */
+
+void get_net_info(char *if_name, NetInfo * netinfo)
+{
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ /* IPv4 */
+ ifr.ifr_addr.sa_family = AF_INET;
+ strcpy(netinfo->name, if_name);
+
+ /* MTU */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ netinfo->mtu = 0;
+ } else {
+ netinfo->mtu = ifr.ifr_mtu;
+ }
+
+ /* HW Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ memset(netinfo->mac, 0, 8);
+ } else {
+ memcpy(netinfo->mac, ifr.ifr_ifru.ifru_hwaddr.sa_data, 8);
+ }
+
+ /* IP Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
+ netinfo->ip[0] = 0;
+ } else {
+ sprintf(netinfo->ip, "%s",
+ inet_ntoa(((struct sockaddr_in *) &ifr.ifr_addr)->
+ sin_addr));
+ }
+
+ /* Mask Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) {
+ netinfo->mask[0] = 0;
+ } else {
+ sprintf(netinfo->mask, "%s",
+ inet_ntoa(((struct sockaddr_in *) &ifr.ifr_addr)->
+ sin_addr));
+ }
+
+ /* Broadcast Address */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) {
+ netinfo->broadcast[0] = 0;
+ } else {
+ sprintf(netinfo->broadcast, "%s",
+ inet_ntoa(((struct sockaddr_in *) &ifr.ifr_addr)->
+ sin_addr));
+ }
+
+#ifdef HAS_LINUX_WE
+ get_wireless_info(fd, netinfo);
+#endif
+
+ shutdown(fd, 0);
+ close(fd);
+}
+
+static struct {
+ char *type;
+ char *label;
+ char *icon;
+} netdev2type[] = {
+ { "eth", "Ethernet", "network-interface" },
+ { "lo", "Loopback", "network" },
+ { "ppp", "Point-to-Point", "modem" },
+ { "ath", "Wireless", "wireless" },
+ { "wlan", "Wireless", "wireless" },
+ { "ra", "Wireless", "wireless" },
+ { "wl", "Wireless", "wireless" },
+ { "wmaster", "Wireless", "wireless" },
+ { "tun", "Virtual Point-to-Point (TUN)", "network" },
+ { "tap", "Ethernet (TAP)", "network" },
+ { "plip", "Parallel Line Internet Protocol", "network" },
+ { "irlan", "Infrared", "network" },
+ { "slip", "Serial Line Internet Protocol", "network" },
+ { "isdn", "Integrated Services Digital Network", "modem" },
+ { "sit", "IPv6-over-IPv4 Tunnel", "network" },
+ { "vmnet8", "VMWare Virtual Network Interface (NAT)", "computer" },
+ { "vmnet", "VMWare Virtual Network Interface", "computer" },
+ { "pan", "Personal Area Network (PAN)", "bluetooth" },
+ { "bnep", "Bluetooth", "bluetooth" },
+ { "br", "Bridge Interface", "network" },
+ { "ham", "Hamachi Virtual Personal Network", "network"},
+ { "net", "Ethernet", "network-interface" },
+ { "ifb", "Intermediate Functional Block", "network" },
+ { "gre", "GRE Network Tunnel", "network" },
+ { "msh", "Mesh Network", "wireless" },
+ { "wmaster", "Wireless Master Interface", "wireless" },
+ { NULL, "Unknown", "network" },
+};
+
+static void net_get_iface_type(gchar * name, gchar ** type, gchar ** icon, NetInfo *ni)
+{
+ int i;
+
+#ifdef HAS_LINUX_WE
+ if (ni->is_wireless) {
+ *type = "Wireless";
+ *icon = "wireless";
+
+ return;
+ }
+#endif
+
+ for (i = 0; netdev2type[i].type; i++) {
+ if (g_str_has_prefix(name, netdev2type[i].type))
+ break;
+ }
+
+ *type = netdev2type[i].label;
+ *icon = netdev2type[i].icon;
+}
+
+static gboolean
+remove_net_devices(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "NET");
+}
+
+static void scan_net_interfaces_24(void)
+{
+ FILE *proc_net;
+ NetInfo ni;
+ gchar buffer[256];
+ gchar *devid, *detailed;
+ gdouble recv_bytes;
+ gdouble recv_errors;
+ gdouble recv_packets;
+
+ gdouble trans_bytes;
+ gdouble trans_errors;
+ gdouble trans_packets;
+
+ if (!g_file_test("/proc/net/dev", G_FILE_TEST_EXISTS)) {
+ if (network_interfaces) {
+ g_free(network_interfaces);
+ network_interfaces = g_strdup("[Network Interfaces]\n"
+ "None found=\n");
+ }
+
+ return;
+ }
+
+ if (network_interfaces) {
+ g_free(network_interfaces);
+ }
+
+ if (network_icons) {
+ g_free(network_icons);
+ }
+
+ network_interfaces = g_strdup("[Network Interfaces]\n");
+ network_icons = g_strdup("");
+
+ proc_net = fopen("/proc/net/dev", "r");
+ if (!proc_net)
+ return;
+
+ while (fgets(buffer, 256, proc_net)) {
+ if (strchr(buffer, ':')) {
+ gint trash;
+ gchar ifacename[16];
+ gchar *buf = buffer;
+ gchar *iface_type, *iface_icon;
+ gint i;
+
+ buf = g_strstrip(buf);
+
+ memset(ifacename, 0, 16);
+
+ for (i = 0; buffer[i] != ':' && i < 16; i++) {
+ ifacename[i] = buffer[i];
+ }
+
+ buf = strchr(buf, ':') + 1;
+
+ /* iface: bytes packets errs drop fifo frame compressed multicast */
+ sscanf(buf, "%lf %lf %lf %d %d %d %d %d %lf %lf %lf",
+ &recv_bytes, &recv_packets,
+ &recv_errors, &trash, &trash, &trash, &trash,
+ &trash, &trans_bytes, &trans_packets, &trans_errors);
+
+ gdouble recv_mb = recv_bytes / 1048576.0;
+ gdouble trans_mb = trans_bytes / 1048576.0;
+
+ get_net_info(ifacename, &ni);
+
+ devid = g_strdup_printf("NET%s", ifacename);
+
+ network_interfaces =
+ h_strdup_cprintf
+ ("$%s$%s=%s|%.2lfMiB|%.2lfMiB\n",
+ network_interfaces, devid, ifacename, ni.ip[0] ? ni.ip : "",
+ trans_mb, recv_mb);
+ net_get_iface_type(ifacename, &iface_type, &iface_icon, &ni);
+
+ network_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n",
+ network_icons, devid,
+ ifacename, iface_icon);
+
+ detailed = g_strdup_printf("[Network Adapter Properties]\n"
+ "Interface Type=%s\n"
+ "Hardware Address (MAC)=%02x:%02x:%02x:%02x:%02x:%02x\n"
+ "MTU=%d\n"
+ "[Transfer Details]\n"
+ "Bytes Received=%.0lf (%.2fMiB)\n"
+ "Bytes Sent=%.0lf (%.2fMiB)\n",
+ iface_type,
+ ni.mac[0], ni.mac[1],
+ ni.mac[2], ni.mac[3],
+ ni.mac[4], ni.mac[5],
+ ni.mtu,
+ recv_bytes, recv_mb,
+ trans_bytes, trans_mb);
+
+#ifdef HAS_LINUX_WE
+ if (ni.is_wireless) {
+ gchar *txpower;
+
+ if (ni.wi_has_txpower) {
+ gint mw, dbm;
+
+ if (ni.wi_txpower.flags & IW_TXPOW_MWATT) {
+ mw = ni.wi_txpower.value;
+ dbm = (int) ceil(10.0 * log10((double) ni.wi_txpower.value));
+ } else {
+ dbm = ni.wi_txpower.value;
+ mw = (int) floor(pow(10.0, ((double) dbm / 10.0)));
+ }
+
+ txpower = g_strdup_printf("%ddBm (%dmW)", dbm, mw);
+ } else {
+ txpower = g_strdup("Unknown");
+ }
+
+ detailed = h_strdup_cprintf("\n[Wireless Properties]\n"
+ "Network Name (SSID)=%s\n"
+ "Bit Rate=%dMb/s\n"
+ "Transmission Power=%s\n"
+ "Mode=%s\n"
+ "Status=%d\n"
+ "Link Quality=%d\n"
+ "Signal / Noise=%d / %d\n",
+ detailed,
+ ni.wi_essid,
+ ni.wi_rate / 1000000,
+ txpower,
+ wi_operation_modes[ni.wi_mode],
+ ni.wi_status,
+ ni.wi_quality_level,
+ ni.wi_signal_level,
+ ni.wi_noise_level);
+
+ g_free(txpower);
+ }
+#endif
+
+ if (ni.ip[0] || ni.mask[0] || ni.broadcast[0]) {
+ detailed =
+ h_strdup_cprintf("\n[Internet Protocol (IPv4)]\n"
+ "IP Address=%s\n" "Mask=%s\n"
+ "Broadcast Address=%s\n", detailed,
+ ni.ip[0] ? ni.ip : "Not set",
+ ni.mask[0] ? ni.mask : "Not set",
+ ni.broadcast[0] ? ni.
+ broadcast : "Not set");
+ }
+
+ g_hash_table_insert(moreinfo, devid, detailed);
+ }
+ }
+ fclose(proc_net);
+}
+
+static void scan_net_interfaces(void)
+{
+ /* FIXME: See if we're running Linux 2.6 and if /sys is mounted, then use
+ that instead of /proc/net/dev */
+
+ /* remove old devices from global device table */
+ g_hash_table_foreach_remove(moreinfo, remove_net_devices, NULL);
+
+ scan_net_interfaces_24();
+}
diff --git a/arch/linux/common/nfs.h b/arch/linux/common/nfs.h
new file mode 100644
index 00000000..894680db
--- /dev/null
+++ b/arch/linux/common/nfs.h
@@ -0,0 +1,55 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static gchar *nfs_shares_list = NULL;
+void
+scan_nfs_shared_directories(void)
+{
+ FILE *exports;
+ gint count = 0;
+ gchar buf[512];
+
+ if (nfs_shares_list) {
+ g_free(nfs_shares_list);
+ }
+
+ nfs_shares_list = g_strdup("");
+
+ if ((exports = fopen("/etc/exports", "r"))) {
+ while (fgets(buf, 512, exports)) {
+ if (buf[0] != '/')
+ continue;
+
+ strend(buf, ' ');
+ strend(buf, '\t');
+
+ nfs_shares_list = h_strdup_cprintf("%s=\n",
+ buf, nfs_shares_list);
+ count++;
+ }
+
+ fclose(exports);
+ }
+
+ if (!count) {
+ g_free(nfs_shares_list);
+
+ nfs_shares_list = g_strdup("No NFS exports=\n");
+ }
+}
+
diff --git a/arch/linux/common/os.h b/arch/linux/common/os.h
new file mode 100644
index 00000000..93d10f13
--- /dev/null
+++ b/arch/linux/common/os.h
@@ -0,0 +1,215 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static gchar *
+get_libc_version(void)
+{
+ FILE *libc;
+ gchar buf[256], *tmp, *p;
+
+ if (g_file_test("/lib/ld-uClibc.so.0", G_FILE_TEST_EXISTS)) {
+ return g_strdup("uClibc Library");
+ } else if (!g_file_test("/lib/libc.so.6", G_FILE_TEST_EXISTS)) {
+ goto err;
+ }
+
+ libc = popen("/lib/libc.so.6", "r");
+ if (!libc) goto err;
+
+ (void)fgets(buf, 256, libc);
+ if (pclose(libc)) goto err;
+
+ tmp = strstr(buf, "version ");
+ if (!tmp) goto err;
+
+ p = strchr(tmp, ',');
+ if (p) *p = '\0';
+ else goto err;
+
+ return g_strdup_printf("GNU C Library version %s (%sstable)",
+ strchr(tmp, ' ') + 1,
+ strstr(buf, " stable ") ? "" : "un");
+ err:
+ return g_strdup("Unknown");
+}
+
+#include <gdk/gdkx.h>
+
+void
+detect_desktop_environment(OperatingSystem * os)
+{
+ const gchar *tmp = g_getenv("GNOME_DESKTOP_SESSION_ID");
+ FILE *version;
+ char vers[16];
+
+ if (tmp) {
+ /* FIXME: this might not be true, as the gnome-panel in path
+ may not be the one that's running.
+ see where the user's running panel is and run *that* to
+ obtain the version. */
+ version = popen("gnome-about --gnome-version", "r");
+ if (version) {
+ (void)fscanf(version, "Version: %s", vers);
+ if (pclose(version))
+ goto unknown;
+ } else {
+ goto unknown;
+ }
+
+ os->desktop = g_strdup_printf("GNOME %s", vers);
+ } else if (g_getenv("KDE_FULL_SESSION")) {
+
+ if (g_getenv("KDE_SESSION_VERSION") && strstr(g_getenv("KDE_SESSION_VERSION"),(gchar *)"4")) {
+ version = popen("kwin --version", "r");
+ } else {
+ version = popen("kcontrol --version", "r");
+ }
+
+ if (version) {
+ char buf[32];
+
+ (void)fgets(buf, 32, version);
+
+ (void)fscanf(version, "KDE: %s", vers);
+ if (pclose(version))
+ goto unknown;
+ } else {
+ goto unknown;
+ }
+
+ os->desktop = g_strdup_printf("KDE %s", vers);
+ } else {
+ unknown:
+ if (!g_getenv("DISPLAY")) {
+ os->desktop = g_strdup("Terminal");
+ } else {
+ GdkScreen *screen = gdk_screen_get_default();
+
+ if (screen && GDK_IS_SCREEN(screen)) {
+ const gchar *windowman;
+
+ windowman = gdk_x11_screen_get_window_manager_name(screen);
+
+ if (g_str_equal(windowman, "Xfwm4")) {
+ /* FIXME: check if xprop -root | grep XFCE_DESKTOP_WINDOW
+ is defined */
+ os->desktop = g_strdup("XFCE 4");
+ } else {
+ os->desktop = g_strdup_printf("Unknown (Window Manager: %s)",
+ windowman);
+ }
+ } else {
+ os->desktop = g_strdup("Unknown");
+ }
+ }
+ }
+}
+
+static OperatingSystem *
+computer_get_os(void)
+{
+ struct utsname utsbuf;
+ OperatingSystem *os;
+ int i;
+
+ os = g_new0(OperatingSystem, 1);
+
+ /* Attempt to get the Distribution name; try using /etc/lsb-release first,
+ then doing the legacy method (checking for /etc/$DISTRO-release files) */
+ if (g_file_test("/etc/lsb-release", G_FILE_TEST_EXISTS)) {
+ FILE *release;
+ gchar buffer[128];
+
+ release = popen("lsb_release -d", "r");
+ if (release) {
+ (void)fgets(buffer, 128, release);
+ pclose(release);
+
+ os->distro = buffer;
+ os->distro = g_strdup(os->distro + strlen("Description:\t"));
+ }
+ }
+
+ for (i = 0;; i++) {
+ if (distro_db[i].file == NULL) {
+ os->distrocode = g_strdup("unk");
+ os->distro = g_strdup("Unknown distribution");
+ break;
+ }
+
+ if (g_file_test(distro_db[i].file, G_FILE_TEST_EXISTS)) {
+ FILE *distro_ver;
+ char buf[128];
+
+ distro_ver = fopen(distro_db[i].file, "r");
+ if (distro_ver) {
+ (void)fgets(buf, 128, distro_ver);
+ fclose(distro_ver);
+ } else {
+ continue;
+ }
+
+ buf[strlen(buf) - 1] = 0;
+
+ if (!os->distro) {
+ /*
+ * HACK: Some Debian systems doesn't include
+ * the distribuition name in /etc/debian_release,
+ * so add them here.
+ */
+ if (!strncmp(distro_db[i].codename, "deb", 3) &&
+ ((buf[0] >= '0' && buf[0] <= '9') || buf[0] != 'D')) {
+ os->distro = g_strdup_printf
+ ("Debian GNU/Linux %s", buf);
+ } else {
+ os->distro = g_strdup(buf);
+ }
+ }
+
+ if (g_str_equal(distro_db[i].codename, "ppy")) {
+ gchar *tmp;
+
+ tmp = g_strdup_printf("Puppy Linux %.2f", atof(os->distro) / 100.0);
+ g_free(os->distro);
+ os->distro = tmp;
+ }
+
+ os->distrocode = g_strdup(distro_db[i].codename);
+
+ break;
+ }
+ }
+
+ os->distro = g_strstrip(os->distro);
+
+ /* Kernel and hostname info */
+ uname(&utsbuf);
+ os->kernel_version = g_strdup(utsbuf.version);
+ os->kernel = g_strdup_printf("%s %s (%s)", utsbuf.sysname,
+ utsbuf.release, utsbuf.machine);
+ os->hostname = g_strdup(utsbuf.nodename);
+ os->language = g_strdup(g_getenv("LC_MESSAGES"));
+ os->homedir = g_strdup(g_get_home_dir());
+ os->username = g_strdup_printf("%s (%s)",
+ g_get_user_name(), g_get_real_name());
+ os->libc = get_libc_version();
+ scan_languages(os);
+ detect_desktop_environment(os);
+
+ return os;
+}
diff --git a/arch/linux/common/pci.h b/arch/linux/common/pci.h
new file mode 100644
index 00000000..f77215b0
--- /dev/null
+++ b/arch/linux/common/pci.h
@@ -0,0 +1,240 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * TODO: This thing must be rewritten. We really should have a struct with all the
+ * PCI stuff we'll present to the user, and hash them by the PCI ID
+ * (domain:bus:device.function).
+ * This way we'll have ways to better organize the output, instead of relying
+ * on the order the information appears on lspci's output.
+ * Also, the "Resources" thing might be better implemented (and we won't need
+ * copies of information scattered everywhere like we do today).
+ */
+
+GHashTable *_pci_devices = NULL;
+
+void
+__scan_pci(void)
+{
+ FILE *lspci;
+ gchar buffer[256], *buf, *strhash = NULL, *strdevice = NULL;
+ gchar *category = NULL, *name = NULL, *icon, *lspci_path, *command_line = NULL;
+ gint n = 0, x = 0;
+
+ if ((lspci_path = find_program("lspci")) == NULL) {
+ goto pci_error;
+ } else {
+ command_line = g_strdup_printf("%s -v", lspci_path);
+ }
+
+ if (!_pci_devices) {
+ _pci_devices = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ buf = g_build_filename(g_get_home_dir(), ".hardinfo", "pci.ids", NULL);
+ if (!g_file_test(buf, G_FILE_TEST_EXISTS)) {
+ DEBUG("using system-provided PCI IDs");
+ g_free(buf);
+ if (!(lspci = popen(command_line, "r"))) {
+ goto pci_error;
+ }
+ } else {
+ gchar *tmp;
+
+ tmp = g_strdup_printf("%s -i '%s'", command_line, buf);
+ g_free(buf);
+ buf = tmp;
+
+ DEBUG("using updated PCI IDs (from %s)", buf);
+ if (!(lspci = popen(tmp, "r"))) {
+ g_free(buf);
+ goto pci_error;
+ } else {
+ g_free(buf);
+ }
+ }
+
+ while (fgets(buffer, 256, lspci)) {
+ buf = g_strstrip(buffer);
+
+ if (!strncmp(buf, "Flags", 5)) {
+ gint irq = 0, freq = 0, latency = 0, i;
+ gchar **list;
+ gboolean bus_master;
+
+ buf += 7;
+
+ bus_master = FALSE;
+
+ list = g_strsplit(buf, ", ", 10);
+ for (i = 0; i <= 10; i++) {
+ if (!list[i])
+ break;
+
+ if (!strncmp(list[i], "IRQ", 3))
+ sscanf(list[i], "IRQ %d", &irq);
+ else if (strstr(list[i], "Mhz"))
+ sscanf(list[i], "%dMhz", &freq);
+ else if (!strncmp(list[i], "bus master", 10))
+ bus_master = TRUE;
+ else if (!strncmp(list[i], "latency", 7))
+ sscanf(list[i], "latency %d", &latency);
+ }
+ g_strfreev(list);
+
+ if (irq)
+ strdevice = h_strdup_cprintf("IRQ=%d\n", strdevice, irq);
+ if (freq)
+ strdevice = h_strdup_cprintf("Frequency=%dMHz\n", strdevice, freq);
+ if (latency)
+ strdevice = h_strdup_cprintf("Latency=%d\n", strdevice, latency);
+
+ strdevice = h_strdup_cprintf("Bus Master=%s\n", strdevice, bus_master ? "Yes" : "No");
+ } else if (!strncmp(buf, "Kernel modules", 14)) {
+ WALK_UNTIL(' ');
+ WALK_UNTIL(':');
+ buf++;
+
+ strdevice = h_strdup_cprintf("Kernel modules=%s\n", strdevice, buf);
+ } else if (!strncmp(buf, "Subsystem", 9)) {
+ WALK_UNTIL(' ');
+ buf++;
+ const gchar *oem_vendor_url = vendor_get_url(buf);
+ if (oem_vendor_url)
+ strdevice = h_strdup_cprintf("OEM Vendor=%s (%s)\n",
+ strdevice,
+ vendor_get_name(buf),
+ oem_vendor_url);
+ } else if (!strncmp(buf, "Capabilities", 12)
+ && !strstr(buf, "only to root") &&
+ !strstr(buf, "access denied")) {
+ WALK_UNTIL(' ');
+ WALK_UNTIL(']');
+ buf++;
+ strdevice = h_strdup_cprintf("Capability#%d=%s\n", strdevice, ++x, buf);
+ } else if (!strncmp(buf, "Memory at", 9) && strstr(buf, "[size=")) {
+ gint mem;
+ gchar unit;
+ gboolean prefetch;
+ gboolean _32bit;
+
+ prefetch = strstr(buf, "non-prefetchable") ? FALSE : TRUE;
+ _32bit = strstr(buf, "32-bit") ? TRUE : FALSE;
+
+ WALK_UNTIL('[');
+ sscanf(buf, "[size=%d%c", &mem, &unit);
+
+ strdevice = h_strdup_cprintf("Memory#%d=%d%cB (%s%s)\n",
+ strdevice, ++x,
+ mem,
+ (unit == ']') ? ' ' : unit,
+ _32bit ? "32-bit, " : "",
+ prefetch ? "prefetchable" :
+ "non-prefetchable");
+
+ } else if (!strncmp(buf, "I/O ports at", 12)) {
+ guint io_addr, io_size;
+
+ sscanf(buf, "I/O ports at %x [size=%d]", &io_addr, &io_size);
+
+ strdevice =
+ h_strdup_cprintf("I/O ports at#%d=0x%x - 0x%x\n",
+ strdevice, ++x, io_addr,
+ io_addr + io_size - 1);
+ } else if ((buf[0] >= '0' && buf[0] <= '9') && (buf[4] == ':' || buf[2] == ':')) {
+ gint bus, device, function, domain;
+ gpointer start, end;
+
+ if (strdevice != NULL && strhash != NULL) {
+ g_hash_table_insert(moreinfo, strhash, strdevice);
+ g_free(category);
+ g_free(name);
+ }
+
+ if (buf[4] == ':') {
+ sscanf(buf, "%x:%x:%x.%d", &domain, &bus, &device, &function);
+ } else {
+ /* lspci without domain field */
+ sscanf(buf, "%x:%x.%x", &bus, &device, &function);
+ domain = 0;
+ }
+
+ WALK_UNTIL(' ');
+
+ start = buf;
+
+ WALK_UNTIL(':');
+ end = buf + 1;
+ *buf = 0;
+
+ buf = start + 1;
+ category = g_strdup(buf);
+
+ buf = end;
+
+ if (strstr(category, "RAM memory")) icon = "mem";
+ else if (strstr(category, "Multimedia")) icon = "media";
+ else if (strstr(category, "USB")) icon = "usb";
+ else icon = "pci";
+
+ name = g_strdup(buf);
+ g_hash_table_insert(_pci_devices,
+ g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),
+ name);
+
+ strhash = g_strdup_printf("PCI%d", n);
+ strdevice = g_strdup_printf("[Device Information]\n"
+ "Name=%s\n"
+ "Class=%s\n"
+ "Domain=%d\n"
+ "Bus, device, function=%d, %d, %d\n",
+ name, category, domain, bus,
+ device, function);
+
+ const gchar *url = vendor_get_url(name);
+ if (url) {
+ strdevice = h_strdup_cprintf("Vendor=%s (%s)\n",
+ strdevice,
+ vendor_get_name(name),
+ url);
+ }
+
+ g_hash_table_insert(_pci_devices,
+ g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),
+ g_strdup(name));
+
+ pci_list = h_strdup_cprintf("$PCI%d$%s=%s\n", pci_list, n, category, name);
+
+ n++;
+ }
+ }
+
+ if (pclose(lspci)) {
+pci_error:
+ /* error (no pci, perhaps?) */
+ pci_list = g_strconcat(pci_list, "No PCI devices found=\n", NULL);
+ } else if (strhash) {
+ /* insert the last device */
+ g_hash_table_insert(moreinfo, strhash, strdevice);
+ g_free(category);
+ g_free(name);
+ }
+
+ g_free(lspci_path);
+ g_free(command_line);
+}
diff --git a/arch/linux/common/resources.h b/arch/linux/common/resources.h
new file mode 100644
index 00000000..e266e375
--- /dev/null
+++ b/arch/linux/common/resources.h
@@ -0,0 +1,103 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+gchar *_resources = NULL;
+
+#if GLIB_CHECK_VERSION(2,14,0)
+static GRegex *_regex_pci = NULL,
+ *_regex_module = NULL;
+
+static gchar *_resource_obtain_name(gchar *name)
+{
+ gchar *temp;
+
+ if (!_regex_pci && !_regex_module) {
+ _regex_pci = g_regex_new("^[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:"
+ "[0-9a-fA-F]{2}\\.[0-9a-fA-F]{1}$",
+ 0, 0, NULL);
+ _regex_module = g_regex_new("^[0-9a-zA-Z\\_\\-]+$", 0, 0, NULL);
+ }
+
+ name = g_strstrip(name);
+
+ if (g_regex_match(_regex_pci, name, 0, NULL)) {
+ temp = module_call_method_param("devices::getPCIDeviceDescription", name);
+ if (temp) {
+ return g_strdup_printf("<b><small>PCI</small></b> %s", (gchar *)idle_free(temp));
+ }
+ } else if (g_regex_match(_regex_module, name, 0, NULL)) {
+ temp = module_call_method_param("computer::getKernelModuleDescription", name);
+ if (temp) {
+ return g_strdup_printf("<b><small>Module</small></b> %s", (gchar *)idle_free(temp));
+ }
+ }
+
+ return g_strdup(name);
+}
+#else
+static gchar *_resource_obtain_name(gchar *name)
+{
+ return g_strdup(name);
+}
+#endif
+
+void scan_device_resources(gboolean reload)
+{
+ SCAN_START();
+ FILE *io;
+ gchar buffer[256];
+ gint i;
+
+ struct {
+ gchar *file;
+ gchar *description;
+ } resources[] = {
+ { "/proc/ioports", "[I/O Ports]\n" },
+ { "/proc/iomem", "[Memory]\n" },
+ { "/proc/dma", "[DMA]\n" }
+ };
+
+ g_free(_resources);
+ _resources = g_strdup("");
+
+ for (i = 0; i < G_N_ELEMENTS(resources); i++) {
+ if ((io = fopen(resources[i].file, "r"))) {
+ _resources = h_strconcat(_resources, resources[i].description, NULL);
+
+ while (fgets(buffer, 256, io)) {
+ gchar **temp = g_strsplit(buffer, ":", 2);
+ gchar *name = _resource_obtain_name(temp[1]);
+
+ _resources = h_strdup_cprintf("<tt>%s</tt>=%s\n", _resources,
+ temp[0], name);
+
+ g_strfreev(temp);
+ g_free(name);
+ }
+
+ fclose(io);
+ }
+ }
+
+ SCAN_END();
+}
+
+gchar *callback_device_resources(void)
+{
+ return g_strdup(_resources);
+}
diff --git a/arch/linux/common/samba.h b/arch/linux/common/samba.h
new file mode 100644
index 00000000..7d835612
--- /dev/null
+++ b/arch/linux/common/samba.h
@@ -0,0 +1,119 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static gchar *smb_shares_list = NULL;
+
+void scan_samba_from_string(gchar *str, gsize length);
+void scan_samba_usershares(void);
+
+void
+scan_samba(void)
+{
+ gchar *str;
+ gsize length;
+
+ if (smb_shares_list) {
+ g_free(smb_shares_list);
+ smb_shares_list = g_strdup("");
+ }
+
+ if (g_file_get_contents("/etc/samba/smb.conf",
+ &str, &length, NULL)) {
+ shell_status_update("Scanning SAMBA shares...");
+ scan_samba_from_string(str, length);
+ g_free(str);
+ }
+
+ scan_samba_usershares();
+}
+
+void
+scan_samba_usershares(void)
+{
+ FILE *usershare_list;
+
+ if ((usershare_list = popen("net usershare list", "r"))) {
+ char buffer[512];
+
+ shell_status_update("Scanning SAMBA user shares...");
+
+ while (fgets(buffer, 512, usershare_list)) {
+ gchar *usershare, *cmdline;
+ gsize length;
+
+ cmdline = g_strdup_printf("net usershare info '%s'",
+ strend(buffer, '\n'));
+ if (g_spawn_command_line_sync(cmdline,
+ &usershare, NULL,
+ NULL, NULL)) {
+ length = strlen(usershare);
+ scan_samba_from_string(usershare, length);
+ g_free(usershare);
+ }
+
+ g_free(cmdline);
+
+ shell_status_pulse();
+ }
+
+ pclose(usershare_list);
+ }
+}
+
+void
+scan_samba_from_string(gchar *str, gsize length)
+{
+ GKeyFile *keyfile;
+ GError *error = NULL;
+ gchar **groups;
+ gint i = 0;
+
+ keyfile = g_key_file_new();
+
+ gchar *_smbconf = str;
+ for (; *_smbconf; _smbconf++)
+ if (*_smbconf == ';') *_smbconf = '\0';
+
+ if (!g_key_file_load_from_data(keyfile, str, length, 0, &error)) {
+ smb_shares_list = g_strdup("Cannot parse smb.conf=\n");
+ if (error)
+ g_error_free(error);
+ goto cleanup;
+ }
+
+ groups = g_key_file_get_groups(keyfile, NULL);
+ while (groups[i]) {
+ shell_status_pulse();
+
+ if (g_key_file_has_key(keyfile, groups[i], "path", NULL)) {
+ gchar *path = g_key_file_get_string(keyfile, groups[i], "path", NULL);
+ smb_shares_list = h_strdup_cprintf("%s=%s\n",
+ smb_shares_list,
+ groups[i], path);
+ g_free(path);
+ }
+
+ i++;
+ }
+
+ g_strfreev(groups);
+
+ cleanup:
+ g_key_file_free(keyfile);
+}
+
diff --git a/arch/linux/common/sensors.h b/arch/linux/common/sensors.h
new file mode 100644
index 00000000..abbe90b4
--- /dev/null
+++ b/arch/linux/common/sensors.h
@@ -0,0 +1,376 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static gchar *sensors = NULL;
+static GHashTable *sensor_labels = NULL;
+static GHashTable *sensor_compute = NULL;
+
+static void read_sensor_labels(gchar * driver)
+{
+ FILE *conf;
+ gchar buf[256], *line, *p;
+ gboolean lock = FALSE;
+ gint i;
+
+ 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);
+
+ /* Try to open lm-sensors config file sensors3.conf */
+ conf = fopen("/etc/sensors3.conf", "r");
+
+ /* If it fails, try to open sensors.conf */
+ if (!conf) conf = fopen("/etc/sensors.conf", "r");
+
+ if (!conf) {
+ /* Cannot open config file. */
+ return;
+ }
+
+ while (fgets(buf, 256, conf)) {
+ line = buf;
+
+ remove_linefeed(line);
+ strend(line, '#');
+
+ if (*line == '\0') {
+ continue;
+ } else if (lock && strstr(line, "label")) { /* label lines */
+ gchar **names = g_strsplit(strstr(line, "label") + 5, " ", 0);
+ gchar *name = NULL, *value = NULL;
+
+ for (i = 0; names[i]; i++) {
+ if (names[i][0] == '\0')
+ continue;
+
+ if (!name)
+ name = g_strdup(names[i]);
+ else if (!value)
+ value = g_strdup(names[i]);
+ else
+ value = g_strconcat(value, " ", names[i], NULL);
+ }
+
+ remove_quotes(value);
+ g_hash_table_insert(sensor_labels, name, value);
+
+ g_strfreev(names);
+ } else if (lock && strstr(line, "ignore")) { /* ignore lines */
+ p = strstr(line, "ignore") + 6;
+ if (!strchr(p, ' '))
+ continue;
+
+ while (*p == ' ')
+ p++;
+ g_hash_table_insert(sensor_labels, g_strdup(p), "ignore");
+ } else if (lock && strstr(line, "compute")) { /* compute lines */
+ gchar **formulas =
+ g_strsplit(strstr(line, "compute") + 7, " ", 0);
+ gchar *name = NULL, *formula = NULL;
+
+ for (i = 0; formulas[i]; i++) {
+ if (formulas[i][0] == '\0')
+ continue;
+ if (formulas[i][0] == ',')
+ break;
+
+ if (!name)
+ name = g_strdup(formulas[i]);
+ else if (!formula)
+ formula = g_strdup(formulas[i]);
+ else
+ formula = g_strconcat(formula, formulas[i], NULL);
+ }
+
+ g_strfreev(formulas);
+ g_hash_table_insert(sensor_compute, name,
+ math_string_to_postfix(formula));
+ } else if (g_str_has_prefix(line, "chip")) { /* chip lines (delimiter) */
+ if (lock == FALSE) {
+ gchar **chips = g_strsplit(line, " ", 0);
+
+ for (i = 1; chips[i]; i++) {
+ strend(chips[i], '*');
+
+ if (g_str_has_prefix(chips[i] + 1, driver)) {
+ lock = TRUE;
+ break;
+ }
+ }
+
+ g_strfreev(chips);
+ } else {
+ break;
+ }
+ }
+ }
+
+ fclose(conf);
+}
+
+static gchar *get_sensor_label(gchar * sensor)
+{
+ gchar *ret;
+
+ ret = g_hash_table_lookup(sensor_labels, sensor);
+ if (!ret)
+ ret = g_strdup(sensor);
+ else
+ ret = g_strdup(ret);
+
+ return ret;
+}
+
+static float adjust_sensor(gchar * name, float value)
+{
+ GSList *postfix;
+
+ postfix = g_hash_table_lookup(sensor_compute, name);
+ if (!postfix)
+ return value;
+
+ return math_postfix_eval(postfix, value);
+}
+
+
+static void read_sensors_hwmon(void)
+{
+ int hwmon, count;
+ gchar *path_hwmon, *path_sensor, *tmp, *driver, *name, *mon;
+ hwmon = 0;
+
+ path_hwmon = g_strdup_printf("/sys/class/hwmon/hwmon%d/device/", hwmon);
+ while (g_file_test(path_hwmon, G_FILE_TEST_EXISTS)) {
+ tmp = g_strdup_printf("%sdriver", path_hwmon);
+ driver = g_file_read_link(tmp, NULL);
+ g_free(tmp);
+
+ tmp = g_path_get_basename(driver);
+ g_free(driver);
+ driver = tmp;
+
+ if (!sensor_labels) {
+ read_sensor_labels(driver);
+ }
+
+ sensors = g_strconcat(sensors, "[Cooling Fans]\n", NULL);
+ for (count = 1;; count++) {
+ path_sensor =
+ g_strdup_printf("%sfan%d_input", path_hwmon, count);
+ if (!g_file_get_contents(path_sensor, &tmp, NULL, NULL)) {
+ g_free(path_sensor);
+ break;
+ }
+
+ mon = g_strdup_printf("fan%d", count);
+ name = get_sensor_label(mon);
+ if (!g_str_equal(name, "ignore")) {
+ sensors = h_strdup_cprintf("%s=%.0fRPM\n",
+ sensors, name,
+ adjust_sensor(mon, atof(tmp)));
+ }
+
+ g_free(name);
+ g_free(mon);
+ g_free(tmp);
+ g_free(path_sensor);
+ }
+
+ sensors = g_strconcat(sensors, "[Temperatures]\n", NULL);
+ for (count = 1;; count++) {
+ path_sensor =
+ g_strdup_printf("%stemp%d_input", path_hwmon, count);
+ if (!g_file_get_contents(path_sensor, &tmp, NULL, NULL)) {
+ g_free(path_sensor);
+ break;
+ }
+
+ mon = g_strdup_printf("temp%d", count);
+ name = get_sensor_label(mon);
+ if (!g_str_equal(name, "ignore")) {
+ sensors = h_strdup_cprintf("%s=%.2f\302\260C\n",
+ sensors, name,
+ adjust_sensor(mon,
+ atof(tmp) /
+ 1000.0));
+ }
+
+ g_free(tmp);
+ g_free(name);
+ g_free(path_sensor);
+ g_free(mon);
+ }
+
+ sensors = g_strconcat(sensors, "[Voltage Values]\n", NULL);
+ for (count = 0;; count++) {
+ path_sensor =
+ g_strdup_printf("%sin%d_input", path_hwmon, count);
+ if (!g_file_get_contents(path_sensor, &tmp, NULL, NULL)) {
+ g_free(path_sensor);
+ break;
+ }
+
+
+ mon = g_strdup_printf("in%d", count);
+ name = get_sensor_label(mon);
+ if (!g_str_equal(name, "ignore")) {
+ sensors = h_strdup_cprintf("%s=%.3fV\n",
+ sensors, name,
+ adjust_sensor(mon,
+ atof(tmp) /
+ 1000.0));
+ }
+
+ g_free(tmp);
+ g_free(mon);
+ g_free(name);
+ g_free(path_sensor);
+ }
+
+ g_free(path_hwmon);
+ g_free(driver);
+ path_hwmon =
+ g_strdup_printf("/sys/class/hwmon/hwmon%d/device/", ++hwmon);
+ }
+
+ g_free(path_hwmon);
+
+}
+
+static void read_sensors_acpi(void)
+{
+ const gchar *path_tz = "/proc/acpi/thermal_zone";
+
+ if (g_file_test(path_tz, G_FILE_TEST_EXISTS)) {
+ GDir *tz;
+
+ if ((tz = g_dir_open(path_tz, 0, NULL))) {
+ const gchar *entry;
+ gchar *temp = g_strdup("");
+
+ while ((entry = g_dir_read_name(tz))) {
+ gchar *path =
+ g_strdup_printf("%s/%s/temperature", path_tz, entry);
+ gchar *contents;
+
+ if (g_file_get_contents(path, &contents, NULL, NULL)) {
+ int temperature;
+
+ sscanf(contents, "temperature: %d C", &temperature);
+
+ temp = h_strdup_cprintf("\n%s=%d\302\260C\n",
+ temp, entry, temperature);
+
+ g_free(contents);
+ }
+ }
+
+ if (*temp != '\0')
+ sensors =
+ h_strdup_cprintf("\n[ACPI Thermal Zone]\n%s",
+ sensors, temp);
+
+ g_dir_close(tz);
+ }
+ }
+
+}
+
+static void read_sensors_omnibook(void)
+{
+ const gchar *path_ob = "/proc/omnibook/temperature";
+ gchar *contents;
+
+ if (g_file_get_contents(path_ob, &contents, NULL, NULL)) {
+ int temperature;
+
+ sscanf(contents, "CPU temperature: %d C", &temperature);
+
+ sensors = h_strdup_cprintf("\n[Omnibook]\n"
+ "CPU temperature=%d\302\260C\n",
+ sensors, temperature);
+
+ g_free(contents);
+ }
+}
+
+static void read_sensors_hddtemp(void)
+{
+ Socket *s;
+ static gchar *old = NULL;
+ gchar buffer[1024];
+ gint len = 0;
+
+ if ((s = sock_connect("127.0.0.1", 7634))) {
+ while (!len)
+ len = sock_read(s, buffer, sizeof(buffer));
+ sock_close(s);
+
+ if (len > 2 && buffer[0] == '|' && buffer[1] == '/') {
+ gchar **disks;
+ int i;
+
+ if (old)
+ g_free(old);
+
+ old = g_strdup("[Hard Disk Temperature]\n");
+
+ disks = g_strsplit(buffer, "\n", 0);
+ for (i = 0; disks[i]; i++) {
+ gchar **fields = g_strsplit(disks[i] + 1, "|", 5);
+
+ /*
+ * 0 -> /dev/hda
+ * 1 -> FUJITSU MHV2080AH
+ * 2 -> 41
+ * 3 -> C
+ */
+ old = h_strdup_cprintf("\n%s (%s)=%s\302\260%s\n",
+ old,
+ fields[1], fields[0],
+ fields[2], fields[3]);
+
+ g_strfreev(fields);
+ }
+
+ g_strfreev(disks);
+ }
+ } else {
+ g_free(old);
+ old = NULL;
+ }
+
+ if (old) {
+ sensors = g_strconcat(sensors, "\n", old, NULL);
+ }
+}
+
+static void __scan_sensors(void)
+{
+ if (sensors)
+ g_free(sensors);
+
+ sensors = g_strdup("");
+
+ read_sensors_hwmon();
+ read_sensors_acpi();
+ read_sensors_omnibook();
+ read_sensors_hddtemp();
+
+ /* FIXME: Add support for ibm acpi and more sensors */
+}
diff --git a/arch/linux/common/storage.h b/arch/linux/common/storage.h
new file mode 100644
index 00000000..ebf9eba1
--- /dev/null
+++ b/arch/linux/common/storage.h
@@ -0,0 +1,372 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static gchar *storage_icons = NULL;
+
+static gboolean
+remove_scsi_devices(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "SCSI");
+}
+
+/* SCSI support by Pascal F.Martin <pascalmartin@earthlink.net> */
+void
+__scan_scsi_devices(void)
+{
+ FILE *proc_scsi;
+ gchar buffer[256], *buf;
+ gint n = 0;
+ gint scsi_controller;
+ gint scsi_channel;
+ gint scsi_id;
+ gint scsi_lun;
+ gchar *vendor = NULL, *revision = NULL, *model = NULL;
+ gchar *scsi_storage_list;
+
+ /* remove old devices from global device table */
+ g_hash_table_foreach_remove(moreinfo, remove_scsi_devices, NULL);
+
+ if (!g_file_test("/proc/scsi/scsi", G_FILE_TEST_EXISTS))
+ return;
+
+ scsi_storage_list = g_strdup("\n[SCSI Disks]\n");
+
+ if ((proc_scsi = fopen("/proc/scsi/scsi", "r"))) {
+ while (fgets(buffer, 256, proc_scsi)) {
+ buf = g_strstrip(buffer);
+ if (!strncmp(buf, "Host: scsi", 10)) {
+ sscanf(buf,
+ "Host: scsi%d Channel: %d Id: %d Lun: %d",
+ &scsi_controller, &scsi_channel, &scsi_id, &scsi_lun);
+
+ n++;
+ } else if (!strncmp(buf, "Vendor: ", 8)) {
+ buf[17] = '\0';
+ buf[41] = '\0';
+ buf[53] = '\0';
+
+ vendor = g_strdup(g_strstrip(buf + 8));
+ model = g_strdup_printf("%s %s", vendor, g_strstrip(buf + 24));
+ revision = g_strdup(g_strstrip(buf + 46));
+ } else if (!strncmp(buf, "Type: ", 8)) {
+ char *p;
+ gchar *type = NULL, *icon = NULL;
+
+ if (!(p = strstr(buf, "ANSI SCSI revision"))) {
+ p = strstr(buf, "ANSI SCSI revision");
+ }
+
+ if (p != NULL) {
+ while (*(--p) == ' ');
+ *(++p) = 0;
+
+ static struct {
+ char *type;
+ char *label;
+ char *icon;
+ } type2icon[] = {
+ { "Direct-Access", "Disk", "hdd"},
+ { "Sequential-Access", "Tape", "tape"},
+ { "Printer", "Printer", "lpr"},
+ { "WORM", "CD-ROM", "cdrom"},
+ { "CD-ROM", "CD-ROM", "cdrom"},
+ { "Scanner", "Scanner", "scanner"},
+ { "Flash Disk", "USB Flash Disk", "usbfldisk" },
+ { NULL, "Generic", "scsi"}
+ };
+ int i;
+
+ if (strstr(model, "Flash Disk")) {
+ type = "Flash Disk";
+ icon = "usbfldisk";
+ } else {
+ for (i = 0; type2icon[i].type != NULL; i++)
+ if (g_str_equal(buf + 8, type2icon[i].type))
+ break;
+
+ type = type2icon[i].label;
+ icon = type2icon[i].icon;
+ }
+ }
+
+ gchar *devid = g_strdup_printf("SCSI%d", n);
+ scsi_storage_list = h_strdup_cprintf("$%s$%s=\n", scsi_storage_list, devid, model);
+ storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, model, icon);
+
+ gchar *strhash = g_strdup_printf("[Device Information]\n"
+ "Model=%s\n", model);
+
+ const gchar *url = vendor_get_url(model);
+ if (url) {
+ strhash = h_strdup_cprintf("Vendor=%s (%s)\n",
+ strhash,
+ vendor_get_name(model),
+ url);
+ } else {
+ strhash = h_strdup_cprintf("Vendor=%s\n",
+ strhash,
+ vendor_get_name(model));
+ }
+
+ strhash = h_strdup_cprintf("Type=%s\n"
+ "Revision=%s\n"
+ "[SCSI Controller]\n"
+ "Controller=scsi%d\n"
+ "Channel=%d\n"
+ "ID=%d\n" "LUN=%d\n",
+ strhash,
+ type,
+ revision,
+ scsi_controller,
+ scsi_channel,
+ scsi_id,
+ scsi_lun);
+ g_hash_table_insert(moreinfo, devid, strhash);
+
+ g_free(model);
+ g_free(revision);
+ g_free(vendor);
+ }
+ }
+ fclose(proc_scsi);
+ }
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, scsi_storage_list, NULL);
+ g_free(scsi_storage_list);
+ }
+}
+
+static gboolean
+remove_ide_devices(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "IDE");
+}
+
+void
+__scan_ide_devices(void)
+{
+ FILE *proc_ide;
+ gchar *device, iface, *model, *media, *pgeometry = NULL, *lgeometry =
+ NULL;
+ gint n = 0, i = 0, cache, nn = 0;
+ gchar *capab = NULL, *speed = NULL, *driver = NULL, *ide_storage_list;
+
+ /* remove old devices from global device table */
+ g_hash_table_foreach_remove(moreinfo, remove_ide_devices, NULL);
+
+ ide_storage_list = g_strdup("\n[IDE Disks]\n");
+
+ iface = 'a';
+ for (i = 0; i <= 16; i++) {
+ device = g_strdup_printf("/proc/ide/hd%c/model", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ gchar buf[128];
+
+ cache = 0;
+
+ proc_ide = fopen(device, "r");
+ (void)fgets(buf, 128, proc_ide);
+ fclose(proc_ide);
+
+ buf[strlen(buf) - 1] = 0;
+
+ model = g_strdup(buf);
+
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/media", iface);
+ proc_ide = fopen(device, "r");
+ (void)fgets(buf, 128, proc_ide);
+ fclose(proc_ide);
+ buf[strlen(buf) - 1] = 0;
+
+ media = g_strdup(buf);
+ if (g_str_equal(media, "cdrom")) {
+ /* obtain cd-rom drive information from cdrecord */
+ GTimer *timer;
+ gchar *tmp = g_strdup_printf("cdrecord dev=/dev/hd%c -prcap 2>/dev/stdout", iface);
+ FILE *prcap;
+
+ if ((prcap = popen(tmp, "r"))) {
+ /* we need a timeout so cdrecord does not try to get information on cd drives
+ with inserted media, which is not possible currently. half second should be
+ enough. */
+ timer = g_timer_new();
+ g_timer_start(timer);
+
+ while (fgets(buf, 128, prcap) && g_timer_elapsed(timer, NULL) < 0.5) {
+ if (g_str_has_prefix(buf, " Does")) {
+ if (g_str_has_suffix(buf, "media\n") && !strstr(buf, "speed")) {
+ gchar *media_type = g_strstrip(strstr(buf, "Does "));
+ gchar **ttmp = g_strsplit(media_type, " ", 0);
+
+ capab = h_strdup_cprintf("\nCan %s#%d=%s\n",
+ capab,
+ ttmp[1], ++nn, ttmp[2]);
+
+ g_strfreev(ttmp);
+ } else if (strstr(buf, "Buffer-Underrun-Free")) {
+ capab = h_strdup_cprintf("\nSupports BurnProof=%s\n",
+ capab,
+ strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "multi-session")) {
+ capab = h_strdup_cprintf("\nCan read multi-session CDs=%s\n",
+ capab,
+ strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "audio CDs")) {
+ capab = h_strdup_cprintf("\nCan play audio CDs=%s\n",
+ capab,
+ strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "PREVENT/ALLOW")) {
+ capab = h_strdup_cprintf("\nCan lock media=%s\n",
+ capab,
+ strstr(buf, "Does not") ? "No" : "Yes");
+ }
+ } else if ((strstr(buf, "read") || strstr(buf, "write")) && strstr(buf, "kB/s")) {
+ speed = g_strconcat(speed ? speed : "",
+ strreplacechr(g_strstrip(buf), ":", '='),
+ "\n", NULL);
+ } else if (strstr(buf, "Device seems to be")) {
+ driver = g_strdup_printf("Driver=%s\n", strchr(buf, ':') + 1);
+ }
+ }
+
+ pclose(prcap);
+ g_timer_destroy(timer);
+ }
+
+ g_free(tmp);
+ }
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/cache", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ proc_ide = fopen(device, "r");
+ (void)fscanf(proc_ide, "%d", &cache);
+ fclose(proc_ide);
+ }
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/geometry", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ gchar *tmp;
+
+ proc_ide = fopen(device, "r");
+
+ (void)fgets(buf, 64, proc_ide);
+ for (tmp = buf; *tmp; tmp++) {
+ if (*tmp >= '0' && *tmp <= '9')
+ break;
+ }
+
+ pgeometry = g_strdup(g_strstrip(tmp));
+
+ (void)fgets(buf, 64, proc_ide);
+ for (tmp = buf; *tmp; tmp++) {
+ if (*tmp >= '0' && *tmp <= '9')
+ break;
+ }
+ lgeometry = g_strdup(g_strstrip(tmp));
+
+ fclose(proc_ide);
+ }
+ g_free(device);
+
+ n++;
+
+ gchar *devid = g_strdup_printf("IDE%d", n);
+
+ ide_storage_list = h_strdup_cprintf("$%s$%s=\n", ide_storage_list,
+ devid, model);
+ storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid,
+ model, g_str_equal(media, "cdrom") ? \
+ "cdrom" : "hdd");
+
+ gchar *strhash = g_strdup_printf("[Device Information]\n"
+ "Model=%s\n",
+ model);
+
+ const gchar *url = vendor_get_url(model);
+
+ if (url) {
+ strhash = h_strdup_cprintf("Vendor=%s (%s)\n",
+ strhash,
+ vendor_get_name(model),
+ url);
+ } else {
+ strhash = h_strdup_cprintf("Vendor=%s\n",
+ strhash,
+ vendor_get_name(model));
+ }
+
+ strhash = h_strdup_cprintf("Device Name=hd%c\n"
+ "Media=%s\n"
+ "Cache=%dkb\n",
+ strhash,
+ iface,
+ media,
+ cache);
+ if (driver) {
+ strhash = h_strdup_cprintf("%s\n", strhash, driver);
+
+ g_free(driver);
+ driver = NULL;
+ }
+
+ if (pgeometry && lgeometry) {
+ strhash = h_strdup_cprintf("[Geometry]\n"
+ "Physical=%s\n"
+ "Logical=%s\n",
+ strhash, pgeometry, lgeometry);
+
+ g_free(pgeometry);
+ pgeometry = NULL;
+ g_free(lgeometry);
+ lgeometry = NULL;
+ }
+
+ if (capab) {
+ strhash = h_strdup_cprintf("[Capabilities]\n%s", strhash, capab);
+
+ g_free(capab);
+ capab = NULL;
+ }
+
+ if (speed) {
+ strhash = h_strdup_cprintf("[Speeds]\n%s", strhash, speed);
+
+ g_free(speed);
+ speed = NULL;
+ }
+
+ g_hash_table_insert(moreinfo, devid, strhash);
+
+ g_free(model);
+ model = g_strdup("");
+ } else
+ g_free(device);
+
+ iface++;
+ }
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, ide_storage_list, NULL);
+ g_free(ide_storage_list);
+ }
+}
diff --git a/arch/linux/common/uptime.h b/arch/linux/common/uptime.h
new file mode 100644
index 00000000..8fdc3a27
--- /dev/null
+++ b/arch/linux/common/uptime.h
@@ -0,0 +1,74 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static UptimeInfo *
+computer_get_uptime(void)
+{
+ UptimeInfo *ui = g_new0(UptimeInfo, 1);
+ FILE *procuptime;
+ gulong minutes;
+
+ if ((procuptime = fopen("/proc/uptime", "r")) != NULL) {
+ (void)fscanf(procuptime, "%lu", &minutes);
+ ui->minutes = minutes / 60;
+ fclose(procuptime);
+ } else {
+ return NULL;
+ }
+
+ ui->hours = ui->minutes / 60;
+ ui->minutes %= 60;
+ ui->days = ui->hours / 24;
+ ui->hours %= 24;
+
+ return ui;
+}
+
+static gchar *
+computer_get_formatted_uptime()
+{
+ UptimeInfo *ui;
+ gchar *tmp;
+
+ ui = computer_get_uptime();
+
+ /* FIXME: Use ngettext */
+#define plural(x) ((x > 1) ? "s" : "")
+
+ if (ui->days < 1) {
+ if (ui->hours < 1) {
+ tmp =
+ g_strdup_printf("%d minute%s", ui->minutes,
+ plural(ui->minutes));
+ } else {
+ tmp =
+ g_strdup_printf("%d hour%s, %d minute%s", ui->hours,
+ plural(ui->hours), ui->minutes,
+ plural(ui->minutes));
+ }
+ } else {
+ tmp =
+ g_strdup_printf("%d day%s, %d hour%s and %d minute%s",
+ ui->days, plural(ui->days), ui->hours,
+ plural(ui->hours), ui->minutes,
+ plural(ui->minutes));
+ }
+
+ g_free(ui);
+ return tmp;
+}
diff --git a/arch/linux/common/usb.h b/arch/linux/common/usb.h
new file mode 100644
index 00000000..7c135d7c
--- /dev/null
+++ b/arch/linux/common/usb.h
@@ -0,0 +1,343 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * FIXME:
+ * - listing with sysfs does not generate device hierarchy
+ */
+static gboolean
+remove_usb_devices(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, "USB");
+}
+
+static gchar *usb_list = NULL;
+
+void __scan_usb_sysfs_add_device(gchar * endpoint, int n)
+{
+ gchar *manufacturer, *product, *mxpwr, *tmp, *strhash;
+ gint bus, classid, vendor, prodid;
+ gfloat version, speed;
+
+ classid = h_sysfs_read_int(endpoint, "bDeviceClass");
+ vendor = h_sysfs_read_int(endpoint, "idVendor");
+ prodid = h_sysfs_read_int(endpoint, "idProduct");
+ bus = h_sysfs_read_int(endpoint, "busnum");
+ speed = h_sysfs_read_float(endpoint, "speed");
+ version = h_sysfs_read_float(endpoint, "version");
+
+ if (!(mxpwr = h_sysfs_read_string(endpoint, "bMaxPower"))) {
+ mxpwr = g_strdup("0 mA");
+ }
+
+ if (!(manufacturer = h_sysfs_read_string(endpoint, "manufacturer"))) {
+ manufacturer = g_strdup("Unknown");
+ }
+
+ if (!(product = h_sysfs_read_string(endpoint, "product"))) {
+ if (classid == 9) {
+ product = g_strdup_printf("USB %.2f Hub", version);
+ } else {
+ product = g_strdup_printf("Unknown USB %.2f Device (class %d)", version, classid);
+ }
+ }
+
+ const gchar *url = vendor_get_url(manufacturer);
+ if (url) {
+ tmp = g_strdup_printf("%s (%s)", vendor_get_name(manufacturer), url);
+
+ g_free(manufacturer);
+ manufacturer = tmp;
+ }
+
+ tmp = g_strdup_printf("USB%d", n);
+ usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product);
+
+ strhash = g_strdup_printf("[Device Information]\n"
+ "Product=%s\n"
+ "Manufacturer=%s\n"
+ "Speed=%.2fMbit/s\n"
+ "Max Current=%s\n"
+ "[Misc]\n"
+ "USB Version=%.2f\n"
+ "Class=0x%x\n"
+ "Vendor=0x%x\n"
+ "Product ID=0x%x\n"
+ "Bus=%d\n",
+ product,
+ manufacturer,
+ speed,
+ mxpwr,
+ version, classid, vendor, prodid, bus);
+
+ g_hash_table_insert(moreinfo, tmp, strhash);
+
+ g_free(manufacturer);
+ g_free(product);
+ g_free(mxpwr);
+}
+
+gboolean __scan_usb_sysfs(void)
+{
+ GDir *sysfs;
+ gchar *filename;
+ const gchar *sysfs_path = "/sys/class/usb_endpoint";
+ gint usb_device_number = 0;
+
+ if (!(sysfs = g_dir_open(sysfs_path, 0, NULL))) {
+ return FALSE;
+ }
+
+ if (usb_list) {
+ g_hash_table_foreach_remove(moreinfo, remove_usb_devices, NULL);
+ g_free(usb_list);
+ }
+ usb_list = g_strdup("[USB Devices]\n");
+
+ while ((filename = (gchar *) g_dir_read_name(sysfs))) {
+ gchar *endpoint =
+ g_build_filename(sysfs_path, filename, "device", NULL);
+ gchar *temp;
+
+ temp = g_build_filename(endpoint, "idVendor", NULL);
+ if (g_file_test(temp, G_FILE_TEST_EXISTS)) {
+ __scan_usb_sysfs_add_device(endpoint, ++usb_device_number);
+ }
+
+ g_free(temp);
+ g_free(endpoint);
+ }
+
+ g_dir_close(sysfs);
+
+ return usb_device_number > 0;
+}
+
+gboolean __scan_usb_procfs(void)
+{
+ FILE *dev;
+ gchar buffer[128];
+ gchar *tmp, *manuf = NULL, *product = NULL, *mxpwr;
+ gint bus, level, port, classid, trash;
+ gint vendor, prodid;
+ gfloat ver, rev, speed;
+ int n = 0;
+
+ dev = fopen("/proc/bus/usb/devices", "r");
+ if (!dev)
+ return 0;
+
+ if (usb_list) {
+ g_hash_table_foreach_remove(moreinfo, remove_usb_devices, NULL);
+ g_free(usb_list);
+ }
+ usb_list = g_strdup("[USB Devices]\n");
+
+ while (fgets(buffer, 128, dev)) {
+ tmp = buffer;
+
+ switch (*tmp) {
+ case 'T':
+ sscanf(tmp,
+ "T: Bus=%d Lev=%d Prnt=%d Port=%d Cnt=%d Dev#=%d Spd=%f",
+ &bus, &level, &trash, &port, &trash, &trash, &speed);
+ break;
+ case 'D':
+ sscanf(tmp, "D: Ver=%f Cls=%x", &ver, &classid);
+ break;
+ case 'P':
+ sscanf(tmp, "P: Vendor=%x ProdID=%x Rev=%f",
+ &vendor, &prodid, &rev);
+ break;
+ case 'S':
+ if (strstr(tmp, "Manufacturer=")) {
+ manuf = g_strdup(strchr(tmp, '=') + 1);
+ remove_linefeed(manuf);
+ } else if (strstr(tmp, "Product=")) {
+ product = g_strdup(strchr(tmp, '=') + 1);
+ remove_linefeed(product);
+ }
+ break;
+ case 'C':
+ mxpwr = strstr(buffer, "MxPwr=") + 6;
+
+ tmp = g_strdup_printf("USB%d", ++n);
+
+ if (*product == '\0') {
+ g_free(product);
+ if (classid == 9) {
+ product = g_strdup_printf("USB %.2f Hub", ver);
+ } else {
+ product =
+ g_strdup_printf
+ ("Unknown USB %.2f Device (class %d)", ver,
+ classid);
+ }
+ }
+
+
+ if (classid == 9) { /* hub */
+ usb_list = h_strdup_cprintf("[%s#%d]\n",
+ usb_list, product, n);
+ } else { /* everything else */
+ usb_list = h_strdup_cprintf("$%s$%s=\n",
+ usb_list, tmp, product);
+
+ const gchar *url = vendor_get_url(manuf);
+ if (url) {
+ gchar *tmp =
+ g_strdup_printf("%s (%s)", vendor_get_name(manuf),
+ url);
+ g_free(manuf);
+ manuf = tmp;
+ }
+
+ gchar *strhash = g_strdup_printf("[Device Information]\n"
+ "Product=%s\n",
+ product);
+ if (manuf && strlen(manuf))
+ strhash = h_strdup_cprintf("Manufacturer=%s\n",
+ strhash, manuf);
+
+ strhash = h_strdup_cprintf("[Port #%d]\n"
+ "Speed=%.2fMbit/s\n"
+ "Max Current=%s\n"
+ "[Misc]\n"
+ "USB Version=%.2f\n"
+ "Revision=%.2f\n"
+ "Class=0x%x\n"
+ "Vendor=0x%x\n"
+ "Product ID=0x%x\n"
+ "Bus=%d\n" "Level=%d\n",
+ strhash,
+ port, speed, mxpwr,
+ ver, rev, classid,
+ vendor, prodid, bus, level);
+
+ g_hash_table_insert(moreinfo, tmp, strhash);
+ }
+
+ g_free(manuf);
+ g_free(product);
+ manuf = g_strdup("");
+ product = g_strdup("");
+ }
+ }
+
+ fclose(dev);
+
+ return n > 0;
+}
+
+void __scan_usb_lsusb_add_device(char *buffer, FILE *lsusb, int usb_device_number)
+{
+ gint bus, device, vendor_id, product_id;
+ gchar *product, *vendor, *max_power, *tmp, *strhash;
+
+ sscanf(buffer, "Bus %d Device %d: ID %x:%x",
+ &bus, &device, &vendor_id, &product_id);
+
+ while (fgets(buffer, 512, lsusb)) {
+ if (g_str_has_prefix(buffer, " idVendor")) {
+ vendor = g_strstrip(g_strdup(buffer + 28));
+ } else if (g_str_has_prefix(buffer, " idProduct")) {
+ product = g_strstrip(g_strdup(buffer + 28));
+ } else if (g_str_has_prefix(buffer, " MaxPower")) {
+ max_power = g_strstrip(g_strdup(buffer + 26));
+ } else if (g_str_has_prefix(buffer, "\n")) {
+ /* device separator */
+ break;
+ }
+ }
+
+ tmp = g_strdup_printf("USB%d", usb_device_number);
+ usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product);
+
+ strhash = g_strdup_printf("[Device Information]\n"
+ "Product=%s\n"
+ "Manufacturer=%s\n"
+ "Max Current=%s\n"
+ "[Misc]\n"
+ "USB Version=%.2f\n"
+ "Class=0x%x\n"
+ "Vendor=0x%x\n"
+ "Product ID=0x%x\n"
+ "Bus=%d\n",
+ product,
+ vendor,
+ max_power,
+ 0.0f /* FIXME */,
+ 0 /* FIXME */,
+ vendor_id, product_id, bus);
+
+ g_hash_table_insert(moreinfo, tmp, strhash);
+
+ g_free(vendor);
+ g_free(product);
+ g_free(max_power);
+}
+
+gboolean __scan_usb_lsusb(void)
+{
+ static gchar *lsusb_path = NULL;
+ int usb_device_number = 0;
+ FILE *lsusb;
+ char buffer[512], *temp;
+
+ if (!lsusb_path) {
+ if (!(lsusb_path = find_program("lsusb"))) {
+ DEBUG("lsusb not found");
+
+ return FALSE;
+ }
+ }
+
+ temp = g_strdup_printf("%s -v", lsusb_path);
+ if (!(lsusb = popen(temp, "r"))) {
+ DEBUG("cannot run %s", lsusb_path);
+
+ g_free(temp);
+ return FALSE;
+ }
+
+ g_free(temp);
+
+ if (usb_list) {
+ g_hash_table_foreach_remove(moreinfo, remove_usb_devices, NULL);
+ g_free(usb_list);
+ }
+ usb_list = g_strdup("[USB Devices]\n");
+
+ while (fgets(buffer, sizeof(buffer), lsusb)) {
+ if (g_str_has_prefix(buffer, "Bus ")) {
+ __scan_usb_lsusb_add_device(buffer, lsusb, ++usb_device_number);
+ }
+ }
+
+ pclose(lsusb);
+
+ return usb_device_number > 0;
+}
+
+void __scan_usb(void)
+{
+ if (!__scan_usb_procfs()) {
+ if (!__scan_usb_sysfs()) {
+ __scan_usb_lsusb();
+ }
+ }
+}