aboutsummaryrefslogtreecommitdiff
path: root/modules/devices/storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/devices/storage.c')
-rw-r--r--modules/devices/storage.c820
1 files changed, 820 insertions, 0 deletions
diff --git a/modules/devices/storage.c b/modules/devices/storage.c
new file mode 100644
index 00000000..bbf9b195
--- /dev/null
+++ b/modules/devices/storage.c
@@ -0,0 +1,820 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
+ * modified by Ondrej Čerman (2019-2021)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 or later.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+
+#include "hardinfo.h"
+#include "devices.h"
+#include "udisks2_util.h"
+#include "storage_util.h"
+
+#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)");
+
+gchar *storage_icons = NULL;
+
+gchar *nvme_pci_sections(pcid *p) {
+ const gchar *vendor, *svendor, *product, *sproduct;
+
+ if (!p) return NULL;
+
+ vendor = UNKIFNULL_AC(p->vendor_id_str);
+ svendor = UNKIFNULL_AC(p->sub_vendor_id_str);
+ product = UNKIFNULL_AC(p->device_id_str);
+ sproduct = UNKIFNULL_AC(p->sub_device_id_str);
+
+ gchar *vendor_device_str;
+ if (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id) {
+ vendor_device_str = g_strdup_printf("[%s]\n"
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n",
+ _("NVMe Controller"),
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product);
+ } else {
+ vendor_device_str = g_strdup_printf("[%s]\n"
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n"
+ /* Sub-device vendor */ "$^$%s=[%04x] %s\n"
+ /* Sub-device */ "%s=[%04x] %s\n",
+ _("NVMe Controller"),
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product,
+ _("SVendor"), p->sub_vendor_id, svendor,
+ _("SDevice"), p->sub_device_id, sproduct);
+ }
+
+ gchar *pcie_str;
+ if (p->pcie_width_curr) {
+ pcie_str = g_strdup_printf("[%s]\n"
+ /* Addy */ "%s=PCI/%s\n"
+ /* Width (max) */ "%s=x%u\n"
+ /* Speed (max) */ "%s=%0.1f %s\n",
+ _("PCI Express"),
+ _("Location"), p->slot_str,
+ _("Maximum Link Width"), p->pcie_width_max,
+ _("Maximum Link Speed"), p->pcie_speed_max, _("GT/s") );
+ } else
+ pcie_str = strdup("");
+
+ gchar *ret = g_strdup_printf("%s%s", vendor_device_str, pcie_str);
+ g_free(vendor_device_str);
+ g_free(pcie_str);
+ return ret;
+}
+
+gboolean __scan_udisks2_devices(void) {
+ GSList *node, *drives;
+ u2driveext *ext;
+ udiskd *disk;
+ udiskp *part;
+ udisksa *attrib;
+ gchar *udisks2_storage_list = NULL, *features = NULL, *moreinfo = NULL;
+ gchar *devid, *size, *tmp = NULL, *media_comp = NULL, *ven_tag = NULL;
+ const gchar *url, *media_label, *alabel, *icon, *media_curr = NULL;
+ int n = 0, i, j, m;
+
+ // http://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.Drive.html#gdbus-property-org-freedesktop-UDisks2-Drive.MediaCompatibility
+ static struct {
+ char *media;
+ char *label;
+ char *icon;
+ } media_info[] = {
+ { "thumb", "Thumb-drive", "usbfldisk" },
+ { "flash", "Flash Card", "usbfldisk" },
+ { "flash_cf", "CompactFlash", "usbfldisk" },
+ { "flash_ms", "MemoryStick", "usbfldisk" },
+ { "flash_sm", "SmartMedia", "usbfldisk" },
+ { "flash_sd", "SD", "usbfldisk" },
+ { "flash_sdhc", "SDHC", "usbfldisk" },
+ { "flash_sdxc", "SDXC", "usbfldisk" },
+ { "flash_mmc", "MMC", "usbfldisk" },
+ { "floppy", "Floppy Disk", "media-floppy" },
+ { "floppy_zip", "Zip Disk", "media-floppy" },
+ { "floppy_jaz", "Jaz Disk", "media-floppy" },
+ { "optical", "Optical Disc", "cdrom" },
+ { "optical_cd", "CD-ROM", "cdrom" },
+ { "optical_cd_r", "CD-R", "cdrom" },
+ { "optical_cd_rw", "CD-RW", "cdrom" },
+ { "optical_dvd", "DVD-ROM", "cdrom" },
+ { "optical_dvd_r", "DVD-R", "cdrom" },
+ { "optical_dvd_rw", "DVD-RW", "cdrom" },
+ { "optical_dvd_ram", "DVD-RAM", "cdrom" },
+ { "optical_dvd_plus_r", "DVD+R" , "cdrom" },
+ { "optical_dvd_plus_rw", "DVD+RW" , "cdrom" },
+ { "optical_dvd_plus_r_dl", "DVD+R DL", "cdrom" },
+ { "optical_dvd_plus_rw_dl", "DVD+RW DL", "cdrom" },
+ { "optical_bd", "BD-ROM", "cdrom" },
+ { "optical_bd_r", "BD-R", "cdrom" },
+ { "optical_bd_re", "BD-RE", "cdrom" },
+ { "optical_hddvd", "HD DVD-ROM", "cdrom" },
+ { "optical_hddvd_r", "HD DVD-R", "cdrom" },
+ { "optical_hddvd_rw", "HD DVD-RW", "cdrom" },
+ { "optical_mo", "MO Disc", "cdrom" },
+ { "optical_mrw", "MRW Media", "cdrom" },
+ { "optical_mrw_w", "MRW Media (write)", "cdrom" },
+ { NULL, NULL }
+ };
+
+ struct {
+ char *identifier;
+ char *label;
+ } smart_attrib_info[] = {
+ { "raw-read-error-rate", _("Read Error Rate" ) },
+ { "throughput-performance", _("Throughput Performance") },
+ { "spin-up-time", _("Spin-Up Time") },
+ { "start-stop-count", _("Start/Stop Count") },
+ { "reallocated-sector-count", _("Reallocated Sector Count") },
+ { "read-channel-margin", _("Read Channel Margin") },
+ { "seek-error-rate", _("Seek Error Rate") },
+ { "seek-time-performance", _("Seek Timer Performance") },
+ { "power-on-hours", _("Power-On Hours") },
+ { "spin-retry-count", _("Spin Retry Count") },
+ { "calibration-retry-count", _("Calibration Retry Count") },
+ { "power-cycle-count", _("Power Cycle Count") },
+ { "read-soft-error-rate", _("Soft Read Error Rate") },
+ { "runtime-bad-block-total", _("Runtime Bad Block") },
+ { "end-to-end-error", _("End-to-End error") },
+ { "reported-uncorrect", _("Reported Uncorrectable Errors") },
+ { "command-timeout", _("Command Timeout") },
+ { "high-fly-writes", _("High Fly Writes") },
+ { "airflow-temperature-celsius", _("Airflow Temperature") },
+ { "g-sense-error-rate", _("G-sense Error Rate") },
+ { "power-off-retract-count", _("Power-off Retract Count") },
+ { "load-cycle-count", _("Load Cycle Count") },
+ { "temperature-celsius-2", _("Temperature") },
+ { "hardware-ecc-recovered", _("Hardware ECC Recovered") },
+ { "reallocated-event-count", _("Reallocation Event Count") },
+ { "current-pending-sector", _("Current Pending Sector Count") },
+ { "offline-uncorrectable", _("Uncorrectable Sector Count") },
+ { "udma-crc-error-count", _("UltraDMA CRC Error Count") },
+ { "multi-zone-error-rate", _("Multi-Zone Error Rate") },
+ { "soft-read-error-rate", _("Soft Read Error Rate") },
+ { "run-out-cancel", _("Run Out Cancel") },
+ { "flying-height", _("Flying Height") },
+ { "spin-high-current", _("Spin High Current") },
+ { "spin-buzz", _("Spin Buzz") },
+ { "offline-seek-performance", _("Offline Seek Performance") },
+ { "disk-shift", _("Disk Shift") },
+ { "g-sense-error-rate-2", _("G-Sense Error Rate") },
+ { "loaded-hours", _("Loaded Hours") },
+ { "load-retry-count", _("Load/Unload Retry Count") },
+ { "load-friction", _("Load Friction") },
+ { "load-cycle-count-2", _("Load/Unload Cycle Count") },
+ { "load-in-time", _("Load-in time") },
+ { "torq-amp-count", _("Torque Amplification Count") },
+ { "power-off-retract-count-2", _("Power-Off Retract Count") },
+ { "head-amplitude", _("GMR Head Amplitude") },
+ { "temperature-celsius", _("Temperature") },
+ { "endurance-remaining", _("Endurance Remaining") },
+ { "power-on-seconds-2", _("Power-On Hours") },
+ { "good-block-rate", _("Good Block Rate") },
+ { "head-flying-hours", _("Head Flying Hours") },
+ { "read-error-retry-rate", _("Read Error Retry Rate") },
+ { "total-lbas-written", _("Total LBAs Written") },
+ { "total-lbas-read", _("Total LBAs Read") },
+ { "wear-leveling-count", _("Wear leveling Count") },
+ { "used-reserved-blocks-total", _("Total Used Reserved Block Count") },
+ { "program-fail-count-total", _("Total Program Fail Count") },
+ { "erase-fail-count-total", _("Total Erase Fail Count") },
+ { "available-reserved-space", _("Available Reserved Space") },
+ { "program-fail-count", _("Program Fail Count") },
+ { "erase-fail-count", _("Erase Fail Count") },
+ { "ta-increase-count", _("TA Counter Increased") },
+ { "unused-reserved-blocks", _("Total Unused Reserved Block Count") },
+ { NULL, NULL }
+ };
+
+ moreinfo_del_with_prefix("DEV:UDISKS");
+ udisks2_storage_list = g_strdup(_("\n[UDisks2]\n"));
+
+ drives = get_udisks2_drives_ext();
+ for (node = drives; node != NULL; node = node->next) {
+ ext = (u2driveext *)node->data;
+ disk = ext->d;
+ devid = g_strdup_printf("UDISKS%d", n++);
+
+ icon = NULL;
+
+ media_curr = disk->media;
+ if (disk->media){
+ for (j = 0; media_info[j].media != NULL; j++) {
+ if (g_strcmp0(disk->media, media_info[j].media) == 0) {
+ media_curr = media_info[j].label;
+ break;
+ }
+ }
+ }
+
+ if (disk->media_compatibility){
+ for (i = 0; disk->media_compatibility[i] != NULL; i++){
+ media_label = disk->media_compatibility[i];
+
+ for (j = 0; media_info[j].media != NULL; j++) {
+ if (g_strcmp0(disk->media_compatibility[i], media_info[j].media) == 0) {
+ media_label = media_info[j].label;
+ if (icon == NULL)
+ icon = media_info[j].icon;
+ break;
+ }
+ }
+
+ if (media_comp == NULL){
+ media_comp = g_strdup(media_label);
+ }
+ else{
+ media_comp = h_strdup_cprintf(", %s", media_comp, media_label);
+ }
+ }
+ }
+ if (icon == NULL && disk->ejectable && g_strcmp0(disk->connection_bus, "usb") == 0) {
+ icon = "usbfldisk";
+ }
+ if (icon == NULL){
+ icon = "hdd";
+ }
+
+ size = size_human_readable((gfloat) disk->size);
+ ven_tag = vendor_list_ribbon(ext->vendors, params.fmt_opts);
+
+ udisks2_storage_list = h_strdup_cprintf("$%s$%s=%s|%s %s\n", udisks2_storage_list, devid, disk->block_dev, size, ven_tag ? ven_tag : "", disk->model);
+ storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, disk->model, icon);
+ features = h_strdup_cprintf("%s", features, disk->removable ? _("Removable"): _("Fixed"));
+
+ if (disk->ejectable) {
+ features = h_strdup_cprintf(", %s", features, _("Ejectable"));
+ }
+ if (disk->smart_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Self-monitoring (S.M.A.R.T.)"));
+ }
+ if (disk->pm_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Power Management"));
+ }
+ if (disk->apm_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Advanced Power Management"));
+ }
+ if (disk->aam_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Automatic Acoustic Management"));
+ }
+
+ moreinfo = g_strdup_printf(_("[Drive Information]\n"
+ "Model=%s\n"),
+ disk->model);
+
+ if (disk->vendor && *disk->vendor) {
+ moreinfo = h_strdup_cprintf("$^$%s=%s\n",
+ moreinfo,
+ _("Vendor"), disk->vendor);
+ }
+
+ moreinfo = h_strdup_cprintf(_("Revision=%s\n"
+ "Block Device=%s\n"
+ "Serial=%s\n"
+ "Size=%s\n"
+ "Features=%s\n"),
+ moreinfo,
+ disk->revision,
+ disk->block_dev,
+ disk->serial,
+ size,
+ features);
+ g_free(size);
+ g_free(ven_tag);
+
+ if (disk->rotation_rate > 0) {
+ moreinfo = h_strdup_cprintf(_("Rotation Rate=%d RPM\n"), moreinfo, disk->rotation_rate);
+ }
+ if (media_comp || media_curr) {
+ moreinfo = h_strdup_cprintf(_("Media=%s\n"
+ "Media compatibility=%s\n"),
+ moreinfo,
+ media_curr ? media_curr : _("(None)"),
+ media_comp ? media_comp : _("(Unknown)"));
+ }
+ if (disk->connection_bus && strlen(disk->connection_bus) > 0) {
+ moreinfo = h_strdup_cprintf(_("Connection bus=%s\n"), moreinfo, disk->connection_bus);
+ }
+
+ tmp = NULL;
+ if (disk->wwid) {
+ m = strlen(disk->wwid);
+ if (m > 2 && m % 2 == 0){
+ for (j = 4; j < m; j = j + 2) {
+ tmp = h_strdup_cprintf("%s%c%c", tmp, j > 4 ? "-": "", disk->wwid[j], disk->wwid[j+1]);
+ }
+ }
+ moreinfo = h_strdup_cprintf("%s=%s\n", moreinfo,
+ g_str_has_prefix(disk->wwid, "nna.") ? _("WWN"):
+ (g_str_has_prefix(disk->wwid, "eui.") ? _("EUI "): "Unknown ID"),
+ tmp);
+ g_free(tmp);
+ }
+ else{
+ moreinfo = h_strdup_cprintf("%s=%s\n", moreinfo, _("WWN / EUI"), _("(None)"));
+ }
+
+ if (ext->wwid_oui.oui) {
+ moreinfo = h_strdup_cprintf(_("$^$%s=[%s] %s\n"),
+ moreinfo,
+ _("IEEE OUI"), ext->wwid_oui.oui,
+ ext->wwid_oui.vendor ?
+ ext->wwid_oui.vendor : _("(Unknown)"));
+ }
+
+ if (ext->nvme_controller) {
+ gchar *nvme = nvme_pci_sections(ext->nvme_controller);
+ if (nvme)
+ moreinfo = h_strdup_cprintf("%s", moreinfo, nvme);
+ g_free(nvme);
+ }
+ if (disk->smart_enabled) {
+ moreinfo = h_strdup_cprintf(_("[Self-monitoring (S.M.A.R.T.)]\n"
+ "Status=%s\n"
+ "Bad Sectors=%" G_GINT64_FORMAT "\n"
+ "Power on time=%" G_GUINT64_FORMAT " days %" G_GUINT64_FORMAT " hours\n"
+ "Temperature=%d°C\n"),
+ moreinfo,
+ disk->smart_failing ? _("Failing"): _("OK"),
+ disk->smart_bad_sectors,
+ disk->smart_poweron/(60*60*24), (disk->smart_poweron/60/60) % 24,
+ disk->smart_temperature);
+
+ if (disk->smart_attributes != NULL) {
+ moreinfo = h_strdup_cprintf(_("[S.M.A.R.T. Attributes]\n"
+ "Attribute=<tt>Value / Normalized / Worst / Threshold</tt>\n"),
+ moreinfo);
+
+ attrib = disk->smart_attributes;
+
+ while (attrib != NULL){
+ tmp = g_strdup("");
+
+ switch (attrib->interpreted_unit){
+ case UDSK_INTPVAL_SKIP:
+ tmp = h_strdup_cprintf("-", tmp);
+ break;
+ case UDSK_INTPVAL_MILISECONDS:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT " ms", tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_HOURS:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT " h", tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_CELSIUS:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT "°C", tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_SECTORS:
+ tmp = h_strdup_cprintf(ngettext("%" G_GINT64_FORMAT " sector",
+ "%" G_GINT64_FORMAT " sectors", attrib->interpreted),
+ tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_DIMENSIONLESS:
+ default:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT, tmp, attrib->interpreted);
+ break;
+ }
+
+ // pad spaces to next col
+ j = g_utf8_strlen(tmp, -1);
+ if (j < 13) tmp = h_strdup_cprintf("%*c", tmp, 13 - j, ' ');
+
+ if (attrib->value != -1)
+ tmp = h_strdup_cprintf("%-13d", tmp, attrib->value);
+ else
+ tmp = h_strdup_cprintf("%-13s", tmp, "???");
+
+ if (attrib->worst != -1)
+ tmp = h_strdup_cprintf("%-8d", tmp, attrib->worst);
+ else
+ tmp = h_strdup_cprintf("%-8s", tmp, "???");
+
+ if (attrib->threshold != -1)
+ tmp = h_strdup_cprintf("%d", tmp, attrib->threshold);
+ else
+ tmp = h_strdup_cprintf("???", tmp);
+
+
+ alabel = attrib->identifier;
+ for (i = 0; smart_attrib_info[i].identifier != NULL; i++) {
+ if (g_strcmp0(attrib->identifier, smart_attrib_info[i].identifier) == 0) {
+ alabel = smart_attrib_info[i].label;
+ break;
+ }
+ }
+
+ moreinfo = h_strdup_cprintf(_("(%d) %s=<tt>%s</tt>\n"),
+ moreinfo,
+ attrib->id, alabel, tmp);
+ g_free(tmp);
+ attrib = attrib->next;
+ }
+ }
+ }
+ if (disk->partition_table || disk->partitions) {
+ moreinfo = h_strdup_cprintf(_("[Partition table]\n"
+ "Type=%s\n"),
+ moreinfo,
+ disk->partition_table ? disk->partition_table : _("(Unknown)"));
+
+ if (disk->partitions != NULL) {
+ part = disk->partitions;
+ while (part != NULL){
+
+ tmp = size_human_readable((gfloat) part->size);
+ if (part->label) {
+ tmp = h_strdup_cprintf(" - %s", tmp, part->label);
+ }
+ if (part->type && part->version) {
+ tmp = h_strdup_cprintf(" (%s %s)", tmp, part->type, part->version);
+ }
+ else if (part->type) {
+ tmp = h_strdup_cprintf(" (%s)", tmp, part->type);
+ }
+ moreinfo = h_strdup_cprintf(_("Partition %s=%s\n"),
+ moreinfo,
+ part->block, tmp);
+ g_free(tmp);
+ part = part->next;
+ }
+ }
+ }
+
+ moreinfo_add_with_prefix("DEV", devid, moreinfo);
+ g_free(devid);
+ g_free(features);
+ g_free(media_comp);
+ media_comp = NULL;
+
+ features = NULL;
+ moreinfo = NULL;
+ devid = NULL;
+
+ u2driveext_free(ext);
+ }
+ g_slist_free(drives);
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, udisks2_storage_list, NULL);
+ g_free(udisks2_storage_list);
+ return TRUE;
+ }
+
+ g_free(udisks2_storage_list);
+ return FALSE;
+}
+
+/* SCSI support by Pascal F.Martin <pascalmartin@earthlink.net> */
+void __scan_scsi_devices(void)
+{
+ FILE *proc_scsi;
+ gchar buffer[256], *buf;
+ gint n = 0;
+ gint scsi_controller = 0;
+ gint scsi_channel = 0;
+ gint scsi_id = 0 ;
+ gint scsi_lun = 0;
+ gchar *vendor = NULL, *revision = NULL, *model = NULL;
+ gchar *scsi_storage_list;
+
+ /* remove old devices from global device table */
+ moreinfo_del_with_prefix("DEV:SCSI");
+
+ scsi_storage_list = g_strdup(_("\n[SCSI Disks]\n"));
+
+ int otype = 0;
+ if (proc_scsi = fopen("/proc/scsi/scsi", "r")) {
+ otype = 1;
+ } else if (proc_scsi = popen("lsscsi -c", "r")) {
+ otype = 2;
+ }
+
+ if (otype) {
+ while (fgets(buffer, 256, proc_scsi)) {
+ buf = g_strstrip(buffer);
+ if (!strncmp(buf, "Host: scsi", 10)) {
+ sscanf(buf,
+ "Host: scsi%d Channel: %d Id: %d Lun: %d",
+ &scsi_controller, &scsi_channel, &scsi_id, &scsi_lun);
+
+ n++;
+ } else if (!strncmp(buf, "Vendor: ", 8)) {
+ buf[17] = '\0';
+ buf[41] = '\0';
+ buf[53] = '\0';
+
+ vendor = g_strdup(g_strstrip(buf + 8));
+ model = g_strdup_printf("%s %s", vendor, g_strstrip(buf + 24));
+ revision = g_strdup(g_strstrip(buf + 46));
+ } else if (!strncmp(buf, "Type: ", 8)) {
+ char *p;
+ gchar *type = NULL, *icon = NULL;
+
+ if (!(p = strstr(buf, "ANSI SCSI revision"))) {
+ p = strstr(buf, "ANSI SCSI revision");
+ }
+
+ if (p != NULL) {
+ while (*(--p) == ' ');
+ *(++p) = 0;
+
+ static struct {
+ char *type;
+ char *label;
+ char *icon;
+ } type2icon[] = {
+ { "Direct-Access", "Disk", "hdd"},
+ { "Sequential-Access", "Tape", "tape"},
+ { "Printer", "Printer", "lpr"},
+ { "WORM", "CD-ROM", "cdrom"},
+ { "CD-ROM", "CD-ROM", "cdrom"},
+ { "Scanner", "Scanner", "scanner"},
+ { "Flash Disk", "USB Flash Disk", "usbfldisk" },
+ { NULL, "Generic", "scsi"}
+ };
+ int i;
+
+ if (model && strstr(model, "Flash Disk")) {
+ type = "Flash Disk";
+ icon = "usbfldisk";
+ } else {
+ for (i = 0; type2icon[i].type != NULL; i++)
+ if (g_str_equal(buf + 8, type2icon[i].type))
+ break;
+
+ type = type2icon[i].label;
+ icon = type2icon[i].icon;
+ }
+ }
+
+ gchar *devid = g_strdup_printf("SCSI%d", n);
+ scsi_storage_list = h_strdup_cprintf("$%s$scsi%d=|%s\n", scsi_storage_list, devid, scsi_controller, model);
+ storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, model, icon);
+
+ gchar *strhash = g_strdup_printf(_("[Device Information]\n"
+ "Model=%s\n"), model);
+
+ strhash = h_strdup_cprintf("$^$%s=%s\n",
+ strhash,
+ _("Vendor"), model);
+
+ strhash = h_strdup_cprintf(_("Type=%s\n"
+ "Revision=%s\n"
+ "[SCSI Controller]\n"
+ "Controller=scsi%d\n"
+ "Channel=%d\n"
+ "ID=%d\n" "LUN=%d\n"),
+ strhash,
+ type,
+ revision,
+ scsi_controller,
+ scsi_channel,
+ scsi_id,
+ scsi_lun);
+
+ moreinfo_add_with_prefix("DEV", devid, strhash);
+ g_free(devid);
+
+ g_free(model);
+ g_free(revision);
+ g_free(vendor);
+
+ scsi_controller = scsi_channel = scsi_id = scsi_lun = 0;
+ }
+ }
+ if (otype == 1)
+ fclose(proc_scsi);
+ else if (otype == 2)
+ pclose(proc_scsi);
+ }
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, scsi_storage_list, NULL);
+ g_free(scsi_storage_list);
+ }
+}
+
+void __scan_ide_devices(void)
+{
+ FILE *proc_ide;
+ gchar *device, *model, *media, *pgeometry = NULL, *lgeometry = NULL;
+ gchar iface;
+ gint n = 0, i = 0, cache, nn = 0;
+ gchar *capab = NULL, *speed = NULL, *driver = NULL, *ide_storage_list;
+
+ /* remove old devices from global device table */
+ moreinfo_del_with_prefix("DEV:IDE");
+
+ ide_storage_list = g_strdup(_("\n[IDE Disks]\n"));
+
+ iface = 'a';
+ for (i = 0; i <= 16; i++) {
+ device = g_strdup_printf("/proc/ide/hd%c/model", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ gchar buf[128];
+
+ cache = 0;
+
+ proc_ide = fopen(device, "r");
+ if (!proc_ide)
+ continue;
+
+ (void) fgets(buf, 128, proc_ide);
+ fclose(proc_ide);
+
+ buf[strlen(buf) - 1] = 0;
+
+ model = g_strdup(buf);
+
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/media", iface);
+ proc_ide = fopen(device, "r");
+ if (!proc_ide) {
+ free(model);
+ continue;
+ }
+
+ (void) fgets(buf, 128, proc_ide);
+ fclose(proc_ide);
+ buf[strlen(buf) - 1] = 0;
+
+ media = g_strdup(buf);
+ if (g_str_equal(media, "cdrom")) {
+ /* obtain cd-rom drive information from cdrecord */
+ GTimer *timer;
+ gchar *tmp = g_strdup_printf("cdrecord dev=/dev/hd%c -prcap 2>/dev/stdout", iface);
+ FILE *prcap;
+
+ if ((prcap = popen(tmp, "r"))) {
+ /* we need a timeout so cdrecord does not try to get information on cd drives
+ with inserted media, which is not possible currently. half second should be
+ enough. */
+ timer = g_timer_new();
+ g_timer_start(timer);
+
+ while (fgets(buf, 128, prcap)
+ && g_timer_elapsed(timer, NULL) < 0.5) {
+ if (g_str_has_prefix(buf, " Does")) {
+ if (g_str_has_suffix(buf, "media\n")
+ && !strstr(buf, "speed")) {
+ gchar *media_type = g_strstrip(strstr(buf, "Does "));
+ gchar **ttmp = g_strsplit(media_type, " ", 0);
+
+ capab = h_strdup_cprintf("\nCan %s#%d=%s\n", capab, ttmp[1], ++nn, ttmp[2]);
+
+ g_strfreev(ttmp);
+ } else if (strstr(buf, "Buffer-Underrun-Free")) {
+ capab =
+ h_strdup_cprintf
+ ("\nSupports BurnProof=%s\n", capab, strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "multi-session")) {
+ capab =
+ h_strdup_cprintf
+ ("\nCan read multi-session CDs=%s\n",
+ capab, strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "audio CDs")) {
+ capab =
+ h_strdup_cprintf
+ ("\nCan play audio CDs=%s\n", capab, strstr(buf, "Does not") ? "No" : "Yes");
+ } else if (strstr(buf, "PREVENT/ALLOW")) {
+ capab =
+ h_strdup_cprintf
+ ("\nCan lock media=%s\n", capab, strstr(buf, "Does not") ? "No" : "Yes");
+ }
+ } else if ((strstr(buf, "read")
+ || strstr(buf, "write"))
+ && strstr(buf, "kB/s")) {
+ speed =
+ g_strconcat(speed ? speed : "", strreplacechr(g_strstrip(buf), ":", '='), "\n", NULL);
+ } else if (strstr(buf, "Device seems to be")) {
+ driver = g_strdup_printf(_("Driver=%s\n"), strchr(buf, ':') + 1);
+ }
+ }
+
+ pclose(prcap);
+ g_timer_destroy(timer);
+ }
+
+ g_free(tmp);
+ }
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/cache", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ proc_ide = fopen(device, "r");
+ if (proc_ide) {
+ (void) fscanf(proc_ide, "%d", &cache);
+ fclose(proc_ide);
+ } else {
+ cache = 0;
+ }
+ }
+ g_free(device);
+
+ device = g_strdup_printf("/proc/ide/hd%c/geometry", iface);
+ if (g_file_test(device, G_FILE_TEST_EXISTS)) {
+ gchar *tmp;
+
+ proc_ide = fopen(device, "r");
+ if (proc_ide) {
+ (void) fgets(buf, 64, proc_ide);
+ for (tmp = buf; *tmp; tmp++) {
+ if (*tmp >= '0' && *tmp <= '9')
+ break;
+ }
+
+ pgeometry = g_strdup(g_strstrip(tmp));
+
+ (void) fgets(buf, 64, proc_ide);
+ for (tmp = buf; *tmp; tmp++) {
+ if (*tmp >= '0' && *tmp <= '9')
+ break;
+ }
+ lgeometry = g_strdup(g_strstrip(tmp));
+
+ fclose(proc_ide);
+ } else {
+ pgeometry = g_strdup("Unknown");
+ lgeometry = g_strdup("Unknown");
+ }
+
+ }
+ g_free(device);
+
+ n++;
+
+ gchar *devid = g_strdup_printf("IDE%d", n);
+
+ ide_storage_list = h_strdup_cprintf("$%s$hd%c=|%s\n", ide_storage_list, devid, iface, model);
+ storage_icons =
+ h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons,
+ devid, model, g_str_equal(media, "cdrom") ? "cdrom" : "hdd");
+
+ gchar *strhash = g_strdup_printf(_("[Device Information]\n" "Model=%s\n"),
+ model);
+
+ strhash = h_strdup_cprintf("$^$%s=%s\n",
+ strhash, _("Vendor"), model);
+
+ strhash = h_strdup_cprintf(_("Device Name=hd%c\n"
+ "Media=%s\n" "Cache=%dkb\n"), strhash, iface, media, cache);
+ if (driver) {
+ strhash = h_strdup_cprintf("%s\n", strhash, driver);
+
+ g_free(driver);
+ driver = NULL;
+ }
+
+ if (pgeometry && lgeometry) {
+ strhash = h_strdup_cprintf(_("[Geometry]\n"
+ "Physical=%s\n" "Logical=%s\n"), strhash, pgeometry, lgeometry);
+
+ g_free(pgeometry);
+ pgeometry = NULL;
+ g_free(lgeometry);
+ lgeometry = NULL;
+ }
+
+ if (capab) {
+ strhash = h_strdup_cprintf(_("[Capabilities]\n%s"), strhash, capab);
+
+ g_free(capab);
+ capab = NULL;
+ }
+
+ if (speed) {
+ strhash = h_strdup_cprintf(_("[Speeds]\n%s"), strhash, speed);
+
+ g_free(speed);
+ speed = NULL;
+ }
+
+ moreinfo_add_with_prefix("DEV", devid, strhash);
+ g_free(devid);
+ g_free(model);
+ } else {
+ g_free(device);
+ }
+
+ iface++;
+ }
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, ide_storage_list, NULL);
+ g_free(ide_storage_list);
+ }
+}