diff options
Diffstat (limited to 'mdk-stage1/probing.c')
-rw-r--r-- | mdk-stage1/probing.c | 984 |
1 files changed, 559 insertions, 425 deletions
diff --git a/mdk-stage1/probing.c b/mdk-stage1/probing.c index 077a664d3..f956bb348 100644 --- a/mdk-stage1/probing.c +++ b/mdk-stage1/probing.c @@ -1,7 +1,7 @@ /* - * Guillaume Cottenceau (gc@mandrakesoft.com) + * Guillaume Cottenceau (gc) * - * Copyright 2000 MandrakeSoft + * Copyright 2000 Mandriva * * This software may be freely redistributed under the terms of the GNU * public license. @@ -35,19 +35,32 @@ #include <string.h> #include <sys/types.h> #include <sys/stat.h> +#include <dirent.h> #include <fcntl.h> +#include <fnmatch.h> #include <sys/socket.h> #include <net/if.h> +#include <linux/sockios.h> +#include <linux/ethtool.h> #include <sys/ioctl.h> #include <sys/mount.h> +#include <pci/pci.h> +#include <libldetect.h> +#include <errno.h> +#include <glob.h> #include "stage1.h" #include "log.h" +#include "utils.h" #include "frontend.h" #include "modules.h" -#include "pci-resource/pci-ids.h" +#include "pci-ids.h" #ifdef ENABLE_USB -#include "usb-resource/usb-ids.h" +#include "usb-ids.h" +#endif +#ifdef ENABLE_PCMCIA +#include "sysfs/libsysfs.h" +#include "pcmcia-ids.h" #endif #include "probing.h" @@ -73,52 +86,265 @@ static void warning_insmod_failed(enum insmod_return r) } #ifndef DISABLE_NETWORK -struct net_description_elem +const char * safe_descr(const char * text) { + return text ? text : "unknown"; +} + +char * get_net_intf_description(char * intf_name) { - char * intf_name; - char * intf_description; -}; -static struct net_description_elem net_descriptions[50]; -static int net_descr_number = 0; -static char * intf_descr_for_discover = NULL; -static char * net_intf_too_early_name[50]; /* for modules providing more than one net intf */ -static int net_intf_too_early_number = 0; -static int net_intf_too_early_ptr = 0; - -void prepare_intf_descr(const char * intf_descr) + struct ifreq ifr; + struct ethtool_drvinfo drvinfo; + int s = socket(AF_INET, SOCK_DGRAM, 0); + char *res; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, intf_name, IFNAMSIZ); + + drvinfo.cmd = ETHTOOL_GDRVINFO; + ifr.ifr_data = (caddr_t) &drvinfo; + + if (ioctl(s, SIOCETHTOOL, &ifr) != -1) { + res = drvinfo.driver; + } else { + perror("SIOCETHTOOL"); + res = "unknown"; + } + close(s); + return strdup(res); +} +#endif + +static int device_match_modules_list(struct pciusb_entry *e, char **modules, unsigned int modules_len) { + int i; + if (!e->module) + return 0; + for (i = 0; i < modules_len; i++) + if (!strcmp(modules[i], e->module)) + return 1; + return 0; +} + +struct pcitable_entry *detected_devices = NULL; +int detected_devices_len = 0; + +static void detected_devices_destroy(void) +{ + if (detected_devices) + free(detected_devices); +} + +static struct pcitable_entry *detected_device_new(void) { - intf_descr_for_discover = strdup(intf_descr); + static int detected_devices_maxlen = 0; + if (detected_devices_len >= detected_devices_maxlen) { + detected_devices_maxlen += 32; + if (detected_devices == NULL) + detected_devices = malloc(detected_devices_maxlen * sizeof(*detected_devices)); + else + detected_devices = realloc(detected_devices, detected_devices_maxlen * sizeof(*detected_devices)); + if (detected_devices == NULL) + log_perror("detected_device_new: could not (re)allocate table. Let it crash, sorry"); + } + return &detected_devices[detected_devices_len++]; } -void net_discovered_interface(char * intf_name) +/* FIXME: factorize with probe_that_type() */ + +static void add_detected_device(unsigned short vendor, unsigned short device, unsigned int subvendor, unsigned int subdevice, const char *name, const char *module) { - if (!intf_descr_for_discover) { - net_intf_too_early_name[net_intf_too_early_number++] = strdup(intf_name); + struct pcitable_entry *dev = detected_device_new(); + dev->vendor = vendor; + dev->device = device; + dev->subvendor = subvendor; + dev->subdevice = subdevice; + strncpy(dev->module, module, sizeof(dev->module) - 1); + dev->module[sizeof(dev->module) - 1] = '\0'; + strncpy(dev->description, safe_descr(name), sizeof(dev->description) - 1); + dev->description[sizeof(dev->description) - 1] = '\0'; + log_message("detected device (%04x, %04x, %04x, %04x, %s, %s)", vendor, device, subvendor, subdevice, name, module); +} + +static int add_detected_device_if_match(struct pciusb_entry *e, char **modules, unsigned int modules_len) +{ + int ret = device_match_modules_list(e, modules, modules_len); + if (ret) + add_detected_device(e->vendor, e->device, e->subvendor, e->subdevice, + e->text, e->module); + return ret; +} + +void probing_detect_devices() +{ + static int already_detected_devices = 0; + struct pciusb_entries entries; + int i; + + if (already_detected_devices) return; + + entries = pci_probe(); + for (i = 0; i < entries.nb; i++) { + struct pciusb_entry *e = &entries.entries[i]; +#ifndef DISABLE_PCIADAPTERS +#ifndef DISABLE_MEDIAS + if (add_detected_device_if_match(e, medias_ide_pci_modules, medias_ide_pci_modules_len)) + continue; + if (add_detected_device_if_match(e, medias_other_pci_modules, medias_other_pci_modules_len)) + continue; +#endif + +#ifndef DISABLE_NETWORK + if (add_detected_device_if_match(e, network_pci_modules, network_pci_modules_len)) + continue; +#endif + +#ifdef ENABLE_USB + if (add_detected_device_if_match(e, usb_controller_modules, usb_controller_modules_len)) + continue; +#endif +#endif + /* device can't be found in built-in pcitables, but keep it */ + add_detected_device(e->vendor, e->device, e->subvendor, e->subdevice, e->text, e->module); } - if (!intf_name) { - if (net_intf_too_early_ptr >= net_intf_too_early_number) { - log_message("NET: was expecting another network interface (broken net module?)"); - return; + pciusb_free(&entries); + + already_detected_devices = 1; +} + +void probing_destroy(void) +{ + detected_devices_destroy(); +} + +#ifndef DISABLE_MEDIAS +static const char * get_alternate_module(const char * name) +{ + struct alternate_mapping { + const char * a; + const char * b; + }; + static struct alternate_mapping mappings[] = { + { "ahci", "ata_piix" }, + }; + int mappings_nb = sizeof(mappings) / sizeof(struct alternate_mapping); + int i; + + for (i=0; i<mappings_nb; i++) { + const char * alternate = NULL; + if (streq(name, mappings[i].a)) + alternate = mappings[i].b; + else if (streq(name, mappings[i].b)) + alternate = mappings[i].a; + if (alternate) { + log_message("found alternate module %s for driver %s", alternate, name); + return alternate; } - net_descriptions[net_descr_number].intf_name = net_intf_too_early_name[net_intf_too_early_ptr++]; } - else - net_descriptions[net_descr_number].intf_name = strdup(intf_name); - net_descriptions[net_descr_number].intf_description = strdup(intf_descr_for_discover); - intf_descr_for_discover = NULL; - net_descr_number++; + return NULL; } +#endif -char * get_net_intf_description(char * intf_name) +void discovered_device(enum driver_type type, const char * description, const char * driver) { + description = safe_descr(description); + + enum insmod_return failed = INSMOD_FAILED; +#ifndef DISABLE_MEDIAS + if (type == MEDIA_ADAPTERS) { + const char * alternate = NULL; + wait_message("Loading driver for media adapter:\n \n%s", description); + failed = my_modprobe(driver, MEDIA_ADAPTERS, NULL); + alternate = get_alternate_module(driver); + if (!IS_NOAUTO && alternate) { + failed = failed || my_modprobe(alternate, MEDIA_ADAPTERS, NULL); + } + remove_wait_message(); + warning_insmod_failed(failed); + } +#endif +#ifndef DISABLE_NETWORK + if (type == NETWORK_DEVICES) { + log_message("NET: Loading driver for network device %s", description); + wait_message("Loading driver for network device:\n \n%s", description); + failed = my_modprobe(driver, NETWORK_DEVICES, NULL); + warning_insmod_failed(failed); + remove_wait_message(); + } +#endif +#ifdef ENABLE_USB + if (type == USB_CONTROLLERS) + /* we can't allow additional modules floppy since we need usbhid for keystrokes of usb keyboards */ + failed = my_modprobe(driver, USB_CONTROLLERS, NULL); +#endif +} + +void probe_pci_modules(enum driver_type type, char **pci_modules, unsigned int pci_modules_len) { + struct pciusb_entries entries; int i; - for (i = 0; i < net_descr_number ; i++) - if (!strcmp(net_descriptions[i].intf_name, intf_name)) - return net_descriptions[i].intf_description; - return strdup("unknown"); + + entries = pci_probe(); + for (i = 0; i < entries.nb; i++) { + struct pciusb_entry *e = &entries.entries[i]; + if (device_match_modules_list(e, pci_modules, pci_modules_len)) { + log_message("PCI: device %04x %04x %04x %04x is \"%s\", driver is %s", + e->vendor, e->device, e->subvendor, e->subdevice, safe_descr(e->text), e->module); + discovered_device(type, e->text, e->module); + } + } + pciusb_free(&entries); +} + +/** Loads modules for known virtio devices + * + * virtio modules are not being loaded using the PCI probing mechanism + * because pcitable.gz does not have IDs for these devices. + * + * The possible correct solution for it is to fix the script which + * generates pcitable.gz to handle the virtio_device_id structure. + */ +void probe_virtio_modules(void) +{ + struct pciusb_entries entries; + int i; + char *name; + char *options; + int loaded_pci = 0; + + entries = pci_probe(); + for (i = 0; i < entries.nb; i++) { + struct pciusb_entry *e = &entries.entries[i]; + if (e->vendor == VIRTIO_PCI_VENDOR) { + if (!loaded_pci) { + log_message("loading virtio-pci"); + my_modprobe("virtio_pci", ANY_DRIVER_TYPE, NULL); + loaded_pci = 1; + } + + name = NULL; + options = NULL; + + switch (e->subdevice) { + case VIRTIO_ID_NET: + name = "virtio_net"; + options = "csum=0"; + break; + case VIRTIO_ID_BLOCK: + name = "virtio_blk"; + break; + case VIRTIO_ID_BALLOON: + name = "virtio_balloon"; + break; + default: + log_message("warning: unknown virtio device %04x", e->device); + } + if (name) { + log_message("virtio: loading %s", name); + my_modprobe(name, ANY_DRIVER_TYPE, options); + } + } + } + pciusb_free(&entries); } -#endif #ifdef ENABLE_USB void probe_that_type(enum driver_type type, enum media_bus bus) @@ -126,424 +352,231 @@ void probe_that_type(enum driver_type type, enum media_bus bus) void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((unused))) #endif { - /* ---- PCI probe ---------------------------------------------- */ - { - FILE * f; - int len = 0; - char buf[200]; - struct pci_module_map * pcidb = NULL; + static int already_probed_usb_controllers = 0; + static int already_loaded_usb_scsi = 0; + static int already_probed_virtio_devices = 0; + /* ---- PCI probe ---------------------------------------------- */ + if (bus != BUS_USB) { switch (type) { #ifndef DISABLE_PCIADAPTERS #ifndef DISABLE_MEDIAS - static int already_probed_scsi_adapters = 0; - case SCSI_ADAPTERS: - if (already_probed_scsi_adapters) - goto end_pci_probe; - already_probed_scsi_adapters = 1; - pcidb = medias_pci_ids; - len = medias_num_ids; + static int already_probed_media_adapters = 0; + case MEDIA_ADAPTERS: + if (already_probed_media_adapters) + break; + already_probed_media_adapters = 1; + probe_pci_modules(type, medias_ide_pci_modules, medias_ide_pci_modules_len); + probe_pci_modules(type, medias_other_pci_modules, medias_other_pci_modules_len); break; #endif #ifndef DISABLE_NETWORK case NETWORK_DEVICES: - pcidb = network_pci_ids; - len = network_num_ids; + probe_pci_modules(type, network_pci_modules, network_pci_modules_len); break; #endif #endif #ifdef ENABLE_USB - static int already_probed_usb_controllers = 0; case USB_CONTROLLERS: if (already_probed_usb_controllers || IS_NOAUTO) - goto end_pci_probe; + break; already_probed_usb_controllers = 1; - pcidb = usb_pci_ids; - len = usb_num_ids; + probe_pci_modules(type, usb_controller_modules, usb_controller_modules_len); break; #endif + case VIRTIO_DEVICES: + if (already_probed_virtio_devices) + break; + probe_virtio_modules(); + already_probed_virtio_devices = 1; + break; default: - goto end_pci_probe; - } - - if (IS_EXPERT && type != USB_CONTROLLERS) { - ask_insmod(type); - return; - } - - if (!(f = fopen("/proc/bus/pci/devices", "rb"))) { - log_message("PCI: could not open proc file"); - goto end_pci_probe; - } - - while (1) { - int i, garb, vendor, device; - - if (!fgets(buf, sizeof(buf), f)) break; - - sscanf(buf, "%x %x", &garb, &vendor); - device = vendor & 0xFFFF; /* because scanf from dietlibc does not support %4f */ - vendor = (vendor >> 16) & 0xFFFF; - - for (i = 0; i < len; i++) { - if (pcidb[i].vendor == vendor && pcidb[i].device == device) { - log_message("PCI: device %04x %04x is \"%s\" (%s)", vendor, device, pcidb[i].name, pcidb[i].module); -#ifndef DISABLE_MEDIAS - if (type == SCSI_ADAPTERS) { - int wait_msg = 0; - enum insmod_return failed; - if (IS_AUTOMATIC) { - wait_message("Loading driver for SCSI adapter:\n \n%s", pcidb[i].name); - wait_msg = 1; - } else - stg1_info_message("About to load driver for SCSI adapter:\n \n%s", pcidb[i].name); - failed = my_insmod(pcidb[i].module, SCSI_ADAPTERS, NULL); - if (wait_msg) - remove_wait_message(); - warning_insmod_failed(failed); - - } -#endif -#ifndef DISABLE_NETWORK - if (type == NETWORK_DEVICES) { - stg1_info_message("About to load driver for network device:\n \n%s", pcidb[i].name); - prepare_intf_descr(pcidb[i].name); - warning_insmod_failed(my_insmod(pcidb[i].module, NETWORK_DEVICES, NULL)); - if (intf_descr_for_discover) /* for modules providing more than one net intf */ - net_discovered_interface(NULL); - } -#endif -#ifdef ENABLE_USB - if (type == USB_CONTROLLERS) - my_insmod(pcidb[i].module, USB_CONTROLLERS, NULL); -#endif - } - } + break; } - fclose(f); - end_pci_probe:; } #ifdef ENABLE_USB /* ---- USB probe ---------------------------------------------- */ if ((bus == BUS_USB || bus == BUS_ANY) && !(IS_NOAUTO)) { - static int already_probed_usb_controllers = 0; static int already_mounted_usbdev = 0; + struct pciusb_entries entries; + int i; - FILE * f; - int len = 0; - char buf[200]; - struct usb_module_map * usbdb = NULL; - - if (!already_probed_usb_controllers) { - already_probed_usb_controllers = 1; + if (!already_probed_usb_controllers) probe_that_type(USB_CONTROLLERS, BUS_ANY); - } if (!already_mounted_usbdev) { already_mounted_usbdev = 1; - my_insmod("usb-storage", SCSI_ADAPTERS, NULL); - if (mount("/proc/bus/usb", "/proc/bus/usb", "usbdevfs", 0, NULL)) { - log_message("USB: couldn't mount /proc/bus/usb"); - goto end_usb_probe; - } wait_message("Detecting USB devices."); sleep(4); /* sucking background work */ - my_insmod("usbkbd", ANY_DRIVER_TYPE, NULL); - my_insmod("keybdev", ANY_DRIVER_TYPE, NULL); + my_modprobe("usbhid", ANY_DRIVER_TYPE, NULL); remove_wait_message(); } - if (!(f = fopen("/proc/bus/usb/devices", "rb"))) { - log_message("USB: could not open proc file"); + if (type != NETWORK_DEVICES) goto end_usb_probe; + + entries = usb_probe(); + for (i = 0; i < entries.nb; i++) { + struct pciusb_entry *e = &entries.entries[i]; + if (device_match_modules_list(e, usb_modules, usb_modules_len)) { + log_message("USB: device %04x %04x is \"%s\" (%s)", e->vendor, e->device, safe_descr(e->text), e->module); + discovered_device(type, e->text, e->module); + } } + pciusb_free(&entries); + end_usb_probe:; + } +#endif + +#ifdef ENABLE_PCMCIA + /* ---- PCMCIA probe ---------------------------------------------- */ + if ((bus == BUS_PCMCIA || bus == BUS_ANY) && !(IS_NOAUTO)) { + struct pcmcia_alias * pcmciadb = NULL; + unsigned int len = 0; + char *base = "/sys/bus/pcmcia/devices"; + DIR *dir; + struct dirent *dent; + + dir = opendir(base); + if (dir == NULL) + goto end_pcmcia_probe; switch (type) { +#ifndef DISABLE_MEDIAS + case MEDIA_ADAPTERS: + pcmciadb = medias_pcmcia_ids; + len = medias_pcmcia_num_ids; + break; +#endif +#ifndef DISABLE_NETWORK case NETWORK_DEVICES: - usbdb = usb_usb_ids; - len = usb_usb_num_ids; + pcmciadb = network_pcmcia_ids; + len = network_pcmcia_num_ids; break; +#endif default: - goto end_usb_probe; - } + goto end_pcmcia_probe; + } - while (1) { - int i, vendor, id; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct sysfs_attribute *modalias_attr; + char keyfile[300]; + int i, id; + + if (dent->d_name[0] == '.') + continue; - if (!fgets(buf, sizeof(buf), f)) break; + log_message("PCMCIA: device found %s", dent->d_name); - if (sscanf(buf, "P: Vendor=%x ProdID=%x", &vendor, &id) != 2) + snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/modalias", base, dent->d_name); + modalias_attr = sysfs_open_attribute(keyfile); + if (!modalias_attr) + continue; + if (sysfs_read_attribute(modalias_attr) != 0 || !modalias_attr->value) { + sysfs_close_attribute(modalias_attr); continue; + } + + log_message("PCMCIA: device found %s", modalias_attr->value); for (i = 0; i < len; i++) { - if (usbdb[i].vendor == vendor && usbdb[i].id == id) { - log_message("USB: device %04x %04x is \"%s\" (%s)", vendor, id, usbdb[i].name, usbdb[i].module); -#ifndef DISABLE_NETWORK - if (type == NETWORK_DEVICES) { - stg1_info_message("About to load driver for usb network device:\n \n%s", usbdb[i].name); - prepare_intf_descr(usbdb[i].name); - warning_insmod_failed(my_insmod(usbdb[i].module, NETWORK_DEVICES, NULL)); - if (intf_descr_for_discover) /* for modules providing more than one net intf */ - net_discovered_interface(NULL); + if (!fnmatch(pcmciadb[i].modalias, modalias_attr->value, 0)) { + char product[256]; + + log_message("PCMCIA: device found %s (%s)", pcmciadb[i].modalias, pcmciadb[i].module); + strcpy(product, ""); + for (id = 1; id <= 4; id++) { + struct sysfs_attribute *product_attr; + snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/prod_id%d", base, dent->d_name, id); + product_attr = sysfs_open_attribute(keyfile); + if (!product_attr) + continue; + if (sysfs_read_attribute(product_attr) || !product_attr->value) { + sysfs_close_attribute(product_attr); + continue; + } + snprintf(product + strlen(product), sizeof(product)-strlen(product)-1, "%s%s", product[0] ? " " : "", product_attr->value); + if (product[strlen(product)-1] == '\n') + product[strlen(product)-1] = '\0'; + sysfs_close_attribute(product_attr); } -#endif + if (!product[0]) + strcpy(product, "PCMCIA device"); + + log_message("PCMCIA: device found %s (%s)", product, pcmciadb[i].module); + discovered_device(type, product, pcmciadb[i].module); } } + + sysfs_close_attribute(modalias_attr); } - fclose(f); - end_usb_probe:; + end_pcmcia_probe:; + if (dir) + closedir(dir); } #endif + + /* be sure to load usb-storage after media adapters, so that they are in + same order than reboot, so that naming is the same */ + if (type == MEDIA_ADAPTERS && (bus == BUS_USB || bus == BUS_SCSI || bus == BUS_ANY) && + already_probed_usb_controllers && !already_loaded_usb_scsi) { + already_loaded_usb_scsi = 1; + /* we can't allow additional modules floppy since we need usbkbd for keystrokes of usb keyboards */ + my_modprobe("usb_storage", MEDIA_ADAPTERS, NULL); + if (module_already_present("ieee1394")) + my_modprobe("sbp2", MEDIA_ADAPTERS, NULL); + wait_message("Detecting USB mass-storage devices."); +#ifndef DEBUG + sleep(10); /* sucking background work */ +#endif + remove_wait_message(); + } } -#ifndef DISABLE_MEDIAS static struct media_info * medias = NULL; -static void find_media(enum media_bus bus) +// Read a short string from a file and strips it, intended for sysfs attributes +static ssize_t read_attribute(char *path, char *buf) { + ssize_t l = 0; + int fd = open(path, O_RDONLY); + buf[0] = '\0'; + if (fd == -1) { + log_message("Failed to open %s for reading", path); + } else { + ssize_t n = read(fd, buf, 32); + if (n == -1) { + log_message("Couldn't read file (%s)", path); + } else { + // Strip whitespaces and newline + for (int i = n-1; i >= 0; i--) { + if (buf[i] == '\n' || buf[i] == ' ') + continue; + l = i+1; + break; + } + buf[l] = '\0'; + } + close(fd); + } + log_message("Content of %s was %s", path, buf); + return l; +} + +void find_media(enum media_bus bus) { - char b[50]; char buf[5000]; struct media_info tmp[50]; int count = 0; - int fd; if (medias) free(medias); /* that does not free the strings, by the way */ - if (bus == BUS_SCSI || bus == BUS_USB || bus == BUS_ANY) - probe_that_type(SCSI_ADAPTERS, bus); - - /* ----------------------------------------------- */ - if (bus != BUS_IDE && bus != BUS_ANY) - goto find_media_after_ide; - log_message("looking for ide media"); - - strcpy(b, "/proc/ide/hd"); - for (b[12] = 'a'; b[12] <= 'h'; b[12]++) { - int i; - char ide_disk[] = "disk"; - char ide_cdrom[] = "cdrom"; - char ide_tape[] = "tape"; - char ide_floppy[] = "floppy"; - - /* first, test if file exists (will tell if attached medium exists) */ - b[13] = '\0'; - if (access(b, R_OK)) - continue; - - tmp[count].name = strdup("hda"); - tmp[count].name[2] = b[12]; - - /* media type */ - strcpy(b + 13, "/media"); - fd = open(b, O_RDONLY); - if (fd == -1) { - log_message("failed to open %s for reading", b); - continue; - } - - i = read(fd, buf, sizeof(buf)); - if (i == -1) { - log_message("failed to read %s", b); - continue; - } - buf[i] = '\0'; - close(fd); - - if (ptr_begins_static_str(buf, ide_disk)) - tmp[count].type = DISK; - else if (ptr_begins_static_str(buf, ide_cdrom)) - tmp[count].type = CDROM; - else if (ptr_begins_static_str(buf, ide_tape)) - tmp[count].type = TAPE; - else if (ptr_begins_static_str(buf, ide_floppy)) - tmp[count].type = FLOPPY; - else - tmp[count].type = UNKNOWN_MEDIA; - - /* media model */ - strcpy(b + 13, "/model"); - fd = open(b, O_RDONLY); - if (fd == -1) { - log_message("failed to open %s for reading", b); - continue; - } - - i = read(fd, buf, sizeof(buf)); - if (i <= 0) { - log_message("failed to read %s", b); - tmp[count].model = strdup("(none)"); - } - else { - buf[i-1] = '\0'; /* eat the \n */ - tmp[count].model = strdup(buf); - } - close(fd); - - log_message("IDE/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model); - count++; - } - - find_media_after_ide: - /* ----------------------------------------------- */ - if (bus != BUS_SCSI && bus != BUS_USB && bus != BUS_ANY) - goto find_media_after_scsi; - log_message("looking for scsi media"); - - fd = open("/proc/scsi/scsi", O_RDONLY); - if (fd != -1) { - enum { SCSI_TOP, SCSI_HOST, SCSI_VENDOR, SCSI_TYPE } state = SCSI_TOP; - char * start, * chptr, * next, * end; - char scsi_disk_count = 'a'; - char scsi_cdrom_count = '0'; - char scsi_tape_count = '0'; - - char scsi_no_devices[] = "Attached devices: none"; - char scsi_some_devices[] = "Attached devices: "; - char scsi_host[] = "Host: "; - char scsi_vendor[] = " Vendor: "; - - int i = read(fd, &buf, sizeof(buf)-1); - if (i < 1) { - close(fd); - goto end_scsi; - } - close(fd); - buf[i] = '\0'; - - if (ptr_begins_static_str(buf, scsi_no_devices)) - goto end_scsi; - - start = buf; - while (*start) { - char tmp_model[50]; - char tmp_name[10]; - - chptr = start; - while (*chptr != '\n') chptr++; - *chptr = '\0'; - next = chptr + 1; - - switch (state) { - case SCSI_TOP: - if (!ptr_begins_static_str(start, scsi_some_devices)) - goto end_scsi; - state = SCSI_HOST; - break; - - case SCSI_HOST: - if (!ptr_begins_static_str(start, scsi_host)) - goto end_scsi; - state = SCSI_VENDOR; - break; - - case SCSI_VENDOR: - if (!ptr_begins_static_str(start, scsi_vendor)) - goto end_scsi; - - /* (1) Grab Vendor info */ - start += 10; - end = chptr = strstr(start, "Model:"); - if (!chptr) - goto end_scsi; - - chptr--; - while (*chptr == ' ') - chptr--; - if (*chptr == ':') { - chptr++; - *(chptr + 1) = '\0'; - strcpy(tmp_model,"(unknown)"); - } else { - *(chptr + 1) = '\0'; - strcpy(tmp_model, start); - } - - /* (2) Grab Model info */ - start = end; - start += 7; - - chptr = strstr(start, "Rev:"); - if (!chptr) - goto end_scsi; - - chptr--; - while (*chptr == ' ') chptr--; - *(chptr + 1) = '\0'; - - strcat(tmp_model, " "); - strcat(tmp_model, start); - - tmp[count].model = strdup(tmp_model); - - state = SCSI_TYPE; - - break; - - case SCSI_TYPE: - if (strncmp(" Type:", start, 7)) - goto end_scsi; - *tmp_name = '\0'; - - if (strstr(start, "Direct-Access")) { - sprintf(tmp_name, "sd%c", scsi_disk_count++); - tmp[count].type = DISK; - } else if (strstr(start, "Sequential-Access")) { - sprintf(tmp_name, "st%c", scsi_tape_count++); - tmp[count].type = TAPE; - } else if (strstr(start, "CD-ROM")) { - sprintf(tmp_name, "sr%c", scsi_cdrom_count++); - tmp[count].type = CDROM; - } - - if (*tmp_name) { - tmp[count].name = strdup(tmp_name); - log_message("SCSI/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model); - count++; - } - - state = SCSI_HOST; - } - - start = next; - } - - end_scsi:; - } - - /* ----------------------------------------------- */ - log_message("looking for Compaq Smart Array media"); - { - char * procfiles[] = { "/proc/driver/cpqarray/ida0", "/proc/driver/cciss/cciss0", // 2.4 style - "/proc/array/ida", "/proc/cciss/cciss", // 2.2 style - NULL }; - static char cpq_descr[] = "Compaq RAID logical disk"; - char ** procfile = procfiles; - FILE * f; - while (procfile && *procfile && (f = fopen(*procfile, "rb"))) { - while (fgets(buf, sizeof(buf), f)) { - if (ptr_begins_static_str(buf, "ida/") || ptr_begins_static_str(buf, "cciss/")) { - char * end = strchr(buf, ':'); - if (!end) - log_message("Inconsistency in %s, line:\n%s", *procfile, buf); - else { - *end = '\0'; - tmp[count].name = strdup(buf); - tmp[count].type = DISK; - tmp[count].model = cpq_descr; - log_message("CPQ: found %s", tmp[count].name); - count++; - } - } - } - fclose(f); - procfile++; - } - } + log_message("looking for media adapters"); + probe_that_type(MEDIA_ADAPTERS, bus); /* ----------------------------------------------- */ log_message("looking for DAC960"); @@ -575,13 +608,102 @@ static void find_media(enum media_bus bus) fclose(f); } } - find_media_after_scsi: + /* ----------------------------------------------- */ + log_message("looking for other disks"); + { + glob_t globbuf; + // TODO: We should switch everything to here, and later switch to ignoring + // some types of disks (ram, loop, ...) rather than a list to accept. + glob("/sys/block/nvme*", 0, NULL, &globbuf); + glob("/sys/block/vd*", GLOB_APPEND, NULL, &globbuf); + glob("/sys/block/cciss*", GLOB_APPEND, NULL, &globbuf); + glob("/sys/block/fd*", GLOB_APPEND, NULL, &globbuf); + glob("/sys/block/sd*", GLOB_APPEND, NULL, &globbuf); + glob("/sys/block/st*", GLOB_APPEND, NULL, &globbuf); + glob("/sys/block/sr*", GLOB_APPEND, NULL, &globbuf); + + for (int i = 0; i < globbuf.gl_pathc; i++) { + char *name, *pathend; + char path[64]; + char model[64]; + int vendor_length = 0; + + strncpy(path, globbuf.gl_pathv[i], sizeof(path)); + name = strdup(path + 11); + + // Replace ! with /, for example for cciss!c0d0 devices + char * c = name; + while((c = strchr(c, '!')) != NULL) { + *c = '/'; + c++; + } + + pathend = path + strlen(path); + + // Check if this device had been handled by other code + int exists = 0; + for (int j = 0; j < count; j++) { + if (!strcmp(name, tmp[j].name)) { + exists = 1; + break; + } + } + if (exists) { + free(name); + continue; + } + + strcpy(model, "Unknown Disk"); + + strcpy(pathend, "/device/vendor"); + vendor_length = read_attribute(path, model); + + if (vendor_length) { + strcat(model, " "); + vendor_length++; + } + + strcpy(pathend, "/device/model"); + read_attribute(path, model+vendor_length); + + strcpy(pathend, "/capability"); + read_attribute(path, buf); + long caps = strtol(buf, NULL, 16); + + // GENHD_FL_UP (0x0010): indicated that the block device is “up” but the kernel has removed that info + if (caps && 0) { + log_message("Ignoring device %s (not up)", name); + free(name); + continue; + } + + if (caps & 0x0400) { + log_message("Ignoring device %s (hidden)", name); + free(name); + continue; + } + + tmp[count].type = DISK; + if (caps & 0x0008 || !strncmp(name, "sr", 2)) { + tmp[count].type = CDROM; + } else if (!strncmp(name, "fd", 2)) { + tmp[count].type = FLOPPY; + } else if (!strncmp(name, "st", 2)) { + tmp[count].type = TAPE; + } + + tmp[count].name = name; + tmp[count].model = strdup(model); + count++; + } + globfree(&globbuf); + } /* ----------------------------------------------- */ tmp[count].name = NULL; count++; - medias = memdup(tmp, sizeof(struct media_info) * count); + medias = _memdup(tmp, sizeof(struct media_info) * count); } @@ -608,62 +730,74 @@ void get_medias(enum media_type media, char *** names, char *** models, enum med tmp_names[count] = NULL; tmp_models[count++] = NULL; - *names = memdup(tmp_names, sizeof(char *) * count); - *models = memdup(tmp_models, sizeof(char *) * count); + *names = _memdup(tmp_names, sizeof(char *) * count); + *models = _memdup(tmp_models, sizeof(char *) * count); } -#endif /* DISABLE_MEDIAS */ #ifndef DISABLE_NETWORK -int net_device_available(char * device) { - struct ifreq req; - int s; - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - log_perror(device); - return 0; - } - strcpy(req.ifr_name, device); - if (ioctl(s, SIOCGIFFLAGS, &req)) { - /* if we can't get the flags, the networking device isn't available */ - close(s); - return 0; +static int is_net_interface_blacklisted(char *intf) +{ + /* see detect_devicess::is_lan_interface() */ + char * blacklist[] = { "lo", "ippp", "isdn", "plip", "ppp", "wifi", "sit", NULL }; + char ** ptr = blacklist; + + while (ptr && *ptr) { + if (!strncmp(intf, *ptr, strlen(*ptr))) + return 1; + ptr++; } - close(s); - return 1; -} + return 0; +} char ** get_net_devices(void) { - char * devices[] = { - "eth0", "eth1", "eth2", "eth3", "eth4", "eth5", - "tr0", - "plip0", "plip1", "plip2", - "fddi0", -#ifdef ENABLE_USB - "usb0", "usb1", "usb2", "usb3", -#endif - NULL - }; - char ** ptr = devices; char * tmp[50]; - int i = 0; static int already_probed = 0; + FILE * f; + int i = 0; if (!already_probed) { - already_probed = 1; /* cut off loop brought by: probe_that_type => my_insmod => get_net_devices */ + already_probed = 1; /* cut off loop brought by: probe_that_type => my_modprobe => get_net_devices */ probe_that_type(NETWORK_DEVICES, BUS_ANY); } - while (ptr && *ptr) { - if (net_device_available(*ptr)) - tmp[i++] = strdup(*ptr); - ptr++; + /* use /proc/net/dev since SIOCGIFCONF doesn't work with some drivers (rt2500) */ + f = fopen("/proc/net/dev", "rb"); + if (f) { + char line[128]; + + /* skip the two first lines */ + fgets(line, sizeof(line), f); + fgets(line, sizeof(line), f); + + while (1) { + char *start, *end; + if (!fgets(line, sizeof(line), f)) + break; + start = line; + while (*start == ' ') + start++; + end = strchr(start, ':'); + if (end) + end[0] = '\0'; + if (!is_net_interface_blacklisted(start)) { + log_message("found net interface %s", start); + tmp[i++] = strdup(start); + } else { + log_message("found net interface %s, but blacklisted", start); + } + } + + fclose(f); + } else { + log_message("net: could not open devices file"); } + tmp[i++] = NULL; - return memdup(tmp, sizeof(char *) * i); + return _memdup(tmp, sizeof(char *) * i); + } #endif /* DISABLE_NETWORK */ |