1/* 2 * $FreeBSD$ 3 * 4 * Copyright (c) 1995 5 * Jordan Hubbard. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * verbatim and that no modifications are made prior to this 13 * point in the file. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32#include "sade.h" 33#include <sys/fcntl.h> 34#include <sys/param.h> 35#include <sys/socket.h> 36#include <sys/ioctl.h> 37#include <sys/errno.h> 38#include <sys/time.h> 39#include <sys/stat.h> 40#include <ctype.h> 41#include <libdisk.h> 42 43/* how much to bias minor number for a given /dev/<ct#><un#>s<s#> slice */ 44#define SLICE_DELTA (0x10000) 45 46static Device *Devices[DEV_MAX]; 47static int numDevs; 48 49#define DEVICE_ENTRY(type, name, descr, max) { type, name, descr, max } 50 51#define DISK(name, descr, max) \ 52 DEVICE_ENTRY(DEVICE_TYPE_DISK, name, descr, max) 53 54static struct _devname { 55 DeviceType type; 56 char *name; 57 char *description; 58 int max; 59} device_names[] = { 60 DISK("da%d", "SCSI disk device", 16), 61 DISK("ad%d", "ATA/IDE disk device", 16), 62 DISK("ar%d", "ATA/IDE RAID device", 16), 63 DISK("afd%d", "ATAPI/IDE floppy device", 4), 64 DISK("mlxd%d", "Mylex RAID disk", 4), 65 DISK("amrd%d", "AMI MegaRAID drive", 4), 66 DISK("idad%d", "Compaq RAID array", 4), 67 DISK("twed%d", "3ware ATA RAID array", 4), 68 DISK("aacd%d", "Adaptec FSA RAID array", 4), 69 DISK("ipsd%d", "IBM ServeRAID RAID array", 4), 70 DISK("mfid%d", "LSI MegaRAID SAS array", 4), 71 { 0, NULL, NULL, 0 }, 72}; 73 74Device * 75new_device(char *name) 76{ 77 Device *dev; 78 79 dev = safe_malloc(sizeof(Device)); 80 bzero(dev, sizeof(Device)); 81 if (name) 82 SAFE_STRCPY(dev->name, name); 83 return dev; 84} 85 86/* Stubs for unimplemented strategy routines */ 87Boolean 88dummyInit(Device *dev) 89{ 90 return TRUE; 91} 92 93FILE * 94dummyGet(Device *dev, char *dist, Boolean probe) 95{ 96 return NULL; 97} 98 99void 100dummyShutdown(Device *dev) 101{ 102 return; 103} 104 105static int 106deviceTry(struct _devname dev, char *try, int i) 107{ 108 int fd; 109 char unit[80]; 110 111 snprintf(unit, sizeof unit, dev.name, i); 112 snprintf(try, FILENAME_MAX, "/dev/%s", unit); 113 if (isDebug()) 114 msgDebug("deviceTry: attempting to open %s\n", try); 115 fd = open(try, O_RDONLY); 116 if (fd >= 0) { 117 if (isDebug()) 118 msgDebug("deviceTry: open of %s succeeded.\n", try); 119 } 120 return fd; 121} 122 123/* Register a new device in the devices array */ 124Device * 125deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled, 126 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean), 127 void (*shutdown)(Device *), void *private) 128{ 129 Device *newdev = NULL; 130 131 if (numDevs == DEV_MAX) 132 msgFatal("Too many devices found!"); 133 else { 134 newdev = new_device(name); 135 newdev->description = desc; 136 newdev->devname = devname; 137 newdev->type = type; 138 newdev->enabled = enabled; 139 newdev->init = init ? init : dummyInit; 140 newdev->get = get ? get : dummyGet; 141 newdev->shutdown = shutdown ? shutdown : dummyShutdown; 142 newdev->private = private; 143 Devices[numDevs] = newdev; 144 Devices[++numDevs] = NULL; 145 } 146 return newdev; 147} 148 149/* Reset the registered device chain */ 150void 151deviceReset(void) 152{ 153 int i; 154 155 for (i = 0; i < numDevs; i++) { 156 DEVICE_SHUTDOWN(Devices[i]); 157 158 /* XXX this potentially leaks Devices[i]->private if it's being 159 * used to point to something dynamic, but you're not supposed 160 * to call this routine at such times that some open instance 161 * has its private ptr pointing somewhere anyway. XXX 162 */ 163 free(Devices[i]); 164 } 165 Devices[numDevs = 0] = NULL; 166} 167 168/* Get all device information for devices we have attached */ 169void 170deviceGetAll(void) 171{ 172 int i, j, fd; 173 char **names; 174 175 msgNotify("Probing devices, please wait (this can take a while)..."); 176 177 /* Next, try to find all the types of devices one might need 178 * during the second stage of the installation. 179 */ 180 for (i = 0; device_names[i].name; i++) { 181 for (j = 0; j < device_names[i].max; j++) { 182 char try[FILENAME_MAX]; 183 184 switch(device_names[i].type) { 185 case DEVICE_TYPE_DISK: 186 fd = deviceTry(device_names[i], try, j); 187 break; 188 189 default: 190 break; 191 } 192 } 193 } 194 195 /* Finally, go get the disks and look for DOS partitions to register */ 196 if ((names = Disk_Names()) != NULL) { 197 int i; 198 199 for (i = 0; names[i]; i++) { 200 Disk *d; 201 202 /* Ignore memory disks */ 203 if (!strncmp(names[i], "md", 2)) 204 continue; 205 206 /* 207 * XXX 208 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a 209 * valid disk. This is main reason why sysinstall presents SCSI 210 * CDROM to available disks in Fdisk/Label menu. In addition, 211 * adding a blank SCSI CDROM to the menu generates floating point 212 * exception in sparc64. Disk_Names() just extracts sysctl 213 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond 214 * me and that should be investigated. 215 * For temporary workaround, ignore SCSI CDROM device. 216 */ 217 if (!strncmp(names[i], "cd", 2)) 218 continue; 219 220 d = Open_Disk(names[i]); 221 if (!d) { 222 msgDebug("Unable to open disk %s\n", names[i]); 223 continue; 224 } 225 226 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE, 227 dummyInit, dummyGet, dummyShutdown, d); 228 if (isDebug()) 229 msgDebug("Found a disk device named %s\n", names[i]); 230 231#if 0 232 /* Look for existing DOS partitions to register as "DOS media devices" */ 233 for (c1 = d->chunks->part; c1; c1 = c1->next) { 234 if (c1->type == fat || c1->type == efi || c1->type == extended) { 235 Device *dev; 236 char devname[80]; 237 238 /* Got one! */ 239 snprintf(devname, sizeof devname, "/dev/%s", c1->name); 240 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE, 241 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL); 242 dev->private = c1; 243 if (isDebug()) 244 msgDebug("Found a DOS partition %s on drive %s\n", c1->name, d->name); 245 } 246 } 247#endif 248 } 249 free(names); 250 } 251 dialog_clear_norefresh(); 252} 253 254/* Rescan all devices, after closing previous set - convenience function */ 255void 256deviceRescan(void) 257{ 258 deviceReset(); 259 deviceGetAll(); 260} 261 262/* 263 * Find all devices that match the criteria, allowing "wildcarding" as well 264 * by allowing NULL or ANY values to match all. The array returned is static 265 * and may be used until the next invocation of deviceFind(). 266 */ 267Device ** 268deviceFind(char *name, DeviceType class) 269{ 270 static Device *found[DEV_MAX]; 271 int i, j; 272 273 j = 0; 274 for (i = 0; i < numDevs; i++) { 275 if ((!name || !strcmp(Devices[i]->name, name)) 276 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type)) 277 found[j++] = Devices[i]; 278 } 279 found[j] = NULL; 280 return j ? found : NULL; 281} 282 283Device ** 284deviceFindDescr(char *name, char *desc, DeviceType class) 285{ 286 static Device *found[DEV_MAX]; 287 int i, j; 288 289 j = 0; 290 for (i = 0; i < numDevs; i++) { 291 if ((!name || !strcmp(Devices[i]->name, name)) && 292 (!desc || !strcmp(Devices[i]->description, desc)) && 293 (class == DEVICE_TYPE_ANY || class == Devices[i]->type)) 294 found[j++] = Devices[i]; 295 } 296 found[j] = NULL; 297 return j ? found : NULL; 298} 299 300int 301deviceCount(Device **devs) 302{ 303 int i; 304 305 if (!devs) 306 return 0; 307 for (i = 0; devs[i]; i++); 308 return i; 309} 310 311/* 312 * Create a menu listing all the devices of a certain type in the system. 313 * The passed-in menu is expected to be a "prototype" from which the new 314 * menu is cloned. 315 */ 316DMenu * 317deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d)) 318{ 319 Device **devs; 320 int numdevs; 321 DMenu *tmp = NULL; 322 int i, j; 323 324 devs = deviceFind(NULL, type); 325 numdevs = deviceCount(devs); 326 if (!numdevs) 327 return NULL; 328 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1))); 329 bcopy(menu, tmp, sizeof(DMenu)); 330 for (i = 0; devs[i]; i++) { 331 tmp->items[i].prompt = devs[i]->name; 332 for (j = 0; j < numDevs; j++) { 333 if (devs[i] == Devices[j]) { 334 tmp->items[i].title = Devices[j]->description; 335 break; 336 } 337 } 338 if (j == numDevs) 339 tmp->items[i].title = "<unknown device type>"; 340 tmp->items[i].fire = hook; 341 tmp->items[i].checked = check; 342 } 343 tmp->items[i].title = NULL; 344 return tmp; 345} 346