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 FLOPPY("fd%d", "floppy drive unit A", 4),
94 SERIAL("cuad%d", "%s on device %s (COM%d)", 16),
95 NETWORK("an", "Aironet 4500/4800 802.11 wireless adapter"),
96 NETWORK("aue", "ADMtek USB ethernet adapter"),
97 NETWORK("axe", "ASIX Electronics USB ethernet adapter"),
98 NETWORK("bfe", "Broadcom BCM440x PCI ethernet card"),
99 NETWORK("bge", "Broadcom BCM570x PCI gigabit ethernet card"),
100 NETWORK("cue", "CATC USB ethernet adapter"),
101 NETWORK("fpa", "DEC DEFPA PCI FDDI card"),
102 NETWORK("sr", "SDL T1/E1 sync serial PCI card"),
103 NETWORK("cc3i", "SDL HSSI sync serial PCI card"),
104 NETWORK("en", "Efficient Networks ATM PCI card"),
105 NETWORK("dc", "DEC/Intel 21143 (and clones) PCI fast ethernet card"),
106 NETWORK("de", "DEC DE435 PCI NIC or other DC21040-AA based card"),
107 NETWORK("fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card"),
108 NETWORK("ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"),
109 NETWORK("ep", "3Com 3C509 ethernet card/3C589 PCMCIA"),
110 NETWORK("el", "3Com 3C501 ethernet card"),
111 NETWORK("em", "Intel(R) PRO/1000 ethernet card"),
112 NETWORK("ex", "Intel EtherExpress Pro/10 ethernet card"),
113 NETWORK("fe", "Fujitsu MB86960A/MB86965A ethernet card"),
114 NETWORK("gem", "Apple/Sun GMAC ethernet adapter"),
115 NETWORK("ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"),
116 NETWORK("ix", "Intel Etherexpress ethernet card"),
117 NETWORK("kue", "Kawasaki LSI USB ethernet adapter"),
118 NETWORK("le", "DEC EtherWorks 2 or 3 ethernet card"),
119 NETWORK("lnc", "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) ethernet"),
120 NETWORK("lge", "Level 1 LXT1001 gigabit ethernet card"),
121 NETWORK("nge", "NatSemi PCI gigabit ethernet card"),
122 NETWORK("pcn", "AMD Am79c79x PCI ethernet card"),
123 NETWORK("ray", "Raytheon Raylink 802.11 wireless adaptor"),
124 NETWORK("re", "RealTek 8139C+/8169/8169S/8110S PCI ethernet card"),
125 NETWORK("rl", "RealTek 8129/8139 PCI ethernet card"),
126 NETWORK("rue", "RealTek USB ethernet card"),
127 NETWORK("sf", "Adaptec AIC-6915 PCI ethernet card"),
128 NETWORK("sis", "SiS 900/SiS 7016 PCI ethernet card"),
130 NETWORK("snc", "SONIC ethernet card"),
132 NETWORK("sn", "SMC/Megahertz ethernet card"),
133 NETWORK("ste", "Sundance ST201 PCI ethernet card"),
134 NETWORK("sk", "SysKonnect PCI gigabit ethernet card"),
135 NETWORK("tx", "SMC 9432TX ethernet card"),
136 NETWORK("txp", "3Com 3cR990 ethernet card"),
137 NETWORK("ti", "Alteon Networks PCI gigabit ethernet card"),
138 NETWORK("tl", "Texas Instruments ThunderLAN PCI ethernet card"),
139 NETWORK("vge", "VIA VT612x PCI gigabit ethernet card"),
140 NETWORK("vr", "VIA VT3043/VT86C100A Rhine PCI ethernet card"),
141 NETWORK("vlan", "IEEE 802.1Q VLAN network interface"),
142 NETWORK("vx", "3COM 3c590 / 3c595 ethernet card"),
143 NETWORK("wb", "Winbond W89C840F PCI ethernet card"),
144 NETWORK("wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter"),
145 NETWORK("wx", "Intel Gigabit Ethernet (82452) card"),
146 NETWORK("xe", "Xircom/Intel EtherExpress Pro100/16 ethernet card"),
147 NETWORK("xl", "3COM 3c90x / 3c90xB PCI ethernet card"),
148 NETWORK("fwe", "FireWire Ethernet emulation"),
149 NETWORK("plip", "Parallel Port IP (PLIP) peer connection"),
150 NETWORK("lo", "Loop-back (local) network interface"),
151 NETWORK("disc", "Software discard network interface"),
156 new_device(char *name)
160 dev = safe_malloc(sizeof(Device));
161 bzero(dev, sizeof(Device));
163 SAFE_STRCPY(dev->name, name);
167 /* Stubs for unimplemented strategy routines */
169 dummyInit(Device *dev)
175 dummyGet(Device *dev, char *dist, Boolean probe)
181 dummyShutdown(Device *dev)
187 deviceTry(struct _devname dev, char *try, int i)
192 snprintf(unit, sizeof unit, dev.name, i);
193 snprintf(try, FILENAME_MAX, "/dev/%s", unit);
195 msgDebug("deviceTry: attempting to open %s\n", try);
196 fd = open(try, O_RDONLY);
199 msgDebug("deviceTry: open of %s succeeded on first try.\n", try);
202 msgDebug("deviceTry: open of %s failed.\n", try);
207 /* Register a new device in the devices array */
209 deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled,
210 Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean),
211 void (*shutdown)(Device *), void *private)
213 Device *newdev = NULL;
215 if (numDevs == DEV_MAX)
216 msgFatal("Too many devices found!");
218 newdev = new_device(name);
219 newdev->description = desc;
220 newdev->devname = devname;
222 newdev->enabled = enabled;
223 newdev->init = init ? init : dummyInit;
224 newdev->get = get ? get : dummyGet;
225 newdev->shutdown = shutdown ? shutdown : dummyShutdown;
226 newdev->private = private;
227 Devices[numDevs] = newdev;
228 Devices[++numDevs] = NULL;
233 /* Reset the registered device chain */
239 for (i = 0; i < numDevs; i++) {
240 DEVICE_SHUTDOWN(Devices[i]);
242 /* XXX this potentially leaks Devices[i]->private if it's being
243 * used to point to something dynamic, but you're not supposed
244 * to call this routine at such times that some open instance
245 * has its private ptr pointing somewhere anyway. XXX
249 Devices[numDevs = 0] = NULL;
252 /* Get all device information for devices we have attached */
258 struct ifreq *ifptr, *end;
260 char buffer[INTERFACE_MAX * sizeof(struct ifreq)];
263 msgNotify("Probing devices, please wait (this can take a while)...");
264 /* First go for the network interfaces. Stolen shamelessly from ifconfig! */
265 ifc.ifc_len = sizeof(buffer);
266 ifc.ifc_buf = buffer;
268 s = socket(AF_INET, SOCK_DGRAM, 0);
270 goto skipif; /* Jump over network iface probing */
272 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
273 goto skipif; /* Jump over network iface probing */
276 ifflags = ifc.ifc_req->ifr_flags;
277 end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
278 for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) {
281 /* If it's not a link entry, forget it */
282 if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK)
285 /* Eliminate network devices that don't make sense */
286 if (!strncmp(ifptr->ifr_name, "lo", 2))
289 /* If we have a slip device, don't register it */
290 if (!strncmp(ifptr->ifr_name, "sl", 2)) {
293 /* And the same for ppp */
294 if (!strncmp(ifptr->ifr_name, "tun", 3) || !strncmp(ifptr->ifr_name, "ppp", 3)) {
297 /* Try and find its description */
298 for (i = 0, descr = NULL; device_names[i].name; i++) {
299 int len = strlen(device_names[i].name);
301 if (!ifptr->ifr_name || !ifptr->ifr_name[0])
303 else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) {
304 descr = device_names[i].description;
309 descr = "<unknown network interface type>";
311 deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE,
312 mediaInitNetwork, NULL, mediaShutdownNetwork, NULL);
314 msgDebug("Found a network device named %s\n", ifptr->ifr_name);
316 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
320 if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */
321 ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr));
326 /* Next, try to find all the types of devices one might need
327 * during the second stage of the installation.
329 for (i = 0; device_names[i].name; i++) {
330 for (j = 0; j < device_names[i].max; j++) {
331 char try[FILENAME_MAX];
333 switch(device_names[i].type) {
334 case DEVICE_TYPE_CDROM:
335 fd = deviceTry(device_names[i], try, j);
336 if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */
339 if (fd >= 0) close(fd);
340 snprintf(n, sizeof n, device_names[i].name, j);
341 deviceRegister(strdup(n), device_names[i].description, strdup(try),
342 DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM,
343 mediaShutdownCDROM, NULL);
345 msgDebug("Found a CDROM device for %s\n", try);
349 case DEVICE_TYPE_TAPE:
350 fd = deviceTry(device_names[i], try, j);
355 snprintf(n, sizeof n, device_names[i].name, j);
356 deviceRegister(strdup(n), device_names[i].description, strdup(try),
357 DEVICE_TYPE_TAPE, TRUE, mediaInitTape, mediaGetTape, mediaShutdownTape, NULL);
359 msgDebug("Found a TAPE device for %s\n", try);
363 case DEVICE_TYPE_DISK:
367 case DEVICE_TYPE_FLOPPY:
368 fd = deviceTry(device_names[i], try, j);
373 snprintf(n, sizeof n, device_names[i].name, j);
374 deviceRegister(strdup(n), device_names[i].description, strdup(try),
375 DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy,
376 mediaShutdownFloppy, NULL);
378 msgDebug("Found a floppy device for %s\n", try);
382 case DEVICE_TYPE_NETWORK:
383 fd = deviceTry(device_names[i], try, j);
384 /* The only network devices that you can open this way are serial ones */
389 cp = device_names[i].description;
390 /* Serial devices get a slip and ppp device each, if supported */
391 newdesc = safe_malloc(strlen(cp) + 40);
392 sprintf(newdesc, cp, "SLIP interface", try, j + 1);
393 deviceRegister("sl0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
394 NULL, mediaShutdownNetwork, NULL);
395 msgDebug("Add mapping for %s to sl0\n", try);
396 newdesc = safe_malloc(strlen(cp) + 50);
397 sprintf(newdesc, cp, "PPP interface", try, j + 1);
398 deviceRegister("ppp0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork,
399 NULL, mediaShutdownNetwork, NULL);
401 msgDebug("Add mapping for %s to ppp0\n", try);
411 /* Finally, go get the disks and look for DOS partitions to register */
412 if ((names = Disk_Names()) != NULL) {
415 for (i = 0; names[i]; i++) {
419 /* Ignore memory disks */
420 if (!strncmp(names[i], "md", 2))
425 * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a
426 * valid disk. This is main reason why sysinstall presents SCSI
427 * CDROM to available disks in Fdisk/Label menu. In addition,
428 * adding a blank SCSI CDROM to the menu generates floating point
429 * exception in sparc64. Disk_Names() just extracts sysctl
430 * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond
431 * me and that should be investigated.
432 * For temporary workaround, ignore SCSI CDROM device.
434 if (!strncmp(names[i], "cd", 2))
437 d = Open_Disk(names[i]);
439 msgDebug("Unable to open disk %s\n", names[i]);
443 deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE,
444 dummyInit, dummyGet, dummyShutdown, d);
446 msgDebug("Found a disk device named %s\n", names[i]);
448 /* Look for existing DOS partitions to register as "DOS media devices" */
449 for (c1 = d->chunks->part; c1; c1 = c1->next) {
450 if (c1->type == fat || c1->type == efi || c1->type == extended) {
455 snprintf(devname, sizeof devname, "/dev/%s", c1->name);
456 dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE,
457 mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL);
460 msgDebug("Found a DOS partition %s on drive %s\n", c1->name, d->name);
466 dialog_clear_norefresh();
469 /* Rescan all devices, after closing previous set - convenience function */
478 * Find all devices that match the criteria, allowing "wildcarding" as well
479 * by allowing NULL or ANY values to match all. The array returned is static
480 * and may be used until the next invocation of deviceFind().
483 deviceFind(char *name, DeviceType class)
485 static Device *found[DEV_MAX];
489 for (i = 0; i < numDevs; i++) {
490 if ((!name || !strcmp(Devices[i]->name, name))
491 && (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
492 found[j++] = Devices[i];
495 return j ? found : NULL;
499 deviceFindDescr(char *name, char *desc, DeviceType class)
501 static Device *found[DEV_MAX];
505 for (i = 0; i < numDevs; i++) {
506 if ((!name || !strcmp(Devices[i]->name, name)) &&
507 (!desc || !strcmp(Devices[i]->description, desc)) &&
508 (class == DEVICE_TYPE_ANY || class == Devices[i]->type))
509 found[j++] = Devices[i];
512 return j ? found : NULL;
516 deviceCount(Device **devs)
522 for (i = 0; devs[i]; i++);
527 * Create a menu listing all the devices of a certain type in the system.
528 * The passed-in menu is expected to be a "prototype" from which the new
532 deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d))
539 devs = deviceFind(NULL, type);
540 numdevs = deviceCount(devs);
543 tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1)));
544 bcopy(menu, tmp, sizeof(DMenu));
545 for (i = 0; devs[i]; i++) {
546 tmp->items[i].prompt = devs[i]->name;
547 for (j = 0; j < numDevs; j++) {
548 if (devs[i] == Devices[j]) {
549 tmp->items[i].title = Devices[j]->description;
554 tmp->items[i].title = "<unknown device type>";
555 tmp->items[i].fire = hook;
556 tmp->items[i].checked = check;
558 tmp->items[i].title = NULL;