diff options
Diffstat (limited to 'mdk-stage1/probing.c')
| -rw-r--r-- | mdk-stage1/probing.c | 533 | 
1 files changed, 219 insertions, 314 deletions
| diff --git a/mdk-stage1/probing.c b/mdk-stage1/probing.c index 9dba6e6e8..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. @@ -40,23 +40,27 @@  #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-resource/pcmcia-ids.h" +#include "pcmcia-ids.h"  #endif  #include "probing.h" @@ -82,54 +86,31 @@ static void warning_insmod_failed(enum insmod_return r)  }  #ifndef DISABLE_NETWORK -struct net_description_elem -{ -	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; -  const char * safe_descr(const char * text) {  	return text ? text : "unknown";  } -void prepare_intf_descr(const char * intf_descr) +char * get_net_intf_description(char * intf_name)  { -	intf_descr_for_discover = strdup(intf_descr); -} +	struct ifreq ifr; +	struct ethtool_drvinfo drvinfo; +	int s = socket(AF_INET, SOCK_DGRAM, 0); +	char *res; -void net_discovered_interface(char * intf_name) -{ -	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++]; -	} -	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++; -} +	memset(&ifr, 0, sizeof(ifr)); +	strncpy(ifr.ifr_name, intf_name, IFNAMSIZ); -char * get_net_intf_description(char * intf_name) -{ -	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"); +	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 @@ -272,10 +253,10 @@ void discovered_device(enum driver_type type, const char * description, const ch  	if (type == MEDIA_ADAPTERS) {  		const char * alternate = NULL;  		wait_message("Loading driver for media adapter:\n \n%s", description); -		failed = my_insmod(driver, MEDIA_ADAPTERS, NULL, 1); +		failed = my_modprobe(driver, MEDIA_ADAPTERS, NULL);  		alternate = get_alternate_module(driver);  		if (!IS_NOAUTO && alternate) { -			failed = failed || my_insmod(alternate, MEDIA_ADAPTERS, NULL, 1); +			failed = failed || my_modprobe(alternate, MEDIA_ADAPTERS, NULL);  		}  		remove_wait_message();  		warning_insmod_failed(failed); @@ -283,19 +264,17 @@ void discovered_device(enum driver_type type, const char * description, const ch  #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); -		prepare_intf_descr(description); -		failed = my_insmod(driver, NETWORK_DEVICES, NULL, 1); +		failed = my_modprobe(driver, NETWORK_DEVICES, NULL);  		warning_insmod_failed(failed);  		remove_wait_message(); -		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)                  /* we can't allow additional modules floppy since we need usbhid for keystrokes of usb keyboards */ -		failed = my_insmod(driver, USB_CONTROLLERS, NULL, 0); +		failed = my_modprobe(driver, USB_CONTROLLERS, NULL);  #endif  } @@ -315,6 +294,58 @@ void probe_pci_modules(enum driver_type type, char **pci_modules, unsigned int  	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); +} +  #ifdef ENABLE_USB  void probe_that_type(enum driver_type type, enum media_bus bus)  #else @@ -323,6 +354,7 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u  {          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) { @@ -352,6 +384,12 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u  			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;  		} @@ -370,14 +408,9 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u  		if (!already_mounted_usbdev) {  			already_mounted_usbdev = 1; -			if (mount("none", "/proc/bus/usb", "usbfs", 0, NULL) && -			    mount("none", "/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("usbhid", ANY_DRIVER_TYPE, NULL, 0); +			my_modprobe("usbhid", ANY_DRIVER_TYPE, NULL);  			remove_wait_message();  		} @@ -429,7 +462,7 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u                  for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {  			struct sysfs_attribute *modalias_attr; -			char keyfile[256]; +			char keyfile[300];  			int i, id;  			if (dent->d_name[0] == '.') @@ -492,11 +525,13 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u              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_insmod("usb_storage", MEDIA_ADAPTERS, NULL, 0);  +                my_modprobe("usb_storage", MEDIA_ADAPTERS, NULL);                   if (module_already_present("ieee1394")) -                        my_insmod("sbp2", MEDIA_ADAPTERS, NULL, 0); +                        my_modprobe("sbp2", MEDIA_ADAPTERS, NULL);                  wait_message("Detecting USB mass-storage devices."); +#ifndef DEBUG                  sleep(10); /* sucking background work */ +#endif                  remove_wait_message();          }  } @@ -504,13 +539,38 @@ void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((u  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 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 */ @@ -519,250 +579,6 @@ void find_media(enum media_bus bus)  	probe_that_type(MEDIA_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] <= 't'; 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_PCMCIA && bus != BUS_ANY) -		goto find_media_after_scsi; -	log_message("looking for scsi media"); - -	fd = open("/proc/scsi/scsi", O_RDONLY); -	if (fd != -1) { -                FILE * f; - -		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 (!(f = fopen("/proc/partitions", "rb")) || !fgets(buf, sizeof(buf), f) || !fgets(buf, sizeof(buf), f)) { -                                        log_message("Couldn't open /proc/partitions"); -                                } else { -                                        while (fgets(buf, sizeof(buf), f)) { -                                                char name[100]; -                                                int major, minor, blocks; -                                                memset(name, 0, sizeof(name)); -                                                sscanf(buf, " %d %d %d %s", &major, &minor, &blocks, name); -                                                if (streq(name, tmp_name) && tmp[count].type == DISK && ((blocks == 1048575) || (blocks == 1440))) -                                                        tmp[count].type = FLOPPY; -                                        } -                                        fclose(f); -                                } - -				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 DAC960");  	{  		FILE * f; @@ -792,13 +608,102 @@ 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);  } @@ -825,8 +730,8 @@ 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);  } @@ -854,7 +759,7 @@ char ** get_net_devices(void)  	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);  	} @@ -892,7 +797,7 @@ char ** get_net_devices(void)  	tmp[i++] = NULL; -	return memdup(tmp, sizeof(char *) * i); +	return _memdup(tmp, sizeof(char *) * i);  }  #endif /* DISABLE_NETWORK */ | 
