diff options
Diffstat (limited to 'mdk-stage1/probing.c')
| -rw-r--r-- | mdk-stage1/probing.c | 959 | 
1 files changed, 635 insertions, 324 deletions
| diff --git a/mdk-stage1/probing.c b/mdk-stage1/probing.c index 93c1614ba..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,391 +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); +	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++]; +} + +/* 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) +{ +	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);  } -#endif -static void probe_that_type(enum driver_type type) +/** 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)  { -	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; +	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); +} + +#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 +{ +        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) { -		case SCSI_ADAPTERS: +#ifndef DISABLE_PCIADAPTERS  #ifndef DISABLE_MEDIAS -			pcidb = scsi_pci_ids; -			len   = scsi_num_ids; -#endif +			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; -		case NETWORK_DEVICES: +#endif  #ifndef DISABLE_NETWORK -			pcidb = eth_pci_ids; -			len   = eth_num_ids; +		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: -			return; +			break;  		} +	} -		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); + +#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; + +		if (!already_probed_usb_controllers) +			probe_that_type(USB_CONTROLLERS, BUS_ANY); + +		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(); +		} + +		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 -					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(); -					} +		case MEDIA_ADAPTERS: +			pcmciadb = medias_pcmcia_ids; +			len      = medias_pcmcia_num_ids; +			break;  #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); -					} +		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);  				}  			} -		} -		fclose(f); +			sysfs_close_attribute(modalias_attr); +		} +	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(void) +// 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; -        int fd; +	int count = 0; -	if (!medias) -		probe_that_type(SCSI_ADAPTERS); -	else +	if (medias)  		free(medias); /* that does not free the strings, by the way */ -	/* ----------------------------------------------- */ -	log_message("looking for ide media"); - -    	count = 0; -    	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; +	log_message("looking for media adapters"); +	probe_that_type(MEDIA_ADAPTERS, bus); -		/* media model */ -		strcpy(b + 13, "/model"); -		fd = open(b, O_RDONLY); -		if (fd == -1) { -			log_message("failed to open %s for reading", b); -			continue; +	/* ----------------------------------------------- */ +	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);  		} +	} +	/* ----------------------------------------------- */ +	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++; +			} -		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); +			pathend = path + strlen(path); -		log_message("IDE/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model); -		tmp[count].bus = IDE; -		count++; -    	} +			// 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"); -	/* ----------------------------------------------- */ -	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; +			strcpy(pathend, "/device/vendor"); +			vendor_length = read_attribute(path, model); -			case SCSI_HOST: -				if (!ptr_begins_static_str(start, scsi_host)) -					goto end_scsi; -				state = SCSI_VENDOR; -				break; +			if (vendor_length) { +				strcat(model, " "); +				vendor_length++; +			} -			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); -				} +			strcpy(pathend, "/device/model"); +			read_attribute(path, model+vendor_length); -				/* (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(pathend, "/capability"); +			read_attribute(path, buf); +			long caps = strtol(buf, NULL, 16); -				break; +			// 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; +			} -			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 (caps & 0x0400) { +				log_message("Ignoring device %s (hidden)", name); +				free(name); +				continue; +			} -				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; +			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; @@ -434,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 */ | 
