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("fpa", "DEC DEFPA PCI FDDI card"),
113 NETWORK("sr", "SDL T1/E1 sync serial PCI card"),
114 NETWORK("cc3i", "SDL HSSI sync serial PCI card"),
115 NETWORK("en", "Efficient Networks ATM PCI card"),
116 NETWORK("dc", "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"),
117 NETWORK("de", "DEC DE435 PCI NIC or other DC21040-AA based card"),
118 NETWORK("fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card"),
119 NETWORK("ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"),
120 NETWORK("ep", "3Com 3C509 Ethernet card/3C589 PCMCIA"),
121 NETWORK("em", "Intel(R) PRO/1000 Ethernet card"),
122 NETWORK("et", "Agere ET1310 based PCI Express Gigabit Ethernet card"),
123 NETWORK("ex", "Intel EtherExpress Pro/10 Ethernet card"),
124 NETWORK("fe", "Fujitsu MB86960A/MB86965A Ethernet card"),
125 NETWORK("gem", "Apple GMAC or Sun ERI/GEM Ethernet adapter"),
126 NETWORK("hme", "Sun HME (Happy Meal Ethernet) Ethernet adapter"),
127 NETWORK("ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"),
128 NETWORK("igb", "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"),
129 NETWORK("ipw", "Intel PRO/Wireless 2100 IEEE 802.11 adapter"),
130 NETWORK("iwi", "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"),
131 NETWORK("iwn", "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"),
132 NETWORK("ixgb", "Intel(R) PRO/10Gb Ethernet card"),
133 NETWORK("ixgbe", "Intel(R) PRO/10Gb Ethernet card"),
134 NETWORK("jme", "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"),
135 NETWORK("kue", "Kawasaki LSI USB Ethernet adapter"),
136 NETWORK("le", "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"),
137 NETWORK("lge", "Level 1 LXT1001 Gigabit Ethernet card"),
138 NETWORK("malo", "Marvell Libertas 88W8335 802.11 wireless adapter"),
139 NETWORK("msk", "Marvell/SysKonnect Yukon II Gigabit Ethernet"),
140 NETWORK("mxge", "Myricom Myri10GE 10Gb Ethernet card"),
141 NETWORK("nfe", "NVIDIA nForce MCP Ethernet"),
142 NETWORK("nge", "NatSemi PCI Gigabit Ethernet card"),
143 NETWORK("nve", "NVIDIA nForce MCP Ethernet"),
144 NETWORK("nxge", "Neterion Xframe 10GbE Server/Storage adapter"),
145 NETWORK("pcn", "AMD Am79c79x PCI Ethernet card"),
146 NETWORK("ral", "Ralink Technology IEEE 802.11 wireless adapter"),
147 NETWORK("ray", "Raytheon Raylink 802.11 wireless adapter"),
148 NETWORK("re", "RealTek 8139C+/8169/8169S/8110S PCI Ethernet card"),
149 NETWORK("rl", "RealTek 8129/8139 PCI Ethernet card"),
150 NETWORK("rue", "RealTek USB Ethernet card"),
151 NETWORK("rum", "Ralink Technology USB IEEE 802.11 wireless adapter"),
152 NETWORK("sf", "Adaptec AIC-6915 PCI Ethernet card"),
153 NETWORK("sge", "Silicon Integrated Systems SiS190/191 Ethernet"),
154 NETWORK("sis", "SiS 900/SiS 7016 PCI Ethernet card"),
156 NETWORK("snc", "SONIC Ethernet card"),
158 NETWORK("sn", "SMC/Megahertz Ethernet card"),
159 NETWORK("ste", "Sundance ST201 PCI Ethernet card"),
160 NETWORK("stge", "Sundance/Tamarack TC9021 Gigabit Ethernet"),
161 NETWORK("sk", "SysKonnect PCI Gigabit Ethernet card"),
162 NETWORK("tx", "SMC 9432TX Ethernet card"),
163 NETWORK("txp", "3Com 3cR990 Ethernet card"),
164 NETWORK("ti", "Alteon Networks PCI Gigabit Ethernet card"),
165 NETWORK("tl", "Texas Instruments ThunderLAN PCI Ethernet card"),
166 NETWORK("uath", "Atheros AR5005UG and AR5005UX USB wireless adapter"),
167 NETWORK("upgt", "Conexant/Intersil PrismGT USB wireless adapter"),
168 NETWORK("ural", "Ralink Technology RT2500USB 802.11 wireless adapter"),
169 NETWORK("urtw", "Realtek 8187L USB wireless adapter"),
170 NETWORK("vge", "VIA VT612x PCI Gigabit Ethernet card"),
171 NETWORK("vr", "VIA VT3043/VT86C100A Rhine PCI Ethernet card"),
172 NETWORK("vlan", "IEEE 802.1Q VLAN network interface"),
173 NETWORK("vx", "3COM 3c590 / 3c595 Ethernet card"),
174 NETWORK("wb", "Winbond W89C840F PCI Ethernet card"),
175 NETWORK("wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter"),
176 NETWORK("wpi", "Intel 3945ABG IEEE 802.11 wireless adapter"),
177 NETWORK("xe", "Xircom/Intel EtherExpress Pro100/16 Ethernet card"),
178 NETWORK("xl", "3COM 3c90x / 3c90xB PCI Ethernet card"),
179 NETWORK("zyd", "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"),
180 NETWORK("fwe", "FireWire Ethernet emulation"),
181 NETWORK("fwip", "IP over FireWire"),
182 NETWORK("plip", "Parallel Port IP (PLIP) peer connection"),
183 NETWORK("lo", "Loop-back (local) network interface"),
184 NETWORK("disc", "Software discard network interface"),
189 new_device(char *name)
193 dev = safe_malloc(sizeof(Device));
194 bzero(dev, sizeof(Device));
196 SAFE_STRCPY(dev->name, name);
200 /* Stubs for unimplemented strategy routines */
202 dummyInit(Device *dev)
208 dummyGet(Device *dev, char *dist, Boolean probe)
214 dummyShutdown(Device *dev)
220 deviceTry(struct _devname dev, char *try, int i)
225 snprintf(unit, sizeof unit, dev.name, i);
226 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
228 msgDebug("deviceTry: attempting to open %s\n", try);
229 fd = open(try, O_RDONLY);
232 msgDebug("deviceTry: open of %s succeeded on first try.\n", try);
235 msgDebug("deviceTry: open of %s failed.\n", try);
240 /* Register a new device in the devices array */
242 deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled,
243 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean),
244 void (*shutdown)(Device *), void *private)
246 Device *newdev = NULL;
248 if (numDevs == DEV_MAX)
249 msgFatal("Too many devices found!");
251 newdev = new_device(name);
252 newdev->description = desc;
253 newdev->devname = devname;
255 newdev->enabled = enabled;
256 newdev->init = init ? init : dummyInit;
257 newdev->get = get ? get : dummyGet;
258 newdev->shutdown = shutdown ? shutdown : dummyShutdown;
259 newdev->private = private;
260 Devices[numDevs] = newdev;
261 Devices[++numDevs] = NULL;
266 /* Reset the registered device chain */
272 for (i = 0; i < numDevs; i++) {
273 DEVICE_SHUTDOWN(Devices[i]);
275 /* XXX this potentially leaks Devices[i]->private if it's being
276 * used to point to something dynamic, but you're not supposed
277 * to call this routine at such times that some open instance
278 * has its private ptr pointing somewhere anyway. XXX
282 Devices[numDevs = 0] = NULL;
285 /* Get all device information for devices we have attached */
291 struct ifreq *ifptr, *end;
293 char buffer[INTERFACE_MAX * sizeof(struct ifreq)];
296 msgNotify("Probing devices, please wait (this can take a while)...");
297 /* First go for the network interfaces. Stolen shamelessly from ifconfig! */
298 memset(&ifc, 0, sizeof(ifc));
299 memset(buffer, 0, INTERFACE_MAX * sizeof(struct ifreq));
300 ifc.ifc_len = sizeof(buffer);
301 ifc.ifc_buf = buffer;
303 s = socket(AF_INET, SOCK_DGRAM, 0);
305 goto skipif; /* Jump over network iface probing */
307 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
308 goto skipif; /* Jump over network iface probing */
311 ifflags = ifc.ifc_req->ifr_flags;
312 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
313 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
316 /* If it's not a link entry, forget it */
317 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
320 /* Eliminate network devices that don't make sense */
321 if (!strncmp(ifptr->ifr_name, "lo", 2))
324 /* Try and find its description */
325 for (i = 0, descr = NULL; device_names[i].name; i++) {
326 int len = strlen(device_names[i].name);
328 if (!ifptr->ifr_name || !ifptr->ifr_name[0])
330 else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) {
331 descr = device_names[i].description;
336 descr = "<unknown network interface type>";
338 deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE,
339 mediaInitNetwork, NULL, mediaShutdownNetwork, NULL);
341 msgDebug("Found a network device named %s\n", ifptr->ifr_name);
343 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
347 if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */
348 ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr));
353 /* Next, try to find all the types of devices one might need
354 * during the second stage of the installation.
356 for (i = 0; device_names[i].name; i++) {
357 for (j = 0; j < device_names[i].max; j++) {
358 char try[FILENAME_MAX];
360 switch(device_names[i].type) {
361 case DEVICE_TYPE_CDROM:
362 fd = deviceTry(device_names[i], try, j);
363 if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */
366 if (fd >= 0) close(fd);
367 snprintf(n, sizeof n, device_names[i].name, j);
368 deviceRegister(n, device_names[i].description, strdup(try),
369 DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM,
370 mediaShutdownCDROM, NULL);
372 msgDebug("Found a CDROM device for %s\n", try);
376 case DEVICE_TYPE_DISK:
380 case DEVICE_TYPE_FLOPPY:
381 fd = deviceTry(device_names[i], try, j);
386 snprintf(n, sizeof n, device_names[i].name, j);
387 deviceRegister(n, device_names[i].description, strdup(try),
388 DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy,
389 mediaShutdownFloppy, NULL);
391 msgDebug("Found a floppy device for %s\n", try);
395 case DEVICE_TYPE_USB:
396 fd = deviceTry(device_names[i], try, j);
401 snprintf(n, sizeof(n), device_names[i].name, j);
402 deviceRegister(n, device_names[i].description,
403 strdup(try), DEVICE_TYPE_USB, TRUE, mediaInitUSB,
404 mediaGetUSB, mediaShutdownUSB, NULL);
407 msgDebug("Found a USB disk for %s\n", try);
417 /* Finally, go get the disks and look for partitions to register */
418 if ((names = Disk_Names()) != NULL) {
421 for (i = 0; names[i]; i++) {
425 /* Ignore memory disks */
426 if (!strncmp(names[i], "md", 2))
431 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
432 * valid disk. This is main reason why sysinstall presents SCSI
433 * CDROM to available disks in Fdisk/Label menu. In addition,
434 * adding a blank SCSI CDROM to the menu generates floating point
435 * exception in sparc64. Disk_Names() just extracts sysctl
436 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
437 * me and that should be investigated.
438 * For temporary workaround, ignore SCSI CDROM device.
440 if (!strncmp(names[i], "cd", 2))
443 d = Open_Disk(names[i]);
445 msgDebug("Unable to open disk %s\n", names[i]);
449 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
450 dummyInit, dummyGet, dummyShutdown, d);
452 msgDebug("Found a disk device named %s\n", names[i]);
454 /* Look for existing DOS partitions to register as "DOS media devices"
455 * XXX: libdisks handling of extended partitions is too
456 * simplistic - it does not handle them containing (for
457 * example) UFS partitions
459 for (c1 = d->chunks->part; c1; c1 = c1->next) {
460 if (c1->type == fat || c1->type == efi || c1->type == extended) {
465 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
466 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
467 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
470 msgDebug("Found a DOS partition %s\n", c1->name);
471 } else if (c1->type == freebsd) {
476 for (c2 = c1->part; c2; c2 = c2->next) {
477 if (c2->type != part || c2->subtype != 7)
480 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
481 dev = deviceRegister(c2->name, c2->name, strdup(devname), DEVICE_TYPE_UFS, TRUE,
482 mediaInitUFS, mediaGetUFS, mediaShutdownUFS, NULL);
485 msgDebug("Found a UFS sub-partition %s\n", c2->name);
493 dialog_clear_norefresh();
496 /* Rescan all devices, after closing previous set - convenience function */
505 * Find all devices that match the criteria, allowing "wildcarding" as well
506 * by allowing NULL or ANY values to match all. The array returned is static
507 * and may be used until the next invocation of deviceFind().
510 deviceFind(char *name, DeviceType class)
512 static Device *found[DEV_MAX];
516 for (i = 0; i < numDevs; i++) {
517 if ((!name || !strcmp(Devices[i]->name, name))
518 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
519 found[j++] = Devices[i];
522 return j ? found : NULL;
526 deviceFindDescr(char *name, char *desc, DeviceType class)
528 static Device *found[DEV_MAX];
532 for (i = 0; i < numDevs; i++) {
533 if ((!name || !strcmp(Devices[i]->name, name)) &&
534 (!desc || !strcmp(Devices[i]->description, desc)) &&
535 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
536 found[j++] = Devices[i];
539 return j ? found : NULL;
543 deviceCount(Device **devs)
549 for (i = 0; devs[i]; i++);
554 * Create a menu listing all the devices of a certain type in the system.
555 * The passed-in menu is expected to be a "prototype" from which the new
559 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
566 devs = deviceFind(NULL, type);
567 numdevs = deviceCount(devs);
570 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
571 bcopy(menu, tmp, sizeof(DMenu));
572 for (i = 0; devs[i]; i++) {
573 tmp->items[i].prompt = devs[i]->name;
574 for (j = 0; j < numDevs; j++) {
575 if (devs[i] == Devices[j]) {
576 tmp->items[i].title = Devices[j]->description;
581 tmp->items[i].title = "<unknown device type>";
582 tmp->items[i].fire = hook;
583 tmp->items[i].checked = check;
585 tmp->items[i].title = NULL;