5 * Jordan Hubbard. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
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>
43 /* how much to bias minor number for a given /dev/<ct#><un#>s<s#> slice */
44 #define SLICE_DELTA (0x10000)
46 static Device *Devices[DEV_MAX];
49 #define DEVICE_ENTRY(type, name, descr, max) { type, name, descr, max }
51 #define DISK(name, descr, max) \
52 DEVICE_ENTRY(DEVICE_TYPE_DISK, name, descr, max)
54 static struct _devname {
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),
75 new_device(char *name)
79 dev = safe_malloc(sizeof(Device));
80 bzero(dev, sizeof(Device));
82 SAFE_STRCPY(dev->name, name);
86 /* Stubs for unimplemented strategy routines */
88 dummyInit(Device *dev)
94 dummyGet(Device *dev, char *dist, Boolean probe)
100 dummyShutdown(Device *dev)
106 deviceTry(struct _devname dev, char *try, int i)
111 snprintf(unit, sizeof unit, dev.name, i);
112 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
114 msgDebug("deviceTry: attempting to open %s\n", try);
115 fd = open(try, O_RDONLY);
118 msgDebug("deviceTry: open of %s succeeded.\n", try);
123 /* Register a new device in the devices array */
125 deviceRegister(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)
129 Device *newdev = NULL;
131 if (numDevs == DEV_MAX)
132 msgFatal("Too many devices found!");
134 newdev = new_device(name);
135 newdev->description = desc;
136 newdev->devname = devname;
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;
149 /* Reset the registered device chain */
155 for (i = 0; i < numDevs; i++) {
156 DEVICE_SHUTDOWN(Devices[i]);
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
165 Devices[numDevs = 0] = NULL;
168 /* Get all device information for devices we have attached */
175 msgNotify("Probing devices, please wait (this can take a while)...");
177 /* Next, try to find all the types of devices one might need
178 * during the second stage of the installation.
180 for (i = 0; device_names[i].name; i++) {
181 for (j = 0; j < device_names[i].max; j++) {
182 char try[FILENAME_MAX];
184 switch(device_names[i].type) {
185 case DEVICE_TYPE_DISK:
186 fd = deviceTry(device_names[i], try, j);
195 /* Finally, go get the disks and look for DOS partitions to register */
196 if ((names = Disk_Names()) != NULL) {
199 for (i = 0; names[i]; i++) {
202 /* Ignore memory disks */
203 if (!strncmp(names[i], "md", 2))
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.
217 if (!strncmp(names[i], "cd", 2))
220 d = Open_Disk(names[i]);
222 msgDebug("Unable to open disk %s\n", names[i]);
226 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
227 dummyInit, dummyGet, dummyShutdown, d);
229 msgDebug("Found a disk device named %s\n", names[i]);
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) {
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);
244 msgDebug("Found a DOS partition %s on drive %s\n", c1->name, d->name);
251 dialog_clear_norefresh();
254 /* Rescan all devices, after closing previous set - convenience function */
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().
268 deviceFind(char *name, DeviceType class)
270 static Device *found[DEV_MAX];
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];
280 return j ? found : NULL;
284 deviceFindDescr(char *name, char *desc, DeviceType class)
286 static Device *found[DEV_MAX];
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];
297 return j ? found : NULL;
301 deviceCount(Device **devs)
307 for (i = 0; devs[i]; i++);
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
317 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
324 devs = deviceFind(NULL, type);
325 numdevs = deviceCount(devs);
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;
339 tmp->items[i].title = "<unknown device type>";
340 tmp->items[i].fire = hook;
341 tmp->items[i].checked = check;
343 tmp->items[i].title = NULL;