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 TAPE(name, descr, max) \
61 DEVICE_ENTRY(DEVICE_TYPE_TAPE, name, descr, max)
62 #define DISK(name, descr, max) \
63 DEVICE_ENTRY(DEVICE_TYPE_DISK, name, descr, max)
64 #define FLOPPY(name, descr, max) \
65 DEVICE_ENTRY(DEVICE_TYPE_FLOPPY, name, descr, max)
66 #define NETWORK(name, descr) \
67 DEVICE_ENTRY(DEVICE_TYPE_NETWORK, name, descr, 0)
68 #define SERIAL(name, descr, max) \
69 DEVICE_ENTRY(DEVICE_TYPE_NETWORK, 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 TAPE("sa%d", "SCSI tape drive", 4),
82 TAPE("rwt%d", "Wangtek tape drive", 4),
83 DISK("da%d", "SCSI disk device", 16),
84 DISK("ad%d", "ATA/IDE disk device", 16),
85 DISK("ar%d", "ATA/IDE RAID device", 16),
86 DISK("afd%d", "ATAPI/IDE floppy device", 4),
87 DISK("mlxd%d", "Mylex RAID disk", 4),
88 DISK("amrd%d", "AMI MegaRAID drive", 4),
89 DISK("idad%d", "Compaq RAID array", 4),
90 DISK("twed%d", "3ware ATA RAID array", 4),
91 DISK("aacd%d", "Adaptec FSA RAID array", 4),
92 DISK("ipsd%d", "IBM ServeRAID RAID array", 4),
93 DISK("mfid%d", "LSI MegaRAID SAS array", 4),
94 FLOPPY("fd%d", "floppy drive unit A", 4),
95 SERIAL("cuad%d", "%s on device %s (COM%d)", 16),
96 NETWORK("ae", "Attansic/Atheros L2 FastEthernet"),
97 NETWORK("age", "Attansic/Atheros L1 Gigabit Ethernet"),
98 NETWORK("an", "Aironet 4500/4800 802.11 wireless adapter"),
99 NETWORK("ath", "Atheros IEEE 802.11 wireless adapter"),
100 NETWORK("aue", "ADMtek USB Ethernet adapter"),
101 NETWORK("axe", "ASIX Electronics USB Ethernet adapter"),
102 NETWORK("bce", "Broadcom NetXtreme II Gigabit Ethernet card"),
103 NETWORK("bfe", "Broadcom BCM440x PCI Ethernet card"),
104 NETWORK("bge", "Broadcom BCM570x PCI Gigabit Ethernet card"),
105 NETWORK("cue", "CATC USB Ethernet adapter"),
106 NETWORK("cxgb", "Chelsio T3 10Gb Ethernet card"),
107 NETWORK("fpa", "DEC DEFPA PCI FDDI card"),
108 NETWORK("sr", "SDL T1/E1 sync serial PCI card"),
109 NETWORK("cc3i", "SDL HSSI sync serial PCI card"),
110 NETWORK("en", "Efficient Networks ATM PCI card"),
111 NETWORK("dc", "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"),
112 NETWORK("de", "DEC DE435 PCI NIC or other DC21040-AA based card"),
113 NETWORK("fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card"),
114 NETWORK("ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"),
115 NETWORK("ep", "3Com 3C509 Ethernet card/3C589 PCMCIA"),
116 NETWORK("em", "Intel(R) PRO/1000 Ethernet card"),
117 NETWORK("ex", "Intel EtherExpress Pro/10 Ethernet card"),
118 NETWORK("fe", "Fujitsu MB86960A/MB86965A Ethernet card"),
119 NETWORK("gem", "Apple GMAC or Sun ERI/GEM Ethernet adapter"),
120 NETWORK("hme", "Sun HME (Happy Meal Ethernet) Ethernet adapter"),
121 NETWORK("ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"),
122 NETWORK("ipw", "Intel PRO/Wireless 2100 IEEE 802.11 adapter"),
123 NETWORK("iwi", "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"),
124 NETWORK("ixgb", "Intel(R) PRO/10Gb Ethernet card"),
125 NETWORK("jme", "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"),
126 NETWORK("kue", "Kawasaki LSI USB Ethernet adapter"),
127 NETWORK("le", "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"),
128 NETWORK("lge", "Level 1 LXT1001 Gigabit Ethernet card"),
129 NETWORK("malo", "Marvell Libertas 88W8335 802.11 wireless adapter"),
130 NETWORK("msk", "Marvell/SysKonnect Yukon II Gigabit Ethernet"),
131 NETWORK("mxge", "Myricom Myri10GE 10Gb Ethernet card"),
132 NETWORK("nfe", "NVIDIA nForce MCP Ethernet"),
133 NETWORK("nge", "NatSemi PCI Gigabit Ethernet card"),
134 NETWORK("nve", "NVIDIA nForce MCP Ethernet"),
135 NETWORK("pcn", "AMD Am79c79x PCI Ethernet card"),
136 NETWORK("ral", "Ralink Technology IEEE 802.11 wireless adapter"),
137 NETWORK("ray", "Raytheon Raylink 802.11 wireless adapter"),
138 NETWORK("re", "RealTek 8139C+/8169/8169S/8110S PCI Ethernet card"),
139 NETWORK("rl", "RealTek 8129/8139 PCI Ethernet card"),
140 NETWORK("rue", "RealTek USB Ethernet card"),
141 NETWORK("rum", "Ralink Technology USB IEEE 802.11 wireless adapter"),
142 NETWORK("sf", "Adaptec AIC-6915 PCI Ethernet card"),
143 NETWORK("sis", "SiS 900/SiS 7016 PCI Ethernet card"),
145 NETWORK("snc", "SONIC Ethernet card"),
147 NETWORK("sn", "SMC/Megahertz Ethernet card"),
148 NETWORK("ste", "Sundance ST201 PCI Ethernet card"),
149 NETWORK("stge", "Sundance/Tamarack TC9021 Gigabit Ethernet"),
150 NETWORK("sk", "SysKonnect PCI Gigabit Ethernet card"),
151 NETWORK("tx", "SMC 9432TX Ethernet card"),
152 NETWORK("txp", "3Com 3cR990 Ethernet card"),
153 NETWORK("ti", "Alteon Networks PCI Gigabit Ethernet card"),
154 NETWORK("tl", "Texas Instruments ThunderLAN PCI Ethernet card"),
155 NETWORK("upgt", "Conexant/Intersil PrismGT USB wireless adapter"),
156 NETWORK("ural", "Ralink Technology RT2500USB 802.11 wireless adapter"),
157 NETWORK("vge", "VIA VT612x PCI Gigabit Ethernet card"),
158 NETWORK("vr", "VIA VT3043/VT86C100A Rhine PCI Ethernet card"),
159 NETWORK("vlan", "IEEE 802.1Q VLAN network interface"),
160 NETWORK("vx", "3COM 3c590 / 3c595 Ethernet card"),
161 NETWORK("wb", "Winbond W89C840F PCI Ethernet card"),
162 NETWORK("wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter"),
163 NETWORK("wpi", "Intel 3945ABG IEEE 802.11 wireless adapter"),
164 NETWORK("xe", "Xircom/Intel EtherExpress Pro100/16 Ethernet card"),
165 NETWORK("xl", "3COM 3c90x / 3c90xB PCI Ethernet card"),
166 NETWORK("zyd", "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"),
167 NETWORK("fwe", "FireWire Ethernet emulation"),
168 NETWORK("fwip", "IP over FireWire"),
169 NETWORK("plip", "Parallel Port IP (PLIP) peer connection"),
170 NETWORK("lo", "Loop-back (local) network interface"),
171 NETWORK("disc", "Software discard network interface"),
176 new_device(char *name)
180 dev = safe_malloc(sizeof(Device));
181 bzero(dev, sizeof(Device));
183 SAFE_STRCPY(dev->name, name);
187 /* Stubs for unimplemented strategy routines */
189 dummyInit(Device *dev)
195 dummyGet(Device *dev, char *dist, Boolean probe)
201 dummyShutdown(Device *dev)
207 deviceTry(struct _devname dev, char *try, int i)
212 snprintf(unit, sizeof unit, dev.name, i);
213 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
215 msgDebug("deviceTry: attempting to open %s\n", try);
216 fd = open(try, O_RDONLY);
219 msgDebug("deviceTry: open of %s succeeded on first try.\n", try);
222 msgDebug("deviceTry: open of %s failed.\n", try);
227 /* Register a new device in the devices array */
229 deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled,
230 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean),
231 void (*shutdown)(Device *), void *private)
233 Device *newdev = NULL;
235 if (numDevs == DEV_MAX)
236 msgFatal("Too many devices found!");
238 newdev = new_device(name);
239 newdev->description = desc;
240 newdev->devname = devname;
242 newdev->enabled = enabled;
243 newdev->init = init ? init : dummyInit;
244 newdev->get = get ? get : dummyGet;
245 newdev->shutdown = shutdown ? shutdown : dummyShutdown;
246 newdev->private = private;
247 Devices[numDevs] = newdev;
248 Devices[++numDevs] = NULL;
253 /* Reset the registered device chain */
259 for (i = 0; i < numDevs; i++) {
260 DEVICE_SHUTDOWN(Devices[i]);
262 /* XXX this potentially leaks Devices[i]->private if it's being
263 * used to point to something dynamic, but you're not supposed
264 * to call this routine at such times that some open instance
265 * has its private ptr pointing somewhere anyway. XXX
269 Devices[numDevs = 0] = NULL;
272 /* Get all device information for devices we have attached */
278 struct ifreq *ifptr, *end;
280 char buffer[INTERFACE_MAX * sizeof(struct ifreq)];
283 msgNotify("Probing devices, please wait (this can take a while)...");
284 /* First go for the network interfaces. Stolen shamelessly from ifconfig! */
285 ifc.ifc_len = sizeof(buffer);
286 ifc.ifc_buf = buffer;
288 s = socket(AF_INET, SOCK_DGRAM, 0);
290 goto skipif; /* Jump over network iface probing */
292 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
293 goto skipif; /* Jump over network iface probing */
296 ifflags = ifc.ifc_req->ifr_flags;
297 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
298 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
301 /* If it's not a link entry, forget it */
302 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
305 /* Eliminate network devices that don't make sense */
306 if (!strncmp(ifptr->ifr_name, "lo", 2))
309 /* If we have a slip device, don't register it */
310 if (!strncmp(ifptr->ifr_name, "sl", 2)) {
313 /* And the same for ppp */
314 if (!strncmp(ifptr->ifr_name, "tun", 3) || !strncmp(ifptr->ifr_name, "ppp", 3)) {
317 /* Try and find its description */
318 for (i = 0, descr = NULL; device_names[i].name; i++) {
319 int len = strlen(device_names[i].name);
321 if (!ifptr->ifr_name || !ifptr->ifr_name[0])
323 else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) {
324 descr = device_names[i].description;
329 descr = "<unknown network interface type>";
331 deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE,
332 mediaInitNetwork, NULL, mediaShutdownNetwork, NULL);
334 msgDebug("Found a network device named %s\n", ifptr->ifr_name);
336 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
340 if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */
341 ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr));
346 /* Next, try to find all the types of devices one might need
347 * during the second stage of the installation.
349 for (i = 0; device_names[i].name; i++) {
350 for (j = 0; j < device_names[i].max; j++) {
351 char try[FILENAME_MAX];
353 switch(device_names[i].type) {
354 case DEVICE_TYPE_CDROM:
355 fd = deviceTry(device_names[i], try, j);
356 if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */
359 if (fd >= 0) close(fd);
360 snprintf(n, sizeof n, device_names[i].name, j);
361 deviceRegister(strdup(n), device_names[i].description, strdup(try),
362 DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM,
363 mediaShutdownCDROM, NULL);
365 msgDebug("Found a CDROM device for %s\n", try);
369 case DEVICE_TYPE_TAPE:
370 fd = deviceTry(device_names[i], try, j);
375 snprintf(n, sizeof n, device_names[i].name, j);
376 deviceRegister(strdup(n), device_names[i].description, strdup(try),
377 DEVICE_TYPE_TAPE, TRUE, mediaInitTape, mediaGetTape, mediaShutdownTape, NULL);
379 msgDebug("Found a TAPE device for %s\n", try);
383 case DEVICE_TYPE_DISK:
387 case DEVICE_TYPE_FLOPPY:
388 fd = deviceTry(device_names[i], try, j);
393 snprintf(n, sizeof n, device_names[i].name, j);
394 deviceRegister(strdup(n), device_names[i].description, strdup(try),
395 DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy,
396 mediaShutdownFloppy, NULL);
398 msgDebug("Found a floppy device for %s\n", try);
402 case DEVICE_TYPE_NETWORK:
403 fd = deviceTry(device_names[i], try, j);
404 /* The only network devices that you can open this way are serial ones */
409 cp = device_names[i].description;
410 /* Serial devices get a slip and ppp device each, if supported */
411 newdesc = safe_malloc(strlen(cp) + 40);
412 sprintf(newdesc, cp, "SLIP interface", try, j + 1);
413 deviceRegister("sl0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
414 NULL, mediaShutdownNetwork, NULL);
415 msgDebug("Add mapping for %s to sl0\n", try);
416 newdesc = safe_malloc(strlen(cp) + 50);
417 sprintf(newdesc, cp, "PPP interface", try, j + 1);
418 deviceRegister("ppp0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
419 NULL, mediaShutdownNetwork, NULL);
421 msgDebug("Add mapping for %s to ppp0\n", try);
431 /* Finally, go get the disks and look for DOS partitions to register */
432 if ((names = Disk_Names()) != NULL) {
435 for (i = 0; names[i]; i++) {
439 /* Ignore memory disks */
440 if (!strncmp(names[i], "md", 2))
445 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
446 * valid disk. This is main reason why sysinstall presents SCSI
447 * CDROM to available disks in Fdisk/Label menu. In addition,
448 * adding a blank SCSI CDROM to the menu generates floating point
449 * exception in sparc64. Disk_Names() just extracts sysctl
450 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
451 * me and that should be investigated.
452 * For temporary workaround, ignore SCSI CDROM device.
454 if (!strncmp(names[i], "cd", 2))
457 d = Open_Disk(names[i]);
459 msgDebug("Unable to open disk %s\n", names[i]);
463 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
464 dummyInit, dummyGet, dummyShutdown, d);
466 msgDebug("Found a disk device named %s\n", names[i]);
468 /* Look for existing DOS partitions to register as "DOS media devices" */
469 for (c1 = d->chunks->part; c1; c1 = c1->next) {
470 if (c1->type == fat || c1->type == efi || c1->type == extended) {
475 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
476 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
477 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
480 msgDebug("Found a DOS partition %s on drive %s\n", c1->name, d->name);
486 dialog_clear_norefresh();
489 /* Rescan all devices, after closing previous set - convenience function */
498 * Find all devices that match the criteria, allowing "wildcarding" as well
499 * by allowing NULL or ANY values to match all. The array returned is static
500 * and may be used until the next invocation of deviceFind().
503 deviceFind(char *name, DeviceType class)
505 static Device *found[DEV_MAX];
509 for (i = 0; i < numDevs; i++) {
510 if ((!name || !strcmp(Devices[i]->name, name))
511 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
512 found[j++] = Devices[i];
515 return j ? found : NULL;
519 deviceFindDescr(char *name, char *desc, DeviceType class)
521 static Device *found[DEV_MAX];
525 for (i = 0; i < numDevs; i++) {
526 if ((!name || !strcmp(Devices[i]->name, name)) &&
527 (!desc || !strcmp(Devices[i]->description, desc)) &&
528 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
529 found[j++] = Devices[i];
532 return j ? found : NULL;
536 deviceCount(Device **devs)
542 for (i = 0; devs[i]; i++);
547 * Create a menu listing all the devices of a certain type in the system.
548 * The passed-in menu is expected to be a "prototype" from which the new
552 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
559 devs = deviceFind(NULL, type);
560 numdevs = deviceCount(devs);
563 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
564 bcopy(menu, tmp, sizeof(DMenu));
565 for (i = 0; devs[i]; i++) {
566 tmp->items[i].prompt = devs[i]->name;
567 for (j = 0; j < numDevs; j++) {
568 if (devs[i] == Devices[j]) {
569 tmp->items[i].title = Devices[j]->description;
574 tmp->items[i].title = "<unknown device type>";
575 tmp->items[i].fire = hook;
576 tmp->items[i].checked = check;
578 tmp->items[i].title = NULL;