18208Sjkh/* 250479Speter * $FreeBSD$ 38208Sjkh * 48208Sjkh * Copyright (c) 1995 58208Sjkh * Jordan Hubbard. All rights reserved. 68208Sjkh * 78208Sjkh * Redistribution and use in source and binary forms, with or without 88208Sjkh * modification, are permitted provided that the following conditions 98208Sjkh * are met: 108208Sjkh * 1. Redistributions of source code must retain the above copyright 118881Srgrimes * notice, this list of conditions and the following disclaimer, 128881Srgrimes * verbatim and that no modifications are made prior to this 138208Sjkh * point in the file. 148208Sjkh * 2. Redistributions in binary form must reproduce the above copyright 158208Sjkh * notice, this list of conditions and the following disclaimer in the 168208Sjkh * documentation and/or other materials provided with the distribution. 178208Sjkh * 188208Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 198208Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 208208Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 218208Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 228208Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 238208Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 248208Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 258208Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 268208Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 278208Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 288208Sjkh * SUCH DAMAGE. 298208Sjkh * 308208Sjkh */ 318208Sjkh 32161060Snetchild#include "sade.h" 338441Sjkh#include <sys/fcntl.h> 348549Sjkh#include <sys/param.h> 358549Sjkh#include <sys/socket.h> 368549Sjkh#include <sys/ioctl.h> 3712781Sjkh#include <sys/errno.h> 3820484Sjkh#include <sys/time.h> 39161060Snetchild#include <sys/stat.h> 408549Sjkh#include <ctype.h> 41133040Smarcel#include <libdisk.h> 428208Sjkh 43161060Snetchild/* how much to bias minor number for a given /dev/<ct#><un#>s<s#> slice */ 44161060Snetchild#define SLICE_DELTA (0x10000) 45161060Snetchild 468549Sjkhstatic Device *Devices[DEV_MAX]; 478549Sjkhstatic int numDevs; 488363Sjkh 49161060Snetchild#define DEVICE_ENTRY(type, name, descr, max) { type, name, descr, max } 50156121Sjhb 51161060Snetchild#define DISK(name, descr, max) \ 52156121Sjhb DEVICE_ENTRY(DEVICE_TYPE_DISK, name, descr, max) 53156121Sjhb 5433223Sjkhstatic struct _devname { 558549Sjkh DeviceType type; 568549Sjkh char *name; 578549Sjkh char *description; 58156120Sjhb int max; 598549Sjkh} device_names[] = { 60161060Snetchild DISK("da%d", "SCSI disk device", 16), 61161060Snetchild DISK("ad%d", "ATA/IDE disk device", 16), 62161060Snetchild DISK("ar%d", "ATA/IDE RAID device", 16), 63161060Snetchild DISK("afd%d", "ATAPI/IDE floppy device", 4), 64161060Snetchild DISK("mlxd%d", "Mylex RAID disk", 4), 65161060Snetchild DISK("amrd%d", "AMI MegaRAID drive", 4), 66161060Snetchild DISK("idad%d", "Compaq RAID array", 4), 67161060Snetchild DISK("twed%d", "3ware ATA RAID array", 4), 68161060Snetchild DISK("aacd%d", "Adaptec FSA RAID array", 4), 69161060Snetchild DISK("ipsd%d", "IBM ServeRAID RAID array", 4), 70161060Snetchild DISK("mfid%d", "LSI MegaRAID SAS array", 4), 71161060Snetchild { 0, NULL, NULL, 0 }, 728549Sjkh}; 738262Sjkh 748641SjkhDevice * 758549Sjkhnew_device(char *name) 768208Sjkh{ 778549Sjkh Device *dev; 788549Sjkh 798549Sjkh dev = safe_malloc(sizeof(Device)); 809202Srgrimes bzero(dev, sizeof(Device)); 818549Sjkh if (name) 8220247Sjkh SAFE_STRCPY(dev->name, name); 838549Sjkh return dev; 848262Sjkh} 858208Sjkh 869202Srgrimes/* Stubs for unimplemented strategy routines */ 879202SrgrimesBoolean 889202SrgrimesdummyInit(Device *dev) 899202Srgrimes{ 909202Srgrimes return TRUE; 919202Srgrimes} 929202Srgrimes 9320315SjkhFILE * 9414321SjkhdummyGet(Device *dev, char *dist, Boolean probe) 959202Srgrimes{ 9620315Sjkh return NULL; 979202Srgrimes} 989202Srgrimes 999202Srgrimesvoid 1009202SrgrimesdummyShutdown(Device *dev) 1019202Srgrimes{ 1029202Srgrimes return; 1039202Srgrimes} 1049202Srgrimes 1058549Sjkhstatic int 10633223SjkhdeviceTry(struct _devname dev, char *try, int i) 1078262Sjkh{ 1088556Sjkh int fd; 10933223Sjkh char unit[80]; 1108262Sjkh 11133223Sjkh snprintf(unit, sizeof unit, dev.name, i); 11233223Sjkh snprintf(try, FILENAME_MAX, "/dev/%s", unit); 11357490Sjkh if (isDebug()) 11457490Sjkh msgDebug("deviceTry: attempting to open %s\n", try); 11534625Sjkh fd = open(try, O_RDONLY); 11657490Sjkh if (fd >= 0) { 11757490Sjkh if (isDebug()) 118161060Snetchild msgDebug("deviceTry: open of %s succeeded.\n", try); 11957490Sjkh } 1208549Sjkh return fd; 1218208Sjkh} 1228208Sjkh 1238641Sjkh/* Register a new device in the devices array */ 1248641SjkhDevice * 1258641SjkhdeviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled, 12620315Sjkh Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean), 12720315Sjkh void (*shutdown)(Device *), void *private) 1288641Sjkh{ 12916348Sjkh Device *newdev = NULL; 1308641Sjkh 1318641Sjkh if (numDevs == DEV_MAX) 1328641Sjkh msgFatal("Too many devices found!"); 13316330Sjkh else { 13416330Sjkh newdev = new_device(name); 13516330Sjkh newdev->description = desc; 13616330Sjkh newdev->devname = devname; 13716330Sjkh newdev->type = type; 13816330Sjkh newdev->enabled = enabled; 13916330Sjkh newdev->init = init ? init : dummyInit; 14016330Sjkh newdev->get = get ? get : dummyGet; 14116330Sjkh newdev->shutdown = shutdown ? shutdown : dummyShutdown; 14216330Sjkh newdev->private = private; 14316330Sjkh Devices[numDevs] = newdev; 14416330Sjkh Devices[++numDevs] = NULL; 14516330Sjkh } 1468641Sjkh return newdev; 1478641Sjkh} 1488722Sjkh 14945371Sjkh/* Reset the registered device chain */ 15045371Sjkhvoid 15145371SjkhdeviceReset(void) 15245371Sjkh{ 15345371Sjkh int i; 15445371Sjkh 15545371Sjkh for (i = 0; i < numDevs; i++) { 15679065Sdd DEVICE_SHUTDOWN(Devices[i]); 15745371Sjkh 15845371Sjkh /* XXX this potentially leaks Devices[i]->private if it's being 15945371Sjkh * used to point to something dynamic, but you're not supposed 16045371Sjkh * to call this routine at such times that some open instance 16145371Sjkh * has its private ptr pointing somewhere anyway. XXX 16245371Sjkh */ 16345371Sjkh free(Devices[i]); 16445371Sjkh } 16545371Sjkh Devices[numDevs = 0] = NULL; 16645371Sjkh} 16745371Sjkh 1688549Sjkh/* Get all device information for devices we have attached */ 1698549Sjkhvoid 1708556SjkhdeviceGetAll(void) 1718208Sjkh{ 172161099Sdelphij int i, j, fd; 1738556Sjkh char **names; 1748208Sjkh 17539800Sdanny msgNotify("Probing devices, please wait (this can take a while)..."); 17618704Sjkh 17733223Sjkh /* Next, try to find all the types of devices one might need 17818704Sjkh * during the second stage of the installation. 1798549Sjkh */ 1808549Sjkh for (i = 0; device_names[i].name; i++) { 18133223Sjkh for (j = 0; j < device_names[i].max; j++) { 18233223Sjkh char try[FILENAME_MAX]; 1838636Sjkh 18433223Sjkh switch(device_names[i].type) { 18533223Sjkh case DEVICE_TYPE_DISK: 18633223Sjkh fd = deviceTry(device_names[i], try, j); 18733223Sjkh break; 18833223Sjkh 18933223Sjkh default: 19033223Sjkh break; 1918576Sjkh } 19233223Sjkh } 19333223Sjkh } 1948576Sjkh 19533223Sjkh /* Finally, go get the disks and look for DOS partitions to register */ 19633223Sjkh if ((names = Disk_Names()) != NULL) { 19733223Sjkh int i; 19816348Sjkh 19933223Sjkh for (i = 0; names[i]; i++) { 20033223Sjkh Disk *d; 20133223Sjkh 20262620Sjkh /* Ignore memory disks */ 203111918Ssobomax if (!strncmp(names[i], "md", 2)) 20462577Sphk continue; 20562620Sjkh 206139168Syongari /* 207139168Syongari * XXX 208139168Syongari * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a 209139168Syongari * valid disk. This is main reason why sysinstall presents SCSI 210139168Syongari * CDROM to available disks in Fdisk/Label menu. In addition, 211139168Syongari * adding a blank SCSI CDROM to the menu generates floating point 212139168Syongari * exception in sparc64. Disk_Names() just extracts sysctl 213139168Syongari * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond 214139168Syongari * me and that should be investigated. 215139168Syongari * For temporary workaround, ignore SCSI CDROM device. 216139168Syongari */ 217139168Syongari if (!strncmp(names[i], "cd", 2)) 218139168Syongari continue; 219139168Syongari 22033223Sjkh d = Open_Disk(names[i]); 22162577Sphk if (!d) { 222106279Skuriyama msgDebug("Unable to open disk %s\n", names[i]); 22362577Sphk continue; 22462577Sphk } 22533223Sjkh 22633223Sjkh deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE, 22733223Sjkh dummyInit, dummyGet, dummyShutdown, d); 22857490Sjkh if (isDebug()) 22957490Sjkh msgDebug("Found a disk device named %s\n", names[i]); 23033223Sjkh 231161060Snetchild#if 0 23233223Sjkh /* Look for existing DOS partitions to register as "DOS media devices" */ 23333223Sjkh for (c1 = d->chunks->part; c1; c1 = c1->next) { 234106839Smarcel if (c1->type == fat || c1->type == efi || c1->type == extended) { 23533223Sjkh Device *dev; 23633223Sjkh char devname[80]; 23733223Sjkh 23833223Sjkh /* Got one! */ 23933223Sjkh snprintf(devname, sizeof devname, "/dev/%s", c1->name); 24033223Sjkh dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE, 241161060Snetchild mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL); 24233223Sjkh dev->private = c1; 24357490Sjkh if (isDebug()) 24457490Sjkh msgDebug("Found a DOS partition %s on drive %s\n", c1->name, d->name); 24533223Sjkh } 2468623Sjkh } 247161060Snetchild#endif 2488549Sjkh } 24933223Sjkh free(names); 2508549Sjkh } 25154722Sjkh dialog_clear_norefresh(); 2528549Sjkh} 2538281Sjkh 25445371Sjkh/* Rescan all devices, after closing previous set - convenience function */ 25545371Sjkhvoid 25645371SjkhdeviceRescan(void) 25745371Sjkh{ 25845371Sjkh deviceReset(); 25945371Sjkh deviceGetAll(); 26045371Sjkh} 26145371Sjkh 2628549Sjkh/* 2638549Sjkh * Find all devices that match the criteria, allowing "wildcarding" as well 2648641Sjkh * by allowing NULL or ANY values to match all. The array returned is static 2658641Sjkh * and may be used until the next invocation of deviceFind(). 2668549Sjkh */ 2678549SjkhDevice ** 2688549SjkhdeviceFind(char *name, DeviceType class) 2698549Sjkh{ 2708549Sjkh static Device *found[DEV_MAX]; 2718549Sjkh int i, j; 2728307Sjkh 27321276Sjkh j = 0; 27421276Sjkh for (i = 0; i < numDevs; i++) { 2758576Sjkh if ((!name || !strcmp(Devices[i]->name, name)) 2768576Sjkh && (class == DEVICE_TYPE_ANY || class == Devices[i]->type)) 2778549Sjkh found[j++] = Devices[i]; 2788208Sjkh } 2798549Sjkh found[j] = NULL; 2808549Sjkh return j ? found : NULL; 2818208Sjkh} 2828262Sjkh 28321730SjkhDevice ** 28421730SjkhdeviceFindDescr(char *name, char *desc, DeviceType class) 28521730Sjkh{ 28621730Sjkh static Device *found[DEV_MAX]; 28721730Sjkh int i, j; 28821730Sjkh 28921730Sjkh j = 0; 29021730Sjkh for (i = 0; i < numDevs; i++) { 29121730Sjkh if ((!name || !strcmp(Devices[i]->name, name)) && 29221730Sjkh (!desc || !strcmp(Devices[i]->description, desc)) && 29321730Sjkh (class == DEVICE_TYPE_ANY || class == Devices[i]->type)) 29421730Sjkh found[j++] = Devices[i]; 29521730Sjkh } 29621730Sjkh found[j] = NULL; 29721730Sjkh return j ? found : NULL; 29821730Sjkh} 29921730Sjkh 3008636Sjkhint 3018636SjkhdeviceCount(Device **devs) 3028636Sjkh{ 3038636Sjkh int i; 3048636Sjkh 3058636Sjkh if (!devs) 3068636Sjkh return 0; 3078636Sjkh for (i = 0; devs[i]; i++); 3088636Sjkh return i; 3098636Sjkh} 3108636Sjkh 3118262Sjkh/* 3128549Sjkh * Create a menu listing all the devices of a certain type in the system. 3138549Sjkh * The passed-in menu is expected to be a "prototype" from which the new 3148549Sjkh * menu is cloned. 3158262Sjkh */ 3168262SjkhDMenu * 31715242SjkhdeviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d)) 3188262Sjkh{ 3198549Sjkh Device **devs; 3208556Sjkh int numdevs; 3218556Sjkh DMenu *tmp = NULL; 3228556Sjkh int i, j; 3238262Sjkh 3248549Sjkh devs = deviceFind(NULL, type); 32516348Sjkh numdevs = deviceCount(devs); 32616348Sjkh if (!numdevs) 3278556Sjkh return NULL; 32815091Sjkh tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1))); 3298556Sjkh bcopy(menu, tmp, sizeof(DMenu)); 3308556Sjkh for (i = 0; devs[i]; i++) { 33115091Sjkh tmp->items[i].prompt = devs[i]->name; 33216348Sjkh for (j = 0; j < numDevs; j++) { 33316348Sjkh if (devs[i] == Devices[j]) { 33416348Sjkh tmp->items[i].title = Devices[j]->description; 3358556Sjkh break; 3368549Sjkh } 3378262Sjkh } 33816348Sjkh if (j == numDevs) 33915091Sjkh tmp->items[i].title = "<unknown device type>"; 34015091Sjkh tmp->items[i].fire = hook; 34115242Sjkh tmp->items[i].checked = check; 3428262Sjkh } 3438556Sjkh tmp->items[i].title = NULL; 3448556Sjkh return tmp; 3458262Sjkh} 346