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("ar%d", "ATA/IDE RAID device", 16),
84 DISK("afd%d", "ATAPI/IDE floppy device", 4),
85 DISK("mlxd%d", "Mylex RAID disk", 4),
86 DISK("amrd%d", "AMI MegaRAID drive", 4),
87 DISK("idad%d", "Compaq RAID array", 4),
88 DISK("twed%d", "3ware ATA RAID array", 4),
89 DISK("aacd%d", "Adaptec FSA RAID array", 4),
90 DISK("ipsd%d", "IBM ServeRAID RAID array", 4),
91 DISK("mfid%d", "LSI MegaRAID SAS array", 4),
92 FLOPPY("fd%d", "floppy drive unit A", 4),
93 SERIAL("cuad%d", "%s on device %s (COM%d)", 16),
94 USB("da%da", "USB Mass Storage Device", 16),
95 NETWORK("ae", "Attansic/Atheros L2 Fast Ethernet"),
96 NETWORK("age", "Attansic/Atheros L1 Gigabit Ethernet"),
97 NETWORK("alc", "Atheros AR8131/AR8132 PCIe Ethernet"),
98 NETWORK("ale", "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"),
99 NETWORK("an", "Aironet 4500/4800 802.11 wireless adapter"),
100 NETWORK("ath", "Atheros IEEE 802.11 wireless adapter"),
101 NETWORK("aue", "ADMtek USB Ethernet adapter"),
102 NETWORK("axe", "ASIX Electronics USB Ethernet adapter"),
103 NETWORK("bce", "Broadcom NetXtreme II Gigabit Ethernet card"),
104 NETWORK("bfe", "Broadcom BCM440x PCI Ethernet card"),
105 NETWORK("bge", "Broadcom BCM570x PCI Gigabit Ethernet card"),
106 NETWORK("bm", "Apple BMAC Built-in Ethernet"),
107 NETWORK("cas", "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"),
108 NETWORK("cue", "CATC USB Ethernet adapter"),
109 NETWORK("cxgb", "Chelsio T3 10Gb Ethernet card"),
110 NETWORK("fpa", "DEC DEFPA PCI FDDI card"),
111 NETWORK("sr", "SDL T1/E1 sync serial PCI card"),
112 NETWORK("cc3i", "SDL HSSI sync serial PCI card"),
113 NETWORK("en", "Efficient Networks ATM PCI card"),
114 NETWORK("dc", "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"),
115 NETWORK("de", "DEC DE435 PCI NIC or other DC21040-AA based card"),
116 NETWORK("fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card"),
117 NETWORK("ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"),
118 NETWORK("ep", "3Com 3C509 Ethernet card/3C589 PCMCIA"),
119 NETWORK("em", "Intel(R) PRO/1000 Ethernet card"),
120 NETWORK("et", "Agere ET1310 based PCI Express Gigabit Ethernet card"),
121 NETWORK("ex", "Intel EtherExpress Pro/10 Ethernet card"),
122 NETWORK("fe", "Fujitsu MB86960A/MB86965A Ethernet card"),
123 NETWORK("gem", "Apple GMAC or Sun ERI/GEM Ethernet adapter"),
124 NETWORK("hme", "Sun HME (Happy Meal Ethernet) Ethernet adapter"),
125 NETWORK("ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"),
126 NETWORK("igb", "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"),
127 NETWORK("ipw", "Intel PRO/Wireless 2100 IEEE 802.11 adapter"),
128 NETWORK("iwi", "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"),
129 NETWORK("iwn", "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"),
130 NETWORK("ixgb", "Intel(R) PRO/10Gb Ethernet card"),
131 NETWORK("ixgbe", "Intel(R) PRO/10Gb Ethernet card"),
132 NETWORK("jme", "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"),
133 NETWORK("kue", "Kawasaki LSI USB Ethernet adapter"),
134 NETWORK("le", "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"),
135 NETWORK("lge", "Level 1 LXT1001 Gigabit Ethernet card"),
136 NETWORK("malo", "Marvell Libertas 88W8335 802.11 wireless adapter"),
137 NETWORK("msk", "Marvell/SysKonnect Yukon II Gigabit Ethernet"),
138 NETWORK("mxge", "Myricom Myri10GE 10Gb Ethernet card"),
139 NETWORK("nfe", "NVIDIA nForce MCP Ethernet"),
140 NETWORK("nge", "NatSemi PCI Gigabit Ethernet card"),
141 NETWORK("nve", "NVIDIA nForce MCP Ethernet"),
142 NETWORK("nxge", "Neterion Xframe 10GbE Server/Storage adapter"),
143 NETWORK("pcn", "AMD Am79c79x PCI Ethernet card"),
144 NETWORK("ral", "Ralink Technology IEEE 802.11 wireless adapter"),
145 NETWORK("ray", "Raytheon Raylink 802.11 wireless adapter"),
146 NETWORK("re", "RealTek 8139C+/8169/8169S/8110S PCI Ethernet card"),
147 NETWORK("rl", "RealTek 8129/8139 PCI Ethernet card"),
148 NETWORK("rue", "RealTek USB Ethernet card"),
149 NETWORK("rum", "Ralink Technology USB IEEE 802.11 wireless adapter"),
150 NETWORK("sf", "Adaptec AIC-6915 PCI Ethernet card"),
151 NETWORK("sis", "SiS 900/SiS 7016 PCI Ethernet card"),
153 NETWORK("snc", "SONIC Ethernet card"),
155 NETWORK("sn", "SMC/Megahertz Ethernet card"),
156 NETWORK("ste", "Sundance ST201 PCI Ethernet card"),
157 NETWORK("stge", "Sundance/Tamarack TC9021 Gigabit Ethernet"),
158 NETWORK("sk", "SysKonnect PCI Gigabit Ethernet card"),
159 NETWORK("tx", "SMC 9432TX Ethernet card"),
160 NETWORK("txp", "3Com 3cR990 Ethernet card"),
161 NETWORK("ti", "Alteon Networks PCI Gigabit Ethernet card"),
162 NETWORK("tl", "Texas Instruments ThunderLAN PCI Ethernet card"),
163 NETWORK("uath", "Atheros AR5005UG and AR5005UX USB wireless adapter"),
164 NETWORK("upgt", "Conexant/Intersil PrismGT USB wireless adapter"),
165 NETWORK("ural", "Ralink Technology RT2500USB 802.11 wireless adapter"),
166 NETWORK("urtw", "Realtek 8187L USB wireless adapter"),
167 NETWORK("vge", "VIA VT612x PCI Gigabit Ethernet card"),
168 NETWORK("vr", "VIA VT3043/VT86C100A Rhine PCI Ethernet card"),
169 NETWORK("vlan", "IEEE 802.1Q VLAN network interface"),
170 NETWORK("vx", "3COM 3c590 / 3c595 Ethernet card"),
171 NETWORK("wb", "Winbond W89C840F PCI Ethernet card"),
172 NETWORK("wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter"),
173 NETWORK("wpi", "Intel 3945ABG IEEE 802.11 wireless adapter"),
174 NETWORK("xe", "Xircom/Intel EtherExpress Pro100/16 Ethernet card"),
175 NETWORK("xl", "3COM 3c90x / 3c90xB PCI Ethernet card"),
176 NETWORK("zyd", "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"),
177 NETWORK("fwe", "FireWire Ethernet emulation"),
178 NETWORK("fwip", "IP over FireWire"),
179 NETWORK("plip", "Parallel Port IP (PLIP) peer connection"),
180 NETWORK("lo", "Loop-back (local) network interface"),
181 NETWORK("disc", "Software discard network interface"),
186 new_device(char *name)
190 dev = safe_malloc(sizeof(Device));
191 bzero(dev, sizeof(Device));
193 SAFE_STRCPY(dev->name, name);
197 /* Stubs for unimplemented strategy routines */
199 dummyInit(Device *dev)
205 dummyGet(Device *dev, char *dist, Boolean probe)
211 dummyShutdown(Device *dev)
217 deviceTry(struct _devname dev, char *try, int i)
222 snprintf(unit, sizeof unit, dev.name, i);
223 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
225 msgDebug("deviceTry: attempting to open %s\n", try);
226 fd = open(try, O_RDONLY);
229 msgDebug("deviceTry: open of %s succeeded on first try.\n", try);
232 msgDebug("deviceTry: open of %s failed.\n", try);
237 /* Register a new device in the devices array */
239 deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled,
240 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean),
241 void (*shutdown)(Device *), void *private)
243 Device *newdev = NULL;
245 if (numDevs == DEV_MAX)
246 msgFatal("Too many devices found!");
248 newdev = new_device(name);
249 newdev->description = desc;
250 newdev->devname = devname;
252 newdev->enabled = enabled;
253 newdev->init = init ? init : dummyInit;
254 newdev->get = get ? get : dummyGet;
255 newdev->shutdown = shutdown ? shutdown : dummyShutdown;
256 newdev->private = private;
257 Devices[numDevs] = newdev;
258 Devices[++numDevs] = NULL;
263 /* Reset the registered device chain */
269 for (i = 0; i < numDevs; i++) {
270 DEVICE_SHUTDOWN(Devices[i]);
272 /* XXX this potentially leaks Devices[i]->private if it's being
273 * used to point to something dynamic, but you're not supposed
274 * to call this routine at such times that some open instance
275 * has its private ptr pointing somewhere anyway. XXX
279 Devices[numDevs = 0] = NULL;
282 /* Get all device information for devices we have attached */
288 struct ifreq *ifptr, *end;
290 char buffer[INTERFACE_MAX * sizeof(struct ifreq)];
293 msgNotify("Probing devices, please wait (this can take a while)...");
294 /* First go for the network interfaces. Stolen shamelessly from ifconfig! */
295 ifc.ifc_len = sizeof(buffer);
296 ifc.ifc_buf = buffer;
298 s = socket(AF_INET, SOCK_DGRAM, 0);
300 goto skipif; /* Jump over network iface probing */
302 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
303 goto skipif; /* Jump over network iface probing */
306 ifflags = ifc.ifc_req->ifr_flags;
307 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
308 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
311 /* If it's not a link entry, forget it */
312 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
315 /* Eliminate network devices that don't make sense */
316 if (!strncmp(ifptr->ifr_name, "lo", 2))
319 /* If we have a slip device, don't register it */
320 if (!strncmp(ifptr->ifr_name, "sl", 2)) {
323 /* And the same for ppp */
324 if (!strncmp(ifptr->ifr_name, "tun", 3) || !strncmp(ifptr->ifr_name, "ppp", 3)) {
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(strdup(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(strdup(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(strdup(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);
414 case DEVICE_TYPE_NETWORK:
415 fd = deviceTry(device_names[i], try, j);
416 /* The only network devices that you can open this way are serial ones */
421 cp = device_names[i].description;
422 /* Serial devices get a slip and ppp device each, if supported */
423 newdesc = safe_malloc(strlen(cp) + 40);
424 sprintf(newdesc, cp, "SLIP interface", try, j + 1);
425 deviceRegister("sl0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
426 NULL, mediaShutdownNetwork, NULL);
427 msgDebug("Add mapping for %s to sl0\n", try);
428 newdesc = safe_malloc(strlen(cp) + 50);
429 sprintf(newdesc, cp, "PPP interface", try, j + 1);
430 deviceRegister("ppp0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
431 NULL, mediaShutdownNetwork, NULL);
433 msgDebug("Add mapping for %s to ppp0\n", try);
443 /* Finally, go get the disks and look for partitions to register */
444 if ((names = Disk_Names()) != NULL) {
447 for (i = 0; names[i]; i++) {
451 /* Ignore memory disks */
452 if (!strncmp(names[i], "md", 2))
457 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
458 * valid disk. This is main reason why sysinstall presents SCSI
459 * CDROM to available disks in Fdisk/Label menu. In addition,
460 * adding a blank SCSI CDROM to the menu generates floating point
461 * exception in sparc64. Disk_Names() just extracts sysctl
462 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
463 * me and that should be investigated.
464 * For temporary workaround, ignore SCSI CDROM device.
466 if (!strncmp(names[i], "cd", 2))
469 d = Open_Disk(names[i]);
471 msgDebug("Unable to open disk %s\n", names[i]);
475 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
476 dummyInit, dummyGet, dummyShutdown, d);
478 msgDebug("Found a disk device named %s\n", names[i]);
480 /* Look for existing DOS partitions to register as "DOS media devices"
481 * XXX: libdisks handling of extended partitions is too
482 * simplistic - it does not handle them containing (for
483 * example) UFS partitions
485 for (c1 = d->chunks->part; c1; c1 = c1->next) {
486 if (c1->type == fat || c1->type == efi || c1->type == extended) {
491 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
492 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
493 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
496 msgDebug("Found a DOS partition %s\n", c1->name);
497 } else if (c1->type == freebsd) {
502 for (c2 = c1->part; c2; c2 = c2->next) {
503 if (c2->type != part || c2->subtype != 7)
506 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
507 dev = deviceRegister(c2->name, c2->name, strdup(devname), DEVICE_TYPE_UFS, TRUE,
508 mediaInitUFS, mediaGetUFS, mediaShutdownUFS, NULL);
511 msgDebug("Found a UFS sub-partition %s\n", c2->name);
519 dialog_clear_norefresh();
522 /* Rescan all devices, after closing previous set - convenience function */
531 * Find all devices that match the criteria, allowing "wildcarding" as well
532 * by allowing NULL or ANY values to match all. The array returned is static
533 * and may be used until the next invocation of deviceFind().
536 deviceFind(char *name, DeviceType class)
538 static Device *found[DEV_MAX];
542 for (i = 0; i < numDevs; i++) {
543 if ((!name || !strcmp(Devices[i]->name, name))
544 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
545 found[j++] = Devices[i];
548 return j ? found : NULL;
552 deviceFindDescr(char *name, char *desc, DeviceType class)
554 static Device *found[DEV_MAX];
558 for (i = 0; i < numDevs; i++) {
559 if ((!name || !strcmp(Devices[i]->name, name)) &&
560 (!desc || !strcmp(Devices[i]->description, desc)) &&
561 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
562 found[j++] = Devices[i];
565 return j ? found : NULL;
569 deviceCount(Device **devs)
575 for (i = 0; devs[i]; i++);
580 * Create a menu listing all the devices of a certain type in the system.
581 * The passed-in menu is expected to be a "prototype" from which the new
585 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
592 devs = deviceFind(NULL, type);
593 numdevs = deviceCount(devs);
596 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
597 bcopy(menu, tmp, sizeof(DMenu));
598 for (i = 0; devs[i]; i++) {
599 tmp->items[i].prompt = devs[i]->name;
600 for (j = 0; j < numDevs; j++) {
601 if (devs[i] == Devices[j]) {
602 tmp->items[i].title = Devices[j]->description;
607 tmp->items[i].title = "<unknown device type>";
608 tmp->items[i].fire = hook;
609 tmp->items[i].checked = check;
611 tmp->items[i].title = NULL;