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("cuad%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 ifc.ifc_len = sizeof(buffer);
299 ifc.ifc_buf = buffer;
301 s = socket(AF_INET, SOCK_DGRAM, 0);
303 goto skipif; /* Jump over network iface probing */
305 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
306 goto skipif; /* Jump over network iface probing */
309 ifflags = ifc.ifc_req->ifr_flags;
310 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
311 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
314 /* If it's not a link entry, forget it */
315 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
318 /* Eliminate network devices that don't make sense */
319 if (!strncmp(ifptr->ifr_name, "lo", 2))
322 /* If we have a slip device, don't register it */
323 if (!strncmp(ifptr->ifr_name, "sl", 2)) {
326 /* And the same for ppp */
327 if (!strncmp(ifptr->ifr_name, "tun", 3) || !strncmp(ifptr->ifr_name, "ppp", 3)) {
330 /* Try and find its description */
331 for (i = 0, descr = NULL; device_names[i].name; i++) {
332 int len = strlen(device_names[i].name);
334 if (!ifptr->ifr_name || !ifptr->ifr_name[0])
336 else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) {
337 descr = device_names[i].description;
342 descr = "<unknown network interface type>";
344 deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE,
345 mediaInitNetwork, NULL, mediaShutdownNetwork, NULL);
347 msgDebug("Found a network device named %s\n", ifptr->ifr_name);
349 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
353 if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */
354 ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr));
359 /* Next, try to find all the types of devices one might need
360 * during the second stage of the installation.
362 for (i = 0; device_names[i].name; i++) {
363 for (j = 0; j < device_names[i].max; j++) {
364 char try[FILENAME_MAX];
366 switch(device_names[i].type) {
367 case DEVICE_TYPE_CDROM:
368 fd = deviceTry(device_names[i], try, j);
369 if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */
372 if (fd >= 0) close(fd);
373 snprintf(n, sizeof n, device_names[i].name, j);
374 deviceRegister(strdup(n), device_names[i].description, strdup(try),
375 DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM,
376 mediaShutdownCDROM, NULL);
378 msgDebug("Found a CDROM device for %s\n", try);
382 case DEVICE_TYPE_DISK:
386 case DEVICE_TYPE_FLOPPY:
387 fd = deviceTry(device_names[i], try, j);
392 snprintf(n, sizeof n, device_names[i].name, j);
393 deviceRegister(strdup(n), device_names[i].description, strdup(try),
394 DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy,
395 mediaShutdownFloppy, NULL);
397 msgDebug("Found a floppy device for %s\n", try);
401 case DEVICE_TYPE_USB:
402 fd = deviceTry(device_names[i], try, j);
407 snprintf(n, sizeof(n), device_names[i].name, j);
408 deviceRegister(strdup(n), device_names[i].description,
409 strdup(try), DEVICE_TYPE_USB, TRUE, mediaInitUSB,
410 mediaGetUSB, mediaShutdownUSB, NULL);
413 msgDebug("Found a USB disk for %s\n", try);
417 case DEVICE_TYPE_NETWORK:
418 fd = deviceTry(device_names[i], try, j);
419 /* The only network devices that you can open this way are serial ones */
424 cp = device_names[i].description;
425 /* Serial devices get a slip and ppp device each, if supported */
426 newdesc = safe_malloc(strlen(cp) + 40);
427 sprintf(newdesc, cp, "SLIP interface", try, j + 1);
428 deviceRegister("sl0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
429 NULL, mediaShutdownNetwork, NULL);
430 msgDebug("Add mapping for %s to sl0\n", try);
431 newdesc = safe_malloc(strlen(cp) + 50);
432 sprintf(newdesc, cp, "PPP interface", try, j + 1);
433 deviceRegister("ppp0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
434 NULL, mediaShutdownNetwork, NULL);
436 msgDebug("Add mapping for %s to ppp0\n", try);
446 /* Finally, go get the disks and look for partitions to register */
447 if ((names = Disk_Names()) != NULL) {
450 for (i = 0; names[i]; i++) {
454 /* Ignore memory disks */
455 if (!strncmp(names[i], "md", 2))
460 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
461 * valid disk. This is main reason why sysinstall presents SCSI
462 * CDROM to available disks in Fdisk/Label menu. In addition,
463 * adding a blank SCSI CDROM to the menu generates floating point
464 * exception in sparc64. Disk_Names() just extracts sysctl
465 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
466 * me and that should be investigated.
467 * For temporary workaround, ignore SCSI CDROM device.
469 if (!strncmp(names[i], "cd", 2))
472 d = Open_Disk(names[i]);
474 msgDebug("Unable to open disk %s\n", names[i]);
478 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
479 dummyInit, dummyGet, dummyShutdown, d);
481 msgDebug("Found a disk device named %s\n", names[i]);
483 /* Look for existing DOS partitions to register as "DOS media devices"
484 * XXX: libdisks handling of extended partitions is too
485 * simplistic - it does not handle them containing (for
486 * example) UFS partitions
488 for (c1 = d->chunks->part; c1; c1 = c1->next) {
489 if (c1->type == fat || c1->type == efi || c1->type == extended) {
494 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
495 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
496 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
499 msgDebug("Found a DOS partition %s\n", c1->name);
500 } else if (c1->type == freebsd) {
505 for (c2 = c1->part; c2; c2 = c2->next) {
506 if (c2->type != part || c2->subtype != 7)
509 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
510 dev = deviceRegister(c2->name, c2->name, strdup(devname), DEVICE_TYPE_UFS, TRUE,
511 mediaInitUFS, mediaGetUFS, mediaShutdownUFS, NULL);
514 msgDebug("Found a UFS sub-partition %s\n", c2->name);
522 dialog_clear_norefresh();
525 /* Rescan all devices, after closing previous set - convenience function */
534 * Find all devices that match the criteria, allowing "wildcarding" as well
535 * by allowing NULL or ANY values to match all. The array returned is static
536 * and may be used until the next invocation of deviceFind().
539 deviceFind(char *name, DeviceType class)
541 static Device *found[DEV_MAX];
545 for (i = 0; i < numDevs; i++) {
546 if ((!name || !strcmp(Devices[i]->name, name))
547 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
548 found[j++] = Devices[i];
551 return j ? found : NULL;
555 deviceFindDescr(char *name, char *desc, DeviceType class)
557 static Device *found[DEV_MAX];
561 for (i = 0; i < numDevs; i++) {
562 if ((!name || !strcmp(Devices[i]->name, name)) &&
563 (!desc || !strcmp(Devices[i]->description, desc)) &&
564 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
565 found[j++] = Devices[i];
568 return j ? found : NULL;
572 deviceCount(Device **devs)
578 for (i = 0; devs[i]; i++);
583 * Create a menu listing all the devices of a certain type in the system.
584 * The passed-in menu is expected to be a "prototype" from which the new
588 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
595 devs = deviceFind(NULL, type);
596 numdevs = deviceCount(devs);
599 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
600 bcopy(menu, tmp, sizeof(DMenu));
601 for (i = 0; devs[i]; i++) {
602 tmp->items[i].prompt = devs[i]->name;
603 for (j = 0; j < numDevs; j++) {
604 if (devs[i] == Devices[j]) {
605 tmp->items[i].title = Devices[j]->description;
610 tmp->items[i].title = "<unknown device type>";
611 tmp->items[i].fire = hook;
612 tmp->items[i].checked = check;
614 tmp->items[i].title = NULL;