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("bxe", "Broadcom NetXtreme II 10Gb Ethernet card"),
110 NETWORK("cas", "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"),
111 NETWORK("cue", "CATC USB Ethernet adapter"),
112 NETWORK("cxgb", "Chelsio T3 10Gb Ethernet card"),
113 NETWORK("cxgbe", "Chelsio T4 10Gb Ethernet card"),
114 NETWORK("fpa", "DEC DEFPA PCI FDDI card"),
115 NETWORK("sr", "SDL T1/E1 sync serial PCI card"),
116 NETWORK("cc3i", "SDL HSSI sync serial PCI card"),
117 NETWORK("en", "Efficient Networks ATM PCI card"),
118 NETWORK("dc", "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"),
119 NETWORK("de", "DEC DE435 PCI NIC or other DC21040-AA based card"),
120 NETWORK("fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card"),
121 NETWORK("ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"),
122 NETWORK("ep", "3Com 3C509 Ethernet card/3C589 PCMCIA"),
123 NETWORK("em", "Intel(R) PRO/1000 Ethernet card"),
124 NETWORK("et", "Agere ET1310 based PCI Express Gigabit Ethernet card"),
125 NETWORK("ex", "Intel EtherExpress Pro/10 Ethernet card"),
126 NETWORK("fe", "Fujitsu MB86960A/MB86965A Ethernet card"),
127 NETWORK("gem", "Apple GMAC or Sun ERI/GEM Ethernet adapter"),
128 NETWORK("hme", "Sun HME (Happy Meal Ethernet) Ethernet adapter"),
129 NETWORK("ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"),
130 NETWORK("igb", "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"),
131 NETWORK("ipw", "Intel PRO/Wireless 2100 IEEE 802.11 adapter"),
132 NETWORK("iwi", "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"),
133 NETWORK("iwn", "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"),
134 NETWORK("ixgb", "Intel(R) PRO/10Gb Ethernet card"),
135 NETWORK("ixgbe", "Intel(R) PRO/10Gb Ethernet card"),
136 NETWORK("jme", "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"),
137 NETWORK("kue", "Kawasaki LSI USB Ethernet adapter"),
138 NETWORK("le", "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"),
139 NETWORK("lge", "Level 1 LXT1001 Gigabit Ethernet card"),
140 NETWORK("malo", "Marvell Libertas 88W8335 802.11 wireless adapter"),
141 NETWORK("msk", "Marvell/SysKonnect Yukon II Gigabit Ethernet"),
142 NETWORK("mxge", "Myricom Myri10GE 10Gb Ethernet card"),
143 NETWORK("nfe", "NVIDIA nForce MCP Ethernet"),
144 NETWORK("nge", "NatSemi PCI Gigabit Ethernet card"),
145 NETWORK("nve", "NVIDIA nForce MCP Ethernet"),
146 NETWORK("nxge", "Neterion Xframe 10GbE Server/Storage adapter"),
147 NETWORK("pcn", "AMD Am79c79x PCI Ethernet card"),
148 NETWORK("ral", "Ralink Technology IEEE 802.11 wireless adapter"),
149 NETWORK("ray", "Raytheon Raylink 802.11 wireless adapter"),
150 NETWORK("re", "RealTek 8139C+/8169/8169S/8110S PCI Ethernet card"),
151 NETWORK("rl", "RealTek 8129/8139 PCI Ethernet card"),
152 NETWORK("rue", "RealTek USB Ethernet card"),
153 NETWORK("rum", "Ralink Technology USB IEEE 802.11 wireless adapter"),
154 NETWORK("sf", "Adaptec AIC-6915 PCI Ethernet card"),
155 NETWORK("sge", "Silicon Integrated Systems SiS190/191 Ethernet"),
156 NETWORK("sis", "SiS 900/SiS 7016 PCI Ethernet card"),
158 NETWORK("snc", "SONIC Ethernet card"),
160 NETWORK("sn", "SMC/Megahertz Ethernet card"),
161 NETWORK("ste", "Sundance ST201 PCI Ethernet card"),
162 NETWORK("stge", "Sundance/Tamarack TC9021 Gigabit Ethernet"),
163 NETWORK("sk", "SysKonnect PCI Gigabit Ethernet card"),
164 NETWORK("tx", "SMC 9432TX Ethernet card"),
165 NETWORK("txp", "3Com 3cR990 Ethernet card"),
166 NETWORK("ti", "Alteon Networks PCI Gigabit Ethernet card"),
167 NETWORK("tl", "Texas Instruments ThunderLAN PCI Ethernet card"),
168 NETWORK("uath", "Atheros AR5005UG and AR5005UX USB wireless adapter"),
169 NETWORK("upgt", "Conexant/Intersil PrismGT USB wireless adapter"),
170 NETWORK("ural", "Ralink Technology RT2500USB 802.11 wireless adapter"),
171 NETWORK("urtw", "Realtek 8187L USB wireless adapter"),
172 NETWORK("vge", "VIA VT612x PCI Gigabit Ethernet card"),
173 NETWORK("vr", "VIA VT3043/VT86C100A Rhine PCI Ethernet card"),
174 NETWORK("vte", "DM&P Vortex86 RDC R6040 Fast Ethernet"),
175 NETWORK("vlan", "IEEE 802.1Q VLAN network interface"),
176 NETWORK("vx", "3COM 3c590 / 3c595 Ethernet card"),
177 NETWORK("wb", "Winbond W89C840F PCI Ethernet card"),
178 NETWORK("wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter"),
179 NETWORK("wpi", "Intel 3945ABG IEEE 802.11 wireless adapter"),
180 NETWORK("xe", "Xircom/Intel EtherExpress Pro100/16 Ethernet card"),
181 NETWORK("xl", "3COM 3c90x / 3c90xB PCI Ethernet card"),
182 NETWORK("zyd", "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"),
183 NETWORK("fwe", "FireWire Ethernet emulation"),
184 NETWORK("fwip", "IP over FireWire"),
185 NETWORK("plip", "Parallel Port IP (PLIP) peer connection"),
186 NETWORK("lo", "Loop-back (local) network interface"),
187 NETWORK("disc", "Software discard network interface"),
192 new_device(char *name)
196 dev = safe_malloc(sizeof(Device));
197 bzero(dev, sizeof(Device));
199 SAFE_STRCPY(dev->name, name);
203 /* Stubs for unimplemented strategy routines */
205 dummyInit(Device *dev)
211 dummyGet(Device *dev, char *dist, Boolean probe)
217 dummyShutdown(Device *dev)
223 deviceTry(struct _devname dev, char *try, int i)
228 snprintf(unit, sizeof unit, dev.name, i);
229 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
231 msgDebug("deviceTry: attempting to open %s\n", try);
232 fd = open(try, O_RDONLY);
235 msgDebug("deviceTry: open of %s succeeded on first try.\n", try);
238 msgDebug("deviceTry: open of %s failed.\n", try);
243 /* Register a new device in the devices array */
245 deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled,
246 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean),
247 void (*shutdown)(Device *), void *private)
249 Device *newdev = NULL;
251 if (numDevs == DEV_MAX)
252 msgFatal("Too many devices found!");
254 newdev = new_device(name);
255 newdev->description = desc;
256 newdev->devname = devname;
258 newdev->enabled = enabled;
259 newdev->init = init ? init : dummyInit;
260 newdev->get = get ? get : dummyGet;
261 newdev->shutdown = shutdown ? shutdown : dummyShutdown;
262 newdev->private = private;
263 Devices[numDevs] = newdev;
264 Devices[++numDevs] = NULL;
269 /* Reset the registered device chain */
275 for (i = 0; i < numDevs; i++) {
276 DEVICE_SHUTDOWN(Devices[i]);
278 /* XXX this potentially leaks Devices[i]->private if it's being
279 * used to point to something dynamic, but you're not supposed
280 * to call this routine at such times that some open instance
281 * has its private ptr pointing somewhere anyway. XXX
285 Devices[numDevs = 0] = NULL;
288 /* Get all device information for devices we have attached */
294 struct ifreq *ifptr, *end;
296 char buffer[INTERFACE_MAX * sizeof(struct ifreq)];
299 msgNotify("Probing devices, please wait (this can take a while)...");
300 /* First go for the network interfaces. Stolen shamelessly from ifconfig! */
301 memset(&ifc, 0, sizeof(ifc));
302 memset(buffer, 0, INTERFACE_MAX * sizeof(struct ifreq));
303 ifc.ifc_len = sizeof(buffer);
304 ifc.ifc_buf = buffer;
306 s = socket(AF_INET, SOCK_DGRAM, 0);
308 goto skipif; /* Jump over network iface probing */
310 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
311 goto skipif; /* Jump over network iface probing */
314 ifflags = ifc.ifc_req->ifr_flags;
315 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
316 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
319 /* If it's not a link entry, forget it */
320 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
323 /* Eliminate network devices that don't make sense */
324 if (!strncmp(ifptr->ifr_name, "lo", 2))
327 /* Try and find its description */
328 for (i = 0, descr = NULL; device_names[i].name; i++) {
329 int len = strlen(device_names[i].name);
331 if (!ifptr->ifr_name || !ifptr->ifr_name[0])
333 else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) {
334 descr = device_names[i].description;
339 descr = "<unknown network interface type>";
341 deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE,
342 mediaInitNetwork, NULL, mediaShutdownNetwork, NULL);
344 msgDebug("Found a network device named %s\n", ifptr->ifr_name);
346 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
350 if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */
351 ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr));
356 /* Next, try to find all the types of devices one might need
357 * during the second stage of the installation.
359 for (i = 0; device_names[i].name; i++) {
360 for (j = 0; j < device_names[i].max; j++) {
361 char try[FILENAME_MAX];
363 switch(device_names[i].type) {
364 case DEVICE_TYPE_CDROM:
365 fd = deviceTry(device_names[i], try, j);
366 if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */
369 if (fd >= 0) close(fd);
370 snprintf(n, sizeof n, device_names[i].name, j);
371 deviceRegister(n, device_names[i].description, strdup(try),
372 DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM,
373 mediaShutdownCDROM, NULL);
375 msgDebug("Found a CDROM device for %s\n", try);
379 case DEVICE_TYPE_DISK:
383 case DEVICE_TYPE_FLOPPY:
384 fd = deviceTry(device_names[i], try, j);
389 snprintf(n, sizeof n, device_names[i].name, j);
390 deviceRegister(n, device_names[i].description, strdup(try),
391 DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy,
392 mediaShutdownFloppy, NULL);
394 msgDebug("Found a floppy device for %s\n", try);
398 case DEVICE_TYPE_USB:
399 fd = deviceTry(device_names[i], try, j);
404 snprintf(n, sizeof(n), device_names[i].name, j);
405 deviceRegister(n, device_names[i].description,
406 strdup(try), DEVICE_TYPE_USB, TRUE, mediaInitUSB,
407 mediaGetUSB, mediaShutdownUSB, NULL);
410 msgDebug("Found a USB disk for %s\n", try);
420 /* Finally, go get the disks and look for partitions to register */
421 if ((names = Disk_Names()) != NULL) {
424 for (i = 0; names[i]; i++) {
428 /* Ignore memory disks */
429 if (!strncmp(names[i], "md", 2))
434 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
435 * valid disk. This is main reason why sysinstall presents SCSI
436 * CDROM to available disks in Fdisk/Label menu. In addition,
437 * adding a blank SCSI CDROM to the menu generates floating point
438 * exception in sparc64. Disk_Names() just extracts sysctl
439 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
440 * me and that should be investigated.
441 * For temporary workaround, ignore SCSI CDROM device.
443 if (!strncmp(names[i], "cd", 2))
446 d = Open_Disk(names[i]);
448 msgDebug("Unable to open disk %s\n", names[i]);
452 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
453 dummyInit, dummyGet, dummyShutdown, d);
455 msgDebug("Found a disk device named %s\n", names[i]);
457 /* Look for existing DOS partitions to register as "DOS media devices"
458 * XXX: libdisks handling of extended partitions is too
459 * simplistic - it does not handle them containing (for
460 * example) UFS partitions
462 for (c1 = d->chunks->part; c1; c1 = c1->next) {
463 if (c1->type == fat || c1->type == efi || c1->type == extended) {
468 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
469 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
470 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
473 msgDebug("Found a DOS partition %s\n", c1->name);
474 } else if (c1->type == freebsd) {
479 for (c2 = c1->part; c2; c2 = c2->next) {
480 if (c2->type != part || c2->subtype != 7)
483 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
484 dev = deviceRegister(c2->name, c2->name, strdup(devname), DEVICE_TYPE_UFS, TRUE,
485 mediaInitUFS, mediaGetUFS, mediaShutdownUFS, NULL);
488 msgDebug("Found a UFS sub-partition %s\n", c2->name);
496 dialog_clear_norefresh();
499 /* Rescan all devices, after closing previous set - convenience function */
508 * Find all devices that match the criteria, allowing "wildcarding" as well
509 * by allowing NULL or ANY values to match all. The array returned is static
510 * and may be used until the next invocation of deviceFind().
513 deviceFind(char *name, DeviceType class)
515 static Device *found[DEV_MAX];
519 for (i = 0; i < numDevs; i++) {
520 if ((!name || !strcmp(Devices[i]->name, name))
521 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
522 found[j++] = Devices[i];
525 return j ? found : NULL;
529 deviceFindDescr(char *name, char *desc, DeviceType class)
531 static Device *found[DEV_MAX];
535 for (i = 0; i < numDevs; i++) {
536 if ((!name || !strcmp(Devices[i]->name, name)) &&
537 (!desc || !strcmp(Devices[i]->description, desc)) &&
538 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
539 found[j++] = Devices[i];
542 return j ? found : NULL;
546 deviceCount(Device **devs)
552 for (i = 0; devs[i]; i++);
557 * Create a menu listing all the devices of a certain type in the system.
558 * The passed-in menu is expected to be a "prototype" from which the new
562 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
569 devs = deviceFind(NULL, type);
570 numdevs = deviceCount(devs);
573 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
574 bcopy(menu, tmp, sizeof(DMenu));
575 for (i = 0; devs[i]; i++) {
576 tmp->items[i].prompt = devs[i]->name;
577 for (j = 0; j < numDevs; j++) {
578 if (devs[i] == Devices[j]) {
579 tmp->items[i].title = Devices[j]->description;
584 tmp->items[i].title = "<unknown device type>";
585 tmp->items[i].fire = hook;
586 tmp->items[i].checked = check;
588 tmp->items[i].title = NULL;