diff options
Diffstat (limited to 'mdk-stage1/probing.c')
| -rw-r--r-- | mdk-stage1/probing.c | 952 |
1 files changed, 636 insertions, 316 deletions
diff --git a/mdk-stage1/probing.c b/mdk-stage1/probing.c index 46bc79acc..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. @@ -22,7 +22,7 @@ /* * This contains stuff related to probing: - * (1) any (actually SCSI and NET only) devices (autoprobe for PCI) + * (1) any (actually only SCSI, NET, CPQ, USB Controllers) devices (autoprobe for PCI and USB) * (2) IDE media * (3) SCSI media * (4) ETH devices @@ -35,382 +35,687 @@ #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-ids.h" +#endif +#ifdef ENABLE_PCMCIA +#include "sysfs/libsysfs.h" +#include "pcmcia-ids.h" +#endif #include "probing.h" -enum bus_type { IDE, SCSI }; - struct media_info { char * name; char * model; enum media_type type; - enum bus_type bus; }; -static void warning_insmod_failed(void) +static void warning_insmod_failed(enum insmod_return r) { - error_message("Warning, installation of driver failed."); + if (IS_AUTOMATIC && r == INSMOD_FAILED_FILE_NOT_FOUND) + return; + if (r != INSMOD_OK) { + if (r == INSMOD_FAILED_FILE_NOT_FOUND) + stg1_error_message("This floppy doesn't contain the driver."); + else + stg1_error_message("Warning, installation of driver failed. (please include msg from <Alt-F3> for bugreports)"); + } } #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) { - intf_descr_for_discover = strdup(intf_descr); + if (detected_devices) + free(detected_devices); } -void net_discovered_interface(char * intf_name) +static struct pcitable_entry *detected_device_new(void) { - if (!intf_descr_for_discover) { - net_intf_too_early_name[net_intf_too_early_number++] = strdup(intf_name); - return; - } - 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; - } - net_descriptions[net_descr_number].intf_name = net_intf_too_early_name[net_intf_too_early_ptr++]; + 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"); } - 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 &detected_devices[detected_devices_len++]; } -char * get_net_intf_description(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) { - 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"); + 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); } -#endif -static void probe_that_type(enum driver_type type) +static int add_detected_device_if_match(struct pciusb_entry *e, char **modules, unsigned int modules_len) { - if (IS_EXPERT) - ask_insmod(type); - else { - /* ---- PCI probe */ - FILE * f; - int len = 0; - char buf[200]; - struct pci_module_map * pcidb = NULL; - - f = fopen("/proc/bus/pci/devices", "rb"); - - if (!f) { - log_message("PCI: could not open proc file"); - return; - } + 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; +} - switch (type) { - case SCSI_ADAPTERS: +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 - pcidb = scsi_pci_ids; - len = scsi_num_ids; + 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 - break; - case NETWORK_DEVICES: + #ifndef DISABLE_NETWORK - pcidb = eth_pci_ids; - len = eth_num_ids; + if (add_detected_device_if_match(e, network_pci_modules, network_pci_modules_len)) + continue; #endif - break; - default: - return; + +#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); + } + 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; } + } + return NULL; +} +#endif - 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: found suggestion for %s (%s)", pcidb[i].name, pcidb[i].module); +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 == SCSI_ADAPTERS) { - /* insmod takes time, let's use the wait message */ - wait_message("Installing %s", pcidb[i].name); - garb = my_insmod(pcidb[i].module, SCSI_ADAPTERS, NULL); - remove_wait_message(); - if (garb) - warning_insmod_failed(); - } + 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) { - /* insmod is quick, let's use the info message */ - info_message("Found %s", pcidb[i].name); - prepare_intf_descr(pcidb[i].name); - if (my_insmod(pcidb[i].module, NETWORK_DEVICES, NULL)) - warning_insmod_failed(); - if (intf_descr_for_discover) /* for modules providing more than one net intf */ - net_discovered_interface(NULL); - } + 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 +} - fclose(f); +void probe_pci_modules(enum driver_type type, char **pci_modules, unsigned int pci_modules_len) { + struct pciusb_entries entries; + int i; + + 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; + } -#ifndef DISABLE_MEDIAS -static struct media_info * medias = NULL; + 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); +} -static void find_media(void) +#ifdef ENABLE_USB +void probe_that_type(enum driver_type type, enum media_bus bus) +#else +void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((unused))) +#endif { - char b[50]; - char buf[500]; - struct media_info tmp[50]; - int count; - int fd; + static int already_probed_usb_controllers = 0; + static int already_loaded_usb_scsi = 0; + static int already_probed_virtio_devices = 0; - if (!medias) - probe_that_type(SCSI_ADAPTERS); - else - free(medias); /* that does not free the strings, by the way */ + /* ---- PCI probe ---------------------------------------------- */ + if (bus != BUS_USB) { + switch (type) { +#ifndef DISABLE_PCIADAPTERS +#ifndef DISABLE_MEDIAS + 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: + probe_pci_modules(type, network_pci_modules, network_pci_modules_len); + break; +#endif +#endif +#ifdef ENABLE_USB + case USB_CONTROLLERS: + if (already_probed_usb_controllers || IS_NOAUTO) + break; + already_probed_usb_controllers = 1; + 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: + break; + } + } - /* ----------------------------------------------- */ - log_message("looking for ide media"); - count = 0; - strcpy(b, "/proc/ide/hd"); - for (b[12] = 'a'; b[12] <= 'h'; b[12]++) { +#ifdef ENABLE_USB + /* ---- USB probe ---------------------------------------------- */ + if ((bus == BUS_USB || bus == BUS_ANY) && !(IS_NOAUTO)) { + static int already_mounted_usbdev = 0; + struct pciusb_entries entries; int i; - - /* 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]; + if (!already_probed_usb_controllers) + probe_that_type(USB_CONTROLLERS, BUS_ANY); - /* media type */ - strcpy(b + 13, "/media"); - fd = open(b, O_RDONLY); - if (fd == -1) { - log_message("failed to open %s for reading", b); - continue; + if (!already_mounted_usbdev) { + already_mounted_usbdev = 1; + wait_message("Detecting USB devices."); + sleep(4); /* sucking background work */ + my_modprobe("usbhid", ANY_DRIVER_TYPE, NULL); + remove_wait_message(); } - i = read(fd, buf, sizeof(buf)); - if (i == -1) { - log_message("failed to read %s", b); - continue; + 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); + } } - buf[i] = '\0'; - close(fd); + pciusb_free(&entries); + end_usb_probe:; + } +#endif - if (!strncmp(buf, "disk", strlen("disk"))) - tmp[count].type = DISK; - else if (!strncmp(buf, "cdrom", strlen("cdrom"))) - tmp[count].type = CDROM; - else if (!strncmp(buf, "tape", strlen("tape"))) - tmp[count].type = TAPE; - else if (!strncmp(buf, "floppy", strlen("floppy"))) - tmp[count].type = FLOPPY; - else - tmp[count].type = UNKNOWN_MEDIA; +#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; - /* media model */ - strcpy(b + 13, "/model"); - fd = open(b, O_RDONLY); - if (fd == -1) { - log_message("failed to open %s for reading", b); - continue; - } + dir = opendir(base); + if (dir == NULL) + goto end_pcmcia_probe; - 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); + 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: + pcmciadb = network_pcmcia_ids; + len = network_pcmcia_num_ids; + break; +#endif + default: + goto end_pcmcia_probe; + } + + 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; + + log_message("PCMCIA: device found %s", dent->d_name); + + 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 (!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); + } + + 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); } - close(fd); + end_pcmcia_probe:; + if (dir) + closedir(dir); + } +#endif - log_message("IDE/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model); - tmp[count].bus = IDE; - count++; - } + /* 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(); + } +} - /* ----------------------------------------------- */ - log_message("looking for scsi media"); +static struct media_info * medias = NULL; + +// 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 buf[5000]; + struct media_info tmp[50]; + int count = 0; + + if (medias) + free(medias); /* that does not free the strings, by the way */ - 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'; + log_message("looking for media adapters"); + probe_that_type(MEDIA_ADAPTERS, bus); - int i = read(fd, &buf, sizeof(buf)); - if (i < 1) { - close(fd); - goto end_scsi; + /* ----------------------------------------------- */ + log_message("looking for DAC960"); + { + FILE * f; + if ((f = fopen("/tmp/syslog", "rb"))) { + while (fgets(buf, sizeof(buf), f)) { + char * start; + if ((start = strstr(buf, "/dev/rd/"))) { + char * end = strchr(start, ':'); + if (!end) + log_message("Inconsistency in syslog, line:\n%s", buf); + else { + *end = '\0'; + tmp[count].name = strdup(start+5); + tmp[count].type = DISK; + start = end + 2; + end = strchr(start, ','); + if (end) { + *end = '\0'; + tmp[count].model = strdup(start); + } else + tmp[count].model = "(unknown)"; + log_message("DAC960: found %s (%s)", tmp[count].name, tmp[count].model); + count++; + } + } + } + fclose(f); } - close(fd); - buf[i] = '\0'; - - if (!strncmp(buf, "Attached devices: none", strlen("Attached devices: none"))) - 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 (strncmp(start, "Attached devices: ", strlen("Attached devices: "))) - goto end_scsi; - state = SCSI_HOST; - break; + } + /* ----------------------------------------------- */ + 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++; + } - case SCSI_HOST: - if (strncmp(start, "Host: ", strlen("Host: "))) - goto end_scsi; - state = SCSI_VENDOR; - break; + pathend = path + strlen(path); - case SCSI_VENDOR: - if (strncmp(start, " Vendor: ", strlen(" 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); + // 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; + } - /* (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; + strcpy(model, "Unknown Disk"); - break; + strcpy(pathend, "/device/vendor"); + vendor_length = read_attribute(path, model); - 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, "scd%c", scsi_cdrom_count++); - tmp[count].type = CDROM; - } + if (vendor_length) { + strcat(model, " "); + vendor_length++; + } - 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); - tmp[count].bus = SCSI; - count++; - } - - state = SCSI_HOST; + 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; } - - start = next; + + tmp[count].name = name; + tmp[count].model = strdup(model); + count++; } - - end_scsi: + globfree(&globbuf); } /* ----------------------------------------------- */ tmp[count].name = NULL; count++; - medias = memdup(tmp, sizeof(struct media_info) * count); + medias = _memdup(tmp, sizeof(struct media_info) * count); } /* Finds by media */ -void get_medias(enum media_type media, char *** names, char *** models) +void get_medias(enum media_type media, char *** names, char *** models, enum media_bus bus) { struct media_info * m; char * tmp_names[50]; char * tmp_models[50]; int count; - find_media(); + find_media(bus); m = medias; @@ -425,59 +730,74 @@ void get_medias(enum media_type media, char *** names, char *** models) 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", - "tr0", - "plip0", "plip1", "plip2", - "fddi0", - 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 */ - probe_that_type(NETWORK_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 */ |
