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