2 * The new sysinstall program.
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
10 * Jordan Hubbard. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer,
17 * verbatim and that no modifications are made prior to this
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "sysinstall.h"
38 #include <sys/fcntl.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/errno.h>
45 #include <net/if_var.h>
46 #include <net/if_dl.h>
47 #include <netinet/in.h>
48 #include <netinet/in_var.h>
49 #include <arpa/inet.h>
53 static Device *Devices[DEV_MAX];
56 #define DEVICE_ENTRY(type, name, descr, max) { type, name, descr, max }
58 #define CDROM(name, descr, max) \
59 DEVICE_ENTRY(DEVICE_TYPE_CDROM, name, descr, max)
60 #define DISK(name, descr, max) \
61 DEVICE_ENTRY(DEVICE_TYPE_DISK, name, descr, max)
62 #define FLOPPY(name, descr, max) \
63 DEVICE_ENTRY(DEVICE_TYPE_FLOPPY, name, descr, max)
64 #define NETWORK(name, descr) \
65 DEVICE_ENTRY(DEVICE_TYPE_NETWORK, name, descr, 0)
66 #define SERIAL(name, descr, max) \
67 DEVICE_ENTRY(DEVICE_TYPE_NETWORK, name, descr, max)
68 #define USB(name, descr, max) \
69 DEVICE_ENTRY(DEVICE_TYPE_USB, name, descr, max)
71 static struct _devname {
77 CDROM("cd%d", "SCSI CDROM drive", 4),
78 CDROM("mcd%d", "Mitsumi (old model) CDROM drive", 4),
79 CDROM("scd%d", "Sony CDROM drive - CDU31/33A type", 4),
80 CDROM("acd%d", "ATAPI/IDE CDROM", 4),
81 DISK("da%d", "SCSI disk device", 16),
82 DISK("ad%d", "ATA/IDE disk device", 16),
83 DISK("ada%d", "SATA disk device", 16),
84 DISK("ar%d", "ATA/IDE RAID device", 16),
85 DISK("afd%d", "ATAPI/IDE floppy device", 4),
86 DISK("mlxd%d", "Mylex RAID disk", 4),
87 DISK("amrd%d", "AMI MegaRAID drive", 4),
88 DISK("idad%d", "Compaq RAID array", 4),
89 DISK("twed%d", "3ware ATA RAID array", 4),
90 DISK("aacd%d", "Adaptec FSA RAID array", 4),
91 DISK("ipsd%d", "IBM ServeRAID RAID array", 4),
92 DISK("mfid%d", "LSI MegaRAID SAS array", 4),
93 FLOPPY("fd%d", "floppy drive unit A", 4),
94 SERIAL("cuau%d", "%s on device %s (COM%d)", 16),
95 USB("da%da", "USB Mass Storage Device", 16),
96 NETWORK("ae", "Attansic/Atheros L2 Fast Ethernet"),
97 NETWORK("age", "Attansic/Atheros L1 Gigabit Ethernet"),
98 NETWORK("alc", "Atheros AR8131/AR8132 PCIe Ethernet"),
99 NETWORK("ale", "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"),
100 NETWORK("an", "Aironet 4500/4800 802.11 wireless adapter"),
101 NETWORK("ath", "Atheros IEEE 802.11 wireless adapter"),
102 NETWORK("aue", "ADMtek USB Ethernet adapter"),
103 NETWORK("axe", "ASIX Electronics USB Ethernet adapter"),
104 NETWORK("bce", "Broadcom NetXtreme II Gigabit Ethernet card"),
105 NETWORK("bfe", "Broadcom BCM440x PCI Ethernet card"),
106 NETWORK("bge", "Broadcom BCM570x PCI Gigabit Ethernet card"),
107 NETWORK("bm", "Apple BMAC Built-in Ethernet"),
108 NETWORK("bwn", "Broadcom BCM43xx IEEE 802.11 wireless adapter"),
109 NETWORK("cas", "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"),
110 NETWORK("cue", "CATC USB Ethernet adapter"),
111 NETWORK("cxgb", "Chelsio T3 10Gb Ethernet card"),
112 NETWORK("cxgbe", "Chelsio T4 10Gb Ethernet card"),
113 NETWORK("fpa", "DEC DEFPA PCI FDDI card"),
114 NETWORK("sr", "SDL T1/E1 sync serial PCI card"),
115 NETWORK("cc3i", "SDL HSSI sync serial PCI card"),
116 NETWORK("en", "Efficient Networks ATM PCI card"),
117 NETWORK("dc", "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"),
118 NETWORK("de", "DEC DE435 PCI NIC or other DC21040-AA based card"),
119 NETWORK("fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card"),
120 NETWORK("ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"),
121 NETWORK("ep", "3Com 3C509 Ethernet card/3C589 PCMCIA"),
122 NETWORK("em", "Intel(R) PRO/1000 Ethernet card"),
123 NETWORK("et", "Agere ET1310 based PCI Express Gigabit Ethernet card"),
124 NETWORK("ex", "Intel EtherExpress Pro/10 Ethernet card"),
125 NETWORK("fe", "Fujitsu MB86960A/MB86965A Ethernet card"),
126 NETWORK("gem", "Apple GMAC or Sun ERI/GEM Ethernet adapter"),
127 NETWORK("hme", "Sun HME (Happy Meal Ethernet) Ethernet adapter"),
128 NETWORK("ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"),
129 NETWORK("igb", "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"),
130 NETWORK("ipw", "Intel PRO/Wireless 2100 IEEE 802.11 adapter"),
131 NETWORK("iwi", "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"),
132 NETWORK("iwn", "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"),
133 NETWORK("ixgb", "Intel(R) PRO/10Gb Ethernet card"),
134 NETWORK("ixgbe", "Intel(R) PRO/10Gb Ethernet card"),
135 NETWORK("jme", "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"),
136 NETWORK("kue", "Kawasaki LSI USB Ethernet adapter"),
137 NETWORK("le", "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"),
138 NETWORK("lge", "Level 1 LXT1001 Gigabit Ethernet card"),
139 NETWORK("malo", "Marvell Libertas 88W8335 802.11 wireless adapter"),
140 NETWORK("msk", "Marvell/SysKonnect Yukon II Gigabit Ethernet"),
141 NETWORK("mxge", "Myricom Myri10GE 10Gb Ethernet card"),
142 NETWORK("nfe", "NVIDIA nForce MCP Ethernet"),
143 NETWORK("nge", "NatSemi PCI Gigabit Ethernet card"),
144 NETWORK("nve", "NVIDIA nForce MCP Ethernet"),
145 NETWORK("nxge", "Neterion Xframe 10GbE Server/Storage adapter"),
146 NETWORK("pcn", "AMD Am79c79x PCI Ethernet card"),
147 NETWORK("ral", "Ralink Technology IEEE 802.11 wireless adapter"),
148 NETWORK("ray", "Raytheon Raylink 802.11 wireless adapter"),
149 NETWORK("re", "RealTek 8139C+/8169/8169S/8110S PCI Ethernet card"),
150 NETWORK("rl", "RealTek 8129/8139 PCI Ethernet card"),
151 NETWORK("rue", "RealTek USB Ethernet card"),
152 NETWORK("rum", "Ralink Technology USB IEEE 802.11 wireless adapter"),
153 NETWORK("sf", "Adaptec AIC-6915 PCI Ethernet card"),
154 NETWORK("sge", "Silicon Integrated Systems SiS190/191 Ethernet"),
155 NETWORK("sis", "SiS 900/SiS 7016 PCI Ethernet card"),
157 NETWORK("snc", "SONIC Ethernet card"),
159 NETWORK("sn", "SMC/Megahertz Ethernet card"),
160 NETWORK("ste", "Sundance ST201 PCI Ethernet card"),
161 NETWORK("stge", "Sundance/Tamarack TC9021 Gigabit Ethernet"),
162 NETWORK("sk", "SysKonnect PCI Gigabit Ethernet card"),
163 NETWORK("tx", "SMC 9432TX Ethernet card"),
164 NETWORK("txp", "3Com 3cR990 Ethernet card"),
165 NETWORK("ti", "Alteon Networks PCI Gigabit Ethernet card"),
166 NETWORK("tl", "Texas Instruments ThunderLAN PCI Ethernet card"),
167 NETWORK("uath", "Atheros AR5005UG and AR5005UX USB wireless adapter"),
168 NETWORK("upgt", "Conexant/Intersil PrismGT USB wireless adapter"),
169 NETWORK("ural", "Ralink Technology RT2500USB 802.11 wireless adapter"),
170 NETWORK("urtw", "Realtek 8187L USB wireless adapter"),
171 NETWORK("vge", "VIA VT612x PCI Gigabit Ethernet card"),
172 NETWORK("vr", "VIA VT3043/VT86C100A Rhine PCI Ethernet card"),
173 NETWORK("vte", "DM&P Vortex86 RDC R6040 Fast Ethernet"),
174 NETWORK("vlan", "IEEE 802.1Q VLAN network interface"),
175 NETWORK("vx", "3COM 3c590 / 3c595 Ethernet card"),
176 NETWORK("wb", "Winbond W89C840F PCI Ethernet card"),
177 NETWORK("wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter"),
178 NETWORK("wpi", "Intel 3945ABG IEEE 802.11 wireless adapter"),
179 NETWORK("xe", "Xircom/Intel EtherExpress Pro100/16 Ethernet card"),
180 NETWORK("xl", "3COM 3c90x / 3c90xB PCI Ethernet card"),
181 NETWORK("zyd", "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"),
182 NETWORK("fwe", "FireWire Ethernet emulation"),
183 NETWORK("fwip", "IP over FireWire"),
184 NETWORK("plip", "Parallel Port IP (PLIP) peer connection"),
185 NETWORK("lo", "Loop-back (local) network interface"),
186 NETWORK("disc", "Software discard network interface"),
191 new_device(char *name)
195 dev = safe_malloc(sizeof(Device));
196 bzero(dev, sizeof(Device));
198 SAFE_STRCPY(dev->name, name);
202 /* Stubs for unimplemented strategy routines */
204 dummyInit(Device *dev)
210 dummyGet(Device *dev, char *dist, Boolean probe)
216 dummyShutdown(Device *dev)
222 deviceTry(struct _devname dev, char *try, int i)
227 snprintf(unit, sizeof unit, dev.name, i);
228 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
230 msgDebug("deviceTry: attempting to open %s\n", try);
231 fd = open(try, O_RDONLY);
234 msgDebug("deviceTry: open of %s succeeded on first try.\n", try);
237 msgDebug("deviceTry: open of %s failed.\n", try);
242 /* Register a new device in the devices array */
244 deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled,
245 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean),
246 void (*shutdown)(Device *), void *private)
248 Device *newdev = NULL;
250 if (numDevs == DEV_MAX)
251 msgFatal("Too many devices found!");
253 newdev = new_device(name);
254 newdev->description = desc;
255 newdev->devname = devname;
257 newdev->enabled = enabled;
258 newdev->init = init ? init : dummyInit;
259 newdev->get = get ? get : dummyGet;
260 newdev->shutdown = shutdown ? shutdown : dummyShutdown;
261 newdev->private = private;
262 Devices[numDevs] = newdev;
263 Devices[++numDevs] = NULL;
268 /* Reset the registered device chain */
274 for (i = 0; i < numDevs; i++) {
275 DEVICE_SHUTDOWN(Devices[i]);
277 /* XXX this potentially leaks Devices[i]->private if it's being
278 * used to point to something dynamic, but you're not supposed
279 * to call this routine at such times that some open instance
280 * has its private ptr pointing somewhere anyway. XXX
284 Devices[numDevs = 0] = NULL;
287 /* Get all device information for devices we have attached */
293 struct ifreq *ifptr, *end;
295 char buffer[INTERFACE_MAX * sizeof(struct ifreq)];
298 msgNotify("Probing devices, please wait (this can take a while)...");
299 /* First go for the network interfaces. Stolen shamelessly from ifconfig! */
300 memset(&ifc, 0, sizeof(ifc));
301 memset(buffer, 0, INTERFACE_MAX * sizeof(struct ifreq));
302 ifc.ifc_len = sizeof(buffer);
303 ifc.ifc_buf = buffer;
305 s = socket(AF_INET, SOCK_DGRAM, 0);
307 goto skipif; /* Jump over network iface probing */
309 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
310 goto skipif; /* Jump over network iface probing */
313 ifflags = ifc.ifc_req->ifr_flags;
314 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
315 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
318 /* If it's not a link entry, forget it */
319 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
322 /* Eliminate network devices that don't make sense */
323 if (!strncmp(ifptr->ifr_name, "lo", 2))
326 /* Try and find its description */
327 for (i = 0, descr = NULL; device_names[i].name; i++) {
328 int len = strlen(device_names[i].name);
330 if (!ifptr->ifr_name || !ifptr->ifr_name[0])
332 else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) {
333 descr = device_names[i].description;
338 descr = "<unknown network interface type>";
340 deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE,
341 mediaInitNetwork, NULL, mediaShutdownNetwork, NULL);
343 msgDebug("Found a network device named %s\n", ifptr->ifr_name);
345 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
349 if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */
350 ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr));
355 /* Next, try to find all the types of devices one might need
356 * during the second stage of the installation.
358 for (i = 0; device_names[i].name; i++) {
359 for (j = 0; j < device_names[i].max; j++) {
360 char try[FILENAME_MAX];
362 switch(device_names[i].type) {
363 case DEVICE_TYPE_CDROM:
364 fd = deviceTry(device_names[i], try, j);
365 if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */
368 if (fd >= 0) close(fd);
369 snprintf(n, sizeof n, device_names[i].name, j);
370 deviceRegister(n, device_names[i].description, strdup(try),
371 DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM,
372 mediaShutdownCDROM, NULL);
374 msgDebug("Found a CDROM device for %s\n", try);
378 case DEVICE_TYPE_DISK:
382 case DEVICE_TYPE_FLOPPY:
383 fd = deviceTry(device_names[i], try, j);
388 snprintf(n, sizeof n, device_names[i].name, j);
389 deviceRegister(n, device_names[i].description, strdup(try),
390 DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy,
391 mediaShutdownFloppy, NULL);
393 msgDebug("Found a floppy device for %s\n", try);
397 case DEVICE_TYPE_USB:
398 fd = deviceTry(device_names[i], try, j);
403 snprintf(n, sizeof(n), device_names[i].name, j);
404 deviceRegister(n, device_names[i].description,
405 strdup(try), DEVICE_TYPE_USB, TRUE, mediaInitUSB,
406 mediaGetUSB, mediaShutdownUSB, NULL);
409 msgDebug("Found a USB disk for %s\n", try);
419 /* Finally, go get the disks and look for partitions to register */
420 if ((names = Disk_Names()) != NULL) {
423 for (i = 0; names[i]; i++) {
427 /* Ignore memory disks */
428 if (!strncmp(names[i], "md", 2))
433 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
434 * valid disk. This is main reason why sysinstall presents SCSI
435 * CDROM to available disks in Fdisk/Label menu. In addition,
436 * adding a blank SCSI CDROM to the menu generates floating point
437 * exception in sparc64. Disk_Names() just extracts sysctl
438 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
439 * me and that should be investigated.
440 * For temporary workaround, ignore SCSI CDROM device.
442 if (!strncmp(names[i], "cd", 2))
445 d = Open_Disk(names[i]);
447 msgDebug("Unable to open disk %s\n", names[i]);
451 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
452 dummyInit, dummyGet, dummyShutdown, d);
454 msgDebug("Found a disk device named %s\n", names[i]);
456 /* Look for existing DOS partitions to register as "DOS media devices"
457 * XXX: libdisks handling of extended partitions is too
458 * simplistic - it does not handle them containing (for
459 * example) UFS partitions
461 for (c1 = d->chunks->part; c1; c1 = c1->next) {
462 if (c1->type == fat || c1->type == efi || c1->type == extended) {
467 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
468 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
469 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
472 msgDebug("Found a DOS partition %s\n", c1->name);
473 } else if (c1->type == freebsd) {
478 for (c2 = c1->part; c2; c2 = c2->next) {
479 if (c2->type != part || c2->subtype != 7)
482 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
483 dev = deviceRegister(c2->name, c2->name, strdup(devname), DEVICE_TYPE_UFS, TRUE,
484 mediaInitUFS, mediaGetUFS, mediaShutdownUFS, NULL);
487 msgDebug("Found a UFS sub-partition %s\n", c2->name);
495 dialog_clear_norefresh();
498 /* Rescan all devices, after closing previous set - convenience function */
507 * Find all devices that match the criteria, allowing "wildcarding" as well
508 * by allowing NULL or ANY values to match all. The array returned is static
509 * and may be used until the next invocation of deviceFind().
512 deviceFind(char *name, DeviceType class)
514 static Device *found[DEV_MAX];
518 for (i = 0; i < numDevs; i++) {
519 if ((!name || !strcmp(Devices[i]->name, name))
520 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
521 found[j++] = Devices[i];
524 return j ? found : NULL;
528 deviceFindDescr(char *name, char *desc, DeviceType class)
530 static Device *found[DEV_MAX];
534 for (i = 0; i < numDevs; i++) {
535 if ((!name || !strcmp(Devices[i]->name, name)) &&
536 (!desc || !strcmp(Devices[i]->description, desc)) &&
537 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
538 found[j++] = Devices[i];
541 return j ? found : NULL;
545 deviceCount(Device **devs)
551 for (i = 0; devs[i]; i++);
556 * Create a menu listing all the devices of a certain type in the system.
557 * The passed-in menu is expected to be a "prototype" from which the new
561 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
568 devs = deviceFind(NULL, type);
569 numdevs = deviceCount(devs);
572 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
573 bcopy(menu, tmp, sizeof(DMenu));
574 for (i = 0; devs[i]; i++) {
575 tmp->items[i].prompt = devs[i]->name;
576 for (j = 0; j < numDevs; j++) {
577 if (devs[i] == Devices[j]) {
578 tmp->items[i].title = Devices[j]->description;
583 tmp->items[i].title = "<unknown device type>";
584 tmp->items[i].fire = hook;
585 tmp->items[i].checked = check;
587 tmp->items[i].title = NULL;