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("cas", "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"),
109 NETWORK("cue", "CATC USB Ethernet adapter"),
110 NETWORK("cxgb", "Chelsio T3 10Gb Ethernet card"),
111 NETWORK("fpa", "DEC DEFPA PCI FDDI card"),
112 NETWORK("sr", "SDL T1/E1 sync serial PCI card"),
113 NETWORK("cc3i", "SDL HSSI sync serial PCI card"),
114 NETWORK("en", "Efficient Networks ATM PCI card"),
115 NETWORK("dc", "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"),
116 NETWORK("de", "DEC DE435 PCI NIC or other DC21040-AA based card"),
117 NETWORK("fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card"),
118 NETWORK("ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"),
119 NETWORK("ep", "3Com 3C509 Ethernet card/3C589 PCMCIA"),
120 NETWORK("em", "Intel(R) PRO/1000 Ethernet card"),
121 NETWORK("et", "Agere ET1310 based PCI Express Gigabit Ethernet card"),
122 NETWORK("ex", "Intel EtherExpress Pro/10 Ethernet card"),
123 NETWORK("fe", "Fujitsu MB86960A/MB86965A Ethernet card"),
124 NETWORK("gem", "Apple GMAC or Sun ERI/GEM Ethernet adapter"),
125 NETWORK("hme", "Sun HME (Happy Meal Ethernet) Ethernet adapter"),
126 NETWORK("ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"),
127 NETWORK("igb", "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"),
128 NETWORK("ipw", "Intel PRO/Wireless 2100 IEEE 802.11 adapter"),
129 NETWORK("iwi", "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"),
130 NETWORK("iwn", "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"),
131 NETWORK("ixgb", "Intel(R) PRO/10Gb Ethernet card"),
132 NETWORK("ixgbe", "Intel(R) PRO/10Gb Ethernet card"),
133 NETWORK("jme", "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"),
134 NETWORK("kue", "Kawasaki LSI USB Ethernet adapter"),
135 NETWORK("le", "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"),
136 NETWORK("lge", "Level 1 LXT1001 Gigabit Ethernet card"),
137 NETWORK("malo", "Marvell Libertas 88W8335 802.11 wireless adapter"),
138 NETWORK("msk", "Marvell/SysKonnect Yukon II Gigabit Ethernet"),
139 NETWORK("mxge", "Myricom Myri10GE 10Gb Ethernet card"),
140 NETWORK("nfe", "NVIDIA nForce MCP Ethernet"),
141 NETWORK("nge", "NatSemi PCI Gigabit Ethernet card"),
142 NETWORK("nve", "NVIDIA nForce MCP Ethernet"),
143 NETWORK("nxge", "Neterion Xframe 10GbE Server/Storage adapter"),
144 NETWORK("pcn", "AMD Am79c79x PCI Ethernet card"),
145 NETWORK("ral", "Ralink Technology IEEE 802.11 wireless adapter"),
146 NETWORK("ray", "Raytheon Raylink 802.11 wireless adapter"),
147 NETWORK("re", "RealTek 8139C+/8169/8169S/8110S PCI Ethernet card"),
148 NETWORK("rl", "RealTek 8129/8139 PCI Ethernet card"),
149 NETWORK("rue", "RealTek USB Ethernet card"),
150 NETWORK("rum", "Ralink Technology USB IEEE 802.11 wireless adapter"),
151 NETWORK("sf", "Adaptec AIC-6915 PCI Ethernet card"),
152 NETWORK("sis", "SiS 900/SiS 7016 PCI Ethernet card"),
154 NETWORK("snc", "SONIC Ethernet card"),
156 NETWORK("sn", "SMC/Megahertz Ethernet card"),
157 NETWORK("ste", "Sundance ST201 PCI Ethernet card"),
158 NETWORK("stge", "Sundance/Tamarack TC9021 Gigabit Ethernet"),
159 NETWORK("sk", "SysKonnect PCI Gigabit Ethernet card"),
160 NETWORK("tx", "SMC 9432TX Ethernet card"),
161 NETWORK("txp", "3Com 3cR990 Ethernet card"),
162 NETWORK("ti", "Alteon Networks PCI Gigabit Ethernet card"),
163 NETWORK("tl", "Texas Instruments ThunderLAN PCI Ethernet card"),
164 NETWORK("uath", "Atheros AR5005UG and AR5005UX USB wireless adapter"),
165 NETWORK("upgt", "Conexant/Intersil PrismGT USB wireless adapter"),
166 NETWORK("ural", "Ralink Technology RT2500USB 802.11 wireless adapter"),
167 NETWORK("urtw", "Realtek 8187L USB wireless adapter"),
168 NETWORK("vge", "VIA VT612x PCI Gigabit Ethernet card"),
169 NETWORK("vr", "VIA VT3043/VT86C100A Rhine PCI Ethernet card"),
170 NETWORK("vlan", "IEEE 802.1Q VLAN network interface"),
171 NETWORK("vx", "3COM 3c590 / 3c595 Ethernet card"),
172 NETWORK("wb", "Winbond W89C840F PCI Ethernet card"),
173 NETWORK("wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter"),
174 NETWORK("wpi", "Intel 3945ABG IEEE 802.11 wireless adapter"),
175 NETWORK("xe", "Xircom/Intel EtherExpress Pro100/16 Ethernet card"),
176 NETWORK("xl", "3COM 3c90x / 3c90xB PCI Ethernet card"),
177 NETWORK("zyd", "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"),
178 NETWORK("fwe", "FireWire Ethernet emulation"),
179 NETWORK("fwip", "IP over FireWire"),
180 NETWORK("plip", "Parallel Port IP (PLIP) peer connection"),
181 NETWORK("lo", "Loop-back (local) network interface"),
182 NETWORK("disc", "Software discard network interface"),
187 new_device(char *name)
191 dev = safe_malloc(sizeof(Device));
192 bzero(dev, sizeof(Device));
194 SAFE_STRCPY(dev->name, name);
198 /* Stubs for unimplemented strategy routines */
200 dummyInit(Device *dev)
206 dummyGet(Device *dev, char *dist, Boolean probe)
212 dummyShutdown(Device *dev)
218 deviceTry(struct _devname dev, char *try, int i)
223 snprintf(unit, sizeof unit, dev.name, i);
224 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
226 msgDebug("deviceTry: attempting to open %s\n", try);
227 fd = open(try, O_RDONLY);
230 msgDebug("deviceTry: open of %s succeeded on first try.\n", try);
233 msgDebug("deviceTry: open of %s failed.\n", try);
238 /* Register a new device in the devices array */
240 deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled,
241 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean),
242 void (*shutdown)(Device *), void *private)
244 Device *newdev = NULL;
246 if (numDevs == DEV_MAX)
247 msgFatal("Too many devices found!");
249 newdev = new_device(name);
250 newdev->description = desc;
251 newdev->devname = devname;
253 newdev->enabled = enabled;
254 newdev->init = init ? init : dummyInit;
255 newdev->get = get ? get : dummyGet;
256 newdev->shutdown = shutdown ? shutdown : dummyShutdown;
257 newdev->private = private;
258 Devices[numDevs] = newdev;
259 Devices[++numDevs] = NULL;
264 /* Reset the registered device chain */
270 for (i = 0; i < numDevs; i++) {
271 DEVICE_SHUTDOWN(Devices[i]);
273 /* XXX this potentially leaks Devices[i]->private if it's being
274 * used to point to something dynamic, but you're not supposed
275 * to call this routine at such times that some open instance
276 * has its private ptr pointing somewhere anyway. XXX
280 Devices[numDevs = 0] = NULL;
283 /* Get all device information for devices we have attached */
289 struct ifreq *ifptr, *end;
291 char buffer[INTERFACE_MAX * sizeof(struct ifreq)];
294 msgNotify("Probing devices, please wait (this can take a while)...");
295 /* First go for the network interfaces. Stolen shamelessly from ifconfig! */
296 ifc.ifc_len = sizeof(buffer);
297 ifc.ifc_buf = buffer;
299 s = socket(AF_INET, SOCK_DGRAM, 0);
301 goto skipif; /* Jump over network iface probing */
303 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
304 goto skipif; /* Jump over network iface probing */
307 ifflags = ifc.ifc_req->ifr_flags;
308 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
309 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
312 /* If it's not a link entry, forget it */
313 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
316 /* Eliminate network devices that don't make sense */
317 if (!strncmp(ifptr->ifr_name, "lo", 2))
320 /* If we have a slip device, don't register it */
321 if (!strncmp(ifptr->ifr_name, "sl", 2)) {
324 /* And the same for ppp */
325 if (!strncmp(ifptr->ifr_name, "tun", 3) || !strncmp(ifptr->ifr_name, "ppp", 3)) {
328 /* Try and find its description */
329 for (i = 0, descr = NULL; device_names[i].name; i++) {
330 int len = strlen(device_names[i].name);
332 if (!ifptr->ifr_name || !ifptr->ifr_name[0])
334 else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) {
335 descr = device_names[i].description;
340 descr = "<unknown network interface type>";
342 deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE,
343 mediaInitNetwork, NULL, mediaShutdownNetwork, NULL);
345 msgDebug("Found a network device named %s\n", ifptr->ifr_name);
347 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
351 if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */
352 ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr));
357 /* Next, try to find all the types of devices one might need
358 * during the second stage of the installation.
360 for (i = 0; device_names[i].name; i++) {
361 for (j = 0; j < device_names[i].max; j++) {
362 char try[FILENAME_MAX];
364 switch(device_names[i].type) {
365 case DEVICE_TYPE_CDROM:
366 fd = deviceTry(device_names[i], try, j);
367 if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */
370 if (fd >= 0) close(fd);
371 snprintf(n, sizeof n, device_names[i].name, j);
372 deviceRegister(strdup(n), device_names[i].description, strdup(try),
373 DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM,
374 mediaShutdownCDROM, NULL);
376 msgDebug("Found a CDROM device for %s\n", try);
380 case DEVICE_TYPE_DISK:
384 case DEVICE_TYPE_FLOPPY:
385 fd = deviceTry(device_names[i], try, j);
390 snprintf(n, sizeof n, device_names[i].name, j);
391 deviceRegister(strdup(n), device_names[i].description, strdup(try),
392 DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy,
393 mediaShutdownFloppy, NULL);
395 msgDebug("Found a floppy device for %s\n", try);
399 case DEVICE_TYPE_USB:
400 fd = deviceTry(device_names[i], try, j);
405 snprintf(n, sizeof(n), device_names[i].name, j);
406 deviceRegister(strdup(n), device_names[i].description,
407 strdup(try), DEVICE_TYPE_USB, TRUE, mediaInitUSB,
408 mediaGetUSB, mediaShutdownUSB, NULL);
411 msgDebug("Found a USB disk for %s\n", try);
415 case DEVICE_TYPE_NETWORK:
416 fd = deviceTry(device_names[i], try, j);
417 /* The only network devices that you can open this way are serial ones */
422 cp = device_names[i].description;
423 /* Serial devices get a slip and ppp device each, if supported */
424 newdesc = safe_malloc(strlen(cp) + 40);
425 sprintf(newdesc, cp, "SLIP interface", try, j + 1);
426 deviceRegister("sl0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
427 NULL, mediaShutdownNetwork, NULL);
428 msgDebug("Add mapping for %s to sl0\n", try);
429 newdesc = safe_malloc(strlen(cp) + 50);
430 sprintf(newdesc, cp, "PPP interface", try, j + 1);
431 deviceRegister("ppp0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
432 NULL, mediaShutdownNetwork, NULL);
434 msgDebug("Add mapping for %s to ppp0\n", try);
444 /* Finally, go get the disks and look for partitions to register */
445 if ((names = Disk_Names()) != NULL) {
448 for (i = 0; names[i]; i++) {
452 /* Ignore memory disks */
453 if (!strncmp(names[i], "md", 2))
458 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
459 * valid disk. This is main reason why sysinstall presents SCSI
460 * CDROM to available disks in Fdisk/Label menu. In addition,
461 * adding a blank SCSI CDROM to the menu generates floating point
462 * exception in sparc64. Disk_Names() just extracts sysctl
463 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
464 * me and that should be investigated.
465 * For temporary workaround, ignore SCSI CDROM device.
467 if (!strncmp(names[i], "cd", 2))
470 d = Open_Disk(names[i]);
472 msgDebug("Unable to open disk %s\n", names[i]);
476 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
477 dummyInit, dummyGet, dummyShutdown, d);
479 msgDebug("Found a disk device named %s\n", names[i]);
481 /* Look for existing DOS partitions to register as "DOS media devices"
482 * XXX: libdisks handling of extended partitions is too
483 * simplistic - it does not handle them containing (for
484 * example) UFS partitions
486 for (c1 = d->chunks->part; c1; c1 = c1->next) {
487 if (c1->type == fat || c1->type == efi || c1->type == extended) {
492 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
493 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
494 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
497 msgDebug("Found a DOS partition %s\n", c1->name);
498 } else if (c1->type == freebsd) {
503 for (c2 = c1->part; c2; c2 = c2->next) {
504 if (c2->type != part || c2->subtype != 7)
507 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
508 dev = deviceRegister(c2->name, c2->name, strdup(devname), DEVICE_TYPE_UFS, TRUE,
509 mediaInitUFS, mediaGetUFS, mediaShutdownUFS, NULL);
512 msgDebug("Found a UFS sub-partition %s\n", c2->name);
520 dialog_clear_norefresh();
523 /* Rescan all devices, after closing previous set - convenience function */
532 * Find all devices that match the criteria, allowing "wildcarding" as well
533 * by allowing NULL or ANY values to match all. The array returned is static
534 * and may be used until the next invocation of deviceFind().
537 deviceFind(char *name, DeviceType class)
539 static Device *found[DEV_MAX];
543 for (i = 0; i < numDevs; i++) {
544 if ((!name || !strcmp(Devices[i]->name, name))
545 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
546 found[j++] = Devices[i];
549 return j ? found : NULL;
553 deviceFindDescr(char *name, char *desc, DeviceType class)
555 static Device *found[DEV_MAX];
559 for (i = 0; i < numDevs; i++) {
560 if ((!name || !strcmp(Devices[i]->name, name)) &&
561 (!desc || !strcmp(Devices[i]->description, desc)) &&
562 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
563 found[j++] = Devices[i];
566 return j ? found : NULL;
570 deviceCount(Device **devs)
576 for (i = 0; devs[i]; i++);
581 * Create a menu listing all the devices of a certain type in the system.
582 * The passed-in menu is expected to be a "prototype" from which the new
586 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
593 devs = deviceFind(NULL, type);
594 numdevs = deviceCount(devs);
597 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
598 bcopy(menu, tmp, sizeof(DMenu));
599 for (i = 0; devs[i]; i++) {
600 tmp->items[i].prompt = devs[i]->name;
601 for (j = 0; j < numDevs; j++) {
602 if (devs[i] == Devices[j]) {
603 tmp->items[i].title = Devices[j]->description;
608 tmp->items[i].title = "<unknown device type>";
609 tmp->items[i].fire = hook;
610 tmp->items[i].checked = check;
612 tmp->items[i].title = NULL;