]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blobdiff - src/hwinfo/src/hd/block.c
... Viel zu tun :D
[people/teissler/ipfire-2.x.git] / src / hwinfo / src / hd / block.c
diff --git a/src/hwinfo/src/hd/block.c b/src/hwinfo/src/hd/block.c
deleted file mode 100644 (file)
index 2a8f400..0000000
+++ /dev/null
@@ -1,1578 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <linux/iso_fs.h>
-#include <scsi/sg.h>
-
-#include "hd.h"
-#include "hd_int.h"
-#include "hddb.h"
-#include "block.h"
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- * block device stuff
- *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- */
-
-static void get_block_devs(hd_data_t *hd_data);
-static void add_partitions(hd_data_t *hd_data, hd_t *hd, char *path);
-static void add_cdrom_info(hd_data_t *hd_data, hd_t *hd);
-static void add_other_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev);
-static void add_ide_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev);
-static void add_scsi_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev);
-static void read_partitions(hd_data_t *hd_data);
-static void read_cdroms(hd_data_t *hd_data);
-static cdrom_info_t *new_cdrom_entry(cdrom_info_t **ci);
-static cdrom_info_t *get_cdrom_entry(cdrom_info_t *ci, int n);
-static void get_scsi_tape(hd_data_t *hd_data);
-static void get_generic_scsi_devs(hd_data_t *hd_data);
-static void add_disk_size(hd_data_t *hd_data, hd_t *hd);
-
-
-void hd_scan_sysfs_block(hd_data_t *hd_data)
-{
-  if(!hd_probe_feature(hd_data, pr_block)) return;
-
-  hd_data->module = mod_block;
-
-  /* some clean-up */
-  remove_hd_entries(hd_data);
-
-  hd_data->disks = free_str_list(hd_data->disks);
-  hd_data->partitions = free_str_list(hd_data->partitions);
-  hd_data->cdroms = free_str_list(hd_data->cdroms);
-
-  if(hd_probe_feature(hd_data, pr_block_mods)) {
-    PROGRESS(1, 0, "block modules");
-    load_module(hd_data, "ide_cd");
-    load_module(hd_data, "sr_mod");
-    load_module(hd_data, "sd_mod");
-    load_module(hd_data, "st");
-  }
-
-  PROGRESS(2, 0, "sysfs drivers");
-
-  hd_sysfs_driver_list(hd_data);
-
-  PROGRESS(3, 0, "cdrom");
-
-  read_cdroms(hd_data);
-
-  PROGRESS(4, 0, "partition");
-
-  read_partitions(hd_data);
-
-  PROGRESS(5, 0, "get sysfs block dev data");
-
-  get_block_devs(hd_data);
-
-  if(hd_data->cdrom) {
-    ADD2LOG("oops: cdrom list not empty\n");
-  }
-}
-
-
-void get_block_devs(hd_data_t *hd_data)
-{
-  str_list_t *sl;
-  char *s, *t;
-  unsigned u1, u2, u3;
-  uint64_t ul0;
-  hd_t *hd, *hd1;
-  hd_dev_num_t dev_num;
-
-  struct sysfs_bus *sf_bus;
-  struct sysfs_class *sf_class;
-  struct sysfs_class_device *sf_cdev;
-  struct sysfs_device *sf_dev;
-  struct dlist *sf_cdev_list;
-  struct dlist *sf_ide_list = NULL;
-  struct sysfs_device *sf_ide;
-
-  sf_bus = sysfs_open_bus("ide");
-  if(sf_bus) {
-    sf_ide_list = sysfs_get_bus_devices(sf_bus);
-    if(sf_ide_list) dlist_for_each_data(sf_ide_list, sf_ide, struct sysfs_device) {
-      ADD2LOG(
-        "  ide: bus_id = %s path = %s\n",
-        sf_ide->bus_id,
-        hd_sysfs_id(sf_ide->path)
-      );
-    }
-  }
-
-  sf_class = sysfs_open_class("block");
-
-  if(!sf_class) {
-    ADD2LOG("sysfs: no such class: block\n");
-    return;
-  }
-
-  sf_cdev_list = sysfs_get_class_devices(sf_class);
-  if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
-    ADD2LOG(
-      "  block: name = %s, path = %s\n",
-      sf_cdev->name,
-      hd_sysfs_id(sf_cdev->path)
-    );
-
-    memset(&dev_num, 0, sizeof dev_num);
-
-    if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) {
-      if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
-        dev_num.type = 'b';
-        dev_num.major = u1;
-        dev_num.minor = u2;
-        dev_num.range = 1;
-      }
-      ADD2LOG("    dev = %u:%u\n", u1, u2);
-    }
-
-    if(hd_attr_uint(sysfs_get_classdev_attr(sf_cdev, "range"), &ul0, 0)) {
-      dev_num.range = ul0;
-      ADD2LOG("    range = %u\n", dev_num.range);
-    }
-
-    sf_dev = sysfs_get_classdev_device(sf_cdev);
-    if(sf_dev) {
-      ADD2LOG(
-        "    block device: bus = %s, bus_id = %s driver = %s\n      path = %s\n",
-        sf_dev->bus,
-        sf_dev->bus_id,
-        sf_dev->driver_name,
-        hd_sysfs_id(sf_dev->path)
-      );
-    }
-
-    hd = NULL;
-
-    /* check if disk is DASD and has already been found by s390.c */
-    if(sf_dev && sf_dev->driver_name && strstr(sf_dev->driver_name,"dasd"))
-    {
-      char bid[9];
-      hd_res_t* res;
-      //fprintf(stderr,"dn %s bi %s\n",sf_dev->driver_name,sf_dev->bus_id);
-      for(hd=hd_data->hd;hd;hd=hd->next)
-      {
-       //fprintf(stderr,"bcid %d\n",hd->base_class.id);
-       if(hd->base_class.id == bc_storage_device
-          && hd->detail
-          && hd->detail->ccw.type == hd_detail_ccw)
-       {
-         for(res=hd->res;res;res=res->next)
-         {
-           if(res->io.type==res_io)
-           {
-             sprintf(bid,"%01x.%01x.%04x",
-                     hd->detail->ccw.data->lcss >> 8,
-                     hd->detail->ccw.data->lcss & 0xff,
-                     (unsigned short)res->io.base);
-             //fprintf(stderr,"bid %s\n",bid);
-             if (strcmp(bid,sf_dev->bus_id)==0) goto out;
-           }
-         }
-       }
-      }
-      hd=NULL;
-      out:;
-    }
-    else if((sl = search_str_list(hd_data->disks, hd_sysfs_name2_dev(sf_cdev->name)))) {
-      hd = add_hd_entry(hd_data, __LINE__, 0);
-      hd->sub_class.id = sc_sdev_disk;
-    }
-    else if((sl = search_str_list(hd_data->cdroms, hd_sysfs_name2_dev(sf_cdev->name)))) {
-      hd = add_hd_entry(hd_data, __LINE__, 0);
-      hd->sub_class.id = sc_sdev_cdrom;
-    }
-    else if(
-      sf_dev &&
-      sf_dev->bus &&
-      (!strcmp(sf_dev->bus, "scsi") || !strcmp(sf_dev->bus, "ide"))
-    ) {
-      hd = add_hd_entry(hd_data, __LINE__, 0);
-      hd->sub_class.id = sc_sdev_other;
-    }
-
-    if(hd) {
-      str_printf(&hd->unix_dev_name, 0, "/dev/%s", hd_sysfs_name2_dev(sf_cdev->name));
-
-      hd->base_class.id = bc_storage_device;
-
-      hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
-
-      if(sf_dev) hd->sysfs_device_link = new_str(hd_sysfs_id(sf_dev->path));
-
-      hd->unix_dev_num = dev_num;
-
-      hd->bus.id = bus_none;
-
-      if(sf_dev) {
-        if(sf_dev->bus) {
-          if(!strcmp(sf_dev->bus, "ide")) hd->bus.id = bus_ide;
-          else if(!strcmp(sf_dev->bus, "scsi")) hd->bus.id = bus_scsi;
-        }
-        hd->sysfs_bus_id = new_str(sf_dev->bus_id);
-      }
-
-      if(sf_dev && (s = hd_sysfs_id(sf_dev->path))) {
-
-        /* parent has longest matching sysfs id */
-        u2 = strlen(s);
-        for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
-          if(hd1->sysfs_id) {
-            u1 = strlen(hd1->sysfs_id);
-            if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
-              u3 = u1;
-              hd->attached_to = hd1->idx;
-            }
-          }
-        }
-
-        /* find longest matching sysfs id we have a driver for */
-        s = new_str(s);
-        t = strrchr(s, '/');
-        if(t) *t = 0;
-        t = hd_sysfs_find_driver(hd_data, s, 0);
-        if(t) {
-          add_str_list(&hd->drivers, t);
-        }
-        s = free_mem(s);
-
-        /* look for ide-scsi handled devices */
-        if(hd->bus.id == bus_scsi) {
-          if(sf_ide_list) dlist_for_each_data(sf_ide_list, sf_ide, struct sysfs_device) {
-            if(
-              strcmp(sf_dev->path, sf_ide->path) &&
-              !strncmp(sf_dev->path, sf_ide->path, strlen(sf_ide->path)) &&
-              sscanf(sf_ide->bus_id, "%u.%u", &u1, &u2) == 2
-            ) {
-              str_printf(&hd->unix_dev_name2, 0, "/dev/hd%c", 'a' + (u1 << 1) + u2);
-            }
-          }
-        }
-      }
-
-      /*
-       * set hd->drivers before calling any of add_xxx_sysfs_info()
-       */
-      if(
-        sf_dev &&
-        sf_dev->driver_name &&
-        *sf_dev->driver_name &&
-        strcmp(sf_dev->driver_name, "unknown")
-      ) {
-        add_str_list(&hd->drivers, sf_dev->driver_name);
-      }
-
-      if(hd->bus.id == bus_ide) {
-        add_ide_sysfs_info(hd_data, hd, sf_dev);
-      }
-      else if(hd->bus.id == bus_scsi) {
-        add_scsi_sysfs_info(hd_data, hd, sf_dev);
-      }
-      else {
-        add_other_sysfs_info(hd_data, hd, sf_dev);
-      }
-
-      
-      if(hd->sub_class.id == sc_sdev_cdrom) {
-        add_cdrom_info(hd_data, hd);
-      }
-
-      if(
-        hd->sub_class.id == sc_sdev_disk &&
-        hd_probe_feature(hd_data, pr_block_part)
-      ) {
-        add_partitions(hd_data, hd, sf_cdev->path);
-      }
-
-    }
-
-  }
-
-  sysfs_close_class(sf_class);
-
-  sysfs_close_bus(sf_bus);
-}
-
-
-/*
- * Find driver for sysfs_id.
- *
- * Return driver for id (exact = 1) or longest matching id (exact = 0).
- */
-char *hd_sysfs_find_driver(hd_data_t *hd_data, char *sysfs_id, int exact)
-{
-  hd_sysfsdrv_t *sf;
-  char *t;
-  unsigned u1, u2, u3;
-
-  if(!sysfs_id || !*sysfs_id) return NULL;
-
-  t = NULL;
-
-  if(exact) {
-    for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
-      if(!strcmp(sysfs_id, sf->device)) {
-        t = sf->driver;
-        break;
-      }
-    }
-  }
-  else {
-    u2 = strlen(sysfs_id);
-    u3 = 0;
-    for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
-      u1 = strlen(sf->device);
-      if(u1 > u3 && u1 <= u2 && !strncmp(sysfs_id, sf->device, u1)) {
-        u3 = u1;
-        t = sf->driver;
-      }
-    }
-  }
-
-  return t;
-}
-
-
-void add_partitions(hd_data_t *hd_data, hd_t *hd, char *path)
-{
-  hd_t *hd1;
-  str_list_t *sl;
-  char *s;
-  size_t len;
-
-  s = hd->unix_dev_name + sizeof "/dev/" - 1;
-  len = strlen(s);
-  for(sl = hd_data->partitions; sl; sl = sl->next) {
-    if(!strncmp(sl->str, s, len)) {
-      hd1 = add_hd_entry(hd_data, __LINE__, 0);
-      hd1->base_class.id = bc_partition;
-      str_printf(&hd1->unix_dev_name, 0, "/dev/%s", sl->str);
-      hd1->attached_to = hd->idx;
-
-      str_printf(&hd1->sysfs_id, 0, "%s/%s", hd->sysfs_id, hd_sysfs_dev2_name(sl->str));
-    }
-  }
-}
-
-
-void add_cdrom_info(hd_data_t *hd_data, hd_t *hd)
-{
-  cdrom_info_t *ci, **prev;
-
-  hd->detail = free_hd_detail(hd->detail);
-  hd->detail = new_mem(sizeof *hd->detail);
-  hd->detail->type = hd_detail_cdrom;
-
-  for(ci = *(prev = &hd_data->cdrom); ci; ci = *(prev = &ci->next)) {
-    if(!strcmp(hd->unix_dev_name + sizeof "/dev/" - 1, ci->name)) {
-      hd->detail->cdrom.data = ci;
-      *prev = ci->next;
-      hd->detail->cdrom.data->next = NULL;
-      break;
-    }
-  }
-
-  if((ci = hd->detail->cdrom.data)) {
-    /* update prog_if: cdr, cdrw, ... */
-    if(
-      /* ###### FIXME: dosn't work anyway: ide-scsi doesn't support sysfs */
-      hd->bus.id == bus_scsi &&
-      !search_str_list(hd->drivers, "ide-scsi")                /* could be ide, though */
-    ) {
-      /* scsi devs lie */
-      if(ci->dvd && (ci->cdrw || ci->dvdr || ci->dvdram)) {
-        ci->dvd = ci->dvdr = ci->dvdram = 0;
-      }
-      ci->dvdr = ci->dvdram = 0;
-      ci->cdr = ci->cdrw = 0;
-      if(hd->prog_if.id == pif_cdr) ci->cdr = 1;
-    }
-
-    /* trust ide info */
-    if(ci->dvd) {
-      hd->is.dvd = 1;
-      hd->prog_if.id = pif_dvd;
-    }
-    if(ci->cdr) {
-      hd->is.cdr = 1;
-      hd->prog_if.id = pif_cdr;
-    }
-    if(ci->cdrw) {
-      hd->is.cdrw = 1;
-      hd->prog_if.id = pif_cdrw;
-    }
-    if(ci->dvdr) {
-      hd->is.dvdr = 1;
-      hd->prog_if.id = pif_dvdr;
-    }
-    if(ci->dvdram) {
-      hd->is.dvdram = 1;
-      hd->prog_if.id = pif_dvdram;
-    }
-  }
-
-  if(
-    hd_probe_feature(hd_data, pr_block_cdrom) &&
-    hd_report_this(hd_data, hd)
-  ) {
-    hd_read_cdrom_info(hd_data, hd);
-  }
-}
-
-
-void add_other_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev)
-{
-  unsigned u0, u1;
-  char c;
-
-  if(hd->sysfs_id) {
-    if(
-      sscanf(hd->sysfs_id, "/block/cciss!c%ud%u", &u0, &u1) == 2
-    ) {
-      hd->slot = (u0 << 8) + u1;
-      str_printf(&hd->device.name, 0, "CCISS disk %u/%u", u0, u1);
-    }
-    else if(
-      sscanf(hd->sysfs_id, "/block/ida!c%ud%u", &u0, &u1) == 2
-    ) {
-      hd->slot = (u0 << 8) + u1;
-      str_printf(&hd->device.name, 0, "SMART Array %u/%u", u0, u1);
-    }
-    else if(
-      sscanf(hd->sysfs_id, "/block/rd!c%ud%u", &u0, &u1) == 2
-    ) {
-      hd->slot = (u0 << 8) + u1;
-      str_printf(&hd->device.name, 0, "DAC960 RAID Array %u/%u", u0, u1);
-    }
-    else if(
-      sscanf(hd->sysfs_id, "/block/i2o!hd%c", &c) == 1 &&
-      c >= 'a'
-    ) {
-      hd->slot = c - 'a';
-      str_printf(&hd->device.name, 0, "I2O disk %u", hd->slot);
-    }
-    else if(
-      sscanf(hd->sysfs_id, "/block/dasd%c", &c) == 1 &&
-      c >= 'a'
-    ) {
-      hd->slot = c - 'a';
-      hd->device.name = new_str("S390 Disk");
-    }
-  }
-
-  add_disk_size(hd_data, hd);
-}
-
-
-void add_ide_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev)
-{
-  char *fname = NULL, buf[256], *dev_name, *s;
-  unsigned u0, u1, u2, size = 0;
-  str_list_t *sl, *sl0;
-  hd_res_t *res;
-  FILE *f;
-
-  if(!hd_report_this(hd_data, hd)) return;
-
-  if(hd->sysfs_bus_id && sscanf(hd->sysfs_bus_id, "%u.%u", &u0, &u1) == 2) {
-    /* host.master/slave */
-    hd->slot = (u0 << 1) + u1;
-  }
-
-  if(
-    hd->unix_dev_name &&
-    strlen(hd->unix_dev_name) > 5
-  ) {
-    dev_name = hd->unix_dev_name + 5;
-
-    str_printf(&fname, 0, PROC_IDE "/%s/media", dev_name);
-    if((sl = read_file(fname, 0, 1))) {
-
-      if(strstr(sl->str, "floppy"))
-        hd->sub_class.id = sc_sdev_floppy;
-      else if(strstr(sl->str, "cdrom"))
-        hd->sub_class.id = sc_sdev_cdrom;
-      else if(strstr(sl->str, "tape"))
-        hd->sub_class.id = sc_sdev_tape;
-
-      free_str_list(sl);
-    }
-
-    str_printf(&fname, 0, PROC_IDE "/%s/model", dev_name);
-    if((sl = read_file(fname, 0, 1))) {
-      hd->vendor.name = canon_str(sl->str, strlen(sl->str));
-      if((s = strchr(hd->vendor.name, ' '))) {
-        hd->device.name = canon_str(s, strlen(s));
-        if(*hd->device.name) {
-          *s = 0;
-        }
-        else {
-          hd->device.name = free_mem(hd->device.name);
-        }
-      }
-      if(!hd->device.name) {
-        hd->device.name = hd->vendor.name;
-        hd->vendor.name = NULL;
-      }
-
-      free_str_list(sl);
-    }
-
-    str_printf(&fname, 0, PROC_IDE "/%s/driver", dev_name);
-    if((sl = read_file(fname, 0, 1))) {
-      if((s = strchr(sl->str, ' '))) *s = 0;
-      s = canon_str(sl->str, strlen(sl->str));
-      add_str_list(&hd->drivers, s);
-      s = free_mem(s);
-      free_str_list(sl);
-    }
-
-    str_printf(&fname, 0, PROC_IDE "/%s/capacity", dev_name);
-    if((sl = read_file(fname, 0, 1))) {
-      if(sscanf(sl->str, "%u", &u0) == 1 && u0 != 0x7fffffff) {
-        res = add_res_entry(&hd->res, new_mem(sizeof *res));
-        res->size.type = res_size;
-        res->size.unit = size_unit_sectors;
-        res->size.val1 = size = u0;
-        res->size.val2 = 512;          // ####### FIXME: sector size?
-      }
-      free_str_list(sl);
-    }
-
-    str_printf(&fname, 0, PROC_IDE "/%s/geometry", dev_name);
-    if((sl0 = read_file(fname, 0, 2))) {
-      for(sl = sl0; sl; sl = sl->next) {
-        if(sscanf(sl->str, " physical %u / %u / %u", &u0, &u1, &u2) == 3) {
-          if(u0 || u1 || u2) {
-            if(size && u1 && u2) {
-              u0 = size / (u1 * u2);
-            }
-            res = add_res_entry(&hd->res, new_mem(sizeof *res));
-            res->disk_geo.type = res_disk_geo;
-            res->disk_geo.cyls = u0;
-            res->disk_geo.heads = u1;
-            res->disk_geo.sectors = u2;
-            res->disk_geo.geotype = geo_physical;
-          }
-          continue;
-        }
-
-        if(sscanf(sl->str, " logical %u / %u / %u", &u0, &u1, &u2) == 3) {
-          if(size && u1 && u2) {
-            u0 = size / (u1 * u2);
-          }
-          res = add_res_entry(&hd->res, new_mem(sizeof *res));
-          res->disk_geo.type = res_disk_geo;
-          res->disk_geo.cyls = u0;
-          res->disk_geo.heads = u1;
-          res->disk_geo.sectors = u2;
-          res->disk_geo.geotype = geo_logical;
-        }
-      }
-      free_str_list(sl0);
-    }
-
-    str_printf(&fname, 0, PROC_IDE "/%s/cache", dev_name);
-    if((sl = read_file(fname, 0, 1))) {
-      if(sscanf(sl->str, "%u", &u0) == 1 && u0) {
-        res = add_res_entry(&hd->res, new_mem(sizeof *res));
-        res->cache.type = res_cache;
-        res->cache.size = u0;
-      }
-      free_str_list(sl);
-    }
-
-    str_printf(&fname, 0, PROC_IDE "/%s/identify", dev_name);
-    if((f = fopen(fname, "r"))) {
-      u1 = 0;
-      memset(buf, sizeof buf, 0);
-      while(u1 < sizeof buf - 1 && fscanf(f, "%x", &u0) == 1) {
-        buf[u1++] = u0 >> 8; buf[u1++] = u0;
-      }
-      fclose(f);
-
-      /* ok, we now have the ATA/ATAPI ident block */
-
-      if(buf[0x14] || buf[0x15]) {     /* has serial id */
-        hd->serial = canon_str(buf + 0x14, 20);
-      }
-      if(buf[0x2e] || buf[0x2f]) {     /* has revision id */
-        hd->revision.name = canon_str(buf + 0x2e, 8);
-      }
-    }
-
-    free_mem(fname);
-  }
-
-  if(!size) add_disk_size(hd_data, hd);
-}
-
-
-/*
- * assumes hd->drivers aleady includes scsi device drivers (like 'sd')
- */
-void add_scsi_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev)
-{
-  hd_t *hd1;
-  char *s, *t, *cs, *pr_str;
-  unsigned u0, u1, u2, u3;
-  int fd, k;
-  unsigned char scsi_cmd_buf[0x300];
-  struct sg_io_hdr hdr;
-  unsigned char *uc;
-  scsi_t *scsi;
-  hd_res_t *geo, *size;
-  uint64_t ul0;
-
-  if(!hd_report_this(hd_data, hd)) return;
-
-  hd->detail = new_mem(sizeof *hd->detail);
-  hd->detail->type = hd_detail_scsi;
-  hd->detail->scsi.data = scsi = new_mem(sizeof *scsi);
-
-  if(hd->sysfs_bus_id && sscanf(hd->sysfs_bus_id, "%u:%u:%u:%u", &u0, &u1, &u2, &u3) == 4) {
-    /* host:channel:id:lun */
-    hd->slot = (u0 << 8) + (u1 << 4) + u2;
-    hd->func = u3;
-  }
-
-  if((s = hd_attr_str(sysfs_get_device_attr(sf_dev, "vendor")))) {
-    cs = canon_str(s, strlen(s));
-    ADD2LOG("    vendor = %s\n", cs);
-    if(*cs) {
-      hd->vendor.name = cs;
-    }
-    else {
-      free_mem(cs);
-    }
-  }
-
-  if((s = hd_attr_str(sysfs_get_device_attr(sf_dev, "model")))) {
-    cs = canon_str(s, strlen(s));
-    ADD2LOG("    model = %s\n", cs);
-    if(*cs) {
-      hd->device.name = cs;
-    }
-    else {
-      free_mem(cs);
-    }
-
-    /* sata entries are somewhat strange... */
-    if(
-      hd->vendor.name &&
-      !strcmp(hd->vendor.name, "ATA") &&
-      hd->device.name
-    ) {
-      hd->bus.id = bus_ide;
-
-      if((cs = strchr(hd->device.name, ' '))) {
-        t = canon_str(cs, strlen(cs));
-        if(*t) {
-          *cs = 0;
-          free_mem(hd->vendor.name);
-          hd->vendor.name = hd->device.name;
-          hd->device.name = t;
-        }
-        else {
-          t = free_mem(t);
-        }
-      }
-
-      if(!strcmp(hd->vendor.name, "ATA")) {
-        hd->vendor.name = free_mem(hd->vendor.name);
-      }
-    }
-  }
-
-  if((s = hd_attr_str(sysfs_get_device_attr(sf_dev, "rev")))) {
-    cs = canon_str(s, strlen(s));
-    ADD2LOG("    rev = %s\n", cs);
-    if(*cs) {
-      hd->revision.name = cs;
-    }
-    else {
-      free_mem(cs);
-    }
-  }
-
-  if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "type"), &ul0, 0)) {
-    ADD2LOG("    type = %u\n", (unsigned) ul0);
-    if(ul0 == 6 /* scanner */) {
-      hd->sub_class.id = sc_sdev_scanner;
-    }
-    else if(ul0 == 3 /* processor */ && hd->vendor.name) {
-      if(
-        !strncmp(hd->vendor.name, "HP", sizeof "HP" - 1) ||
-        !strncmp(hd->vendor.name, "EPSON", sizeof "EPSON" - 1)
-      ) {
-        hd->sub_class.id = sc_sdev_scanner;
-      }
-    }
-
-    /*
-     * typically needed for usb card readers (unused slots)
-     */
-    if(
-      hd->base_class.id == bc_storage_device &&
-      hd->sub_class.id == sc_sdev_other
-    ) {
-      switch(ul0) {
-        case 0:
-          if(search_str_list(hd->drivers, "sd")) {
-            hd->sub_class.id = sc_sdev_disk;
-          }
-          break;
-
-        case 5:
-          if(search_str_list(hd->drivers, "sr")) {
-            hd->sub_class.id = sc_sdev_cdrom;
-          }
-          break;
-      }
-    }
-
-  }
-
-  /* s390: wwpn & fcp lun */
-  if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "wwpn"), &ul0, 0)) {
-    ADD2LOG("    wwpn = 0x%016"PRIx64"\n", ul0);
-    scsi->wwpn = ul0;
-
-    /* it's a bit of a hack, actually */
-    t = new_str(hd_sysfs_id(sf_dev->path));
-    if(t) {
-      if((s = strrchr(t, '/'))) *s = 0;
-      if((s = strrchr(t, '/'))) *s = 0;
-      if((s = strrchr(t, '/'))) {
-        scsi->controller_id = new_str(s + 1);
-      }
-    }
-    t = free_mem(t);
-  }
-
-  if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "fcp_lun"), &ul0, 0)) {
-    ADD2LOG("    fcp_lun = 0x%016"PRIx64"\n", ul0);
-    scsi->fcp_lun = ul0;
-  }
-
-  /* ppc: get rom id */
-  if((hd1 = hd_get_device_by_idx(hd_data, hd->attached_to)) && hd1->rom_id) {
-    str_printf(&hd->rom_id, 0, "%s/@%u", hd1->rom_id, (hd->slot & 0xf));
-  }
-
-  pr_str = NULL;
-
-  if(
-    hd_report_this(hd_data, hd) &&
-    hd->unix_dev_name &&
-    hd->sub_class.id == sc_sdev_cdrom &&
-    hd_data->in_vmware != 1            /* VMWare doesn't like it */
-  ) {
-    PROGRESS(5, 0, hd->unix_dev_name);
-    fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
-    if(fd >= 0) {
-
-      str_printf(&pr_str, 0, "%s cache", hd->unix_dev_name);
-      PROGRESS(5, 1, pr_str);
-
-      memset(scsi_cmd_buf, 0, sizeof scsi_cmd_buf);
-      memset(&hdr, 0, sizeof(hdr));
-
-      hdr.interface_id = 'S';
-      hdr.cmd_len = 6;
-      hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-      hdr.dxferp = scsi_cmd_buf + 8 + 6;
-      hdr.dxfer_len = 0xff;
-      hdr.cmdp = scsi_cmd_buf + 8;
-      hdr.cmdp[0] = 0x1a;
-      hdr.cmdp[2] = 0x08;
-      hdr.cmdp[4] = 0xff;
-
-      k = ioctl(fd, SG_IO, &hdr);
-
-      if(k) {
-        ADD2LOG("%s status(0x1a:8) 0x%x\n", hd->unix_dev_name, k);
-      }
-      else {
-        unsigned char *ptr = hdr.dxferp;
-
-        uc = ptr + 4 + ptr[3] + 2;
-        scsi->cache = uc[0];
-        ADD2LOG("  scsi cache: 0x%02x\n", uc[0]);
-    
-        if((scsi->cache & 4)) {
-          hd->prog_if.id = pif_cdr;
-        }
-      }
-
-      close(fd);
-    }
-  }
-
-
-  if(
-    hd_report_this(hd_data, hd) &&
-    hd->unix_dev_name &&
-    hd->sub_class.id == sc_sdev_disk &&
-    !hd_probe_feature(hd_data, pr_scsi_noserial)
-  ) {
-    PROGRESS(5, 0, hd->unix_dev_name);
-    fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
-    if(fd >= 0) {
-
-      str_printf(&pr_str, 0, "%s geo", hd->unix_dev_name);
-      PROGRESS(5, 1, pr_str);
-
-      if(hd_getdisksize(hd_data, hd->unix_dev_name, fd, &geo, &size) == 1) {
-        /* (low-level) unformatted disk */
-        hd->is.notready = 1;
-      }
-
-      if(geo) add_res_entry(&hd->res, geo);
-      if(size) add_res_entry(&hd->res, size);
-
-      str_printf(&pr_str, 0, "%s serial", hd->unix_dev_name);
-      PROGRESS(5, 2, pr_str);
-
-      memset(scsi_cmd_buf, 0, sizeof scsi_cmd_buf);
-      memset(&hdr, 0, sizeof(hdr));
-
-      hdr.interface_id = 'S';
-      hdr.cmd_len = 6;
-      hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-      hdr.dxferp = scsi_cmd_buf + 8 + 6;
-      hdr.dxfer_len = 0x24;
-      hdr.cmdp = scsi_cmd_buf + 8;
-      hdr.cmdp[0] = 0x12;
-      hdr.cmdp[1] = 0x01;
-      hdr.cmdp[2] = 0x80;
-      hdr.cmdp[4] = 0x24;
-      k = ioctl(fd, SG_IO, &hdr);
-
-      if(k) {
-        ADD2LOG("%s status(0x12) 0x%x\n", scsi->dev_name, k);
-      }
-      else {
-        unsigned char *ptr = hdr.dxferp;
-
-        ADD2LOG("  serial id len: %u\n", ptr[3]);
-
-        if((hd->serial = canon_str(ptr + 4, ptr[3]))) {
-          if(!*hd->serial) hd->serial = free_mem(hd->serial);
-        }
-      }
-
-      close(fd);
-    }
-  }
-
-  pr_str = free_mem(pr_str);
-
-
-  if(
-    hd->base_class.id == bc_storage_device &&
-    hd->sub_class.id == sc_sdev_scanner
-  ) {
-    hd->base_class.id = bc_scanner;
-  }
-
-  // ###### FIXME: usb-storage: disk vs. floppy?
-}
-
-
-void read_partitions(hd_data_t *hd_data)
-{
-  str_list_t *sl, *sl0, *pl0 = NULL;
-  char buf[256], *s1, *name, *base;
-  char *last_base = new_str(" ");
-  char *last_name = new_str(" ");
-  int l, is_disk;
-
-  if(!(sl0 = read_file(PROC_PARTITIONS, 2, 0))) return;
-
-  if(hd_data->debug) {
-    ADD2LOG("----- "PROC_PARTITIONS" -----\n");
-    for(sl = sl0; sl; sl = sl->next) {
-      ADD2LOG("  %s", sl->str);
-    }
-    ADD2LOG("----- "PROC_PARTITIONS" end -----\n");
-  }
-
-  for(sl = sl0; sl; sl = sl->next) {
-    *buf = 0;
-    if(sscanf(sl->str, "%*s %*s %*s %255s", buf) > 0) {
-      if(*buf) add_str_list(&pl0, buf);
-    }
-  }
-
-  free_str_list(sl0);
-
-  for(is_disk = 1, sl = pl0; sl; sl = sl->next) {
-    base = sl->str;
-    l = strlen(base);
-    if(!l) continue;
-
-    s1 = base + l - 1;
-    while(isdigit(*s1) && s1 > base) s1--;
-    if(s1 == base) continue;
-
-    name = new_str(base);
-    s1[1] = 0;
-
-    if(!strcmp(last_base, base)) {
-      if(!strcmp(last_name, base)) is_disk = 0;
-    }
-    else {
-      is_disk = strncmp(last_name, base, strlen(last_name)) ? 1 : 0;
-    }
-
-    if(!search_str_list(hd_data->cdroms, name)) {
-      if(
-        strncmp(name, "loop", sizeof "loop" - 1) &&
-        (
-          hd_data->flags.list_md ||
-          (
-            strncmp(name, "md", sizeof "md" - 1) &&
-            strncmp(name, "dm-", sizeof "dm-" - 1)
-          )
-        )
-      ) {
-        add_str_list(is_disk ? &hd_data->disks : &hd_data->partitions, name);
-      }
-    }
-    free_mem(last_base);
-    free_mem(last_name);
-
-    last_base = new_str(base);
-    last_name = name; name = NULL;
-  }
-
-  free_mem(last_base);
-  free_mem(last_name);
-
-  free_str_list(pl0);
-
-  if(hd_data->debug) {
-    ADD2LOG("disks:\n");
-    for(sl = hd_data->disks; sl; sl = sl->next) ADD2LOG("  %s\n", sl->str);
-    ADD2LOG("partitions:\n");
-    for(sl = hd_data->partitions; sl; sl = sl->next) ADD2LOG("  %s\n", sl->str);
-  }
-}
-
-
-/*
- * Read iso9660/el torito info, if there is a CD inserted.
- * Returns NULL if nothing was found
- */
-cdrom_info_t *hd_read_cdrom_info(hd_data_t *hd_data, hd_t *hd)
-{
-  int fd;
-  char *s;
-  cdrom_info_t *ci;
-  struct iso_primary_descriptor iso_desc;
-  unsigned char sector[0x800];
-  unsigned et;
-  unsigned u0, u1, u2;
-
-#ifdef LIBHD_MEMCHECK
-  {
-    if(libhd_log)
-      fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_read_cdrom_info, hd_data), hd_data);
-  }
-#endif
-
-  /* free existing entry */
-  if(hd->detail && hd->detail->type != hd_detail_cdrom) {
-    hd->detail = free_hd_detail(hd->detail);
-  }
-
-  if(!hd->detail) {
-    hd->detail = new_mem(sizeof *hd->detail);
-    hd->detail->type = hd_detail_cdrom;
-    hd->detail->cdrom.data = new_mem(sizeof *hd->detail->cdrom.data);
-  }
-
-  ci = hd->detail->cdrom.data;
-
-  hd->is.notready = 0;
-
-  if((fd = open(hd->unix_dev_name, O_RDONLY)) < 0) {
-    /* we are here if there is no CD in the drive */
-    hd->is.notready = 1;
-    return NULL;
-  }
-
-  ci->iso9660.ok = 0;
-  if(
-    lseek(fd, 0x8000, SEEK_SET) >= 0 &&
-    read(fd, &iso_desc, sizeof iso_desc) == sizeof iso_desc
-  ) {
-    ci->cdrom = 1;
-    if(!memcmp(iso_desc.id, "CD001", 5)) {
-      ci->iso9660.ok = 1;
-      /* now, fill in the fields */
-      s = canon_str(iso_desc.volume_id, sizeof iso_desc.volume_id);
-      if(!*s) s = free_mem(s);
-      ci->iso9660.volume = s;
-
-      s = canon_str(iso_desc.publisher_id, sizeof iso_desc.publisher_id);
-      if(!*s) s = free_mem(s);
-      ci->iso9660.publisher = s;
-
-      s = canon_str(iso_desc.preparer_id, sizeof iso_desc.preparer_id);
-      if(!*s) s = free_mem(s);
-      ci->iso9660.preparer = s;
-
-      s = canon_str(iso_desc.application_id, sizeof iso_desc.application_id);
-      if(!*s) s = free_mem(s);
-      ci->iso9660.application = s;
-
-      s = canon_str(iso_desc.creation_date, sizeof iso_desc.creation_date);
-      if(!*s) s = free_mem(s);
-      ci->iso9660.creation_date = s;
-    }
-  }
-
-  if(
-    ci->iso9660.ok &&
-    lseek(fd, 0x8800, SEEK_SET) >= 0 &&
-    read(fd, &sector, sizeof sector) == sizeof sector
-  ) {
-    if(
-      sector[0] == 0 && sector[6] == 1 &&
-      !memcmp(sector + 1, "CD001", 5) &&
-      !memcmp(sector + 7, "EL TORITO SPECIFICATION", 23)
-    ) {
-      et = sector[0x47] + (sector[0x48] << 8) + (sector[0x49] << 16) + (sector[0x4a] << 24);
-      ADD2LOG("  %s: el torito boot catalog at 0x%04x\n", ci->name, et);
-      if(
-        lseek(fd, et * 0x800, SEEK_SET) >= 0 &&
-        read(fd, &sector, sizeof sector) == sizeof sector &&
-        sector[0] == 1
-      ) {
-        ci->el_torito.ok = 1;
-        ci->el_torito.catalog = et;
-        ci->el_torito.platform = sector[1];
-        s = canon_str(sector + 4, 24);
-        if(!*s) s = free_mem(s);
-        ci->el_torito.id_string = s;
-        ci->el_torito.bootable = sector[0x20] == 0x88 ? 1 : 0;
-        ci->el_torito.media_type = sector[0x21];
-        ADD2LOG("    media type: %u\n",  ci->el_torito.media_type);
-        ci->el_torito.load_address = (sector[0x22] + (sector[0x23] << 8)) << 4;
-        ADD2LOG("    load address: 0x%04x\n",  ci->el_torito.load_address);
-#if 0
-        if(ci->el_torito.platform == 0 && ci->el_torito.load_address == 0)
-          ci->el_torito.load_address = 0x7c00;
-#endif
-        ci->el_torito.load_count = sector[0x26] + (sector[0x27] << 8);
-        ci->el_torito.start = sector[0x28] + (sector[0x29] << 8) + (sector[0x2a] << 16) + (sector[0x2b] << 24);
-        if(ci->el_torito.media_type >= 1 && ci->el_torito.media_type <= 3) {
-          ci->el_torito.geo.c = 80;
-          ci->el_torito.geo.h = 2;
-        }
-        switch(ci->el_torito.media_type) {
-          case 1:
-            ci->el_torito.geo.s = 15;
-            break;
-          case 2:
-            ci->el_torito.geo.s = 18;
-            break;
-          case 3:
-            ci->el_torito.geo.s = 36;
-            break;
-        }
-        if(
-          lseek(fd, ci->el_torito.start * 0x800, SEEK_SET) >= 0 &&
-          read(fd, &sector, sizeof sector) == sizeof sector
-        ) {
-          if(ci->el_torito.media_type == 4) {
-            /* ##### we should go on and read the 1st partition sector in this case... */
-            ci->el_torito.geo.h = (unsigned) sector[0x1be + 5] + 1;
-            ci->el_torito.geo.s = sector[0x1be + 6] & 0x3f;
-            ci->el_torito.geo.c = sector[0x1be + 7] + (((unsigned) sector[0x1be + 6] >> 6) << 8);
-          }
-          if(
-            sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa &&
-            sector[0x0b] == 0 && sector[0x0c] == 2 &&
-            sector[0x0e] == 1 && sector[0x0f] == 0
-          ) {
-            u0 = sector[0x13] + (sector[0x14] << 8);   /* partition size */
-            u1 = sector[0x18] + (sector[0x19] << 8);   /* sectors per track */
-            u2 = sector[0x1a] + (sector[0x1b] << 8);   /* heads */
-            u0 = u0 ? u0 : sector[0x20] + (sector[0x21] << 8) + (sector[0x22] << 16) + ((unsigned) sector[0x23] << 24);
-            if(sector[0x26] == 0x29) {
-              s = canon_str(sector + 0x2b, 11);
-              if(!*s) s = free_mem(s);
-              ci->el_torito.label = s;
-            }
-            if(!ci->el_torito.label) {
-              s = canon_str(sector + 3, 8);
-              if(!*s) s = free_mem(s);
-              ci->el_torito.label = s;
-            }
-            if(
-              (ci->el_torito.media_type == 0 || ci->el_torito.media_type > 3) &&
-              u0 && u1 && u2
-            ) {
-              ci->el_torito.geo.h = u2;
-              ci->el_torito.geo.s = u1;
-              ci->el_torito.geo.size = u0;
-              ci->el_torito.geo.c = ci->el_torito.geo.size / (u1 * u2);
-            }
-          }
-        }
-
-        ci->el_torito.geo.size = ci->el_torito.geo.s * ci->el_torito.geo.c * ci->el_torito.geo.h;
-      }
-    }
-  }
-
-  close(fd);
-
-  return ci;
-}
-
-
-/*
- * Read the list of CDROM devices known to the kernel. The info is taken
- * from /proc/sys/dev/cdrom/info.
- */
-void read_cdroms(hd_data_t *hd_data)
-{
-  char *s, *t, *v;
-  str_list_t *sl, *sl0;
-  cdrom_info_t *ci;
-  int i, line, entries = 0;
-  unsigned val;
-
-  if(!(sl0 = read_file(PROC_CDROM_INFO, 2, 0))) return;
-
-  if((hd_data->debug & HD_DEB_CDROM)) {
-    ADD2LOG("----- "PROC_CDROM_INFO" -----\n");
-    for(sl = sl0; sl; sl = sl->next) {
-      if(*sl->str != '\n') ADD2LOG("%s", sl->str);
-    }
-    ADD2LOG("----- "PROC_CDROM_INFO" end -----\n");
-  }
-
-  for(sl = sl0; sl; sl = sl->next) {
-    if(
-      (line = 0, strstr(sl->str, "drive name:") == sl->str) ||
-      (line++, strstr(sl->str, "drive speed:") == sl->str) ||
-      (line++, strstr(sl->str, "Can write CD-R:") == sl->str) ||
-      (line++, strstr(sl->str, "Can write CD-RW:") == sl->str) ||
-      (line++, strstr(sl->str, "Can read DVD:") == sl->str) ||
-      (line++, strstr(sl->str, "Can write DVD-R:") == sl->str) ||
-      (line++, strstr(sl->str, "Can write DVD-RAM:") == sl->str)
-    ) {
-      s = strchr(sl->str, ':') + 1;
-      i = 0;
-      while((t = strsep(&s, " \t\n"))) {
-        if(!*t) continue;
-        i++;
-        switch(line) {
-          case 0:      /* drive name */
-            ci = new_cdrom_entry(&hd_data->cdrom);
-            entries++;
-            add_str_list(&hd_data->cdroms, t);
-            ci->name = new_str(t);
-            break;
-
-          case 1:      /* drive speed */
-          case 2:      /* Can write CD-R */
-          case 3:      /* Can write CD-RW */
-          case 4:      /* Can read DVD */
-          case 5:      /* Can write DVD-R */
-          case 6:      /* Can write DVD-RAM */
-            ci = get_cdrom_entry(hd_data->cdrom, entries - i);
-            if(ci) {
-              val = strtoul(t, &v, 10);
-              if(!*v) {
-                switch(line) {
-                  case 1:
-                    ci->speed = val;
-                    break;
-                  case 2:
-                    ci->cdr = val;
-                    break;
-                  case 3:
-                    ci->cdrw = val;
-                    break;
-                  case 4:
-                    ci->dvd = val;
-                    break;
-                  case 5:
-                    ci->dvdr = val;
-                    break;
-                  case 6:
-                    ci->dvdram = val;
-                    break;
-                }
-              }
-            }
-            break;
-        }
-      }
-    }  
-  }
-
-  free_str_list(sl0);
-}
-
-
-/* add new entries at the _start_ of the list */
-cdrom_info_t *new_cdrom_entry(cdrom_info_t **ci)
-{
-  cdrom_info_t *new_ci = new_mem(sizeof *new_ci);
-
-  new_ci->next = *ci;
-  return *ci = new_ci;
-}
-
-
-/* return nth entry */
-cdrom_info_t *get_cdrom_entry(cdrom_info_t *ci, int n)
-{
-  if(n < 0) return NULL;
-
-  while(n--) {
-    if(!ci) return NULL;
-    ci = ci->next;
-  }
-
-  return ci;
-}
-
-
-/*
- * Add generic scsi devs.
- */
-void hd_scan_sysfs_scsi(hd_data_t *hd_data)
-{
-  if(!hd_probe_feature(hd_data, pr_scsi)) return;
-
-  hd_data->module = mod_scsi;
-
-  /* some clean-up */
-  remove_hd_entries(hd_data);
-
-  PROGRESS(1, 0, "scsi modules");
-
-  load_module(hd_data, "sg");
-
-  PROGRESS(2, 0, "scsi tape");
-
-  get_scsi_tape(hd_data);
-
-  PROGRESS(3, 0, "scsi generic");
-
-  get_generic_scsi_devs(hd_data);
-}
-
-
-void get_scsi_tape(hd_data_t *hd_data)
-{
-  char *s, *t;
-  unsigned u1, u2, u3;
-  uint64_t ul0;
-  hd_t *hd, *hd1;
-  hd_dev_num_t dev_num;
-
-  struct sysfs_class *sf_class;
-  struct sysfs_class_device *sf_cdev;
-  struct sysfs_device *sf_dev;
-  struct dlist *sf_cdev_list;
-
-  sf_class = sysfs_open_class("scsi_tape");
-
-  if(!sf_class) {
-    ADD2LOG("sysfs: no such class: scsi_tape\n");
-    return;
-  }
-
-  sf_cdev_list = sysfs_get_class_devices(sf_class);
-  if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
-    ADD2LOG(
-      "  scsi tape: name = %s, path = %s\n",
-      sf_cdev->name,
-      hd_sysfs_id(sf_cdev->path)
-    );
-
-    memset(&dev_num, 0, sizeof dev_num);
-
-    if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) {
-      if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
-        dev_num.type = 'c';
-        dev_num.major = u1;
-        dev_num.minor = u2;
-        dev_num.range = 1;
-      }
-      ADD2LOG("    dev = %u:%u\n", u1, u2);
-    }
-
-    if(hd_attr_uint(sysfs_get_classdev_attr(sf_cdev, "range"), &ul0, 0)) {
-      dev_num.range = ul0;
-      ADD2LOG("    range = %u\n", dev_num.range);
-    }
-
-    sf_dev = sysfs_get_classdev_device(sf_cdev);
-    if(sf_dev) {
-      s = hd_sysfs_id(sf_dev->path);
-      ADD2LOG(
-        "    scsi device: bus = %s, bus_id = %s driver = %s\n      path = %s\n",
-        sf_dev->bus,
-        sf_dev->bus_id,
-        sf_dev->driver_name,
-        s
-      );
-
-      for(hd = hd_data->hd; hd; hd = hd->next) {
-        if(
-          hd->module == hd_data->module &&
-          hd->sysfs_device_link &&
-          hd->base_class.id == bc_storage_device &&
-          hd->sub_class.id == sc_sdev_tape &&
-          s &&
-          !strcmp(hd->sysfs_device_link, s)
-        ) break;
-      }
-
-      if(!hd) {
-        hd = add_hd_entry(hd_data, __LINE__, 0);
-        hd->base_class.id = bc_storage_device;
-        hd->sub_class.id = sc_sdev_tape;
-
-        hd->bus.id = bus_scsi;
-
-        hd->sysfs_device_link = new_str(s);
-
-        hd->sysfs_bus_id = new_str(sf_dev->bus_id);
-
-        /* parent has longest matching sysfs id */
-        u2 = strlen(s);
-        for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
-          if(hd1->sysfs_id) {
-            u1 = strlen(hd1->sysfs_id);
-            if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
-              u3 = u1;
-              hd->attached_to = hd1->idx;
-            }
-          }
-        }
-
-        /* find longest matching sysfs id we have a driver for */
-        s = new_str(s);
-        t = strrchr(s, '/');
-        if(t) *t = 0;
-        t = hd_sysfs_find_driver(hd_data, s, 0);
-        if(t) {
-          add_str_list(&hd->drivers, t);
-        }
-        s = free_mem(s);
-
-        if(
-          sf_dev->driver_name &&
-          *sf_dev->driver_name &&
-          strcmp(sf_dev->driver_name, "unknown")
-        ) {
-          add_str_list(&hd->drivers, sf_dev->driver_name);
-        }
-
-        add_scsi_sysfs_info(hd_data, hd, sf_dev);
-      }
-
-      s = hd_sysfs_name2_dev(sf_cdev->name);
-
-      if(!hd->unix_dev_name || strlen(s) + sizeof "/dev/" - 1 < strlen(hd->unix_dev_name)) {
-        str_printf(&hd->unix_dev_name, 0, "/dev/%s", s);
-        hd->unix_dev_num = dev_num;
-        free_mem(hd->sysfs_id);
-        hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
-      }
-    }
-  }
-
-  sysfs_close_class(sf_class);
-}
-
-
-void get_generic_scsi_devs(hd_data_t *hd_data)
-{
-  char *s, *t;
-  unsigned u1, u2, u3;
-  uint64_t ul0;
-  hd_t *hd, *hd1;
-  hd_dev_num_t dev_num;
-
-  struct sysfs_class *sf_class;
-  struct sysfs_class_device *sf_cdev;
-  struct sysfs_device *sf_dev;
-  struct dlist *sf_cdev_list;
-
-  sf_class = sysfs_open_class("scsi_generic");
-
-  if(!sf_class) {
-    ADD2LOG("sysfs: no such class: scsi_generic\n");
-    return;
-  }
-
-  sf_cdev_list = sysfs_get_class_devices(sf_class);
-  if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
-    ADD2LOG(
-      "  scsi: name = %s, path = %s\n",
-      sf_cdev->name,
-      hd_sysfs_id(sf_cdev->path)
-    );
-
-    memset(&dev_num, 0, sizeof dev_num);
-
-    if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) {
-      if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
-        dev_num.type = 'c';
-        dev_num.major = u1;
-        dev_num.minor = u2;
-        dev_num.range = 1;
-      }
-      ADD2LOG("    dev = %u:%u\n", u1, u2);
-    }
-
-    if(hd_attr_uint(sysfs_get_classdev_attr(sf_cdev, "range"), &ul0, 0)) {
-      dev_num.range = ul0;
-      ADD2LOG("    range = %u\n", dev_num.range);
-    }
-
-    sf_dev = sysfs_get_classdev_device(sf_cdev);
-    if(sf_dev) {
-      s = hd_sysfs_id(sf_dev->path);
-
-      ADD2LOG(
-        "    scsi device: bus = %s, bus_id = %s driver = %s\n      path = %s\n",
-        sf_dev->bus,
-        sf_dev->bus_id,
-        sf_dev->driver_name,
-        s
-      );
-    }
-
-    for(hd = hd_data->hd; hd; hd = hd->next) {
-      if(
-        hd->sysfs_device_link &&
-        hd->bus.id == bus_scsi &&
-        s &&
-        !strcmp(hd->sysfs_device_link, s)
-      ) break;
-    }
-
-    if(hd) {
-      if(!hd->unix_dev_name2) {
-        str_printf(&hd->unix_dev_name2, 0, "/dev/%s", hd_sysfs_name2_dev(sf_cdev->name));
-        hd->unix_dev_num2 = dev_num;
-      }
-    }
-
-    hd = NULL;
-
-    if(
-      sf_dev &&
-      sf_dev->driver_name &&
-      !strcmp(sf_dev->driver_name, "unknown")
-    ) {
-      hd = add_hd_entry(hd_data, __LINE__, 0);
-      hd->base_class.id = bc_storage_device;
-      hd->sub_class.id = sc_sdev_other;
-
-      str_printf(&hd->unix_dev_name, 0, "/dev/%s", hd_sysfs_name2_dev(sf_cdev->name));
-
-      hd->bus.id = bus_scsi;
-
-      hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
-
-      hd->unix_dev_num = dev_num;
-
-      if(sf_dev) hd->sysfs_bus_id = new_str(sf_dev->bus_id);
-
-      if(sf_dev && (s = hd_sysfs_id(sf_dev->path))) {
-
-        /* parent has longest matching sysfs id */
-        u2 = strlen(s);
-        for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
-          if(hd1->sysfs_id) {
-            u1 = strlen(hd1->sysfs_id);
-            if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
-              u3 = u1;
-              hd->attached_to = hd1->idx;
-            }
-          }
-        }
-
-        /* find longest matching sysfs id we have a driver for */
-        s = new_str(s);
-        t = strrchr(s, '/');
-        if(t) *t = 0;
-        t = hd_sysfs_find_driver(hd_data, s, 0);
-        if(t) {
-          add_str_list(&hd->drivers, t);
-        }
-        s = free_mem(s);
-
-      }
-
-      add_scsi_sysfs_info(hd_data, hd, sf_dev);
-
-    }
-
-  }
-
-  sysfs_close_class(sf_class);
-}
-
-
-void add_disk_size(hd_data_t *hd_data, hd_t *hd)
-{
-  hd_res_t *geo, *size;
-  int fd;
-  char *pr_str;
-
-  pr_str = NULL;
-
-  if(
-    hd->unix_dev_name &&
-    hd->sub_class.id == sc_sdev_disk
-  ) {
-    PROGRESS(5, 0, hd->unix_dev_name);
-    fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
-    if(fd >= 0) {
-
-      str_printf(&pr_str, 0, "%s geo", hd->unix_dev_name);
-      PROGRESS(5, 1, pr_str);
-
-      if(hd_getdisksize(hd_data, hd->unix_dev_name, fd, &geo, &size) == 1) {
-        /* (low-level) unformatted disk */
-        hd->is.notready = 1;
-      }
-
-      if(geo) add_res_entry(&hd->res, geo);
-      if(size) add_res_entry(&hd->res, size);
-
-      close(fd);
-    }
-  }
-
-  pr_str = free_mem(pr_str);
-}
-
-