Index: head/usr.sbin/sysinstall/Makefile =================================================================== --- head/usr.sbin/sysinstall/Makefile (revision 209068) +++ head/usr.sbin/sysinstall/Makefile (revision 209069) @@ -1,125 +1,125 @@ # $FreeBSD$ .if ${MACHINE_ARCH} != "ia64" _wizard= wizard.c .endif PROG= sysinstall MAN= sysinstall.8 SRCS= anonFTP.c cdrom.c command.c config.c devices.c dhcp.c \ disks.c dispatch.c dist.c dmenu.c doc.c dos.c floppy.c \ ftp.c globals.c http.c index.c install.c installUpgrade.c keymap.c \ label.c main.c makedevs.c media.c menus.c misc.c modules.c \ mouse.c msg.c network.c nfs.c options.c package.c \ system.c tcpip.c termcap.c ttys.c ufs.c usb.c user.c \ variable.c ${_wizard} keymap.h countries.h -CFLAGS+= -DUSE_GZIP=1 +CFLAGS+= -DUSE_GZIP=1 -fno-strict-aliasing .if ${MACHINE} == "pc98" CFLAGS+= -DPC98 .endif CFLAGS+= -I${.CURDIR}/../../gnu/lib/libdialog -I. -WARNS?= 1 +WARNS?= 2 DPADD= ${LIBDIALOG} ${LIBNCURSES} ${LIBUTIL} ${LIBDISK} ${LIBFTPIO} LDADD= -ldialog -lncurses -lutil -ldisk -lftpio CLEANFILES= makedevs.c rtermcap CLEANFILES+= keymap.tmp keymap.h countries.tmp countries.h .if exists(${.CURDIR}/../../share/termcap/termcap.src) RTERMCAP= TERMCAP=${.CURDIR}/../../share/termcap/termcap.src ./rtermcap .else RTERMCAP= ./rtermcap .endif makedevs.c: Makefile rtermcap echo '#include ' > makedevs.c ${RTERMCAP} ansi | \ file2c 'const char termcap_ansi[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} cons25w | \ file2c 'const char termcap_cons25w[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} cons25 | \ file2c 'const char termcap_cons25[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} cons25-m | \ file2c 'const char termcap_cons25_m[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} cons25r | \ file2c 'const char termcap_cons25r[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} cons25r-m | \ file2c 'const char termcap_cons25r_m[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} cons25l1 | \ file2c 'const char termcap_cons25l1[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} cons25l1-m | \ file2c 'const char termcap_cons25l1_m[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} vt100 | \ file2c 'const char termcap_vt100[] = {' ',0};' \ >> makedevs.c ${RTERMCAP} xterm | \ file2c 'const char termcap_xterm[] = {' ',0};' \ >> makedevs.c build-tools: rtermcap rtermcap: rtermcap.c ${CC} -o ${.TARGET} ${.ALLSRC} -ltermcap .if ${MACHINE} == "pc98" KEYMAPS= jp.pc98 jp.pc98.iso .else KEYMAPS= be.iso bg.bds.ctrlcaps bg.phonetic.ctrlcaps br275.iso \ ce.iso2 cs.latin2.qwertz danish.iso el.iso07 \ estonian.cp850 estonian.iso estonian.iso15 finnish.iso fr.iso \ german.iso gr.elot.acc gr.us101.acc hr.iso hu.iso2.101keys \ it.iso icelandic.iso jp.106 norwegian.iso pl_PL.ISO8859-2 \ pt.iso ru.koi8-r si.iso sk.iso2 spanish.iso swedish.iso \ swissfrench.iso \ swissgerman.iso ua.koi8-u ua.koi8-u.shift.alt uk.iso us.dvorak \ us.iso us.pc-ctrl us.unix .endif keymap.h: rm -f keymap.tmp for map in ${KEYMAPS} ; do \ KEYMAP_PATH=${.CURDIR}/../../share/syscons/keymaps \ kbdcontrol -L $$map | \ sed -e '/^static accentmap_t/,$$d' >> keymap.tmp ; \ done echo "static struct keymapInfo keymapInfos[] = {" >> keymap.tmp for map in ${KEYMAPS} ; do \ echo -n ' { "'$$map'", ' >> keymap.tmp ; \ echo "&keymap_$$map }," | tr '[-.]' '_' >> keymap.tmp ; \ done ( echo " { NULL, NULL }"; echo "};" ; echo "" ) >> keymap.tmp mv keymap.tmp keymap.h countries.h: ${.CURDIR}/../../share/misc/iso3166 rm -f countries.tmp awk 'BEGIN { \ FS = "\t"; \ num = 1; \ print "DMenu MenuCountry = {"; \ print " DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS,"; \ print " \"Country Selection\","; \ print " \"Please choose a country, region, or group.\\n\""; \ print " \"Select an item using [SPACE] or [ENTER].\","; \ printf " NULL,\n NULL,\n { "; \ } \ /^[[:space:]]*#/ {next;} \ {if (num > 1) {printf " ";} \ print "{ \"" num "\", \"" $$4 "\"" \ ", dmenuVarCheck, dmenuSetCountryVariable" \ ", NULL, VAR_COUNTRY \"=" tolower($$1) "\" },"; \ ++num;} \ END {print " { NULL } }\n};\n";}' < ${.ALLSRC} > countries.tmp mv countries.tmp ${.TARGET} .include Index: head/usr.sbin/sysinstall/install.c =================================================================== --- head/usr.sbin/sysinstall/install.c (revision 209068) +++ head/usr.sbin/sysinstall/install.c (revision 209069) @@ -1,1313 +1,1312 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include #define MSDOSFS #include #include #include #undef MSDOSFS #include #include #include #include #include #include /* Hack for rsaref package add, which displays interactive license. * Used by package.c */ int _interactiveHack; int FixItMode = 0; int NCpus; static void create_termcap(void); static void fixit_common(void); int fixit_livefs_common(dialogMenuItem *self); #define TERMCAP_FILE "/usr/share/misc/termcap" static void installConfigure(void); Boolean checkLabels(Boolean whinge) { Device **devs; Boolean status; Disk *disk; PartInfo *pi; Chunk *c1, *c2; int i; /* Don't allow whinging if noWarn is set */ if (variable_get(VAR_NO_WARN)) whinge = FALSE; status = TRUE; HomeChunk = RootChunk = SwapChunk = NULL; TmpChunk = UsrChunk = VarChunk = NULL; #ifdef __ia64__ EfiChunk = NULL; #endif /* We don't need to worry about root/usr/swap if we're already multiuser */ if (!RunningAsInit) return status; devs = deviceFind(NULL, DEVICE_TYPE_DISK); /* First verify that we have a root device */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for root filesystem\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { #ifdef __ia64__ c2 = c1; #elif defined(__powerpc__) if (c1->type == apple) { for (c2 = c1->part; c2; c2 = c2->next) { #else if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { #endif pi = (PartInfo *)c2->private_data; if (c2->type == part && c2->subtype != FS_SWAP && pi != NULL) { if (!strcmp(pi->mountpoint, "/")) { if (RootChunk) { if (whinge) msgConfirm("WARNING: You have more than one root device set?!\n" "Using the first one found."); continue; } else { RootChunk = c2; if (isDebug()) msgDebug("Found rootdev at %s!\n", RootChunk->name); } } else if (!strcmp(pi->mountpoint, "/usr")) { if (UsrChunk) { if (whinge) msgConfirm("WARNING: You have more than one /usr filesystem.\n" "Using the first one found."); continue; } else { UsrChunk = c2; if (isDebug()) msgDebug("Found usrdev at %s!\n", UsrChunk->name); } } else if (!strcmp(pi->mountpoint, "/var")) { if (VarChunk) { if (whinge) msgConfirm("WARNING: You have more than one /var filesystem.\n" "Using the first one found."); continue; } else { VarChunk = c2; if (isDebug()) msgDebug("Found vardev at %s!\n", VarChunk->name); } } else if (!strcmp(pi->mountpoint, "/tmp")) { if (TmpChunk) { if (whinge) msgConfirm("WARNING: You have more than one /tmp filesystem.\n" "Using the first one found."); continue; } else { TmpChunk = c2; if (isDebug()) msgDebug("Found tmpdev at %s!\n", TmpChunk->name); } } else if (!strcmp(pi->mountpoint, "/home")) { if (HomeChunk) { if (whinge) msgConfirm("WARNING: You have more than one /home filesystem.\n" "Using the first one found."); continue; } else { HomeChunk = c2; if (isDebug()) msgDebug("Found homedev at %s!\n", HomeChunk->name); } } } #ifndef __ia64__ } } #endif } } /* Now check for swap devices */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for swap partitions\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { #ifdef __ia64__ c2 = c1; #elif defined(__powerpc__) if (c1->type == apple) { for (c2 = c1->part; c2; c2 = c2->next) { #else if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { #endif if (c2->type == part && c2->subtype == FS_SWAP && !SwapChunk) { SwapChunk = c2; if (isDebug()) msgDebug("Found swapdev at %s!\n", SwapChunk->name); break; } #ifndef __ia64__ } } #endif } } #ifdef __ia64__ for (i = 0; devs[i] != NULL; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; for (c1 = disk->chunks->part; c1 != NULL; c1 = c1->next) { pi = (PartInfo *)c1->private_data; if (c1->type == efi && pi != NULL && pi->mountpoint[0] == '/') EfiChunk = c1; } } #endif if (!RootChunk && whinge) { msgConfirm("No root device found - you must label a partition as /\n" "in the label editor."); status = FALSE; } if (!SwapChunk && whinge) { if (msgYesNo("No swap devices found - you should create at least one\n" "swap partition. Without swap, the install will fail\n" "if you do not have enough RAM. Continue anyway?")) status = FALSE; } #ifdef __ia64__ if (EfiChunk == NULL && whinge) { if (msgYesNo("No (mounted) EFI system partition found. Is this what you want?")) status = FALSE; } #endif return status; } static int installInitial(void) { static Boolean alreadyDone = FALSE; int status = DITEM_SUCCESS; if (alreadyDone) return DITEM_SUCCESS; if (!variable_get(DISK_LABELLED)) { msgConfirm("You need to assign disk labels before you can proceed with\n" "the installation."); return DITEM_FAILURE; } /* If it's labelled, assume it's also partitioned */ if (!variable_get(DISK_PARTITIONED)) variable_set2(DISK_PARTITIONED, "yes", 0); /* If we refuse to proceed, bail. */ dialog_clear_norefresh(); if (!variable_get(VAR_NO_WARN)) { if (msgYesNo( "Last Chance! Are you SURE you want continue the installation?\n\n" "If you're running this on a disk with data you wish to save\n" "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n" "proceeding!\n\n" "We can take no responsibility for lost disk contents!") != 0) return DITEM_FAILURE; } if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) { msgConfirm("Couldn't make filesystems properly. Aborting."); return DITEM_FAILURE; } if (!copySelf()) { msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n" "root file system. Aborting!"); return DITEM_FAILURE; } if (!Restarting && chroot("/mnt") == -1) { msgConfirm("installInitial: Unable to chroot to %s - this is bad!", "/mnt"); return DITEM_FAILURE; } chdir("/"); variable_set2(RUNNING_ON_ROOT, "yes", 0); /* Configure various files in /etc */ if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; if (DITEM_STATUS(configFstab(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; /* stick a helpful shell over on the 4th VTY */ if (!variable_get(VAR_NO_HOLOSHELL)) systemCreateHoloshell(); alreadyDone = TRUE; return status; } int installFixitHoloShell(dialogMenuItem *self) { FixItMode = 1; systemCreateHoloshell(); FixItMode = 0; return DITEM_SUCCESS; } /* * Load the live filesystem from USB media. */ int installFixitUSB(dialogMenuItem *self) { if (!RunningAsInit) return (DITEM_SUCCESS); variable_set2(SYSTEM_STATE, "fixit", 0); if (DITEM_STATUS(mediaSetUSB(NULL)) != DITEM_SUCCESS || !DEVICE_INIT(mediaDevice)) { msgConfirm("No USB devices found!"); return (DITEM_FAILURE); } else if (!file_readable("/dist/rescue/ldconfig")) { msgConfirm("Unable to find a FreeBSD live filesystem."); return (DITEM_FAILURE); } if (DITEM_STATUS(fixit_livefs_common(self)) == DITEM_FAILURE) return (DITEM_FAILURE); mediaClose(); return (DITEM_SUCCESS); } int installFixitCDROM(dialogMenuItem *self) { - struct stat sb; int need_eject; if (!RunningAsInit) return DITEM_SUCCESS; variable_set2(SYSTEM_STATE, "fixit", 0); need_eject = 0; CDROMInitQuiet = 1; while (1) { if (need_eject) msgConfirm( "Please insert a FreeBSD live filesystem CD/DVD and press return"); if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !DEVICE_INIT(mediaDevice)) { /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */ mediaClose(); if (need_eject && msgYesNo("Unable to mount the disc. Do you want to try again?") != 0) return DITEM_FAILURE; } else if (!file_readable("/dist/rescue/ldconfig")) { mediaClose(); if (need_eject && msgYesNo("Unable to find a FreeBSD live filesystem. Do you want to try again?") != 0) return DITEM_FAILURE; } else break; CDROMInitQuiet = 0; need_eject = 1; } CDROMInitQuiet = 0; if (DITEM_STATUS(fixit_livefs_common(self)) == DITEM_FAILURE) return (DITEM_FAILURE); mediaClose(); if (need_eject) msgConfirm("Please remove the FreeBSD fixit CDROM/DVD now."); return DITEM_SUCCESS; } int installFixitFloppy(dialogMenuItem *self) { struct ufs_args args; extern char *distWanted; if (!RunningAsInit) return DITEM_SUCCESS; /* Try to open the floppy drive */ if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE || !mediaDevice) { msgConfirm("Unable to set media device to floppy."); mediaClose(); return DITEM_FAILURE; } memset(&args, 0, sizeof(args)); args.fspec = mediaDevice->devname; mediaDevice->private = "/mnt2"; distWanted = NULL; Mkdir("/mnt2"); variable_set2(SYSTEM_STATE, "fixit", 0); while (1) { if (!DEVICE_INIT(mediaDevice)) { if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n" "or unclean filesystem. Do you want to try again?")) return DITEM_FAILURE; } else break; } if (!directory_exists("/tmp")) (void)symlink("/mnt2/tmp", "/tmp"); fixit_common(); mediaClose(); msgConfirm("Please remove the fixit floppy now."); return DITEM_SUCCESS; } /* * The common code for both fixit variants. */ static void fixit_common(void) { pid_t child; int waitstatus; if (!directory_exists("/var/tmp/vi.recover")) { if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) { msgConfirm("Warning: Was unable to create a /var/tmp/vi.recover directory.\n" "vi will kvetch and moan about it as a result but should still\n" "be essentially usable."); } } if (!directory_exists("/bin")) (void)Mkdir("/bin"); (void)symlink("/stand/sh", "/bin/sh"); /* Link the /etc/ files */ if (DITEM_STATUS(Mkdir("/etc")) != DITEM_SUCCESS) msgConfirm("Unable to create an /etc directory! Things are weird on this floppy.."); else if ((symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/protocols", "/etc/protocols") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/group", "/etc/group") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/services", "/etc/services") == -1 && errno != EEXIST)) msgConfirm("Couldn't symlink the /etc/ files! I'm not sure I like this.."); if (!file_readable(TERMCAP_FILE)) create_termcap(); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if (!(child = fork())) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("fixit: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(0, TCSANOW, &foo) == -1) msgDebug("fixit shell: Unable to set erase character.\n"); } else msgDebug("fixit shell: Unable to get terminal attributes!\n"); setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:" "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Waiting for fixit shell to exit.\n" "When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here.\n\n"); fflush(stdout); } else { ioctl(fd, VT_ACTIVATE, 0); } /* use the .profile from the fixit medium */ setenv("HOME", "/mnt2", 1); chdir("/mnt2"); execlp("sh", "-sh", (char *)0); msgDebug("fixit shell: Failed to execute shell!\n"); _exit(1);; } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { dialog_clear_norefresh(); msgNotify("Waiting for fixit shell to exit. Go to VTY4 now by\n" "typing ALT-F4. When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here.\n"); } (void)waitpid(child, &waitstatus, 0); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemResumeDialog(); else if (OnVTY) { ioctl(0, VT_ACTIVATE, 0); msgInfo(NULL); } } dialog_clear(); } /* * Some path/lib setup is required for the livefs fixit image. Since there's * more than one media type for livefs now, this has been broken off into it's * own function. */ int fixit_livefs_common(dialogMenuItem *self) { struct stat sb; /* * USB and CDROM media get mounted to /dist, but fixit code looks in * /mnt2. */ unlink("/mnt2"); rmdir("/mnt2"); if (symlink("/dist", "/mnt2")) { msgConfirm("Unable to symlink /mnt2 to the disc mount point."); return (DITEM_FAILURE); } /* * If /tmp points to /mnt2/tmp from a previous fixit floppy session, * recreate it. */ if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK) unlink("/tmp"); Mkdir("/tmp"); /* Generate a new ld.so.hints */ if (!file_readable("/var/run/ld.so.hints")) { Mkdir("/var/run"); if (vsystem("/mnt2/rescue/ldconfig -s /mnt2/lib " "/mnt2/usr/lib")) { msgConfirm("Warning: ldconfig could not create the " "ld.so hints file.\nDynamic executables from the " "disc likely won't work."); } } /* Create required libexec symlinks. */ Mkdir("/libexec"); if (!file_readable("/libexec/ld.so") && file_readable("/mnt2/libexec/ld.so")) { if (symlink("/mnt2/libexec/ld.so", "/libexec/ld.so")) msgDebug("Couldn't link to ld.so\n"); } if (!file_readable("/libexec/ld-elf.so.1")) { if (symlink("/mnt2/libexec/ld-elf.so.1", "/libexec/ld-elf.so.1")) { msgConfirm("Warning: could not create the symlink for " "ld-elf.so.1\nDynamic executables from the disc " "likely won't work."); } } /* $PATH doesn't include /mnt2 by default. Create convenient symlink. */ if (!file_readable("/usr/bin/vi")) symlink("/mnt2/usr/bin/vi", "/usr/bin/vi"); /* Shared code used by all fixit types. */ fixit_common(); return (DITEM_SUCCESS); } int installExpress(dialogMenuItem *self) { int i; dialog_clear_norefresh(); variable_set2(SYSTEM_STATE, "express", 0); #ifdef WITH_SLICES if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE) return i; #endif if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE) return i; if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) { i |= DITEM_LEAVE_MENU; /* Give user the option of one last configuration spree */ installConfigure(); } return i; } /* Standard mode installation */ int installStandard(dialogMenuItem *self) { int i, tries = 0; Device **devs; variable_set2(SYSTEM_STATE, "standard", 0); dialog_clear_norefresh(); #ifdef WITH_SLICES msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n" "scheme for your hard disk. If you simply wish to devote all disk space\n" "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n" "then use the (A)ll command to select the default partitioning scheme followed\n" "by a (Q)uit. If you wish to allocate only free space to FreeBSD, move to a\n" "partition marked \"unused\" and use the (C)reate command."); nodisks: if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (diskGetSelectCount(&devs) <= 0 && tries < 3) { msgConfirm("You need to select some disks to operate on! Be sure to use SPACE\n" "instead of RETURN in the disk selection menu when selecting a disk."); ++tries; goto nodisks; } msgConfirm("Now you need to create BSD partitions inside of the fdisk partition(s)\n" "just created. If you have a reasonable amount of disk space (1GB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #else msgConfirm("First you need to create BSD partitions on the disk which you are\n" "installing to. If you have a reasonable amount of disk space (1GB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #endif if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) { dialog_clear(); msgConfirm("Installation completed with some errors. You may wish to\n" "scroll through the debugging messages on VTY1 with the\n" "scroll-lock feature. You can also choose \"No\" at the next\n" "prompt and go back into the installation menus to retry\n" "whichever operations have failed."); return i; } else { dialog_clear(); msgConfirm("Congratulations! You now have FreeBSD installed on your system.\n\n" "We will now move on to the final configuration questions.\n" "For any option you do not wish to configure, simply select\n" "No.\n\n" "If you wish to re-enter this utility after the system is up, you\n" "may do so by typing: /usr/sbin/sysinstall."); } if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) { if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) { Device *tmp = tcpDeviceSelect(); if (tmp && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) if (!DEVICE_INIT(tmp)) msgConfirm("Initialization of %s device failed.", tmp->name); } dialog_clear_norefresh(); } if (!msgNoYes("Do you want this machine to function as a network gateway?")) variable_set2("gateway_enable", "YES", 1); dialog_clear_norefresh(); if (!msgNoYes("Do you want to configure inetd and the network services that it provides?")) configInetd(self); dialog_clear_norefresh(); if (!msgNoYes("Would you like to enable SSH login?")) variable_set2("sshd_enable", "YES", 1); dialog_clear_norefresh(); if (!msgNoYes("Do you want to have anonymous FTP access to this machine?")) configAnonFTP(self); dialog_clear_norefresh(); if (!msgNoYes("Do you want to configure this machine as an NFS server?")) configNFSServer(self); dialog_clear_norefresh(); if (!msgNoYes("Do you want to configure this machine as an NFS client?")) variable_set2("nfs_client_enable", "YES", 1); #ifdef WITH_SYSCONS dialog_clear_norefresh(); if (!msgNoYes("Would you like to customize your system console settings?")) dmenuOpenSimple(&MenuSyscons, FALSE); #endif dialog_clear_norefresh(); if (!msgYesNo("Would you like to set this machine's time zone now?")) systemExecute("tzsetup"); #ifdef WITH_MICE dialog_clear_norefresh(); if (!msgNoYes("Does this system have a PS/2, serial, or bus mouse?")) dmenuOpenSimple(&MenuMouse, FALSE); #endif #ifdef __i386__ if (checkLoaderACPI() != 0) { dialog_clear_norefresh(); if (!msgNoYes("ACPI was disabled during boot.\n" "Would you like to disable it permanently?")) (void)configLoaderACPI(1 /*disable*/); } #endif /* Now would be a good time to checkpoint the configuration data */ configRC_conf(); sync(); dialog_clear_norefresh(); if (!msgYesNo("The FreeBSD package collection is a collection of thousands of ready-to-run\n" "applications, from text editors to games to WEB servers and more. Would you\n" "like to browse the collection now?")) { (void)configPackages(self); } if (!msgYesNo("Would you like to add any initial user accounts to the system?\n" "Adding at least one account for yourself at this stage is suggested\n" "since working as the \"root\" user is dangerous (it is easy to do\n" "things which adversely affect the entire system).")) (void)configUsers(self); msgConfirm("Now you must set the system manager's password.\n" "This is the password you'll use to log in as \"root\"."); if (!systemExecute("passwd root")) variable_set2("root_password", "YES", 0); /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */ /* Give user the option of one last configuration spree */ dialog_clear_norefresh(); installConfigure(); return DITEM_LEAVE_MENU; } /* The version of commit we call from the Install Custom menu */ int installCustomCommit(dialogMenuItem *self) { int i; i = installCommit(self); if (DITEM_STATUS(i) == DITEM_SUCCESS) { /* Give user the option of one last configuration spree */ installConfigure(); return i; } else msgConfirm("The commit operation completed with errors. Not\n" "updating /etc files."); return i; } /* * What happens when we finally decide to going ahead with the installation. * * This is broken into multiple stages so that the user can do a full * installation but come back here again to load more distributions, * perhaps from a different media type. This would allow, for * example, the user to load the majority of the system from CDROM and * then use ftp to load a different dist. */ int installCommit(dialogMenuItem *self) { int i; char *str; dialog_clear_norefresh(); if (!Dists) distConfig(NULL); if (!Dists) { (void)dmenuOpenSimple(&MenuDistributions, FALSE); /* select reasonable defaults if necessary */ if (!Dists) Dists = _DIST_USER; if (!KernelDists) KernelDists = selectKernel(); } if (!mediaVerify()) return DITEM_FAILURE; str = variable_get(SYSTEM_STATE); if (isDebug()) msgDebug("installCommit: System state is `%s'\n", str); /* Installation stuff we wouldn't do to a running system */ if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE) return i; try_media: if (!DEVICE_INIT(mediaDevice)) { if (!msgYesNo("Unable to initialize selected media. Would you like to\n" "adjust your media configuration and try again?")) { mediaDevice = NULL; if (!mediaVerify()) return DITEM_FAILURE; else goto try_media; } else return DITEM_FAILURE; } /* Now go get it all */ i = distExtractAll(self); /* When running as init, *now* it's safe to grab the rc.foo vars */ installEnvironment(); variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0); return i; } static void installConfigure(void) { /* Final menu of last resort */ if (!msgNoYes("Visit the general configuration menu for a chance to set\n" "any last options?")) dmenuOpenSimple(&MenuConfigure, FALSE); configRC_conf(); sync(); } int installFixupBase(dialogMenuItem *self) { FILE *fp; #ifdef __ia64__ const char *efi_mntpt; #endif /* All of this is done only as init, just to be safe */ if (RunningAsInit) { #if defined(__i386__) || defined(__amd64__) if ((fp = fopen("/boot/loader.conf", "a")) != NULL) { if (!OnVTY) { fprintf(fp, "# -- sysinstall generated deltas -- #\n"); fprintf(fp, "console=\"comconsole\"\n"); } fclose(fp); } #endif /* BOGON #2: We leave /etc in a bad state */ chmod("/etc", 0755); /* BOGON #3: No /var/db/mountdtab complains */ Mkdir("/var/db"); creat("/var/db/mountdtab", 0644); /* BOGON #4: /compat created by default in root fs */ Mkdir("/usr/compat"); vsystem("ln -s usr/compat /compat"); /* BOGON #5: aliases database not built for bin */ vsystem("newaliases"); /* BOGON #6: Remove /stand (finally) */ vsystem("rm -rf /stand"); /* Now run all the mtree stuff to fix things up */ vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /"); vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var"); vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr"); #ifdef __ia64__ /* Move /boot to the the EFI partition and make /boot a link to it. */ efi_mntpt = (EfiChunk != NULL) ? ((PartInfo *)EfiChunk->private_data)->mountpoint : NULL; if (efi_mntpt != NULL) { vsystem("if [ ! -L /boot ]; then mv /boot %s; fi", efi_mntpt); vsystem("if [ ! -e /boot ]; then ln -sf %s/boot /boot; fi", efi_mntpt + 1); /* Skip leading '/' */ /* Make sure the kernel knows which partition is the root file system. */ vsystem("echo 'vfs.root.mountfrom=\"ufs:/dev/%s\"' >> /boot/loader.conf", RootChunk->name); } #endif /* Do all the last ugly work-arounds here */ } return DITEM_SUCCESS | DITEM_RESTORE; } int installFixupKernel(dialogMenuItem *self, int dists) { /* All of this is done only as init, just to be safe */ if (RunningAsInit) { /* * Install something as /boot/kernel. * * NB: we assume any existing kernel has been saved * already and the /boot/kernel we remove is empty. */ vsystem("rm -rf /boot/kernel"); vsystem("mv /boot/GENERIC /boot/kernel"); } return DITEM_SUCCESS | DITEM_RESTORE; } #define QUEUE_YES 1 #define QUEUE_NO 0 static int performNewfs(PartInfo *pi, char *dname, int queue) { char buffer[LINE_MAX]; if (pi->do_newfs) { switch(pi->newfs_type) { case NEWFS_UFS: snprintf(buffer, LINE_MAX, "%s %s %s %s %s", NEWFS_UFS_CMD, pi->newfs_data.newfs_ufs.softupdates ? "-U" : "", pi->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2", pi->newfs_data.newfs_ufs.user_options, dname); break; case NEWFS_MSDOS: snprintf(buffer, LINE_MAX, "%s %s", NEWFS_MSDOS_CMD, dname); break; case NEWFS_CUSTOM: snprintf(buffer, LINE_MAX, "%s %s", pi->newfs_data.newfs_custom.command, dname); break; } if (queue == QUEUE_YES) { command_shell_add(pi->mountpoint, buffer); return (0); } else return (vsystem(buffer)); } return (0); } /* Go newfs and/or mount all the filesystems we've been asked to */ int installFilesystems(dialogMenuItem *self) { int i; Disk *disk; Chunk *c1, *c2; Device **devs; PartInfo *root; char dname[80]; Boolean upgrade = FALSE; /* If we've already done this, bail out */ if (!variable_cmp(DISK_LABELLED, "written")) return DITEM_SUCCESS; upgrade = !variable_cmp(SYSTEM_STATE, "upgrade"); if (!checkLabels(TRUE)) return DITEM_FAILURE; root = (RootChunk != NULL) ? (PartInfo *)RootChunk->private_data : NULL; command_clear(); if (SwapChunk && RunningAsInit) { /* As the very first thing, try to get ourselves some swap space */ sprintf(dname, "/dev/%s", SwapChunk->name); if (!Fake && !file_readable(dname)) { msgConfirm("Unable to find device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE; } if (!Fake) { if (!swapon(dname)) { dialog_clear_norefresh(); msgNotify("Added %s as initial swap device", dname); } else { msgConfirm("WARNING! Unable to swap to %s: %s\n" "This may cause the installation to fail at some point\n" "if you don't have a lot of memory.", dname, strerror(errno)); } } } if (RootChunk && RunningAsInit) { /* Next, create and/or mount the root device */ sprintf(dname, "/dev/%s", RootChunk->name); if (!Fake && !file_readable(dname)) { msgConfirm("Unable to make device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE | DITEM_RESTORE; } if (strcmp(root->mountpoint, "/")) msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", RootChunk->name, root->mountpoint); if (root->do_newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs " "the root partition?"))) { int i; dialog_clear_norefresh(); msgNotify("Making a new root filesystem on %s", dname); i = performNewfs(root, dname, QUEUE_NO); if (i) { msgConfirm("Unable to make new root filesystem on %s!\n" "Command returned status %d", dname, i); return DITEM_FAILURE | DITEM_RESTORE; } } else { if (!upgrade) { msgConfirm("Warning: Using existing root partition."); } dialog_clear_norefresh(); msgNotify("Checking integrity of existing %s filesystem.", dname); i = vsystem("fsck_ffs -y %s", dname); if (i) msgConfirm("Warning: fsck returned status of %d for %s.\n" "This partition may be unsafe to use.", i, dname); } /* * If soft updates was enabled in the editor but we didn't newfs, * use tunefs to update the soft updates flag on the file system. */ if (!root->do_newfs && root->newfs_type == NEWFS_UFS && root->newfs_data.newfs_ufs.softupdates) { i = vsystem("tunefs -n enable %s", dname); if (i) msgConfirm("Warning: Unable to enable soft updates" " for root file system on %s", dname); } /* Switch to block device */ sprintf(dname, "/dev/%s", RootChunk->name); if (Mount("/mnt", dname)) { msgConfirm("Unable to mount the root file system on %s! Giving up.", dname); return DITEM_FAILURE | DITEM_RESTORE; } /* Mount devfs for other partitions to mount */ Mkdir("/mnt/dev"); if (!Fake) { struct iovec iov[4]; iov[0].iov_base = "fstype"; iov[0].iov_len = strlen(iov[0].iov_base) + 1; iov[1].iov_base = "devfs"; iov[1].iov_len = strlen(iov[1].iov_base) + 1; iov[2].iov_base = "fspath"; iov[2].iov_len = strlen(iov[2].iov_base) + 1; iov[3].iov_base = "/mnt/dev"; iov[3].iov_len = strlen(iov[3].iov_base) + 1; i = nmount(iov, 4, 0); if (i) { dialog_clear_norefresh(); msgConfirm("Unable to mount DEVFS (error %d)", errno); return DITEM_FAILURE | DITEM_RESTORE; } } } /* Now buzz through the rest of the partitions and mount them too */ devs = deviceFind(NULL, DEVICE_TYPE_DISK); for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; if (!disk->chunks) { msgConfirm("No chunk list found for %s!", disk->name); return DITEM_FAILURE | DITEM_RESTORE; } for (c1 = disk->chunks->part; c1; c1 = c1->next) { #ifdef __ia64__ if (c1->type == part) { c2 = c1; { #elif defined(__powerpc__) if (c1->type == apple) { for (c2 = c1->part; c2; c2 = c2->next) { #else if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { #endif if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { PartInfo *tmp = (PartInfo *)c2->private_data; /* Already did root */ if (c2 == RootChunk) continue; sprintf(dname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); if (tmp->do_newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you" " want to newfs /dev/%s?", c2->name))) performNewfs(tmp, dname, QUEUE_YES); else command_shell_add(tmp->mountpoint, "fsck_ffs -y %s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); #if 0 if (tmp->soft) command_shell_add(tmp->mountpoint, "tunefs -n enable %s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); #endif command_func_add(tmp->mountpoint, Mount, c2->name); } else if (c2->type == part && c2->subtype == FS_SWAP) { char fname[80]; int i; if (c2 == SwapChunk) continue; sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); i = (Fake || swapon(fname)); if (!i) { dialog_clear_norefresh(); msgNotify("Added %s as an additional swap device", fname); } else { msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); } } } } else if (c1->type == fat && c1->private_data && (root->do_newfs || upgrade)) { char name[FILENAME_MAX]; sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint); Mkdir(name); } #if defined(__ia64__) else if (c1->type == efi && c1->private_data) { char bootdir[FILENAME_MAX]; PartInfo *pi = (PartInfo *)c1->private_data; char *p; sprintf(dname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c1->name); if (pi->do_newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to " "newfs /dev/%s?", c1->name))) performNewfs(pi, dname, QUEUE_YES); command_func_add(pi->mountpoint, Mount_msdosfs, c1->name); } #endif } } command_sort(); command_execute(); dialog_clear_norefresh(); return DITEM_SUCCESS | DITEM_RESTORE; } /* Initialize various user-settable values to their defaults */ int installVarDefaults(dialogMenuItem *self) { char *cp, ncpus[10]; /* Set default startup options */ cp = getsysctlbyname("kern.osrelease"); variable_set2(VAR_RELNAME, cp, 0); free(cp); variable_set2(VAR_CPIO_VERBOSITY, "high", 0); variable_set2(VAR_INSTALL_ROOT, "/", 0); variable_set2(VAR_INSTALL_CFG, "install.cfg", 0); cp = getenv("EDITOR"); if (!cp) cp = "/usr/bin/ee"; variable_set2(VAR_EDITOR, cp, 0); variable_set2(VAR_FTP_USER, "ftp", 0); variable_set2(VAR_BROWSER_PACKAGE, "links", 0); variable_set2(VAR_BROWSER_BINARY, "/usr/local/bin/links", 0); variable_set2(VAR_FTP_STATE, "passive", 0); variable_set2(VAR_NFS_SECURE, "NO", -1); variable_set2(VAR_NFS_TCP, "NO", -1); variable_set2(VAR_NFS_V3, "YES", -1); if (OnVTY) variable_set2(VAR_FIXIT_TTY, "standard", 0); else variable_set2(VAR_FIXIT_TTY, "serial", 0); variable_set2(VAR_PKG_TMPDIR, "/var/tmp", 0); variable_set2(VAR_MEDIA_TIMEOUT, itoa(MEDIA_TIMEOUT), 0); if (getpid() != 1) variable_set2(SYSTEM_STATE, "update", 0); else variable_set2(SYSTEM_STATE, "init", 0); variable_set2(VAR_NEWFS_ARGS, "-b 16384 -f 2048", 0); variable_set2(VAR_CONSTERM, "NO", 0); if (NCpus <= 0) NCpus = 1; snprintf(ncpus, sizeof(ncpus), "%u", NCpus); variable_set2(VAR_NCPUS, ncpus, 0); return DITEM_SUCCESS; } /* Load the environment up from various system configuration files */ void installEnvironment(void) { configEnvironmentRC_conf(); if (file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); } /* Copy the boot floppy contents into /stand */ Boolean copySelf(void) { int i; if (file_readable("/boot.help")) vsystem("cp /boot.help /mnt"); msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (i) { msgConfirm("Copy returned error status of %d!", i); return FALSE; } /* Copy the /etc files into their rightful place */ if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) { msgConfirm("Couldn't copy up the /etc files!"); return TRUE; } return TRUE; } static void create_termcap(void) { FILE *fp; const char *caps[] = { termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r, termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, termcap_xterm, NULL, }; const char **cp; if (!file_readable(TERMCAP_FILE)) { Mkdir("/usr/share/misc"); fp = fopen(TERMCAP_FILE, "w"); if (!fp) { msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work."); return; } cp = caps; while (*cp) fprintf(fp, "%s\n", *(cp++)); fclose(fp); } } Index: head/usr.sbin/sysinstall/installUpgrade.c =================================================================== --- head/usr.sbin/sysinstall/installUpgrade.c (revision 209068) +++ head/usr.sbin/sysinstall/installUpgrade.c (revision 209069) @@ -1,526 +1,526 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include static int installUpgradeNonInteractive(dialogMenuItem *self); typedef struct _hitList { enum { JUST_COPY, CALL_HANDLER } action ; char *name; Boolean optional; void (*handler)(struct _hitList *self); } HitList; /* These are the only meaningful files I know about */ static HitList etc_files [] = { { JUST_COPY, "Xaccel.ini", TRUE, NULL }, { JUST_COPY, "X11", TRUE, NULL }, { JUST_COPY, "adduser.conf", TRUE, NULL }, { JUST_COPY, "aliases", TRUE, NULL }, { JUST_COPY, "aliases.db", TRUE, NULL }, { JUST_COPY, "amd.map", TRUE, NULL }, { JUST_COPY, "auth.conf", TRUE, NULL }, { JUST_COPY, "crontab", TRUE, NULL }, { JUST_COPY, "csh.cshrc", TRUE, NULL }, { JUST_COPY, "csh.login", TRUE, NULL }, { JUST_COPY, "csh.logout", TRUE, NULL }, { JUST_COPY, "cvsupfile", TRUE, NULL }, { JUST_COPY, "devfs.conf", TRUE, NULL }, { JUST_COPY, "dhclient.conf", TRUE, NULL }, { JUST_COPY, "disktab", TRUE, NULL }, { JUST_COPY, "dumpdates", TRUE, NULL }, { JUST_COPY, "exports", TRUE, NULL }, { JUST_COPY, "fbtab", TRUE, NULL }, { JUST_COPY, "fstab", FALSE, NULL }, { JUST_COPY, "ftpusers", TRUE, NULL }, { JUST_COPY, "gettytab", TRUE, NULL }, { JUST_COPY, "gnats", TRUE, NULL }, { JUST_COPY, "group", FALSE, NULL }, { JUST_COPY, "hosts", TRUE, NULL }, { JUST_COPY, "hosts.allow", TRUE, NULL }, { JUST_COPY, "hosts.equiv", TRUE, NULL }, { JUST_COPY, "hosts.lpd", TRUE, NULL }, { JUST_COPY, "inetd.conf", TRUE, NULL }, { JUST_COPY, "localtime", TRUE, NULL }, { JUST_COPY, "login.access", TRUE, NULL }, { JUST_COPY, "login.conf", TRUE, NULL }, { JUST_COPY, "mail", TRUE, NULL }, { JUST_COPY, "mail.rc", TRUE, NULL }, { JUST_COPY, "mac.conf", TRUE, NULL }, { JUST_COPY, "make.conf", TRUE, NULL }, { JUST_COPY, "manpath.config", TRUE, NULL }, { JUST_COPY, "master.passwd", FALSE, NULL }, { JUST_COPY, "mergemaster.rc", TRUE, NULL }, { JUST_COPY, "motd", TRUE, NULL }, { JUST_COPY, "namedb", TRUE, NULL }, { JUST_COPY, "networks", TRUE, NULL }, { JUST_COPY, "newsyslog.conf", TRUE, NULL }, { JUST_COPY, "nsmb.conf", TRUE, NULL }, { JUST_COPY, "nsswitch.conf", TRUE, NULL }, { JUST_COPY, "ntp.conf", TRUE, NULL }, { JUST_COPY, "pam.conf", TRUE, NULL }, { JUST_COPY, "passwd", TRUE, NULL }, { JUST_COPY, "periodic", TRUE, NULL }, { JUST_COPY, "pf.conf", TRUE, NULL }, { JUST_COPY, "portsnap.conf", TRUE, NULL }, { JUST_COPY, "ppp", TRUE, NULL }, { JUST_COPY, "printcap", TRUE, NULL }, { JUST_COPY, "profile", TRUE, NULL }, { JUST_COPY, "protocols", TRUE, NULL }, { JUST_COPY, "pwd.db", TRUE, NULL }, { JUST_COPY, "rc.local", TRUE, NULL }, { JUST_COPY, "rc.firewall", TRUE, NULL }, { JUST_COPY, "rc.conf.local", TRUE, NULL }, { JUST_COPY, "remote", TRUE, NULL }, { JUST_COPY, "resolv.conf", TRUE, NULL }, { JUST_COPY, "rmt", TRUE, NULL }, { JUST_COPY, "sendmail.cf", TRUE, NULL }, { JUST_COPY, "sendmail.cw", TRUE, NULL }, { JUST_COPY, "services", TRUE, NULL }, { JUST_COPY, "shells", TRUE, NULL }, { JUST_COPY, "skeykeys", TRUE, NULL }, { JUST_COPY, "snmpd.config", TRUE, NULL }, { JUST_COPY, "spwd.db", TRUE, NULL }, { JUST_COPY, "src.conf", TRUE, NULL }, { JUST_COPY, "ssh", TRUE, NULL }, { JUST_COPY, "sysctl.conf", TRUE, NULL }, { JUST_COPY, "syslog.conf", TRUE, NULL }, { JUST_COPY, "ttys", TRUE, NULL }, { 0, NULL, FALSE, NULL }, }; static void traverseHitlist(HitList *h) { system("rm -rf /etc/upgrade"); Mkdir("/etc/upgrade"); while (h->name) { if (!file_readable(h->name)) { if (!h->optional) msgConfirm("Unable to find an old /etc/%s file! That is decidedly non-standard and\n" "your upgraded system may function a little strangely as a result.", h->name); } else { if (h->action == JUST_COPY) { /* Move the just-loaded copy aside */ vsystem("mv /etc/%s /etc/upgrade/%s", h->name, h->name); /* Copy the old one into its place */ msgNotify("Resurrecting %s..", h->name); /* Do this with tar so that symlinks and such are preserved */ if (vsystem("tar cf - %s | tar xpf - -C /etc", h->name)) msgConfirm("Unable to resurrect your old /etc/%s! Hmmmm.", h->name); } else /* call handler */ h->handler(h); } ++h; } } int installUpgrade(dialogMenuItem *self) { char saved_etc[FILENAME_MAX]; Boolean extractingBin = TRUE; if (variable_get(VAR_NONINTERACTIVE)) return installUpgradeNonInteractive(self); variable_set2(SYSTEM_STATE, "upgrade", 0); dialog_clear(); if (msgYesNo("Before beginning a binary upgrade, please review the upgrade instructions,\n" "which are located in the \"Install\" document under the main documentation\n" "menu. Given that you have read these instructions and understand the risks\n" "and precautions involved, are you sure that you want to proceed with\n" "this upgrade?") != 0) return DITEM_FAILURE; if (!Dists) { msgConfirm("First, you must select some distribution components. The upgrade procedure\n" "will only upgrade the distributions you select in the next set of menus."); if (!dmenuOpenSimple(&MenuDistributions, FALSE) || !Dists) return DITEM_FAILURE; } else if (!(Dists & DIST_BASE)) { /* No base selected? Not much of an upgrade.. */ if (msgYesNo("You didn't select the base distribution as one of the distributons to load.\n" "This one is pretty vital to a successful upgrade. Are you SURE you don't\n" "want to select the base distribution? Chose No to bring up the Distributions\n" "menu again.") != 0) { if (!dmenuOpenSimple(&MenuDistributions, FALSE)) return DITEM_FAILURE; } } /* Still?! OK! They must know what they're doing.. */ if (!(Dists & DIST_BASE)) extractingBin = FALSE; if (RunningAsInit) { Device **devs; int i, cnt; char *cp; cp = variable_get(VAR_DISK); devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(devs); if (!cnt) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE | DITEM_RESTORE; } else { /* Enable all the drives before we start */ for (i = 0; i < cnt; i++) devs[i]->enabled = TRUE; } msgConfirm("OK. First, we're going to go to the disk label editor. In this editor\n" "you will be expected to Mount any partitions you're interested in\n" "upgrading. DO NOT set the Newfs flag to Y on anything in the label editor\n" "unless you're absolutely sure you know what you're doing! In this\n" "instance, you'll be using the label editor as little more than a fancy\n" "screen-oriented partition mounting tool.\n\n" "Once you're done in the label editor, press Q to return here for the next\n" "step."); if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) { msgConfirm("The disk label editor returned an error status. Upgrade operation\n" "aborted."); return DITEM_FAILURE | DITEM_RESTORE; } /* Don't write out MBR info */ variable_set2(DISK_PARTITIONED, "written", 0); if (DITEM_STATUS(diskLabelCommit(self)) == DITEM_FAILURE) { msgConfirm("Not all file systems were properly mounted. Upgrade operation\n" "aborted."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE | DITEM_RESTORE; } msgNotify("Updating /stand on root filesystem"); (void)vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (DITEM_STATUS(chroot("/mnt")) == DITEM_FAILURE) { msgConfirm("Unable to chroot to /mnt - something is wrong with the\n" "root partition or the way it's mounted if this doesn't work."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE | DITEM_RESTORE; } chdir("/"); installEnvironment(); systemCreateHoloshell(); } saved_etc[0] = '\0'; /* Don't allow sources to be upgraded if we have src already */ if (directory_exists("/usr/src/") && (Dists & DIST_SRC)) { Dists &= ~DIST_SRC; SrcDists = 0; msgConfirm("Warning: /usr/src exists and sources were selected as upgrade\n" "targets. Unfortunately, this is not the way to upgrade your\n" "sources - please use CTM or CVSup or some other method which\n" "handles ``deletion events'', unlike this particular feature.\n\n" "Your existing /usr/src will not be affected by this upgrade.\n"); } if (extractingBin) { while (!*saved_etc) { char *cp = msgGetInput("/var/tmp/etc", "Under which directory do you wish to save your current /etc?"); if (!cp || !*cp || Mkdir(cp)) { if (msgYesNo("Directory was not specified, was invalid or user selected Cancel.\n\n" "Doing an upgrade without first backing up your /etc directory is a very\n" "bad idea! Do you want to go back and specify the save directory again?") != 0) break; } else { SAFE_STRCPY(saved_etc, cp); } } if (saved_etc[0]) { msgNotify("Preserving /etc directory.."); if (vsystem("tar -cBpf - -C /etc . | tar --unlink -xBpf - -C %s", saved_etc)) if (msgYesNo("Unable to backup your /etc into %s.\n" "Do you want to continue anyway?", saved_etc) != 0) return DITEM_FAILURE; msgNotify("Preserving /root directory.."); vsystem("tar -cBpf - -C / root | tar --unlink -xBpf - -C %s", saved_etc); } msgNotify("chflags'ing old binaries - please wait."); (void)vsystem("chflags -R noschg /bin /sbin /lib /libexec /usr/bin /usr/sbin /usr/lib /usr/libexec /var/empty /boot/kernel*"); if (directory_exists("/boot/kernel")) { if (directory_exists("/boot/kernel.prev")) { msgNotify("Removing /boot/kernel.prev"); if (system("rm -fr /boot/kernel.prev")) { msgConfirm("NOTICE: I'm trying to back up /boot/kernel to\n" "/boot/kernel.prev, but /boot/kernel.prev exists and I\n" "can't remove it. This means that the backup will, in\n" "all probability, fail."); } } msgNotify("Moving old kernel to /boot/kernel.prev"); if (system("mv /boot/kernel /boot/kernel.prev")) { if (!msgYesNo("Hmmm! I couldn't move the old kernel over! Do you want to\n" "treat this as a big problem and abort the upgrade? Due to the\n" "way that this upgrade process works, you will have to reboot\n" "and start over from the beginning. Select Yes to reboot now")) systemShutdown(1); } else msgConfirm("NOTICE: Your old kernel is in /boot/kernel.prev should this\n" "upgrade fail for any reason and you need to boot your old\n" "kernel."); } } media: /* We do this very late, but we unfortunately need to back up /etc first */ if (!mediaVerify()) return DITEM_FAILURE; if (!DEVICE_INIT(mediaDevice)) { if (!msgYesNo("Couldn't initialize the media. Would you like\n" "to adjust your media selection and try again?")) { mediaDevice = NULL; goto media; } else return DITEM_FAILURE | DITEM_REDRAW | DITEM_RESTORE; } msgNotify("Beginning extraction of distributions."); if (DITEM_STATUS(distExtractAll(self)) == DITEM_FAILURE) { msgConfirm("Hmmmm. We couldn't even extract the base distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } else if (Dists) { if (!extractingBin || !(Dists & DIST_BASE)) { msgNotify("The extraction process seems to have had some problems, but we got most\n" "of the essentials. We'll treat this as a warning since it may have been\n" "only non-essential distributions which failed to load."); } else { msgConfirm("Hmmmm. We couldn't even extract the base distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } } if (extractingBin) vsystem("disklabel -B `awk '$2~/\\/$/ {print substr($1, 6, 5)}' /etc/fstab`"); msgNotify("First stage of upgrade completed successfully!\n\n" "Next comes stage 2, where we attempt to resurrect your /etc\n" "directory!"); - if (saved_etc && chdir(saved_etc)) { + if (chdir(saved_etc)) { msgConfirm("Unable to go to your saved /etc directory in %s?! Argh!\n" "Something went seriously wrong! It's quite possible that\n" "your former /etc is toast. I hope you didn't have any\n" "important customizations you wanted to keep in there.. :(", saved_etc); } else { /* Now try to resurrect the /etc files */ traverseHitlist(etc_files); /* Resurrect the root dotfiles */ vsystem("tar -cBpf - root | tar -xBpf - -C / && rm -rf root"); } msgConfirm("Upgrade completed! All of your old /etc files have been restored.\n" "For your reference, the new /etc files are in /etc/upgrade/ in case\n" "you wish to upgrade these files by hand (though that should not be\n" "strictly necessary). If your root partition is specified in /etc/fstab\n" "using the old \"compatibility\" slice, you may also wish to update it to\n" "use a fully qualified slice name in order to avoid warnings on startup.\n\n" "When you're ready to reboot into the new system, simply exit the installation."); return DITEM_SUCCESS | DITEM_REDRAW | DITEM_RESTORE; } static int installUpgradeNonInteractive(dialogMenuItem *self) { char *saved_etc; Boolean extractingBin = TRUE; variable_set2(SYSTEM_STATE, "upgrade", 0); /* Make sure at least BIN is selected */ Dists |= DIST_BASE; if (RunningAsInit) { Device **devs; int i, cnt; char *cp; cp = variable_get(VAR_DISK); devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(devs); if (!cnt) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else { /* Enable all the drives before we start */ for (i = 0; i < cnt; i++) devs[i]->enabled = TRUE; } msgConfirm("OK. First, we're going to go to the disk label editor. In this editor\n" "you will be expected to Mount any partitions you're interested in\n" "upgrading. DO NOT set the Newfs flag to Y on anything in the label editor\n" "unless you're absolutely sure you know what you're doing! In this\n" "instance, you'll be using the label editor as little more than a fancy\n" "screen-oriented partition mounting tool.\n\n" "Once you're done in the label editor, press Q to return here for the next\n" "step."); if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) { msgConfirm("The disk label editor returned an error status. Upgrade operation\n" "aborted."); return DITEM_FAILURE; } /* Don't write out MBR info */ variable_set2(DISK_PARTITIONED, "written", 0); if (DITEM_STATUS(diskLabelCommit(self)) == DITEM_FAILURE) { msgConfirm("Not all file systems were properly mounted. Upgrade operation\n" "aborted."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE; } if (extractingBin) { msgNotify("chflags'ing old binaries - please wait."); (void)vsystem("chflags -R noschg /mnt/"); } msgNotify("Updating /stand on root filesystem"); (void)vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (DITEM_STATUS(chroot("/mnt")) == DITEM_FAILURE) { msgConfirm("Unable to chroot to /mnt - something is wrong with the\n" "root partition or the way it's mounted if this doesn't work."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE; } chdir("/"); systemCreateHoloshell(); } if (!mediaVerify() || !DEVICE_INIT(mediaDevice)) { msgNotify("Upgrade: Couldn't initialize media."); return DITEM_FAILURE; } saved_etc = "/var/tmp/etc"; Mkdir(saved_etc); msgNotify("Preserving /etc directory.."); if (vsystem("tar -cpBf - -C /etc . | tar -xpBf - -C %s", saved_etc)) { msgNotify("Unable to backup your /etc into %s.", saved_etc); return DITEM_FAILURE; } /* * Back up the old kernel, leaving it in place in case we * crash and reboot. */ if (directory_exists("/boot/kernel")) { if (directory_exists("/boot/kernel.prev")) { msgNotify("Removing /boot/kernel.prev"); if (system("rm -fr /boot/kernel.prev")) { msgConfirm("NOTICE: I'm trying to back up /boot/kernel to\n" "/boot/kernel.prev, but /boot/kernel.prev exists and I\n" "can't remove it. This means that the backup will, in\n" "all probability, fail."); } } msgNotify("Copying old kernel to /boot/kernel.prev"); vsystem("cp -Rp /boot/kernel /boot/kernel.prev"); } msgNotify("Beginning extraction of distributions."); if (DITEM_STATUS(distExtractAll(self)) == DITEM_FAILURE) { msgConfirm("Hmmmm. We couldn't even extract the base distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } else if (Dists) { if (!(Dists & DIST_BASE)) { msgNotify("The extraction process seems to have had some problems, but we got most\n" "of the essentials. We'll treat this as a warning since it may have been\n" "only non-essential distributions which failed to upgrade."); } else { msgConfirm("Hmmmm. We couldn't even extract the base distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } } msgNotify("First stage of upgrade completed successfully."); if (vsystem("tar -cpBf - -C %s . | tar --unlink -xpBf - -C /etc", saved_etc)) { msgNotify("Unable to resurrect your old /etc!"); return DITEM_FAILURE; } return DITEM_SUCCESS | DITEM_REDRAW; } Index: head/usr.sbin/sysinstall/media.c =================================================================== --- head/usr.sbin/sysinstall/media.c (revision 209068) +++ head/usr.sbin/sysinstall/media.c (revision 209069) @@ -1,881 +1,881 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include static Boolean got_intr = FALSE; static Boolean ftp_skip_resolve = FALSE; /* timeout handler */ static void handle_intr(int sig) { msgDebug("User generated interrupt.\n"); got_intr = TRUE; } static int check_for_interrupt(void) { if (got_intr) { got_intr = FALSE; return TRUE; } return FALSE; } static int genericHook(dialogMenuItem *self, DeviceType type) { Device **devs; devs = deviceFind(self->prompt, type); if (devs) mediaDevice = devs[0]; return (devs ? DITEM_LEAVE_MENU : DITEM_FAILURE); } static int cdromHook(dialogMenuItem *self) { return genericHook(self, DEVICE_TYPE_CDROM); } static void kickstart_dns(void) { static Boolean initted = FALSE; int time; char *cp; cp = variable_get(VAR_MEDIA_TIMEOUT); if (!cp) time = MEDIA_TIMEOUT; else time = atoi(cp); if (!time) time = 100; if (!initted) { res_init(); _res.retry = 2; /* 2 times seems a reasonable number to me */ _res.retrans = time / 2; /* so spend half our alloted time on each try */ initted = TRUE; } } char * cpioVerbosity() { char *cp = variable_get(VAR_CPIO_VERBOSITY); if (cp && !strcmp(cp, "high")) return "-v"; else if (cp && !strcmp(cp, "medium")) return "-V"; return ""; } int mediaOpen(void) { if (!mediaDevice || !mediaVerify() || !DEVICE_INIT(mediaDevice)) return DITEM_FAILURE; return DITEM_SUCCESS; } void mediaClose(void) { if (mediaDevice) DEVICE_SHUTDOWN(mediaDevice); mediaDevice = NULL; } /* * Return 1 if we successfully found and set the installation type to * be a CD. */ int mediaSetCDROM(dialogMenuItem *self) { Device **devs; int cnt; mediaClose(); devs = deviceFind(NULL, DEVICE_TYPE_CDROM); cnt = deviceCount(devs); if (!cnt) { if (self) /* Interactive? */ msgConfirm("No CD/DVD devices found! Please check that your system's\n" "configuration is correct and that the CD/DVD drive is of a supported\n" "type. For more information, consult the hardware guide\n" "in the Doc menu."); return DITEM_FAILURE | DITEM_CONTINUE; } else if (cnt > 1) { DMenu *menu; int status; menu = deviceCreateMenu(&MenuMediaCDROM, DEVICE_TYPE_CDROM, cdromHook, NULL); if (!menu) msgFatal("Unable to create CDROM menu! Something is seriously wrong."); status = dmenuOpenSimple(menu, FALSE); free(menu); if (!status) return DITEM_FAILURE; } else mediaDevice = devs[0]; return (mediaDevice ? DITEM_SUCCESS | DITEM_LEAVE_MENU : DITEM_FAILURE); } static int floppyHook(dialogMenuItem *self) { return genericHook(self, DEVICE_TYPE_FLOPPY); } /* * Return 1 if we successfully found and set the installation type to * be a floppy */ int mediaSetFloppy(dialogMenuItem *self) { Device **devs; int cnt; mediaClose(); devs = deviceFind(NULL, DEVICE_TYPE_FLOPPY); cnt = deviceCount(devs); if (!cnt) { msgConfirm("No floppy devices found! Please check that your system's configuration\n" "is correct. For more information, consult the hardware guide in the Doc\n" "menu."); return DITEM_FAILURE | DITEM_CONTINUE; } else if (cnt > 1) { DMenu *menu; int status; menu = deviceCreateMenu(&MenuMediaFloppy, DEVICE_TYPE_FLOPPY, floppyHook, NULL); if (!menu) msgFatal("Unable to create Floppy menu! Something is seriously wrong."); status = dmenuOpenSimple(menu, FALSE); free(menu); if (!status) return DITEM_FAILURE; } else mediaDevice = devs[0]; if (mediaDevice) mediaDevice->private = NULL; return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE); } static int USBHook(dialogMenuItem *self) { return genericHook(self, DEVICE_TYPE_USB); } /* * Attempt to use USB as the installation media type. */ int mediaSetUSB(dialogMenuItem *self) { Device **devs; int cnt; mediaClose(); devs = deviceFind(NULL, DEVICE_TYPE_USB); cnt = deviceCount(devs); if (!cnt) { msgConfirm("No USB devices found!"); return DITEM_FAILURE | DITEM_CONTINUE; } else if (cnt > 1) { DMenu *menu; int status; menu = deviceCreateMenu(&MenuMediaUSB, DEVICE_TYPE_USB, USBHook, NULL); if (!menu) msgFatal("Unable to create USB menu! Something is " \ "seriously wrong."); status = dmenuOpenSimple(menu, FALSE); free(menu); if (!status) return DITEM_FAILURE; } else mediaDevice = devs[0]; if (mediaDevice) mediaDevice->private = NULL; if (!variable_get(VAR_NONINTERACTIVE)) msgConfirm("Using USB device: %s", mediaDevice->name); return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE); } static int DOSHook(dialogMenuItem *self) { return genericHook(self, DEVICE_TYPE_DOS); } /* * Return 1 if we successfully found and set the installation type to * be a DOS partition. */ int mediaSetDOS(dialogMenuItem *self) { Device **devs; int cnt; mediaClose(); devs = deviceFind(NULL, DEVICE_TYPE_DOS); cnt = deviceCount(devs); if (!cnt) { msgConfirm("No DOS primary partitions found! This installation method is unavailable"); return DITEM_FAILURE | DITEM_CONTINUE; } else if (cnt > 1) { DMenu *menu; int status; menu = deviceCreateMenu(&MenuMediaDOS, DEVICE_TYPE_DOS, DOSHook, NULL); if (!menu) msgFatal("Unable to create DOS menu! Something is seriously wrong."); status = dmenuOpenSimple(menu, FALSE); free(menu); if (!status) return DITEM_FAILURE; } else mediaDevice = devs[0]; return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE); } /* * Return 0 if we successfully found and set the installation type to * be an ftp server */ int mediaSetFTP(dialogMenuItem *self) { static Device ftpDevice; char *cp, hbuf[MAXHOSTNAMELEN], *hostname, *dir; struct addrinfo hints, *res; int af; size_t urllen; extern int FtpPort; static Device *networkDev = NULL; mediaClose(); cp = variable_get(VAR_FTP_PATH); /* If we've been through here before ... */ if (networkDev && cp && msgYesNo("Re-use old FTP site selection values?")) cp = NULL; if (!cp) { if (!dmenuOpenSimple(&MenuMediaFTP, FALSE)) return DITEM_FAILURE; else cp = variable_get(VAR_FTP_PATH); } if (!cp) return DITEM_FAILURE; else if (!strcmp(cp, "other")) { variable_set2(VAR_FTP_PATH, "ftp://", 0); cp = variable_get_value(VAR_FTP_PATH, "Please specify the URL of a FreeBSD distribution on a\n" "remote ftp site. This site must accept either anonymous\n" "ftp or you should have set an ftp username and password\n" "in the Options screen.\n\n" "A URL looks like this: ftp:///\n" "Where is relative to the anonymous ftp directory or the\n" "home directory of the user being logged in as.", 0); if (!cp || !*cp || !strcmp(cp, "ftp://")) { variable_unset(VAR_FTP_PATH); return DITEM_FAILURE; } urllen = strlen(cp); if (urllen >= sizeof(ftpDevice.name)) { - msgConfirm("Length of specified URL is %d characters. Allowable maximum is %d.", + msgConfirm("Length of specified URL is %zu characters. Allowable maximum is %zu.", urllen,sizeof(ftpDevice.name)-1); variable_unset(VAR_FTP_PATH); return DITEM_FAILURE; } } if (strncmp("ftp://", cp, 6)) { msgConfirm("Sorry, %s is an invalid URL!", cp); variable_unset(VAR_FTP_PATH); return DITEM_FAILURE; } SAFE_STRCPY(ftpDevice.name, cp); SAFE_STRCPY(hbuf, cp + 6); hostname = hbuf; if (!networkDev || msgYesNo("You've already done the network configuration once,\n" "would you like to skip over it now?") != 0) { if (networkDev) DEVICE_SHUTDOWN(networkDev); if (!(networkDev = tcpDeviceSelect())) { variable_unset(VAR_FTP_PATH); return DITEM_FAILURE; } } if (!DEVICE_INIT(networkDev)) { if (isDebug()) msgDebug("mediaSetFTP: Net device init failed.\n"); variable_unset(VAR_FTP_PATH); return DITEM_FAILURE; } if (*hostname == '[' && (cp = index(hostname + 1, ']')) != NULL && (*++cp == '\0' || *cp == '/' || *cp == ':')) { ++hostname; *(cp - 1) = '\0'; } else cp = index(hostname, ':'); if (cp != NULL && *cp == ':') { *(cp++) = '\0'; FtpPort = strtol(cp, 0, 0); } else FtpPort = 21; if ((dir = index(cp ? cp : hostname, '/')) != NULL) *(dir++) = '\0'; if (isDebug()) { msgDebug("hostname = `%s'\n", hostname); msgDebug("dir = `%s'\n", dir ? dir : "/"); msgDebug("port # = `%d'\n", FtpPort); } if (!ftp_skip_resolve && variable_get(VAR_NAMESERVER)) { msgNotify("Looking up host %s.", hostname); if (isDebug()) msgDebug("Starting DNS.\n"); kickstart_dns(); if (isDebug()) msgDebug("Looking up hostname, %s, using getaddrinfo(AI_NUMERICHOST).\n", hostname); af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC; memset(&hints, 0, sizeof(hints)); hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(hostname, NULL, &hints, &res) != 0) { if (isDebug()) msgDebug("Looking up hostname, %s, using getaddrinfo().\n", hostname); hints.ai_flags = AI_PASSIVE; if (getaddrinfo(hostname, NULL, &hints, &res) != 0) { msgConfirm("Cannot resolve hostname `%s'! Are you sure that" " your\nname server, gateway and network interface are" " correctly configured?", hostname); if (networkDev) DEVICE_SHUTDOWN(networkDev); networkDev = NULL; variable_unset(VAR_FTP_PATH); return DITEM_FAILURE; } } freeaddrinfo(res); if (isDebug()) msgDebug("Found DNS entry for %s successfully..\n", hostname); } variable_set2(VAR_FTP_HOST, hostname, 0); variable_set2(VAR_FTP_DIR, dir ? dir : "/", 0); variable_set2(VAR_FTP_PORT, itoa(FtpPort), 0); ftpDevice.type = DEVICE_TYPE_FTP; ftpDevice.init = mediaInitFTP; ftpDevice.get = mediaGetFTP; ftpDevice.shutdown = mediaShutdownFTP; ftpDevice.private = networkDev; mediaDevice = &ftpDevice; return DITEM_SUCCESS | DITEM_LEAVE_MENU | DITEM_RESTORE; } int mediaSetFTPActive(dialogMenuItem *self) { variable_set2(VAR_FTP_STATE, "active", 0); return mediaSetFTP(self); } int mediaSetFTPPassive(dialogMenuItem *self) { variable_set2(VAR_FTP_STATE, "passive", 0); return mediaSetFTP(self); } int mediaSetHTTP(dialogMenuItem *self) { Boolean tmp; int result; char *cp, *idx, hbuf[MAXHOSTNAMELEN], *hostname; int HttpPort; int what = DITEM_RESTORE; tmp = ftp_skip_resolve; ftp_skip_resolve = TRUE; result = mediaSetFTP(self); ftp_skip_resolve = tmp; if (DITEM_STATUS(result) != DITEM_SUCCESS) return result; cp = variable_get_value(VAR_HTTP_PROXY, "Please enter the address of the HTTP proxy in this format:\n" " hostname:port (the ':port' is optional, default is 3128)",0); if (!cp) return DITEM_FAILURE; SAFE_STRCPY(hbuf, cp); hostname = hbuf; if (*hostname == '[' && (idx = index(hostname + 1, ']')) != NULL && (*++idx == '\0' || *idx == ':')) { ++hostname; *(idx - 1) = '\0'; } else idx = index(hostname, ':'); if (idx == NULL || *idx != ':') HttpPort = 3128; /* try this as default */ else { *(idx++) = '\0'; HttpPort = strtol(idx, 0, 0); } variable_set2(VAR_HTTP_HOST, hostname, 0); variable_set2(VAR_HTTP_PORT, itoa(HttpPort), 0); if (isDebug()) { msgDebug("VAR_FTP_PATH : %s\n",variable_get(VAR_FTP_PATH)); msgDebug("VAR_HTTP_HOST, _PORT: %s:%s\n",variable_get(VAR_HTTP_HOST), variable_get(VAR_HTTP_PORT)); } /* mediaDevice has been set by mediaSetFTP(), overwrite partly: */ mediaDevice->type = DEVICE_TYPE_HTTP; mediaDevice->init = mediaInitHTTP; mediaDevice->get = mediaGetHTTP; mediaDevice->shutdown = dummyShutdown; return DITEM_SUCCESS | DITEM_LEAVE_MENU | what; } int mediaSetUFS(dialogMenuItem *self) { static Device ufsDevice; struct statfs st; char *cp; mediaClose(); cp = variable_get_value(VAR_UFS_PATH, "Enter a fully qualified pathname for the directory\n" "containing the FreeBSD distribution files:", 0); if (!cp) return DITEM_FAILURE; /* If they gave us a CDROM or something, try and pick a better name */ if (statfs(cp, &st)) strcpy(ufsDevice.name, "ufs"); else strcpy(ufsDevice.name, st.f_fstypename); ufsDevice.type = DEVICE_TYPE_UFS; ufsDevice.init = dummyInit; ufsDevice.get = mediaGetUFS; ufsDevice.shutdown = dummyShutdown; ufsDevice.private = strdup(cp); mediaDevice = &ufsDevice; return DITEM_LEAVE_MENU; } int mediaSetNFS(dialogMenuItem *self) { static Device nfsDevice; static Device *networkDev = NULL; char *cp, *idx; char hostname[MAXPATHLEN]; size_t pathlen; mediaClose(); cp = variable_get_value(VAR_NFS_PATH, "Please enter the full NFS file specification for the remote\n" "host and directory containing the FreeBSD distribution files.\n" "This should be in the format: hostname:/some/freebsd/dir", 0); if (!cp) return DITEM_FAILURE; SAFE_STRCPY(hostname, cp); if (!(idx = index(hostname, ':'))) { msgConfirm("Invalid NFS path specification. Must be of the form:\n" "host:/full/pathname/to/FreeBSD/distdir"); return DITEM_FAILURE; } pathlen = strlen(hostname); if (pathlen >= sizeof(nfsDevice.name)) { - msgConfirm("Length of specified NFS path is %d characters. Allowable maximum is %d.", + msgConfirm("Length of specified NFS path is %zu characters. Allowable maximum is %zu.", pathlen,sizeof(nfsDevice.name)-1); variable_unset(VAR_NFS_PATH); return DITEM_FAILURE; } SAFE_STRCPY(nfsDevice.name, hostname); *idx = '\0'; if (!networkDev || msgYesNo("You've already done the network configuration once,\n" "would you like to skip over it now?") != 0) { if (networkDev) DEVICE_SHUTDOWN(networkDev); if (!(networkDev = tcpDeviceSelect())) return DITEM_FAILURE; } if (!DEVICE_INIT(networkDev)) { if (isDebug()) msgDebug("mediaSetNFS: Net device init failed\n"); } if (variable_get(VAR_NAMESERVER)) { kickstart_dns(); if ((inet_addr(hostname) == INADDR_NONE) && (gethostbyname(hostname) == NULL)) { msgConfirm("Cannot resolve hostname `%s'! Are you sure that your\n" "name server, gateway and network interface are correctly configured?", hostname); if (networkDev) DEVICE_SHUTDOWN(networkDev); networkDev = NULL; variable_unset(VAR_NFS_PATH); return DITEM_FAILURE; } else { if (isDebug()) msgDebug("Found DNS entry for %s successfully..\n", hostname); } } variable_set2(VAR_NFS_HOST, hostname, 0); nfsDevice.type = DEVICE_TYPE_NFS; nfsDevice.init = mediaInitNFS; nfsDevice.get = mediaGetNFS; nfsDevice.shutdown = mediaShutdownNFS; nfsDevice.private = networkDev; mediaDevice = &nfsDevice; return DITEM_LEAVE_MENU; } Boolean mediaExtractDistBegin(char *dir, int *fd, int *zpid, int *cpid) { int i, pfd[2],qfd[2]; if (!dir) dir = "/"; Mkdir(dir); chdir(dir); pipe(pfd); pipe(qfd); *zpid = fork(); if (!*zpid) { char *unzipper = RunningAsInit ? "/stand/" UNZIPPER : "/usr/bin/" UNZIPPER; dup2(qfd[0], 0); close(qfd[0]); dup2(pfd[1], 1); close(pfd[1]); if (DebugFD != -1) dup2(DebugFD, 2); else { close(2); open("/dev/null", O_WRONLY); } close(qfd[1]); close(pfd[0]); i = execl(unzipper, unzipper, (char *)0); if (isDebug()) msgDebug("%s command returns %d status\n", unzipper, i); exit(i); } *fd = qfd[1]; close(qfd[0]); *cpid = fork(); if (!*cpid) { char *cpio = RunningAsInit ? "/stand/cpio" : "/usr/bin/cpio"; dup2(pfd[0], 0); close(pfd[0]); close(pfd[1]); close(qfd[1]); if (DebugFD != -1) { dup2(DebugFD, 1); dup2(DebugFD, 2); } else { close(1); open("/dev/null", O_WRONLY); dup2(1, 2); } if (strlen(cpioVerbosity())) i = execl(cpio, cpio, "-idum", cpioVerbosity(), (char *)0); else i = execl(cpio, cpio, "-idum", (char *)0); if (isDebug()) msgDebug("%s command returns %d status\n", cpio, i); exit(i); } close(pfd[0]); close(pfd[1]); return TRUE; } Boolean mediaExtractDistEnd(int zpid, int cpid) { int i,j; i = waitpid(zpid, &j, 0); /* Don't check exit status - gunzip seems to return a bogus one! */ if (i < 0) { if (isDebug()) msgDebug("wait for %s returned status of %d!\n", UNZIPPER, i); return FALSE; } i = waitpid(cpid, &j, 0); if (i < 0 || WEXITSTATUS(j)) { if (isDebug()) msgDebug("cpio returned error status of %d!\n", WEXITSTATUS(j)); return FALSE; } return TRUE; } Boolean mediaExtractDist(char *dir, char *dist, FILE *fp) { int i, j, total, seconds, zpid, cpid, pfd[2], qfd[2]; char buf[BUFSIZ]; struct timeval start, stop; struct sigaction new, old; if (!dir) dir = "/"; Mkdir(dir); chdir(dir); pipe(pfd); /* read end */ pipe(qfd); /* write end */ zpid = fork(); if (!zpid) { char *unzipper = RunningAsInit ? "/stand/" UNZIPPER : "/usr/bin/" UNZIPPER; fclose(fp); close(qfd[1]); dup2(qfd[0], 0); close(qfd[0]); close(pfd[0]); dup2(pfd[1], 1); close(pfd[1]); if (DebugFD != -1) dup2(DebugFD, 2); else { close(2); open("/dev/null", O_WRONLY); } i = execl(unzipper, unzipper, (char *)0); if (isDebug()) msgDebug("%s command returns %d status\n", unzipper, i); exit(i); } cpid = fork(); if (!cpid) { char *cpio = RunningAsInit ? "/stand/cpio" : "/usr/bin/cpio"; close(pfd[1]); dup2(pfd[0], 0); close(pfd[0]); close (qfd[0]); close(qfd[1]); fclose(fp); if (DebugFD != -1) { dup2(DebugFD, 1); dup2(DebugFD, 2); } else { dup2(open("/dev/null", O_WRONLY), 1); dup2(1, 2); } if (strlen(cpioVerbosity())) i = execl(cpio, cpio, "-idum", cpioVerbosity(), (char *)0); else i = execl(cpio, cpio, "-idum", "--block-size", (char *)0); if (isDebug()) msgDebug("%s command returns %d status\n", cpio, i); exit(i); } close(pfd[0]); close(pfd[1]); close(qfd[0]); total = 0; (void)gettimeofday(&start, (struct timezone *)0); /* Make ^C abort the current transfer rather than the whole show */ new.sa_handler = handle_intr; new.sa_flags = 0; (void)sigemptyset(&new.sa_mask); sigaction(SIGINT, &new, &old); while ((i = fread(buf, 1, BUFSIZ, fp)) > 0) { if (check_for_interrupt()) { msgConfirm("Failure to read from media: User interrupt."); break; } if (write(qfd[1], buf, i) != i) { msgConfirm("Write error on transfer to cpio process, try of %d bytes.", i); break; } else { (void)gettimeofday(&stop, (struct timezone *)0); stop.tv_sec = stop.tv_sec - start.tv_sec; stop.tv_usec = stop.tv_usec - start.tv_usec; if (stop.tv_usec < 0) stop.tv_sec--, stop.tv_usec += 1000000; seconds = stop.tv_sec + (stop.tv_usec / 1000000.0); if (!seconds) seconds = 1; total += i; msgInfo("%10d bytes read from %s dist @ %.1f KB/sec.", total, dist, (total / seconds) / 1024.0); } } sigaction(SIGINT, &old, NULL); /* restore sigint */ close(qfd[1]); i = waitpid(zpid, &j, 0); /* Don't check exit status - gunzip seems to return a bogus one! */ if (i < 0) { if (isDebug()) msgDebug("wait for %s returned status of %d!\n", UNZIPPER, i); return FALSE; } i = waitpid(cpid, &j, 0); if (i < 0 || WEXITSTATUS(j)) { if (isDebug()) msgDebug("cpio returned error status of %d!\n", WEXITSTATUS(j)); return FALSE; } return TRUE; } int mediaGetType(dialogMenuItem *self) { return ((dmenuOpenSimple(&MenuMedia, FALSE) && mediaDevice) ? DITEM_SUCCESS : DITEM_FAILURE); } /* Return TRUE if all the media variables are set up correctly */ Boolean mediaVerify(void) { if (!mediaDevice) return (DITEM_STATUS(mediaGetType(NULL)) == DITEM_SUCCESS); return TRUE; } /* Set the FTP username and password fields */ int mediaSetFTPUserPass(dialogMenuItem *self) { char *pass; if (variable_get_value(VAR_FTP_USER, "Please enter the username you wish to login as:", 0)) { DialogInputAttrs |= DITEM_NO_ECHO; pass = variable_get_value(VAR_FTP_PASS, "Please enter the password for this user:", 0); DialogInputAttrs &= ~DITEM_NO_ECHO; } else pass = NULL; return (pass ? DITEM_SUCCESS : DITEM_FAILURE); } /* Set CPIO verbosity level */ int mediaSetCPIOVerbosity(dialogMenuItem *self) { char *cp = variable_get(VAR_CPIO_VERBOSITY); if (!cp) { msgConfirm("CPIO Verbosity is not set to anything!"); return DITEM_FAILURE; } else { if (!strcmp(cp, "low")) variable_set2(VAR_CPIO_VERBOSITY, "medium", 0); else if (!strcmp(cp, "medium")) variable_set2(VAR_CPIO_VERBOSITY, "high", 0); else /* must be "high" - wrap around */ variable_set2(VAR_CPIO_VERBOSITY, "low", 0); } return DITEM_SUCCESS; } /* A generic open which follows a well-known "path" of places to look */ FILE * mediaGenericGet(char *base, const char *file) { char buf[PATH_MAX]; snprintf(buf, PATH_MAX, "%s/%s", base, file); if (file_readable(buf)) return fopen(buf, "r"); snprintf(buf, PATH_MAX, "%s/FreeBSD/%s", base, file); if (file_readable(buf)) return fopen(buf, "r"); snprintf(buf, PATH_MAX, "%s/releases/%s", base, file); if (file_readable(buf)) return fopen(buf, "r"); snprintf(buf, PATH_MAX, "%s/%s/%s", base, variable_get(VAR_RELNAME), file); if (file_readable(buf)) return fopen(buf, "r"); snprintf(buf, PATH_MAX, "%s/releases/%s/%s", base, variable_get(VAR_RELNAME), file); return fopen(buf, "r"); } Index: head/usr.sbin/sysinstall/system.c =================================================================== --- head/usr.sbin/sysinstall/system.c (revision 209068) +++ head/usr.sbin/sysinstall/system.c (revision 209069) @@ -1,549 +1,549 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Jordan Hubbard * * My contributions are in the public domain. * * Parts of this file are also blatantly stolen from Poul-Henning Kamp's * previous version of sysinstall, and as such fall under his "BEERWARE license" * so buy him a beer if you like it! Buy him a beer for me, too! * Heck, get him completely drunk and send me pictures! :-) */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include #include #include /* Where we stick our temporary expanded doc file */ #define DOC_TMP_DIR "/tmp/.doc" #define DOC_TMP_FILE "/tmp/.doc/doc.tmp" static pid_t ehs_pid; /* * Handle interrupt signals - this probably won't work in all cases * due to our having bogotified the internal state of dialog or curses, * but we'll give it a try. */ static int intr_continue(dialogMenuItem *self) { return DITEM_LEAVE_MENU; } static int intr_reboot(dialogMenuItem *self) { systemShutdown(-1); /* NOTREACHED */ return 0; } static int intr_restart(dialogMenuItem *self) { int ret, fd, fdmax; mediaClose(); free_variables(); fdmax = getdtablesize(); for (fd = 3; fd < fdmax; fd++) close(fd); ret = execl(StartName, StartName, "-restart", (char *)NULL); msgDebug("execl failed (%s)\n", strerror(errno)); /* NOTREACHED */ return -1; } static dialogMenuItem intrmenu[] = { { "Abort", "Abort the installation", NULL, intr_reboot }, { "Restart", "Restart the installation program", NULL, intr_restart }, { "Continue", "Continue the installation", NULL, intr_continue }, }; static void handle_intr(int sig) { WINDOW *save = savescr(); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } (void)dialog_menu("Installation interrupt", "Do you want to abort the installation?", -1, -1, 3, -3, intrmenu, NULL, NULL, NULL); restorescr(save); } #if 0 /* * Harvest children if we are init. */ static void reap_children(int sig) { int errbak = errno; while (waitpid(-1, NULL, WNOHANG) > 0) ; errno = errbak; } #endif /* Expand a file into a convenient location, nuking it each time */ static char * expand(char *fname) { char *unzipper = RunningAsInit ? "/stand/" UNZIPPER : "/usr/bin/" UNZIPPER; if (!directory_exists(DOC_TMP_DIR)) { Mkdir(DOC_TMP_DIR); if (chown(DOC_TMP_DIR, 0, 0) < 0) return NULL; if (chmod(DOC_TMP_DIR, S_IRWXU) < 0) return NULL; } else unlink(DOC_TMP_FILE); if (!file_readable(fname) || vsystem("%s < %s > %s", unzipper, fname, DOC_TMP_FILE)) return NULL; return DOC_TMP_FILE; } /* Initialize system defaults */ void systemInitialize(int argc, char **argv) { size_t i; int boothowto; sigset_t signalset; signal(SIGINT, SIG_IGN); globalsInit(); i = sizeof(boothowto); if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, 0) && (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE)) variable_set2(VAR_DEBUG, "YES", 0); /* Are we running as init? */ if (getpid() == 1) { struct ufs_args ufs_args; int fd; RunningAsInit = 1; setsid(); close(0); fd = open("/dev/ttyv0", O_RDWR); if (fd == -1) { fd = open("/dev/console", O_RDWR); /* fallback */ variable_set2(VAR_FIXIT_TTY, "serial", 0); /* give fixit a hint */ } else OnVTY = TRUE; /* * To make _sure_ we're on a VTY and don't have /dev/console switched * away to a serial port or something, attempt to set the cursor appearance. */ if (OnVTY) { int fd2, type; type = 0; /* normal */ if ((fd2 = open("/dev/console", O_RDWR)) != -1) { if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) { OnVTY = FALSE; variable_set2(VAR_FIXIT_TTY, "serial", 0); /* Tell Fixit the console type */ close(fd); close(fd2); open("/dev/console", O_RDWR); } else close(fd2); } } close(1); dup(0); close(2); dup(0); printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console"); ioctl(0, TIOCSCTTY, (char *)NULL); setlogin("root"); setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin", 1); setbuf(stdin, 0); setbuf(stderr, 0); #if 0 signal(SIGCHLD, reap_children); #endif memset(&ufs_args, 0, sizeof(ufs_args)); mount("ufs", "/", MNT_UPDATE, &ufs_args); } else { char hname[256]; /* Initalize various things for a multi-user environment */ if (!gethostname(hname, sizeof hname)) variable_set2(VAR_HOSTNAME, hname, 0); } if (set_termcap() == -1) { printf("Can't find terminal entry\n"); exit(-1); } /* XXX - libdialog has particularly bad return value checking */ init_dialog(); /* If we haven't crashed I guess dialog is running ! */ DialogActive = TRUE; /* Make sure HOME is set for those utilities that need it */ if (!getenv("HOME")) setenv("HOME", "/", 1); signal(SIGINT, handle_intr); /* * Make sure we can be interrupted even if we were re-executed * from an interrupt. */ sigemptyset(&signalset); sigaddset(&signalset, SIGINT); sigprocmask(SIG_UNBLOCK, &signalset, NULL); (void)vsystem("rm -rf %s", DOC_TMP_DIR); } /* Close down and prepare to exit */ void systemShutdown(int status) { /* If some media is open, close it down */ if (status >=0) { if (mediaDevice != NULL && mediaDevice->type == DEVICE_TYPE_CDROM) { mediaClose(); msgConfirm("Be sure to remove the media from the drive."); } else mediaClose(); } /* write out any changes to rc.conf .. */ configRC_conf(); /* Shut down the dialog library */ if (DialogActive) { end_dialog(); DialogActive = FALSE; } /* Shut down curses */ endwin(); /* If we have a temporary doc dir lying around, nuke it */ (void)vsystem("rm -rf %s", DOC_TMP_DIR); /* REALLY exit! */ if (RunningAsInit) { /* Put the console back */ ioctl(0, VT_ACTIVATE, 2); #if defined(__sparc64__) reboot(RB_HALT); #else reboot(RB_AUTOBOOT); #endif } else exit(status); } /* Run some general command */ int systemExecute(char *command) { int status; struct termios foo; WINDOW *w = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; tcsetattr(0, TCSANOW, &foo); } if (!Fake) status = system(command); else { status = 0; msgDebug("systemExecute: Faked execution of `%s'\n", command); } DialogActive = TRUE; restorescr(w); return status; } /* suspend/resume libdialog/curses screen */ static WINDOW *oldW; void systemSuspendDialog(void) { oldW = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; } void systemResumeDialog(void) { DialogActive = TRUE; restorescr(oldW); } /* Display a help file in a filebox */ int systemDisplayHelp(char *file) { char *fname = NULL; char buf[FILENAME_MAX]; int ret = 0; WINDOW *w = savescr(); fname = systemHelpFile(file, buf); if (!fname) { snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file); use_helpfile(NULL); use_helpline(NULL); dialog_mesgbox("Sorry!", buf, -1, -1); ret = 1; } else { use_helpfile(NULL); use_helpline(NULL); dialog_textbox(file, fname, LINES, COLS); } restorescr(w); return ret; } char * systemHelpFile(char *file, char *buf) { if (!file) return NULL; if (file[0] == '/') return file; snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.hlp", ProgName, file); if (file_readable(buf)) return buf; snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.TXT", ProgName, file); if (file_readable(buf)) return buf; return NULL; } void systemChangeTerminal(char *color, const u_char c_term[], char *mono, const u_char m_term[]) { if (OnVTY) { int setupterm(char *color, int, int *); if (ColorDisplay) { setenv("TERM", color, 1); setenv("TERMCAP", c_term, 1); reset_shell_mode(); setterm(color); cbreak(); noecho(); } else { setenv("TERM", mono, 1); setenv("TERMCAP", m_term, 1); reset_shell_mode(); setterm(mono); cbreak(); noecho(); } } clear(); refresh(); dialog_clear(); } int vsystem(char *fmt, ...) { va_list args; int pstat; pid_t pid; int omask; sig_t intsave, quitsave; char *cmd; int i; struct stat sb; cmd = (char *)alloca(FILENAME_MAX); cmd[0] = '\0'; va_start(args, fmt); vsnprintf(cmd, FILENAME_MAX, fmt, args); va_end(args); omask = sigblock(sigmask(SIGCHLD)); if (Fake) { msgDebug("vsystem: Faked execution of `%s'\n", cmd); return 0; } if (isDebug()) msgDebug("Executing command `%s'\n", cmd); pid = fork(); if (pid == -1) { (void)sigsetmask(omask); i = 127; } else if (!pid) { /* Junior */ (void)sigsetmask(omask); if (DebugFD != -1) { dup2(DebugFD, 0); dup2(DebugFD, 1); dup2(DebugFD, 2); } else { close(1); open("/dev/null", O_WRONLY); dup2(1, 2); } if (stat("/stand/sh", &sb) == 0) execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL); else execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); exit(1); } else { intsave = signal(SIGINT, SIG_IGN); quitsave = signal(SIGQUIT, SIG_IGN); pid = waitpid(pid, &pstat, 0); (void)sigsetmask(omask); (void)signal(SIGINT, intsave); (void)signal(SIGQUIT, quitsave); i = (pid == -1) ? -1 : WEXITSTATUS(pstat); if (isDebug()) msgDebug("Command `%s' returns status of %d\n", cmd, i); } return i; } void systemCreateHoloshell(void) { int waitstatus; if ((FixItMode || OnVTY) && RunningAsInit) { if (ehs_pid != 0) { int pstat; if (kill(ehs_pid, 0) == 0) { if (msgNoYes("There seems to be an emergency holographic shell\n" "already running on VTY 4.\n\n" "Kill it and start a new one?")) return; /* try cleaning up as much as possible */ (void) kill(ehs_pid, SIGHUP); sleep(1); (void) kill(ehs_pid, SIGKILL); } /* avoid too many zombies */ (void) waitpid(ehs_pid, &pstat, WNOHANG); } if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if ((ehs_pid = fork()) == 0) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("Doctor: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(fd, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(fd, TCSANOW, &foo) == -1) msgDebug("Doctor: I'm unable to set the erase character.\n"); } else msgDebug("Doctor: I'm unable to get the terminal attributes!\n"); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n"); fflush(stdout); } - execlp("sh", "-sh", 0); + execlp("sh", "-sh", NULL); msgDebug("Was unable to execute sh for Holographic shell!\n"); exit(1); } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { WINDOW *w = savescr(); msgNotify("Starting an emergency holographic shell on VTY4"); sleep(2); restorescr(w); } else { (void)waitpid(ehs_pid, &waitstatus, 0); /* we only wait for shell to finish in serial mode since there is no virtual console */ systemResumeDialog(); } } } } Index: head/usr.sbin/sysinstall/tcpip.c =================================================================== --- head/usr.sbin/sysinstall/tcpip.c (revision 209068) +++ head/usr.sbin/sysinstall/tcpip.c (revision 209069) @@ -1,776 +1,775 @@ /* * $FreeBSD$ * * Copyright (c) 1995 * Gary J Palmer. All rights reserved. * Copyright (c) 1996 * Jordan K. Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * All kinds of hacking also performed by jkh on this code. Don't * blame Gary for every bogosity you see here.. :-) * * -jkh */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include #include #include /* The help file for the TCP/IP setup screen */ #define TCP_HELPFILE "tcp" /* These are nasty, but they make the layout structure a lot easier ... */ static char hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN], gateway[IPADDR_FIELD_LEN], nameserver[INET6_ADDRSTRLEN]; static int okbutton, cancelbutton; static char ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN]; static char ipv6addr[INET6_ADDRSTRLEN]; /* What the screen size is meant to be */ #define TCP_DIALOG_Y 0 #define TCP_DIALOG_X 8 #define TCP_DIALOG_WIDTH COLS - 16 #define TCP_DIALOG_HEIGHT LINES - 2 static Layout layout[] = { #define LAYOUT_HOSTNAME 0 { 1, 2, 25, HOSTNAME_FIELD_LEN - 1, "Host:", "Your fully-qualified hostname, e.g. foo.bar.com", hostname, STRINGOBJ, NULL }, #define LAYOUT_DOMAINNAME 1 { 1, 35, 20, HOSTNAME_FIELD_LEN - 1, "Domain:", "The name of the domain that your machine is in, e.g. bar.com", domainname, STRINGOBJ, NULL }, #define LAYOUT_GATEWAY 2 { 5, 2, 18, IPADDR_FIELD_LEN - 1, "IPv4 Gateway:", "IPv4 address of host forwarding packets to non-local destinations", gateway, STRINGOBJ, NULL }, #define LAYOUT_NAMESERVER 3 { 5, 35, 18, INET6_ADDRSTRLEN - 1, "Name server:", "IPv4 or IPv6 address of your local DNS server", nameserver, STRINGOBJ, NULL }, #define LAYOUT_IPADDR 4 { 10, 10, 18, IPADDR_FIELD_LEN - 1, "IPv4 Address:", "The IPv4 address to be used for this interface", ipaddr, STRINGOBJ, NULL }, #define LAYOUT_NETMASK 5 { 10, 35, 18, IPADDR_FIELD_LEN - 1, "Netmask:", "The netmask for this interface, e.g. 0xffffff00 for a class C network", netmask, STRINGOBJ, NULL }, #define LAYOUT_EXTRAS 6 { 14, 10, 37, HOSTNAME_FIELD_LEN - 1, "Extra options to ifconfig (usually empty):", "Any interface-specific options to ifconfig you would like to add", extras, STRINGOBJ, NULL }, #define LAYOUT_OKBUTTON 7 { 19, 15, 0, 0, "OK", "Select this if you are happy with these settings", &okbutton, BUTTONOBJ, NULL }, #define LAYOUT_CANCELBUTTON 8 { 19, 35, 0, 0, "CANCEL", "Select this if you wish to cancel this screen", &cancelbutton, BUTTONOBJ, NULL }, LAYOUT_END, }; #define _validByte(b) ((b) >= 0 && (b) <= 255) /* whine */ static void feepout(char *msg) { beep(); msgConfirm("%s", msg); } /* Verify IP address integrity */ static int verifyIP(char *ip, unsigned long *mask, unsigned long *out) { long a, b, c, d; char *endptr, *endptr_prev; unsigned long parsedip; unsigned long max_addr = (255 << 24) | (255 << 16) | (255 << 8) | 255; if (ip == NULL) return 0; a = strtol(ip, &endptr, 10); if (endptr - ip == 0 || *endptr++ != '.') return 0; endptr_prev = endptr; b = strtol(endptr, &endptr, 10); if (endptr - endptr_prev == 0 || *endptr++ != '.') return 0; endptr_prev = endptr; c = strtol(endptr, &endptr, 10); if (endptr - endptr_prev == 0 || *endptr++ != '.') return 0; endptr_prev = endptr; d = strtol(endptr, &endptr, 10); if (*endptr != '\0' || endptr - endptr_prev == 0) return 0; if (!_validByte(a) || !_validByte(b) || !_validByte(c) || !_validByte(d)) return 0; parsedip = (a << 24) | (b << 16) | (c << 8) | d; if (out) *out = parsedip; /* * The ip address must not be network or broadcast address. */ if (mask && ((parsedip == (parsedip & *mask)) || (parsedip == ((parsedip & *mask) + max_addr - *mask)))) return 0; return 1; } static int verifyIP6(char *ip) { struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(ip, NULL, &hints, &res) == 0) { freeaddrinfo(res); return 1; } return 0; } /* Verify IPv4 netmask as being well-formed as a 0x or AAA.BBB.CCC.DDD mask */ static int verifyNetmask(const char *netmask, unsigned long *out) { unsigned long mask; long tmp; char *endptr; if (netmask[0] == '0' && (netmask[1] == 'x' || netmask[1] == 'X')) { /* Parse out hex mask */ mask = strtoul(netmask, &endptr, 0); if (*endptr != '\0') return 0; } else { /* Parse out quad decimal mask */ tmp = strtoul(netmask, &endptr, 10); if (!_validByte(tmp) || *endptr++ != '.') return 0; mask = tmp; tmp = strtoul(endptr, &endptr, 10); if (!_validByte(tmp) || *endptr++ != '.') return 0; mask = (mask << 8) + tmp; tmp = strtoul(endptr, &endptr, 10); if (!_validByte(tmp) || *endptr++ != '.') return 0; mask = (mask << 8) + tmp; tmp = strtoul(endptr, &endptr, 10); if (!_validByte(tmp) || *endptr++ != '\0') return 0; mask = (mask << 8) + tmp; } /* Verify that we have a continous netmask */ if ((((-mask & mask) - 1) | mask) != 0xffffffff) return 0; if (out) *out = mask; return 1; } static int verifyGW(char *gw, unsigned long *ip, unsigned long *mask) { unsigned long parsedgw; if (!verifyIP(gw, mask, &parsedgw)) return 0; /* Gateway needs to be within the set of IPs reachable through the interface */ if (ip && mask && ((parsedgw & *mask) != (*ip & *mask))) return 0; return 1; } /* Check for the settings on the screen - the per-interface stuff is moved to the main handling code now to do it on the fly - sigh */ static int verifySettings(void) { unsigned long parsedip; unsigned long parsednetmask; if (!hostname[0]) feepout("Must specify a host name of some sort!"); else if (netmask[0] && !verifyNetmask(netmask, &parsednetmask)) feepout("Invalid netmask value"); else if (nameserver[0] && !verifyIP(nameserver, NULL, NULL) && !verifyIP6(nameserver)) feepout("Invalid name server IP address specified"); else if (ipaddr[0] && !verifyIP(ipaddr, &parsednetmask, &parsedip)) feepout("Invalid IPv4 address"); else if (gateway[0] && strcmp(gateway, "NO") && !verifyGW(gateway, ipaddr[0] ? &parsedip : NULL, netmask[0] ? &parsednetmask : NULL)) feepout("Invalid gateway IPv4 address specified"); else return 1; return 0; } static void dhcpGetInfo(Device *devp) { char leasefile[PATH_MAX]; snprintf(leasefile, sizeof(leasefile), "%sdhclient.leases.%s", _PATH_VARDB, devp->name); /* If it fails, do it the old-fashioned way */ if (dhcpParseLeases(leasefile, hostname, domainname, nameserver, ipaddr, gateway, netmask) == -1) { FILE *ifp; char *cp, cmd[256], data[2048]; int i, j; /* Bah, now we have to kludge getting the information from ifconfig */ snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); ifp = popen(cmd, "r"); if (ifp) { j = fread(data, 1, sizeof(data), ifp); fclose(ifp); if (j < 0) /* paranoia */ j = 0; data[j] = '\0'; if (isDebug()) msgDebug("DHCP configured interface returns %s\n", data); /* XXX This is gross as it assumes a certain ordering to ifconfig's output! XXX */ if ((cp = strstr(data, "inet ")) != NULL) { i = 0; cp += 5; /* move over keyword */ while (*cp != ' ') ipaddr[i++] = *(cp++); ipaddr[i] = '\0'; if (!strncmp(++cp, "netmask", 7)) { i = 0; cp += 8; while (*cp != ' ') netmask[i++] = *(cp++); netmask[i] = '\0'; } } } } /* If we didn't get a name server value, hunt for it in resolv.conf */ if (!nameserver[0] && file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); if (hostname[0]) variable_set2(VAR_HOSTNAME, hostname, 0); } static void rtsolGetInfo(Device *devp) { FILE *ifp; char *cp, cmd[256], data[2048]; int i; snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); if ((ifp = popen(cmd, "r")) == NULL) return; while (fgets(data, sizeof(data), ifp) != NULL) { if (isDebug()) msgDebug("RTSOL configured interface returns %s\n", data); if ((cp = strstr(data, "inet6 ")) != NULL) { cp += 6; /* move over keyword */ if (strncmp(cp, "fe80:", 5)) { i = 0; while (*cp != ' ') ipv6addr[i++] = *(cp++); ipv6addr[i] = '\0'; } } } fclose(ifp); } /* This is it - how to get TCP setup values */ int tcpOpenDialog(Device *devp) { WINDOW *ds_win, *save = NULL; ComposeObj *obj = NULL; int n = 0, filled = 0, cancel = FALSE; int max, ret = DITEM_SUCCESS; int use_dhcp = FALSE; int use_rtsol = FALSE; char *tmp; char title[80]; save = savescr(); /* Initialise vars from previous device values */ if (devp->private) { DevInfo *di = (DevInfo *)devp->private; SAFE_STRCPY(ipaddr, di->ipaddr); SAFE_STRCPY(netmask, di->netmask); SAFE_STRCPY(extras, di->extras); use_dhcp = di->use_dhcp; use_rtsol = di->use_rtsol; } else { /* See if there are any defaults */ char *cp; char *old_interactive = NULL; /* * This is a hack so that the dialogs below are interactive in a * script if we have requested interactive behavior. */ if (variable_get(VAR_NONINTERACTIVE) && variable_get(VAR_NETINTERACTIVE)) { old_interactive = strdup(VAR_NONINTERACTIVE); variable_unset(VAR_NONINTERACTIVE); } /* * Try a RTSOL scan if such behavior is desired. * If the variable was configured and is YES, do it. * If it was configured to anything else, treat it as NO. * Otherwise, ask the question interactively. */ if (!variable_get(VAR_NO_INET6) && (!variable_cmp(VAR_TRY_RTSOL, "YES") || (variable_get(VAR_TRY_RTSOL)==0 && !msgNoYes("Do you want to try IPv6 configuration of the interface?")))) { int i; size_t len; i = 0; sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &i, sizeof(i)); i = 1; sysctlbyname("net.inet6.ip6.accept_rtadv", NULL, 0, &i, sizeof(i)); vsystem("ifconfig %s up", devp->name); len = sizeof(i); sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); sleep(i + 1); Mkdir("/var/run"); msgNotify("Scanning for RA servers..."); if (0 == vsystem("rtsol %s", devp->name)) { len = sizeof(i); sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); sleep(i + 1); rtsolGetInfo(devp); use_rtsol = TRUE; } else use_rtsol = FALSE; } /* * First try a DHCP scan if such behavior is desired. * If the variable was configured and is YES, do it. * If it was configured to anything else, treat it as NO. * Otherwise, ask the question interactively. */ if (!variable_cmp(VAR_TRY_DHCP, "YES") || (variable_get(VAR_TRY_DHCP)==0 && !msgNoYes("Do you want to try DHCP configuration of the interface?"))) { Mkdir("/var/db"); Mkdir("/var/run"); Mkdir("/tmp"); msgNotify("Scanning for DHCP servers..."); /* XXX clear any existing lease */ /* XXX limit protocol to N tries */ if (0 == vsystem("dhclient %s", devp->name)) { dhcpGetInfo(devp); use_dhcp = TRUE; } else use_dhcp = FALSE; } /* Restore old VAR_NONINTERACTIVE if needed. */ if (old_interactive != NULL) { variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); free(old_interactive); } /* Special hack so it doesn't show up oddly in the tcpip setup menu */ if (!strcmp(gateway, "NO")) gateway[0] = '\0'; /* Get old IP address from variable space, if available */ if (!ipaddr[0]) { if ((cp = variable_get(VAR_IPADDR)) != NULL) SAFE_STRCPY(ipaddr, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_IPADDR))) != NULL) SAFE_STRCPY(ipaddr, cp); } /* Get old netmask from variable space, if available */ if (!netmask[0]) { if ((cp = variable_get(VAR_NETMASK)) != NULL) SAFE_STRCPY(netmask, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_NETMASK))) != NULL) SAFE_STRCPY(netmask, cp); } /* Get old extras string from variable space, if available */ if (!extras[0]) { if ((cp = variable_get(VAR_EXTRAS)) != NULL) SAFE_STRCPY(extras, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_EXTRAS))) != NULL) SAFE_STRCPY(extras, cp); } } /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */ if (!hostname[0]) { tmp = variable_get(VAR_HOSTNAME); if (tmp) SAFE_STRCPY(hostname, tmp); } if (!domainname[0]) { tmp = variable_get(VAR_DOMAINNAME); if (tmp) SAFE_STRCPY(domainname, tmp); } if (!gateway[0]) { tmp = variable_get(VAR_GATEWAY); if (tmp && strcmp(tmp, "NO")) SAFE_STRCPY(gateway, tmp); } if (!nameserver[0]) { tmp = variable_get(VAR_NAMESERVER); if (tmp) SAFE_STRCPY(nameserver, tmp); } /* If non-interactive, jump straight over the dialog crap and into config section */ if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_NETINTERACTIVE)) { if (!hostname[0]) msgConfirm("WARNING: hostname variable not set and is a non-optional\n" "parameter. Please add this to your installation script\n" "or set the netInteractive variable (see sysinstall man page)"); else goto netconfig; } /* Now do all the screen I/O */ dialog_clear_norefresh(); /* Modify the help line for PLIP config */ if (!strncmp(devp->name, "plip", 4)) layout[LAYOUT_EXTRAS].help = "For PLIP configuration, you must enter the peer's IP address here."; /* We need a curses window */ tmp = " Network Configuration "; if (ipv6addr[0]) tmp = string_concat(tmp, "(IPv6 ready) "); if (!(ds_win = openLayoutDialog(TCP_HELPFILE, tmp, TCP_DIALOG_X, TCP_DIALOG_Y, TCP_DIALOG_WIDTH, TCP_DIALOG_HEIGHT))) { beep(); msgConfirm("Cannot open TCP/IP dialog window!!"); restorescr(save); return DITEM_FAILURE; } /* Draw interface configuration box */ draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17, dialog_attr, border_attr); wattrset(ds_win, dialog_attr); sprintf(title, " Configuration for Interface %s ", devp->name); mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 14, title); /* Some more initialisation before we go into the main input loop */ obj = initLayoutDialog(ds_win, layout, TCP_DIALOG_X, TCP_DIALOG_Y, &max); reenter: cancelbutton = okbutton = 0; while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)) { /* Prevent this from being irritating if user really means NO */ if (filled < 3) { /* Insert a default value for the netmask, 0xffffff00 is * the most appropriate one (entire class C, or subnetted * class A/B network). */ if (!netmask[0]) { strcpy(netmask, "255.255.255.0"); RefreshStringObj(layout[LAYOUT_NETMASK].obj); ++filled; } if (!index(hostname, '.') && domainname[0]) { strcat(hostname, "."); strcat(hostname, domainname); RefreshStringObj(layout[LAYOUT_HOSTNAME].obj); ++filled; } else if (((tmp = index(hostname, '.')) != NULL) && !domainname[0]) { SAFE_STRCPY(domainname, tmp + 1); RefreshStringObj(layout[LAYOUT_DOMAINNAME].obj); ++filled; } } } if (!cancel && !verifySettings()) goto reenter; /* Clear this crap off the screen */ delwin(ds_win); dialog_clear_norefresh(); use_helpfile(NULL); /* We actually need to inform the rest of sysinstall about this data now if the user hasn't selected cancel. Save the stuff out to the environment via the variable_set() mechanism */ netconfig: if (!cancel) { DevInfo *di; char temp[512], ifn[255]; int ipv4_enable = FALSE; if (hostname[0]) { variable_set2(VAR_HOSTNAME, hostname, 1); sethostname(hostname, strlen(hostname)); } if (domainname[0]) variable_set2(VAR_DOMAINNAME, domainname, 0); if (gateway[0]) variable_set2(VAR_GATEWAY, gateway, use_dhcp ? 0 : 1); if (nameserver[0]) variable_set2(VAR_NAMESERVER, nameserver, 0); if (ipaddr[0]) variable_set2(VAR_IPADDR, ipaddr, 0); if (ipv6addr[0]) variable_set2(VAR_IPV6ADDR, ipv6addr, 0); if (!devp->private) devp->private = (DevInfo *)safe_malloc(sizeof(DevInfo)); di = devp->private; SAFE_STRCPY(di->ipaddr, ipaddr); SAFE_STRCPY(di->netmask, netmask); SAFE_STRCPY(di->extras, extras); di->use_dhcp = use_dhcp; di->use_rtsol = use_rtsol; if (use_dhcp || ipaddr[0]) ipv4_enable = TRUE; if (ipv4_enable) { sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name); if (use_dhcp) { if (strlen(extras) > 0) sprintf(temp, "DHCP %s", extras); else sprintf(temp, "DHCP"); } else sprintf(temp, "inet %s %s netmask %s", ipaddr, extras, netmask); variable_set2(ifn, temp, 1); } if (use_rtsol) variable_set2(VAR_IPV6_ENABLE, "YES", 1); if (!use_dhcp) configResolv(NULL); /* XXX this will do it on the MFS copy XXX */ ret = DITEM_SUCCESS; } else ret = DITEM_FAILURE; restorescr(save); return ret; } static Device *NetDev; static int netHook(dialogMenuItem *self) { Device **devs; devs = deviceFindDescr(self->prompt, self->title, DEVICE_TYPE_NETWORK); if (devs) { if (DITEM_STATUS(tcpOpenDialog(devs[0])) != DITEM_FAILURE) NetDev = devs[0]; else NetDev = NULL; } return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE; } static char * tcpDeviceScan(void) { int s; struct ifmediareq ifmr; struct ifaddrs *ifap, *ifa; - struct if_data *ifd; char *network_dev; if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) return (NULL); if (getifaddrs(&ifap) < 0) return (NULL); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name)); if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) continue; /* some devices don't support this */ if ((ifmr.ifm_status & IFM_AVALID) == 0) continue; /* not active */ if (IFM_TYPE(ifmr.ifm_active) != IFM_ETHER) continue; /* not an ethernet device */ if (ifmr.ifm_status & IFM_ACTIVE) { network_dev = strdup(ifa->ifa_name); freeifaddrs(ifap); if (!variable_get(VAR_NONINTERACTIVE)) msgConfirm("Using interface %s", network_dev); msgDebug("tcpDeviceScan found %s", network_dev); return (network_dev); } } close(s); freeifaddrs(ifap); return (NULL); } /* Get a network device */ Device * tcpDeviceSelect(void) { DMenu *menu; Device **devs, *rval; char *dev, *network_dev; int cnt; rval = NULL; if (variable_get(VAR_NETWORK_DEVICE)) { network_dev = variable_get(VAR_NETWORK_DEVICE); /* * netDev can be set to several types of values. * If netDev is set to ANY, scan all network devices * looking for a valid link, and go with the first * device found. netDev can also be specified as a * comma delimited list, with each network device * tried in order. netDev can also be set to a single * network device. */ if (!strcmp(network_dev, "ANY")) network_dev = strdup(tcpDeviceScan()); while ((dev = strsep(&network_dev, ",")) != NULL) { devs = deviceFind(dev, DEVICE_TYPE_NETWORK); cnt = deviceCount(devs); if (cnt) { if (DITEM_STATUS(tcpOpenDialog(devs[0])) == DITEM_SUCCESS) return (devs[0]); } } if (!variable_get(VAR_NONINTERACTIVE)) msgConfirm("No network devices available!"); return (NULL); } devs = deviceFind(NULL, DEVICE_TYPE_NETWORK); cnt = deviceCount(devs); if ((!RunningAsInit) && (variable_check("NETWORK_CONFIGURED=NO") != TRUE)) { if (!msgYesNo("Running multi-user, assume that the network is already configured?")) return devs[0]; } if (cnt == 1) { if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) rval = devs[0]; } else { int status; menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook, NULL); if (!menu) msgFatal("Unable to create network device menu! Argh!"); status = dmenuOpenSimple(menu, FALSE); free(menu); if (status) rval = NetDev; } return rval; } /* Do it from a menu that doesn't care about status */ int tcpMenuSelect(dialogMenuItem *self) { Device *tmp; WINDOW *save; variable_set("NETWORK_CONFIGURED=NO",0); tmp = tcpDeviceSelect(); variable_unset("NETWORK_CONFIGURED"); save = savescr(); if (tmp && tmp->private && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) if (!DEVICE_INIT(tmp)) msgConfirm("Initialization of %s device failed.", tmp->name); restorescr(save); return DITEM_SUCCESS; }