10 #include <sys/ioctl.h>
11 #include <linux/iso_fs.h>
20 * @defgroup BLOCKint Block devices
21 * @ingroup libhdDEVint
22 * @brief Block device functions
27 static void get_block_devs(hd_data_t *hd_data);
28 static void add_partitions(hd_data_t *hd_data, hd_t *hd, char *path);
29 static void add_cdrom_info(hd_data_t *hd_data, hd_t *hd);
30 static void add_other_sysfs_info(hd_data_t *hd_data, hd_t *hd);
31 static void add_ide_sysfs_info(hd_data_t *hd_data, hd_t *hd);
32 static void add_scsi_sysfs_info(hd_data_t *hd_data, hd_t *hd, char *sf_dev);
33 static void read_partitions(hd_data_t *hd_data);
34 static void read_cdroms(hd_data_t *hd_data);
35 static cdrom_info_t *new_cdrom_entry(cdrom_info_t **ci);
36 static cdrom_info_t *get_cdrom_entry(cdrom_info_t *ci, int n);
37 static void get_scsi_tape(hd_data_t *hd_data);
38 static void get_generic_scsi_devs(hd_data_t *hd_data);
39 static void add_disk_size(hd_data_t *hd_data, hd_t *hd);
42 void hd_scan_sysfs_block(hd_data_t *hd_data)
44 if(!hd_probe_feature(hd_data, pr_block)) return;
46 hd_data->module = mod_block;
49 remove_hd_entries(hd_data);
51 hd_data->disks = free_str_list(hd_data->disks);
52 hd_data->partitions = free_str_list(hd_data->partitions);
53 hd_data->cdroms = free_str_list(hd_data->cdroms);
55 if(hd_probe_feature(hd_data, pr_block_mods)) {
56 PROGRESS(1, 0, "block modules");
57 // load_module(hd_data, "ide-cd");
58 load_module(hd_data, "ide-cd_mod");
59 load_module(hd_data, "ide-disk");
60 load_module(hd_data, "sr_mod");
61 load_module(hd_data, "sd_mod");
62 #if !defined(__s390__) && !defined(__s390x__)
63 load_module(hd_data, "st");
67 PROGRESS(2, 0, "sysfs drivers");
69 hd_sysfs_driver_list(hd_data);
71 PROGRESS(3, 0, "cdrom");
75 PROGRESS(4, 0, "partition");
77 read_partitions(hd_data);
79 PROGRESS(5, 0, "get sysfs block dev data");
81 get_block_devs(hd_data);
84 ADD2LOG("oops: cdrom list not empty\n");
89 void get_block_devs(hd_data_t *hd_data)
97 str_list_t *sf_class, *sf_class_e;
98 char *sf_cdev = NULL, *sf_dev = NULL, *sf_dev_ide;
99 char *sf_drv_name, *sf_drv, *bus_id, *bus_name, *ide_bus_id;
100 str_list_t *sf_bus, *sf_bus_e;
103 hd_data->lsscsi = free_str_list(hd_data->lsscsi);
104 hd_data->lsscsi = read_file("|/usr/bin/lsscsi -t 2>/dev/null", 0, 0);
106 ADD2LOG("----- lsscsi -----\n");
107 for(sl = hd_data->lsscsi; sl; sl = sl->next) {
108 ADD2LOG(" %s", sl->str);
110 ADD2LOG("----- lsscsi end -----\n");
112 sf_bus = read_dir("/sys/bus/ide/devices", 'l');
115 for(sf_bus_e = sf_bus; sf_bus_e; sf_bus_e = sf_bus_e->next) {
116 sf_dev = new_str(hd_read_sysfs_link("/sys/bus/ide/devices", sf_bus_e->str));
118 " ide: bus_id = %s path = %s\n",
126 sf_block_dir = "/sys/subsystem/block";
127 sf_class = read_dir(sf_block_dir, 'l');
130 sf_block_dir = "/sys/class/block";
131 sf_class = read_dir(sf_block_dir, 'l');
135 sf_block_dir = "/sys/block";
136 sf_class = read_dir(sf_block_dir, 'd');
140 ADD2LOG("sysfs: no such class: block\n");
144 for(sf_class_e = sf_class; sf_class_e; sf_class_e = sf_class_e->next) {
145 str_printf(&sf_cdev, 0, "%s/%s", sf_block_dir, sf_class_e->str);
147 " block: name = %s, path = %s\n",
152 memset(&dev_num, 0, sizeof dev_num);
154 if((s = get_sysfs_attr_by_path(sf_cdev, "dev"))) {
155 if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
161 ADD2LOG(" dev = %u:%u\n", u1, u2);
164 if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "range"), &ul0, 0)) {
166 ADD2LOG(" range = %u\n", dev_num.range);
169 sf_dev = new_str(hd_read_sysfs_link(sf_cdev, "device"));
171 sf_drv = hd_read_sysfs_link(sf_dev, "driver");
173 /* maybe older kernel */
174 sf_drv = hd_read_sysfs_link(sf_cdev, "driver");
177 sf_drv_name = strrchr(sf_drv, '/');
178 if(sf_drv_name) sf_drv_name++;
181 sf_drv_name = new_str(sf_drv_name);
183 bus_id = sf_dev ? strrchr(sf_dev, '/') : NULL;
188 (s = hd_read_sysfs_link(sf_dev, "subsystem")) ||
189 (s = hd_read_sysfs_link(sf_dev, "bus"))
191 bus_name = strrchr(s, '/');
192 if(bus_name) bus_name++;
193 bus_name = new_str(bus_name);
198 " block device: bus = %s, bus_id = %s driver = %s\n path = %s\n",
208 #if defined(__s390x__) || defined(__s390__)
209 /* check if disk is DASD and has already been found by s390.c */
210 if(sf_drv_name && strstr(sf_drv_name,"dasd"))
214 //fprintf(stderr,"dn %s bi %s\n",sf_drv_name,bus_id);
215 for(hd=hd_data->hd;hd;hd=hd->next)
217 //fprintf(stderr,"bcid %d\n",hd->base_class.id);
218 if(hd->base_class.id == bc_storage_device
220 && hd->detail->ccw.type == hd_detail_ccw)
222 for(res=hd->res;res;res=res->next)
224 if(res->io.type==res_io)
226 sprintf(bid,"%01x.%01x.%04x",
227 hd->detail->ccw.data->lcss >> 8,
228 hd->detail->ccw.data->lcss & 0xff,
229 (unsigned short)res->io.base);
230 //fprintf(stderr,"bid %s\n",bid);
231 if (strcmp(bid,bus_id)==0) goto out;
242 if((sl = search_str_list(hd_data->disks, hd_sysfs_name2_dev(sf_class_e->str)))) {
243 hd = add_hd_entry(hd_data, __LINE__, 0);
244 hd->sub_class.id = sc_sdev_disk;
246 else if((sl = search_str_list(hd_data->cdroms, hd_sysfs_name2_dev(sf_class_e->str)))) {
247 hd = add_hd_entry(hd_data, __LINE__, 0);
248 hd->sub_class.id = sc_sdev_cdrom;
252 (!strcmp(bus_name, "scsi") || !strcmp(bus_name, "ide"))
254 hd = add_hd_entry(hd_data, __LINE__, 0);
255 hd->sub_class.id = sc_sdev_other;
259 str_printf(&hd->unix_dev_name, 0, "/dev/%s", hd_sysfs_name2_dev(sf_class_e->str));
261 hd->base_class.id = bc_storage_device;
263 hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev));
265 hd->sysfs_device_link = new_str(hd_sysfs_id(sf_dev));
267 hd->unix_dev_num = dev_num;
269 hd->bus.id = bus_none;
272 if(!strcmp(bus_name, "ide")) hd->bus.id = bus_ide;
273 else if(!strcmp(bus_name, "scsi")) hd->bus.id = bus_scsi;
275 hd->sysfs_bus_id = new_str(bus_id);
277 if((s = hd_sysfs_id(sf_dev))) {
279 /* parent has longest matching sysfs id */
281 for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
283 u1 = strlen(hd1->sysfs_id);
284 if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
286 hd->attached_to = hd1->idx;
291 /* find longest matching sysfs id we have a driver for */
295 t = hd_sysfs_find_driver(hd_data, s, 0);
297 add_str_list(&hd->drivers, t);
301 /* look for ide-scsi handled devices */
302 if(hd->bus.id == bus_scsi) {
303 for(sf_bus_e = sf_bus; sf_bus_e; sf_bus_e = sf_bus_e->next) {
304 sf_dev_ide = new_str(hd_read_sysfs_link("/sys/bus/ide/devices", sf_bus_e->str));
305 ide_bus_id = sf_dev_ide ? strrchr(sf_dev_ide, '/') : NULL;
306 if(ide_bus_id) ide_bus_id++;
309 strcmp(sf_dev, sf_dev_ide) &&
310 !strncmp(sf_dev, sf_dev_ide, strlen(sf_dev_ide)) &&
311 sscanf(ide_bus_id, "%u.%u", &u1, &u2) == 2
313 str_printf(&hd->unix_dev_name2, 0, "/dev/hd%c", 'a' + (u1 << 1) + u2);
316 sf_dev_ide = free_mem(sf_dev_ide);
322 * set hd->drivers before calling any of add_xxx_sysfs_info()
325 add_str_list(&hd->drivers, sf_drv_name);
328 if(hd->bus.id == bus_ide) {
329 add_ide_sysfs_info(hd_data, hd);
331 else if(hd->bus.id == bus_scsi) {
332 add_scsi_sysfs_info(hd_data, hd, sf_dev);
335 add_other_sysfs_info(hd_data, hd);
338 if(hd->sub_class.id == sc_sdev_cdrom) {
339 add_cdrom_info(hd_data, hd);
343 hd->sub_class.id == sc_sdev_disk &&
344 hd_probe_feature(hd_data, pr_block_part)
346 add_partitions(hd_data, hd, sf_cdev);
350 sf_drv_name = free_mem(sf_drv_name);
351 bus_name = free_mem(bus_name);
352 sf_dev = free_mem(sf_dev);
355 sf_cdev = free_mem(sf_cdev);
356 sf_class = free_str_list(sf_class);
357 sf_bus = free_str_list(sf_bus);
362 * Find driver for sysfs_id.
364 * Return driver for id (exact = 1) or longest matching id (exact = 0).
366 char *hd_sysfs_find_driver(hd_data_t *hd_data, char *sysfs_id, int exact)
372 if(!sysfs_id || !*sysfs_id) return NULL;
377 for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
378 if(sf->device && !strcmp(sysfs_id, sf->device)) {
385 u2 = strlen(sysfs_id);
387 for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
388 if(!sf->device) continue;
389 u1 = strlen(sf->device);
390 if(u1 > u3 && u1 <= u2 && !strncmp(sysfs_id, sf->device, u1)) {
401 void add_partitions(hd_data_t *hd_data, hd_t *hd, char *path)
408 s = hd->unix_dev_name + sizeof "/dev/" - 1;
410 for(sl = hd_data->partitions; sl; sl = sl->next) {
411 if(!strncmp(sl->str, s, len)) {
412 hd1 = add_hd_entry(hd_data, __LINE__, 0);
413 hd1->base_class.id = bc_partition;
414 str_printf(&hd1->unix_dev_name, 0, "/dev/%s", sl->str);
415 hd1->attached_to = hd->idx;
417 str_printf(&hd1->sysfs_id, 0, "%s/%s", hd->sysfs_id, hd_sysfs_dev2_name(sl->str));
423 void add_cdrom_info(hd_data_t *hd_data, hd_t *hd)
425 cdrom_info_t *ci, **prev;
427 hd->detail = free_hd_detail(hd->detail);
428 hd->detail = new_mem(sizeof *hd->detail);
429 hd->detail->type = hd_detail_cdrom;
431 for(ci = *(prev = &hd_data->cdrom); ci; ci = *(prev = &ci->next)) {
432 if(!strcmp(hd->unix_dev_name + sizeof "/dev/" - 1, ci->name)) {
433 hd->detail->cdrom.data = ci;
435 hd->detail->cdrom.data->next = NULL;
440 if((ci = hd->detail->cdrom.data)) {
441 /* update prog_if: cdr, cdrw, ... */
443 /* ###### FIXME: dosn't work anyway: ide-scsi doesn't support sysfs */
444 hd->bus.id == bus_scsi &&
445 !search_str_list(hd->drivers, "ide-scsi") /* could be ide, though */
448 if(ci->dvd && (ci->cdrw || ci->dvdr || ci->dvdram)) {
449 ci->dvd = ci->dvdr = ci->dvdram = 0;
451 ci->dvdr = ci->dvdram = 0;
452 ci->cdr = ci->cdrw = 0;
453 if(hd->prog_if.id == pif_cdr) ci->cdr = 1;
459 hd->prog_if.id = pif_dvd;
463 hd->prog_if.id = pif_cdr;
467 hd->prog_if.id = pif_cdrw;
471 hd->prog_if.id = pif_dvdr;
475 hd->prog_if.id = pif_dvdram;
480 hd_probe_feature(hd_data, pr_block_cdrom) &&
481 hd_report_this(hd_data, hd)
483 hd_read_cdrom_info(hd_data, hd);
488 void add_other_sysfs_info(hd_data_t *hd_data, hd_t *hd)
495 sscanf(hd->sysfs_id, "/block/cciss!c%ud%u", &u0, &u1) == 2
497 hd->slot = (u0 << 8) + u1;
498 str_printf(&hd->device.name, 0, "CCISS disk %u/%u", u0, u1);
501 sscanf(hd->sysfs_id, "/block/ida!c%ud%u", &u0, &u1) == 2
503 hd->slot = (u0 << 8) + u1;
504 str_printf(&hd->device.name, 0, "SMART Array %u/%u", u0, u1);
507 sscanf(hd->sysfs_id, "/block/rd!c%ud%u", &u0, &u1) == 2
509 hd->slot = (u0 << 8) + u1;
510 str_printf(&hd->device.name, 0, "DAC960 RAID Array %u/%u", u0, u1);
513 sscanf(hd->sysfs_id, "/block/i2o!hd%c", &c) == 1 &&
517 str_printf(&hd->device.name, 0, "I2O disk %u", hd->slot);
520 sscanf(hd->sysfs_id, "/block/dasd%c", &c) == 1 &&
524 hd->device.name = new_str("S390 Disk");
528 add_disk_size(hd_data, hd);
532 void add_ide_sysfs_info(hd_data_t *hd_data, hd_t *hd)
534 char *fname = NULL, buf[256], *dev_name, *s;
535 unsigned u0, u1, u2, size = 0;
536 str_list_t *sl, *sl0;
540 if(!hd_report_this(hd_data, hd)) return;
542 if(hd->sysfs_bus_id && sscanf(hd->sysfs_bus_id, "%u.%u", &u0, &u1) == 2) {
543 /* host.master/slave */
544 hd->slot = (u0 << 1) + u1;
549 strlen(hd->unix_dev_name) > 5
551 dev_name = hd->unix_dev_name + 5;
553 str_printf(&fname, 0, PROC_IDE "/%s/media", dev_name);
554 if((sl = read_file(fname, 0, 1))) {
556 if(strstr(sl->str, "floppy"))
557 hd->sub_class.id = sc_sdev_floppy;
558 else if(strstr(sl->str, "cdrom"))
559 hd->sub_class.id = sc_sdev_cdrom;
560 else if(strstr(sl->str, "tape"))
561 hd->sub_class.id = sc_sdev_tape;
566 str_printf(&fname, 0, PROC_IDE "/%s/model", dev_name);
567 if((sl = read_file(fname, 0, 1))) {
568 hd->vendor.name = canon_str(sl->str, strlen(sl->str));
569 if((s = strchr(hd->vendor.name, ' '))) {
570 hd->device.name = canon_str(s, strlen(s));
571 if(*hd->device.name) {
575 hd->device.name = free_mem(hd->device.name);
578 if(!hd->device.name) {
579 hd->device.name = hd->vendor.name;
580 hd->vendor.name = NULL;
586 str_printf(&fname, 0, PROC_IDE "/%s/driver", dev_name);
587 if((sl = read_file(fname, 0, 1))) {
588 if((s = strchr(sl->str, ' '))) *s = 0;
589 s = canon_str(sl->str, strlen(sl->str));
590 if(!search_str_list(hd->drivers, s)) add_str_list(&hd->drivers, s);
595 str_printf(&fname, 0, PROC_IDE "/%s/capacity", dev_name);
596 if((sl = read_file(fname, 0, 1))) {
597 if(sscanf(sl->str, "%u", &u0) == 1 && u0 != 0x7fffffff) {
598 res = add_res_entry(&hd->res, new_mem(sizeof *res));
599 res->size.type = res_size;
600 res->size.unit = size_unit_sectors;
601 res->size.val1 = size = u0;
602 res->size.val2 = 512; // ####### FIXME: sector size?
607 str_printf(&fname, 0, PROC_IDE "/%s/geometry", dev_name);
608 if((sl0 = read_file(fname, 0, 2))) {
609 for(sl = sl0; sl; sl = sl->next) {
610 if(sscanf(sl->str, " physical %u / %u / %u", &u0, &u1, &u2) == 3) {
612 if(size && u1 && u2) {
613 u0 = size / (u1 * u2);
615 res = add_res_entry(&hd->res, new_mem(sizeof *res));
616 res->disk_geo.type = res_disk_geo;
617 res->disk_geo.cyls = u0;
618 res->disk_geo.heads = u1;
619 res->disk_geo.sectors = u2;
620 res->disk_geo.geotype = geo_physical;
625 if(sscanf(sl->str, " logical %u / %u / %u", &u0, &u1, &u2) == 3) {
626 if(size && u1 && u2) {
627 u0 = size / (u1 * u2);
629 res = add_res_entry(&hd->res, new_mem(sizeof *res));
630 res->disk_geo.type = res_disk_geo;
631 res->disk_geo.cyls = u0;
632 res->disk_geo.heads = u1;
633 res->disk_geo.sectors = u2;
634 res->disk_geo.geotype = geo_logical;
640 str_printf(&fname, 0, PROC_IDE "/%s/cache", dev_name);
641 if((sl = read_file(fname, 0, 1))) {
642 if(sscanf(sl->str, "%u", &u0) == 1 && u0) {
643 res = add_res_entry(&hd->res, new_mem(sizeof *res));
644 res->cache.type = res_cache;
645 res->cache.size = u0;
650 str_printf(&fname, 0, PROC_IDE "/%s/identify", dev_name);
651 if((f = fopen(fname, "r"))) {
653 memset(buf, 0, sizeof buf);
654 while(u1 < sizeof buf - 1 && fscanf(f, "%x", &u0) == 1) {
655 buf[u1++] = u0 >> 8; buf[u1++] = u0;
659 /* ok, we now have the ATA/ATAPI ident block */
661 if(buf[0x14] || buf[0x15]) { /* has serial id */
662 hd->serial = canon_str(buf + 0x14, 20);
664 if(buf[0x2e] || buf[0x2f]) { /* has revision id */
665 hd->revision.name = canon_str(buf + 0x2e, 8);
672 if(!size) add_disk_size(hd_data, hd);
677 * assumes hd->drivers aleady includes scsi device drivers (like 'sd')
679 void add_scsi_sysfs_info(hd_data_t *hd_data, hd_t *hd, char *sf_dev)
682 char *s, *t, *cs, *pr_str;
683 unsigned u0, u1, u2, u3;
685 unsigned char scsi_cmd_buf[0x300];
686 struct sg_io_hdr hdr;
689 hd_res_t *geo, *size;
695 if(!hd_report_this(hd_data, hd)) return;
697 hd->detail = new_mem(sizeof *hd->detail);
698 hd->detail->type = hd_detail_scsi;
699 hd->detail->scsi.data = scsi = new_mem(sizeof *scsi);
701 if(hd->sysfs_bus_id && sscanf(hd->sysfs_bus_id, "%u:%u:%u:%u", &u0, &u1, &u2, &u3) == 4) {
702 /* host:channel:id:lun */
703 hd->slot = (u0 << 8) + (u1 << 4) + u2;
707 if((s = get_sysfs_attr_by_path(sf_dev, "vendor"))) {
708 cs = canon_str(s, strlen(s));
709 ADD2LOG(" vendor = %s\n", cs);
711 hd->vendor.name = cs;
718 if((s = get_sysfs_attr_by_path(sf_dev, "model"))) {
719 cs = canon_str(s, strlen(s));
720 ADD2LOG(" model = %s\n", cs);
722 hd->device.name = cs;
728 /* sata entries are somewhat strange... */
731 !strcmp(hd->vendor.name, "ATA") &&
734 hd->bus.id = bus_ide;
736 if((cs = strchr(hd->device.name, ' '))) {
737 t = canon_str(cs, strlen(cs));
740 free_mem(hd->vendor.name);
741 hd->vendor.name = hd->device.name;
749 if(!strcmp(hd->vendor.name, "ATA")) {
750 hd->vendor.name = free_mem(hd->vendor.name);
755 if((s = get_sysfs_attr_by_path(sf_dev, "rev"))) {
756 cs = canon_str(s, strlen(s));
757 ADD2LOG(" rev = %s\n", cs);
759 hd->revision.name = cs;
766 if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "type"), &ul0, 0)) {
767 ADD2LOG(" type = %u\n", (unsigned) ul0);
768 if(ul0 == 6 /* scanner */) {
769 hd->sub_class.id = sc_sdev_scanner;
771 else if(ul0 == 3 /* processor */ && hd->vendor.name) {
773 !strncmp(hd->vendor.name, "HP", sizeof "HP" - 1) ||
774 !strncmp(hd->vendor.name, "EPSON", sizeof "EPSON" - 1)
776 hd->sub_class.id = sc_sdev_scanner;
781 * typically needed for usb card readers (unused slots)
784 hd->base_class.id == bc_storage_device &&
785 hd->sub_class.id == sc_sdev_other
789 if(search_str_list(hd->drivers, "sd")) {
790 hd->sub_class.id = sc_sdev_disk;
795 if(search_str_list(hd->drivers, "sr")) {
796 hd->sub_class.id = sc_sdev_cdrom;
803 res = new_mem(sizeof *res);
804 res->any.type = res_fc;
806 if(hd->sysfs_bus_id) {
807 for(sl = hd_data->lsscsi; sl; sl = sl->next) {
809 sscanf(sl->str, "[%15[^]]] %*s fc:%"SCNx64" , %x ", buf, &ul0, &u0) == 3 &&
810 !strcmp(hd->sysfs_bus_id, buf)
812 ADD2LOG(" lsscsi: wwpn = 0x%"PRIx64", port_id = 0x%x\n", ul0, u0);
815 res->fc.port_id = u0;
816 res->fc.port_id_ok = 1;
821 /* s390: wwpn & fcp lun */
822 if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "wwpn"), &ul0, 0)) {
823 ADD2LOG(" wwpn = 0x%016"PRIx64"\n", ul0);
829 /* it's a bit of a hack, actually */
830 t = new_str(hd_sysfs_id(sf_dev));
832 if((s = strrchr(t, '/'))) *s = 0;
833 if((s = strrchr(t, '/'))) *s = 0;
834 if((s = strrchr(t, '/'))) *s = 0;
835 if((s = strrchr(t, '/'))) *s = 0;
836 if((s = strrchr(t, '/'))) {
837 scsi->controller_id = new_str(s + 1);
838 res->fc.controller_id = new_str(s + 1);
844 if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "fcp_lun"), &ul0, 0)) {
845 ADD2LOG(" fcp_lun = 0x%016"PRIx64"\n", ul0);
846 res->fc.fcp_lun = ul0;
847 res->fc.fcp_lun_ok = 1;
849 scsi->fcp_lun_ok = 1;
852 if(res->fc.wwpn_ok || res->fc.port_id_ok || res->fc.fcp_lun_ok || res->fc.controller_id) {
853 add_res_entry(&hd->res, res);
859 /* ppc: get rom id */
860 if((hd1 = hd_get_device_by_idx(hd_data, hd->attached_to)) && hd1->rom_id) {
861 str_printf(&hd->rom_id, 0, "%s/@%u", hd1->rom_id, (hd->slot & 0xf));
867 hd_report_this(hd_data, hd) &&
869 hd->sub_class.id == sc_sdev_cdrom &&
870 !hd_data->flags.vmware /* VMWare doesn't like it */
872 PROGRESS(5, 0, hd->unix_dev_name);
873 fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
876 str_printf(&pr_str, 0, "%s cache", hd->unix_dev_name);
877 PROGRESS(5, 1, pr_str);
879 memset(scsi_cmd_buf, 0, sizeof scsi_cmd_buf);
880 memset(&hdr, 0, sizeof(hdr));
882 hdr.interface_id = 'S';
884 hdr.dxfer_direction = SG_DXFER_FROM_DEV;
885 hdr.dxferp = scsi_cmd_buf + 8 + 6;
886 hdr.dxfer_len = 0xff;
887 hdr.cmdp = scsi_cmd_buf + 8;
892 k = ioctl(fd, SG_IO, &hdr);
895 ADD2LOG("%s status(0x1a:8) 0x%x\n", hd->unix_dev_name, k);
898 unsigned char *ptr = hdr.dxferp;
900 uc = ptr + 4 + ptr[3] + 2;
902 ADD2LOG(" scsi cache: 0x%02x\n", uc[0]);
904 if((scsi->cache & 4)) {
905 hd->prog_if.id = pif_cdr;
915 hd_report_this(hd_data, hd) &&
917 hd->sub_class.id == sc_sdev_disk &&
918 !hd_probe_feature(hd_data, pr_scsi_noserial)
920 PROGRESS(5, 0, hd->unix_dev_name);
921 fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
924 str_printf(&pr_str, 0, "%s geo", hd->unix_dev_name);
925 PROGRESS(5, 1, pr_str);
927 if(hd_getdisksize(hd_data, hd->unix_dev_name, fd, &geo, &size) == 1) {
928 /* (low-level) unformatted disk */
932 if(geo) add_res_entry(&hd->res, geo);
933 if(size) add_res_entry(&hd->res, size);
935 str_printf(&pr_str, 0, "%s serial", hd->unix_dev_name);
936 PROGRESS(5, 2, pr_str);
938 memset(scsi_cmd_buf, 0, sizeof scsi_cmd_buf);
939 memset(&hdr, 0, sizeof(hdr));
941 hdr.interface_id = 'S';
943 hdr.dxfer_direction = SG_DXFER_FROM_DEV;
944 hdr.dxferp = scsi_cmd_buf + 8 + 6;
945 hdr.dxfer_len = 0x24;
946 hdr.cmdp = scsi_cmd_buf + 8;
952 k = ioctl(fd, SG_IO, &hdr);
955 ADD2LOG("%s status(0x12) 0x%x\n", scsi->dev_name, k);
958 unsigned char *ptr = hdr.dxferp;
960 ADD2LOG(" serial id len: %u\n", ptr[3]);
962 if((hd->serial = canon_str(ptr + 4, ptr[3]))) {
963 if(!*hd->serial) hd->serial = free_mem(hd->serial);
971 pr_str = free_mem(pr_str);
975 hd->base_class.id == bc_storage_device &&
976 hd->sub_class.id == sc_sdev_scanner
978 hd->base_class.id = bc_scanner;
981 // ###### FIXME: usb-storage: disk vs. floppy?
986 void read_partitions(hd_data_t *hd_data)
988 str_list_t *sl, *sl0, *pl0 = NULL;
989 char buf[256], *s1, *name, *base;
990 char *last_base = new_str(" ");
991 char *last_name = new_str(" ");
994 if(!(sl0 = read_file(PROC_PARTITIONS, 2, 0))) return;
997 ADD2LOG("----- "PROC_PARTITIONS" -----\n");
998 for(sl = sl0; sl; sl = sl->next) {
999 ADD2LOG(" %s", sl->str);
1001 ADD2LOG("----- "PROC_PARTITIONS" end -----\n");
1004 for(sl = sl0; sl; sl = sl->next) {
1006 if(sscanf(sl->str, "%*s %*s %*s %255s", buf) > 0) {
1007 if(*buf) add_str_list(&pl0, buf);
1013 for(is_disk = 1, sl = pl0; sl; sl = sl->next) {
1019 while(isdigit(*s1) && s1 > base) s1--;
1020 if(s1 == base) continue;
1022 name = new_str(base);
1025 if(!strcmp(last_base, base)) {
1026 if(!strcmp(last_name, base)) is_disk = 0;
1029 is_disk = strncmp(last_name, base, strlen(last_name)) ? 1 : 0;
1032 if(!search_str_list(hd_data->cdroms, name)) {
1034 strncmp(name, "loop", sizeof "loop" - 1) &&
1036 hd_data->flags.list_md ||
1038 strncmp(name, "md", sizeof "md" - 1) &&
1039 strncmp(name, "dm-", sizeof "dm-" - 1)
1043 add_str_list(is_disk ? &hd_data->disks : &hd_data->partitions, name);
1046 free_mem(last_base);
1047 free_mem(last_name);
1049 last_base = new_str(base);
1050 last_name = name; name = NULL;
1053 free_mem(last_base);
1054 free_mem(last_name);
1058 if(hd_data->debug) {
1059 ADD2LOG("disks:\n");
1060 for(sl = hd_data->disks; sl; sl = sl->next) ADD2LOG(" %s\n", sl->str);
1061 ADD2LOG("partitions:\n");
1062 for(sl = hd_data->partitions; sl; sl = sl->next) ADD2LOG(" %s\n", sl->str);
1068 * Read iso9660/el torito info, if there is a CD inserted.
1069 * Returns NULL if nothing was found
1071 cdrom_info_t *hd_read_cdrom_info(hd_data_t *hd_data, hd_t *hd)
1076 struct iso_primary_descriptor iso_desc;
1077 unsigned char sector[0x800];
1079 unsigned u0, u1, u2;
1081 /* free existing entry */
1082 if(hd->detail && hd->detail->type != hd_detail_cdrom) {
1083 hd->detail = free_hd_detail(hd->detail);
1087 hd->detail = new_mem(sizeof *hd->detail);
1088 hd->detail->type = hd_detail_cdrom;
1089 hd->detail->cdrom.data = new_mem(sizeof *hd->detail->cdrom.data);
1092 ci = hd->detail->cdrom.data;
1094 hd->is.notready = 0;
1096 if((fd = open(hd->unix_dev_name, O_RDONLY)) < 0) {
1097 /* we are here if there is no CD in the drive */
1098 hd->is.notready = 1;
1104 lseek(fd, 0x8000, SEEK_SET) >= 0 &&
1105 read(fd, &iso_desc, sizeof iso_desc) == sizeof iso_desc
1108 if(!memcmp(iso_desc.id, "CD001", 5)) {
1110 /* now, fill in the fields */
1111 s = canon_str(iso_desc.volume_id, sizeof iso_desc.volume_id);
1112 if(!*s) s = free_mem(s);
1113 ci->iso9660.volume = s;
1115 s = canon_str(iso_desc.publisher_id, sizeof iso_desc.publisher_id);
1116 if(!*s) s = free_mem(s);
1117 ci->iso9660.publisher = s;
1119 s = canon_str(iso_desc.preparer_id, sizeof iso_desc.preparer_id);
1120 if(!*s) s = free_mem(s);
1121 ci->iso9660.preparer = s;
1123 s = canon_str(iso_desc.application_id, sizeof iso_desc.application_id);
1124 if(!*s) s = free_mem(s);
1125 ci->iso9660.application = s;
1127 s = canon_str(iso_desc.creation_date, sizeof iso_desc.creation_date);
1128 if(!*s) s = free_mem(s);
1129 ci->iso9660.creation_date = s;
1135 lseek(fd, 0x8800, SEEK_SET) >= 0 &&
1136 read(fd, §or, sizeof sector) == sizeof sector
1139 sector[0] == 0 && sector[6] == 1 &&
1140 !memcmp(sector + 1, "CD001", 5) &&
1141 !memcmp(sector + 7, "EL TORITO SPECIFICATION", 23)
1143 et = sector[0x47] + (sector[0x48] << 8) + (sector[0x49] << 16) + (sector[0x4a] << 24);
1144 ADD2LOG(" %s: el torito boot catalog at 0x%04x\n", ci->name, et);
1146 lseek(fd, et * 0x800, SEEK_SET) >= 0 &&
1147 read(fd, §or, sizeof sector) == sizeof sector &&
1150 ci->el_torito.ok = 1;
1151 ci->el_torito.catalog = et;
1152 ci->el_torito.platform = sector[1];
1153 s = canon_str(sector + 4, 24);
1154 if(!*s) s = free_mem(s);
1155 ci->el_torito.id_string = s;
1156 ci->el_torito.bootable = sector[0x20] == 0x88 ? 1 : 0;
1157 ci->el_torito.media_type = sector[0x21];
1158 ADD2LOG(" media type: %u\n", ci->el_torito.media_type);
1159 ci->el_torito.load_address = (sector[0x22] + (sector[0x23] << 8)) << 4;
1160 ADD2LOG(" load address: 0x%04x\n", ci->el_torito.load_address);
1162 if(ci->el_torito.platform == 0 && ci->el_torito.load_address == 0)
1163 ci->el_torito.load_address = 0x7c00;
1165 ci->el_torito.load_count = sector[0x26] + (sector[0x27] << 8);
1166 ci->el_torito.start = sector[0x28] + (sector[0x29] << 8) + (sector[0x2a] << 16) + (sector[0x2b] << 24);
1167 if(ci->el_torito.media_type >= 1 && ci->el_torito.media_type <= 3) {
1168 ci->el_torito.geo.c = 80;
1169 ci->el_torito.geo.h = 2;
1171 switch(ci->el_torito.media_type) {
1173 ci->el_torito.geo.s = 15;
1176 ci->el_torito.geo.s = 18;
1179 ci->el_torito.geo.s = 36;
1183 lseek(fd, ci->el_torito.start * 0x800, SEEK_SET) >= 0 &&
1184 read(fd, §or, sizeof sector) == sizeof sector
1186 if(ci->el_torito.media_type == 4) {
1187 /* ##### we should go on and read the 1st partition sector in this case... */
1188 ci->el_torito.geo.h = (unsigned) sector[0x1be + 5] + 1;
1189 ci->el_torito.geo.s = sector[0x1be + 6] & 0x3f;
1190 ci->el_torito.geo.c = sector[0x1be + 7] + (((unsigned) sector[0x1be + 6] >> 6) << 8);
1193 sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa &&
1194 sector[0x0b] == 0 && sector[0x0c] == 2 &&
1195 sector[0x0e] == 1 && sector[0x0f] == 0
1197 u0 = sector[0x13] + (sector[0x14] << 8); /* partition size */
1198 u1 = sector[0x18] + (sector[0x19] << 8); /* sectors per track */
1199 u2 = sector[0x1a] + (sector[0x1b] << 8); /* heads */
1200 u0 = u0 ? u0 : sector[0x20] + (sector[0x21] << 8) + (sector[0x22] << 16) + ((unsigned) sector[0x23] << 24);
1201 if(sector[0x26] == 0x29) {
1202 s = canon_str(sector + 0x2b, 11);
1203 if(!*s) s = free_mem(s);
1204 ci->el_torito.label = s;
1206 if(!ci->el_torito.label) {
1207 s = canon_str(sector + 3, 8);
1208 if(!*s) s = free_mem(s);
1209 ci->el_torito.label = s;
1212 (ci->el_torito.media_type == 0 || ci->el_torito.media_type > 3) &&
1215 ci->el_torito.geo.h = u2;
1216 ci->el_torito.geo.s = u1;
1217 ci->el_torito.geo.size = u0;
1218 ci->el_torito.geo.c = ci->el_torito.geo.size / (u1 * u2);
1223 ci->el_torito.geo.size = ci->el_torito.geo.s * ci->el_torito.geo.c * ci->el_torito.geo.h;
1235 * Read the list of CDROM devices known to the kernel. The info is taken
1236 * from /proc/sys/dev/cdrom/info.
1238 void read_cdroms(hd_data_t *hd_data)
1241 str_list_t *sl, *sl0;
1243 int i, line, entries = 0;
1246 if(!(sl0 = read_file(PROC_CDROM_INFO, 2, 0))) return;
1248 if((hd_data->debug & HD_DEB_CDROM)) {
1249 ADD2LOG("----- "PROC_CDROM_INFO" -----\n");
1250 for(sl = sl0; sl; sl = sl->next) {
1251 if(*sl->str != '\n') ADD2LOG("%s", sl->str);
1253 ADD2LOG("----- "PROC_CDROM_INFO" end -----\n");
1256 for(sl = sl0; sl; sl = sl->next) {
1258 (line = 0, strstr(sl->str, "drive name:") == sl->str) ||
1259 (line++, strstr(sl->str, "drive speed:") == sl->str) ||
1260 (line++, strstr(sl->str, "Can write CD-R:") == sl->str) ||
1261 (line++, strstr(sl->str, "Can write CD-RW:") == sl->str) ||
1262 (line++, strstr(sl->str, "Can read DVD:") == sl->str) ||
1263 (line++, strstr(sl->str, "Can write DVD-R:") == sl->str) ||
1264 (line++, strstr(sl->str, "Can write DVD-RAM:") == sl->str)
1266 s = strchr(sl->str, ':') + 1;
1268 while((t = strsep(&s, " \t\n"))) {
1272 case 0: /* drive name */
1273 ci = new_cdrom_entry(&hd_data->cdrom);
1275 add_str_list(&hd_data->cdroms, t);
1276 ci->name = new_str(t);
1279 case 1: /* drive speed */
1280 case 2: /* Can write CD-R */
1281 case 3: /* Can write CD-RW */
1282 case 4: /* Can read DVD */
1283 case 5: /* Can write DVD-R */
1284 case 6: /* Can write DVD-RAM */
1285 ci = get_cdrom_entry(hd_data->cdrom, entries - i);
1287 val = strtoul(t, &v, 10);
1321 /* add new entries at the _start_ of the list */
1322 cdrom_info_t *new_cdrom_entry(cdrom_info_t **ci)
1324 cdrom_info_t *new_ci = new_mem(sizeof *new_ci);
1327 return *ci = new_ci;
1331 /* return nth entry */
1332 cdrom_info_t *get_cdrom_entry(cdrom_info_t *ci, int n)
1334 if(n < 0) return NULL;
1337 if(!ci) return NULL;
1346 * Add generic scsi devs.
1348 void hd_scan_sysfs_scsi(hd_data_t *hd_data)
1350 if(!hd_probe_feature(hd_data, pr_scsi)) return;
1352 hd_data->module = mod_scsi;
1355 remove_hd_entries(hd_data);
1357 PROGRESS(1, 0, "scsi modules");
1359 load_module(hd_data, "sg");
1361 PROGRESS(2, 0, "scsi tape");
1363 get_scsi_tape(hd_data);
1365 PROGRESS(3, 0, "scsi generic");
1367 get_generic_scsi_devs(hd_data);
1371 void get_scsi_tape(hd_data_t *hd_data)
1374 unsigned u1, u2, u3;
1377 hd_dev_num_t dev_num;
1378 str_list_t *sf_class, *sf_class_e;
1379 char *sf_cdev = NULL, *sf_dev = NULL;
1380 char *sf_drv_name, *sf_drv, *bus_id;
1382 sf_class = read_dir("/sys/class/scsi_tape", 'D');
1385 ADD2LOG("sysfs: no such class: scsi_tape\n");
1389 for(sf_class_e = sf_class; sf_class_e; sf_class_e = sf_class_e->next) {
1390 str_printf(&sf_cdev, 0, "/sys/class/scsi_tape/%s", sf_class_e->str);
1393 " scsi tape: name = %s, path = %s\n",
1395 hd_sysfs_id(sf_cdev)
1398 memset(&dev_num, 0, sizeof dev_num);
1400 if((s = get_sysfs_attr_by_path(sf_cdev, "dev"))) {
1401 if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
1407 ADD2LOG(" dev = %u:%u\n", u1, u2);
1410 if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "range"), &ul0, 0)) {
1411 dev_num.range = ul0;
1412 ADD2LOG(" range = %u\n", dev_num.range);
1415 sf_dev = new_str(hd_read_sysfs_link(sf_cdev, "device"));
1417 sf_drv = hd_read_sysfs_link(sf_dev, "driver");
1419 /* maybe older kernel */
1420 sf_drv = hd_read_sysfs_link(sf_cdev, "driver");
1423 sf_drv_name = strrchr(sf_drv, '/');
1424 if(sf_drv_name) sf_drv_name++;
1427 bus_id = sf_dev ? strrchr(sf_dev, '/') : NULL;
1428 if(bus_id) bus_id++;
1431 s = hd_sysfs_id(sf_dev);
1434 " scsi device: bus_id = %s driver = %s\n path = %s\n",
1440 for(hd = hd_data->hd; hd; hd = hd->next) {
1442 hd->module == hd_data->module &&
1443 hd->sysfs_device_link &&
1444 hd->base_class.id == bc_storage_device &&
1445 hd->sub_class.id == sc_sdev_tape &&
1447 !strcmp(hd->sysfs_device_link, s)
1452 hd = add_hd_entry(hd_data, __LINE__, 0);
1453 hd->base_class.id = bc_storage_device;
1454 hd->sub_class.id = sc_sdev_tape;
1456 hd->bus.id = bus_scsi;
1458 hd->sysfs_device_link = new_str(s);
1460 hd->sysfs_bus_id = new_str(bus_id);
1462 /* parent has longest matching sysfs id */
1464 for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
1466 u1 = strlen(hd1->sysfs_id);
1467 if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
1469 hd->attached_to = hd1->idx;
1474 /* find longest matching sysfs id we have a driver for */
1476 t = strrchr(s, '/');
1478 t = hd_sysfs_find_driver(hd_data, s, 0);
1480 add_str_list(&hd->drivers, t);
1485 add_str_list(&hd->drivers, sf_drv_name);
1488 add_scsi_sysfs_info(hd_data, hd, sf_dev);
1491 s = hd_sysfs_name2_dev(sf_class_e->str);
1493 if(!hd->unix_dev_name || strlen(s) + sizeof "/dev/" - 1 < strlen(hd->unix_dev_name)) {
1494 str_printf(&hd->unix_dev_name, 0, "/dev/%s", s);
1495 hd->unix_dev_num = dev_num;
1496 free_mem(hd->sysfs_id);
1497 hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev));
1502 sf_cdev = free_mem(sf_cdev);
1503 sf_class = free_str_list(sf_class);
1507 void get_generic_scsi_devs(hd_data_t *hd_data)
1510 unsigned u1, u2, u3;
1513 hd_dev_num_t dev_num;
1514 str_list_t *sf_class, *sf_class_e;
1515 char *sf_cdev = NULL, *sf_dev = NULL;
1516 char *sf_drv_name, *sf_drv, *bus_id;
1518 sf_class = read_dir("/sys/class/scsi_generic", 'D');
1521 ADD2LOG("sysfs: no such class: scsi_generic\n");
1525 for(sf_class_e = sf_class; sf_class_e; sf_class_e = sf_class_e->next) {
1526 str_printf(&sf_cdev, 0, "/sys/class/scsi_generic/%s", sf_class_e->str);
1529 " scsi: name = %s, path = %s\n",
1531 hd_sysfs_id(sf_cdev)
1534 memset(&dev_num, 0, sizeof dev_num);
1536 if((s = get_sysfs_attr_by_path(sf_cdev, "dev"))) {
1537 if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
1543 ADD2LOG(" dev = %u:%u\n", u1, u2);
1546 if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "range"), &ul0, 0)) {
1547 dev_num.range = ul0;
1548 ADD2LOG(" range = %u\n", dev_num.range);
1551 sf_dev = new_str(hd_read_sysfs_link(sf_cdev, "device"));
1553 sf_drv = hd_read_sysfs_link(sf_dev, "driver");
1555 /* maybe older kernel */
1556 sf_drv = hd_read_sysfs_link(sf_cdev, "driver");
1559 sf_drv_name = strrchr(sf_drv, '/');
1560 if(sf_drv_name) sf_drv_name++;
1563 bus_id = sf_dev ? strrchr(sf_dev, '/') : NULL;
1564 if(bus_id) bus_id++;
1569 s = hd_sysfs_id(sf_dev);
1572 " scsi device: bus_id = %s driver = %s\n path = %s\n",
1579 for(hd = hd_data->hd; hd; hd = hd->next) {
1581 hd->sysfs_device_link &&
1582 hd->bus.id == bus_scsi &&
1584 !strcmp(hd->sysfs_device_link, s)
1589 if(!hd->unix_dev_name2) {
1590 str_printf(&hd->unix_dev_name2, 0, "/dev/%s", hd_sysfs_name2_dev(sf_class_e->str));
1591 hd->unix_dev_num2 = dev_num;
1597 if(sf_dev && !sf_drv_name) {
1598 hd = add_hd_entry(hd_data, __LINE__, 0);
1599 hd->base_class.id = bc_storage_device;
1600 hd->sub_class.id = sc_sdev_other;
1602 str_printf(&hd->unix_dev_name, 0, "/dev/%s", hd_sysfs_name2_dev(sf_class_e->str));
1604 hd->bus.id = bus_scsi;
1606 hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev));
1608 hd->unix_dev_num = dev_num;
1610 hd->sysfs_bus_id = new_str(bus_id);
1612 if((s = hd_sysfs_id(sf_dev))) {
1614 /* parent has longest matching sysfs id */
1616 for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
1618 u1 = strlen(hd1->sysfs_id);
1619 if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
1621 hd->attached_to = hd1->idx;
1626 /* find longest matching sysfs id we have a driver for */
1628 t = strrchr(s, '/');
1630 t = hd_sysfs_find_driver(hd_data, s, 0);
1632 add_str_list(&hd->drivers, t);
1638 add_scsi_sysfs_info(hd_data, hd, sf_dev);
1641 sf_dev = free_mem(sf_dev);
1644 sf_cdev = free_mem(sf_cdev);
1645 sf_class = free_str_list(sf_class);
1649 void add_disk_size(hd_data_t *hd_data, hd_t *hd)
1651 hd_res_t *geo, *size;
1658 hd->unix_dev_name &&
1659 hd->sub_class.id == sc_sdev_disk
1661 PROGRESS(5, 0, hd->unix_dev_name);
1662 fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
1665 str_printf(&pr_str, 0, "%s geo", hd->unix_dev_name);
1666 PROGRESS(5, 1, pr_str);
1668 if(hd_getdisksize(hd_data, hd->unix_dev_name, fd, &geo, &size) == 1) {
1669 /* (low-level) unformatted disk */
1670 hd->is.notready = 1;
1673 if(geo) add_res_entry(&hd->res, geo);
1674 if(size) add_res_entry(&hd->res, size);
1680 pr_str = free_mem(pr_str);