diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 2005-04-20 19:11:07 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 2005-04-20 19:11:07 +0000 |
| commit | 79c906b55063e4f0f0d3281363970da4e619cf56 (patch) | |
| tree | 09cc3ca07e7d7250dd9d9d550c76eacaf462ca91 /usr.sbin/sysinstall | |
| parent | 7b100a2efc2b0855b788d000f7b2215fb73a5221 (diff) | |
| parent | 1e4e7f70c04a80eee7cfe0ecc6787272a43ba8bc (diff) | |
Notes
Diffstat (limited to 'usr.sbin/sysinstall')
66 files changed, 21736 insertions, 0 deletions
diff --git a/usr.sbin/sysinstall/Makefile b/usr.sbin/sysinstall/Makefile new file mode 100644 index 0000000000000..7bd2c13668739 --- /dev/null +++ b/usr.sbin/sysinstall/Makefile @@ -0,0 +1,99 @@ +# $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 tape.c tcpip.c termcap.c ttys.c ufs.c usb.c user.c \ + variable.c ${_wizard} keymap.h + +.if ${MACHINE} == "pc98" +SRCS+= pccard.c +.endif + +CFLAGS+= -DUSE_GZIP=1 +.if ${MACHINE} == "pc98" +CFLAGS+= -DPC98 +.endif +CFLAGS+= -I${.CURDIR}/../../gnu/lib/libdialog -I. + +DPADD= ${LIBDIALOG} ${LIBNCURSES} ${LIBUTIL} ${LIBDISK} ${LIBFTPIO} +LDADD= -ldialog -lncurses -lutil -ldisk -lftpio + +CLEANFILES= makedevs.c rtermcap +CLEANFILES+= keymap.tmp keymap.h + +makedevs.c: Makefile rtermcap + echo '#include <sys/types.h>' > 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 \ + 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 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 " { 0 }"; echo "};" ; echo "" ) >> keymap.tmp + mv keymap.tmp keymap.h + +.include <bsd.prog.mk> diff --git a/usr.sbin/sysinstall/anonFTP.c b/usr.sbin/sysinstall/anonFTP.c new file mode 100644 index 0000000000000..7d130f14e95d1 --- /dev/null +++ b/usr.sbin/sysinstall/anonFTP.c @@ -0,0 +1,327 @@ +/* + * 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 + * Coranth Gryphon. 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 OR THEIR 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 <sys/param.h> +#include <pwd.h> +#include <grp.h> + +/* This doesn't change until FTP itself changes */ + +#define FTP_NAME "ftp" +#define MOTD_FILE "ftpmotd" + +/* These change if we want to use different defaults */ + +#define FTP_UID 14 +#define FTP_GID 5 +#define FTP_GROUP "operator" +#define FTP_UPLOAD "incoming" +#define FTP_COMMENT "Anonymous FTP Admin" +#define FTP_HOMEDIR "/var/ftp" + +#define ANONFTP_HELPFILE "anonftp" + +/* Set up the structure to hold configuration information */ +/* Note that this is only what we could fit onto the one screen */ + +typedef struct +{ + char homedir[64]; /* Home Dir for Anon FTP */ + char group[32]; /* Group */ + char uid[8]; /* UID */ + char comment[64]; /* PWD Comment */ + char upload[32]; /* Upload Dir */ +} FTPConf; + +static FTPConf tconf; + +#define ANONFTP_HOMEDIR_LEN 64 +#define ANONFTP_COMMENT_LEN 64 +#define ANONFTP_UPLOAD_LEN 32 +#define ANONFTP_GROUP_LEN 32 +#define ANONFTP_UID_LEN 8 + +static int okbutton, cancelbutton; + +/* What the screen size is meant to be */ +#define ANONFTP_DIALOG_Y 0 +#define ANONFTP_DIALOG_X 8 +#define ANONFTP_DIALOG_WIDTH COLS - 16 +#define ANONFTP_DIALOG_HEIGHT LINES - 2 + +static Layout layout[] = { +#define LAYOUT_UID 0 + { 2, 3, 8, ANONFTP_UID_LEN - 1, + "UID:", "What user ID to assign to FTP Admin", + tconf.uid, STRINGOBJ, NULL }, +#define LAYOUT_GROUP 1 + { 2, 15, 15, ANONFTP_GROUP_LEN - 1, + "Group:", "Group name that ftp process belongs to", + tconf.group, STRINGOBJ, NULL }, +#define LAYOUT_COMMENT 2 + { 2, 35, 24, ANONFTP_COMMENT_LEN - 1, + "Comment:", "Password file comment for FTP Admin", + tconf.comment, STRINGOBJ, NULL }, +#define LAYOUT_HOMEDIR 3 + { 9, 10, 43, ANONFTP_HOMEDIR_LEN - 1, + "FTP Root Directory:", + "The top directory to chroot to when doing anonymous ftp", + tconf.homedir, STRINGOBJ, NULL }, +#define LAYOUT_UPLOAD 4 + { 14, 20, 22, ANONFTP_UPLOAD_LEN - 1, + "Upload Subdirectory:", "Designated sub-directory that holds uploads", + tconf.upload, STRINGOBJ, NULL }, +#define LAYOUT_OKBUTTON 5 + { 19, 15, 0, 0, + "OK", "Select this if you are happy with these settings", + &okbutton, BUTTONOBJ, NULL }, +#define LAYOUT_CANCELBUTTON 6 + { 19, 35, 0, 0, + "CANCEL", "Select this if you wish to cancel this screen", + &cancelbutton, BUTTONOBJ, NULL }, + { 0 }, +}; + +static int +createFtpUser(void) +{ + struct passwd *tpw; + struct group *tgrp; + char pwline[256]; + char *tptr; + int gid; + FILE *fptr; + + if ((gid = atoi(tconf.group)) <= 0) { + if (!(tgrp = getgrnam(tconf.group))) { + /* group does not exist, create it by name */ + + tptr = msgGetInput("14", "What group ID to use for group %s ?", tconf.group); + if (tptr && *tptr && ((gid = atoi(tptr)) > 0)) { + if ((fptr = fopen(_PATH_GROUP,"a"))) { + fprintf(fptr,"%s:*:%d:%s\n",tconf.group,gid,FTP_NAME); + fclose(fptr); + } + } + else + gid = FTP_GID; + } + else + gid = tgrp->gr_gid; + } + else if (!getgrgid(gid)) { + /* group does not exist, create it by number */ + + tptr = msgGetInput("14", "What group name to use for gid %d ?", gid); + if (tptr && *tptr) { + SAFE_STRCPY(tconf.group, tptr); + if ((tgrp = getgrnam(tconf.group))) { + gid = tgrp->gr_gid; + } + else if ((fptr = fopen(_PATH_GROUP,"a"))) { + fprintf(fptr,"%s:*:%d:%s\n",tconf.group,gid,FTP_NAME); + fclose(fptr); + } + } + } + + if ((tpw = getpwnam(FTP_NAME))) { + if (tpw->pw_uid != FTP_UID) + msgConfirm("FTP user already exists with a different uid."); + + return DITEM_SUCCESS; /* succeeds if already exists */ + } + + sprintf(pwline, "%s:*:%s:%d::0:0:%s:%s:/nonexistent\n", FTP_NAME, tconf.uid, gid, tconf.comment, tconf.homedir); + + fptr = fopen(_PATH_MASTERPASSWD,"a"); + if (! fptr) { + msgConfirm("Could not open master password file."); + return DITEM_FAILURE; + } + fprintf(fptr, "%s", pwline); + fclose(fptr); + msgNotify("Remaking password file: %s", _PATH_MASTERPASSWD); + vsystem("pwd_mkdb -p %s", _PATH_MASTERPASSWD); + return DITEM_SUCCESS | DITEM_RESTORE; +} + +/* This is it - how to get the setup values */ +static int +anonftpOpenDialog(void) +{ + WINDOW *ds_win; + ComposeObj *obj = NULL; + int n = 0, cancel = FALSE; + int max; + char title[80]; + WINDOW *w = savescr(); + + /* We need a curses window */ + if (!(ds_win = openLayoutDialog(ANONFTP_HELPFILE, " Anonymous FTP Configuration ", + ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, ANONFTP_DIALOG_WIDTH, ANONFTP_DIALOG_HEIGHT))) { + beep(); + msgConfirm("Cannot open anonymous ftp dialog window!!"); + restorescr(w); + return DITEM_FAILURE; + } + + /* Draw a sub-box for the path configuration */ + draw_box(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 8, + ANONFTP_DIALOG_HEIGHT - 11, ANONFTP_DIALOG_WIDTH - 17, + dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + sprintf(title, " Path Configuration "); + mvwaddstr(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 22, title); + + /** Initialize the config Data Structure **/ + bzero(&tconf, sizeof(tconf)); + + SAFE_STRCPY(tconf.group, FTP_GROUP); + SAFE_STRCPY(tconf.upload, FTP_UPLOAD); + SAFE_STRCPY(tconf.comment, FTP_COMMENT); + SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR); + sprintf(tconf.uid, "%d", FTP_UID); + + /* Some more initialisation before we go into the main input loop */ + obj = initLayoutDialog(ds_win, layout, ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, &max); + + cancelbutton = okbutton = 0; + while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)); + + /* Clear this crap off the screen */ + delwin(ds_win); + use_helpfile(NULL); + restorescr(w); + if (cancel) + return DITEM_FAILURE; + return DITEM_SUCCESS; +} + +int +configAnonFTP(dialogMenuItem *self __unused) +{ + int i; + + + if (msgYesNo("Anonymous FTP permits un-authenticated users to connect to the system\n" + "FTP server, if FTP service is enabled. Anonymous users are\n" + "restricted to a specific subset of the file system, and the default\n" + "configuration provides a drop-box incoming directory to which uploads\n" + "are permitted. You must separately enable both inetd(8), and enable\n" + "ftpd(8) in inetd.conf(5) for FTP services to be available. If you\n" + "did not do so earlier, you will have the opportunity to enable inetd(8)\n" + "again later.\n\n" + "Do you wish to continue configuring anonymous FTP?")) { + return DITEM_FAILURE; + } + + /* Be optimistic */ + i = DITEM_SUCCESS; + + i = anonftpOpenDialog(); + if (DITEM_STATUS(i) != DITEM_SUCCESS) { + msgConfirm("Configuration of Anonymous FTP cancelled per user request."); + return i; + } + + /*** Use defaults for any invalid values ***/ + if (atoi(tconf.uid) <= 0) + sprintf(tconf.uid, "%d", FTP_UID); + + if (!tconf.group[0]) + SAFE_STRCPY(tconf.group, FTP_GROUP); + + if (!tconf.upload[0]) + SAFE_STRCPY(tconf.upload, FTP_UPLOAD); + + /*** If the user did not specify a directory, use default ***/ + + if (tconf.homedir[strlen(tconf.homedir) - 1] == '/') + tconf.homedir[strlen(tconf.homedir) - 1] = '\0'; + + if (!tconf.homedir[0]) + SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR); + + /*** If HomeDir does not exist, create it ***/ + + if (!directory_exists(tconf.homedir)) + vsystem("mkdir -p %s", tconf.homedir); + + if (directory_exists(tconf.homedir)) { + msgNotify("Configuring %s for use by anon FTP.", tconf.homedir); + vsystem("chmod 555 %s && chown root.%s %s", tconf.homedir, tconf.group, tconf.homedir); + vsystem("mkdir %s/bin && chmod 555 %s/bin", tconf.homedir, tconf.homedir); + vsystem("cp /bin/ls %s/bin && chmod 111 %s/bin/ls", tconf.homedir, tconf.homedir); + vsystem("cp /bin/date %s/bin && chmod 111 %s/bin/date", tconf.homedir, tconf.homedir); + vsystem("mkdir %s/etc && chmod 555 %s/etc", tconf.homedir, tconf.homedir); + vsystem("mkdir -p %s/pub", tconf.homedir); + vsystem("mkdir -p %s/%s", tconf.homedir, tconf.upload); + vsystem("chmod 1777 %s/%s", tconf.homedir, tconf.upload); + + if (DITEM_STATUS(createFtpUser()) == DITEM_SUCCESS) { + msgNotify("Copying password information for anon FTP."); + vsystem("awk -F: '{if ($3 < 10 || $1 == \"ftp\") print $0}' /etc/passwd > %s/etc/passwd && chmod 444 %s/etc/passwd", tconf.homedir, tconf.homedir); + vsystem("awk -F: '{if ($3 < 100) print $0}' /etc/group > %s/etc/group && chmod 444 %s/etc/group", tconf.homedir, tconf.homedir); + vsystem("chown -R root.%s %s/pub", tconf.group, tconf.homedir); + } + else { + msgConfirm("Unable to create FTP user! Anonymous FTP setup failed."); + i = DITEM_FAILURE; + } + + if (!msgYesNo("Create a welcome message file for anonymous FTP users?")) { + char cmd[256]; + vsystem("echo Your welcome message here. > %s/etc/%s", tconf.homedir, MOTD_FILE); + sprintf(cmd, "%s %s/etc/%s", variable_get(VAR_EDITOR), tconf.homedir, MOTD_FILE); + if (!systemExecute(cmd)) + i = DITEM_SUCCESS; + else + i = DITEM_FAILURE; + } + } + else { + msgConfirm("Invalid Directory: %s\n" + "Anonymous FTP will not be set up.", tconf.homedir); + i = DITEM_FAILURE; + } + if (DITEM_STATUS(i) == DITEM_SUCCESS) + variable_set2("anon_ftp", "YES", 0); + return i | DITEM_RESTORE; +} diff --git a/usr.sbin/sysinstall/cdrom.c b/usr.sbin/sysinstall/cdrom.c new file mode 100644 index 0000000000000..75151f4305888 --- /dev/null +++ b/usr.sbin/sysinstall/cdrom.c @@ -0,0 +1,218 @@ +/* + * 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. + * Copyright (c) 1995 + * Gary J Palmer. 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. + * + */ + +/* These routines deal with getting things off of CDROM media */ + +#include "sysinstall.h" +#include <sys/stat.h> +#include <sys/errno.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <unistd.h> +#include <grp.h> +#include <fcntl.h> +#include <libutil.h> + +#define CD9660 +#include <sys/mount.h> +#include <isofs/cd9660/cd9660_mount.h> +#undef CD9660 + +static Boolean cdromMounted; +static Boolean previouslyMounted; /* Was the disc already mounted? */ +static char mountpoint[MAXPATHLEN] = "/dist"; +int CDROMInitQuiet; + +static properties +read_props(char *name) +{ + int fd; + properties n; + + fd = open(name, O_RDONLY); + if (fd == -1) + return NULL; + n = properties_read(fd); + close(fd); + return n; +} + +Boolean +mediaInitCDROM(Device *dev) +{ + struct iso_args args; + properties cd_attr = NULL; + char *cp = NULL; + Boolean readInfo = TRUE; + static Boolean bogusCDOK = FALSE; + + if (cdromMounted) + return TRUE; + + Mkdir(mountpoint); + bzero(&args, sizeof(args)); + args.fspec = dev->devname; + args.flags = 0; + if (mount("cd9660", mountpoint, MNT_RDONLY, (caddr_t) &args) == -1) { + if (errno == EINVAL) { + msgConfirm("The disc in your drive looks more like an Audio disc than a FreeBSD release."); + return FALSE; + } + if (errno == EBUSY) { + /* Perhaps the CDROM drive is already mounted as /cdrom */ + if (file_readable("/cdrom/cdrom.inf")) { + previouslyMounted = TRUE; + strlcpy(mountpoint, "/cdrom", 7); + errno = 0; + } + } + if (errno) { + if (!CDROMInitQuiet) + msgConfirm("Error mounting %s on %s: %s (%u)", dev->devname, + mountpoint, strerror(errno), errno); + return FALSE; + } + } + cdromMounted = TRUE; + + if (!file_readable(string_concat(mountpoint, "/cdrom.inf")) && !bogusCDOK) { + if (msgYesNo("Warning: The disc currently in the drive is either not a FreeBSD\n" + "disc or it is an older (pre 2.1.5) FreeBSD CD which does not\n" + "have a version number on it. Do you wish to use this disc anyway?") != 0) { + if (!previouslyMounted) + unmount(mountpoint, MNT_FORCE); + cdromMounted = FALSE; + return FALSE; + } + else { + readInfo = FALSE; + bogusCDOK = TRUE; + } + } + + if (readInfo) { + if (!(cd_attr = read_props(string_concat(mountpoint, "/cdrom.inf"))) + || !(cp = property_find(cd_attr, "CD_VERSION"))) { + msgConfirm("Unable to find a %s/cdrom.inf file.\n" + "Either this is not a FreeBSD disc, there is a problem with\n" + "the CDROM driver or something is wrong with your hardware.\n" + "Please fix this problem (check the console logs on VTY2) and\n" + "try again.", mountpoint); + } + else { + if (variable_cmp(VAR_RELNAME, cp) && + variable_cmp(VAR_RELNAME, "any") && + variable_cmp(cp, "any") && + !bogusCDOK) { + msgConfirm("Warning: The version of the FreeBSD disc currently in the drive\n" + "(%s) does not match the version of the boot floppy\n" + "(%s).\n\n" + "If this is intentional, to avoid this message in the future\n" + "please visit the Options editor to set the boot floppy version\n" + "string to match that of the disc before selecting it as your\n" + "installation media.", cp, variable_get(VAR_RELNAME)); + + if (msgYesNo("Would you like to try and use this disc anyway?") != 0) { + if (!previouslyMounted) + unmount(mountpoint, MNT_FORCE); + cdromMounted = FALSE; + properties_free(cd_attr); + return FALSE; + } + else + bogusCDOK = TRUE; + } + if ((cp = property_find(cd_attr, "CD_MACHINE_ARCH")) != NULL) { + if (strcmp(cp, "any") && +#ifdef __alpha__ + strcmp(cp, "alpha")) { +#elif defined(PC98) + strcmp(cp, "pc98")) { +#elif defined(__sparc64__) + strcmp(cp, "sparc64")) { +#else + strcmp(cp, "x86")) { +#endif + msgConfirm("Fatal: The FreeBSD install CD/DVD currently in the drive\n" + "is for the %s architecture, not the machine you're using.\n\n" + + "Please use the correct installation CD/DVD for your machine type.", cp); + + if (!previouslyMounted) + unmount(mountpoint, MNT_FORCE); + cdromMounted = FALSE; + properties_free(cd_attr); + return FALSE; + } + } + if ((cp = property_find(cd_attr, "CD_VOLUME")) != NULL) { + dev->volume = atoi(cp); + /* XXX - Sanity check the volume here? */ + msgDebug("CD Volume %d initialized!\n", dev->volume); + } else { + dev->volume = 0; + } + } + } + if (cd_attr) + properties_free(cd_attr); + return TRUE; +} + +FILE * +mediaGetCDROM(Device *dev, char *file, Boolean probe) +{ + return mediaGenericGet(mountpoint, file); +} + +void +mediaShutdownCDROM(Device *dev) +{ + if (!cdromMounted) + return; + + if (previouslyMounted) { + cdromMounted = FALSE; + return; + } + + if (unmount(mountpoint, MNT_FORCE) != 0) + msgConfirm("Could not unmount the CDROM/DVD from %s: %s", mountpoint, strerror(errno)); + else + cdromMounted = FALSE; +} diff --git a/usr.sbin/sysinstall/command.c b/usr.sbin/sysinstall/command.c new file mode 100644 index 0000000000000..33ebc352544a4 --- /dev/null +++ b/usr.sbin/sysinstall/command.c @@ -0,0 +1,184 @@ +/* + * 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" + +#define MAX_NUM_COMMANDS 10 + +typedef struct { + char key[FILENAME_MAX]; + struct { + enum { CMD_SHELL, CMD_FUNCTION } type; + void *ptr, *data; + } cmds[MAX_NUM_COMMANDS]; + int ncmds; +} Command; + +#define MAX_CMDS 200 +static Command *commandStack[MAX_CMDS]; +int numCommands; + +/* Nuke the command stack */ +void +command_clear(void) +{ + int i, j; + + for (i = 0; i < numCommands; i++) + for (j = 0; j < commandStack[i]->ncmds; j++) + if (commandStack[i]->cmds[j].type == CMD_SHELL) + free(commandStack[i]->cmds[j].ptr); + free(commandStack[i]); + numCommands = 0; +} + +static void +addit(char *key, int type, void *cmd, void *data) +{ + int i; + + /* First, look for the key already present and add a command to it if found */ + for (i = 0; i < numCommands; i++) { + if (!strcmp(commandStack[i]->key, key)) { + if (commandStack[i]->ncmds == MAX_NUM_COMMANDS) + msgFatal("More than %d commands stacked up behind %s??", MAX_NUM_COMMANDS, key); + commandStack[i]->cmds[commandStack[i]->ncmds].type = type; + commandStack[i]->cmds[commandStack[i]->ncmds].ptr = cmd; + commandStack[i]->cmds[commandStack[i]->ncmds].data = data; + ++(commandStack[i]->ncmds); + return; + } + } + if (numCommands == MAX_CMDS) + msgFatal("More than %d commands accumulated??", MAX_CMDS); + + /* If we fell to here, it's a new key */ + commandStack[numCommands] = safe_malloc(sizeof(Command)); + strcpy(commandStack[numCommands]->key, key); + commandStack[numCommands]->ncmds = 1; + commandStack[numCommands]->cmds[0].type = type; + commandStack[numCommands]->cmds[0].ptr = cmd; + commandStack[numCommands]->cmds[0].data = data; + ++numCommands; +} + +/* Add a shell command under a given key */ +void +command_shell_add(char *key, char *fmt, ...) +{ + va_list args; + char *cmd; + + cmd = (char *)safe_malloc(256); + va_start(args, fmt); + vsnprintf(cmd, 256, fmt, args); + va_end(args); + + addit(key, CMD_SHELL, cmd, NULL); +} + +/* Add a shell command under a given key */ +void +command_func_add(char *key, commandFunc func, void *data) +{ + addit(key, CMD_FUNCTION, func, data); +} + +static int +sort_compare(Command *p1, Command *p2) +{ + if (!p1 && !p2) + return 0; + else if (!p1 && p2) /* NULL has a "greater" value for commands */ + return 1; + else if (p1 && !p2) + return -1; + else + return strcmp(p1->key, p2->key); +} + +void +command_sort(void) +{ + int i, j; + + commandStack[numCommands] = NULL; + /* Just do a crude bubble sort since the list is small */ + for (i = 0; i < numCommands; i++) { + for (j = 0; j < numCommands; j++) { + if (sort_compare(commandStack[j], commandStack[j + 1]) > 0) { + Command *tmp = commandStack[j]; + + commandStack[j] = commandStack[j + 1]; + commandStack[j + 1] = tmp; + } + } + } +} + +/* Run all accumulated commands in sorted order */ +void +command_execute(void) +{ + int i, j, ret; + commandFunc func; + + for (i = 0; i < numCommands; i++) { + for (j = 0; j < commandStack[i]->ncmds; j++) { + /* If it's a shell command, run system on it */ + if (commandStack[i]->cmds[j].type == CMD_SHELL) { + msgNotify("Doing %s", (char *)commandStack[i]->cmds[j].ptr); + ret = vsystem("%s", (char *)commandStack[i]->cmds[j].ptr); + if (isDebug()) + msgDebug("Command `%s' returns status %d\n", + (char *)commandStack[i]->cmds[j].ptr, ret); + } + else { + /* It's a function pointer - call it with the key and + the data */ + func = (commandFunc)commandStack[i]->cmds[j].ptr; + if (isDebug()) + msgDebug("%p: Execute(%s, %s)\n", + func, commandStack[i]->key, + (char *)commandStack[i]->cmds[j].data); + ret = (*func)(commandStack[i]->key, commandStack[i]->cmds[j].data); + if (isDebug()) + msgDebug("Function @ %p returns status %d\n", + commandStack[i]->cmds[j].ptr, ret); + } + } + } +} diff --git a/usr.sbin/sysinstall/devices.c b/usr.sbin/sysinstall/devices.c new file mode 100644 index 0000000000000..5431afdd87013 --- /dev/null +++ b/usr.sbin/sysinstall/devices.c @@ -0,0 +1,597 @@ +/* + * 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 <sys/fcntl.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <libdisk.h> + +/* how much to bias minor number for a given /dev/<ct#><un#>s<s#> slice */ +#define SLICE_DELTA (0x10000) + +static Device *Devices[DEV_MAX]; +static int numDevs; + +static struct _devname { + DeviceType type; + char *name; + char *description; + int major, minor, delta, max; +} device_names[] = { + { DEVICE_TYPE_CDROM, "cd%d", "SCSI CDROM drive", 15, 2, 8, 4 }, + { DEVICE_TYPE_CDROM, "mcd%d", "Mitsumi (old model) CDROM drive", 29, 0, 8, 4 }, + { DEVICE_TYPE_CDROM, "scd%d", "Sony CDROM drive - CDU31/33A type", 45, 0, 8, 4 }, +#ifdef notdef + { DEVICE_TYPE_CDROM, "matcd%d", "Matsushita CDROM ('sound blaster' type)", 46, 0, 8, 4 }, +#endif + { DEVICE_TYPE_CDROM, "acd%d", "ATAPI/IDE CDROM", 117, 0, 8, 4 }, + { DEVICE_TYPE_TAPE, "sa%d", "SCSI tape drive", 14, 0, 16, 4 }, + { DEVICE_TYPE_TAPE, "rwt%d", "Wangtek tape drive", 10, 0, 1, 4 }, + { DEVICE_TYPE_DISK, "da%d", "SCSI disk device", 13, 65538, 8, 16 }, + { DEVICE_TYPE_DISK, "ad%d", "ATA/IDE disk device", 116, 65538, 8, 16 }, + { DEVICE_TYPE_DISK, "ar%d", "ATA/IDE RAID device", 157, 65538, 8, 16 }, + { DEVICE_TYPE_DISK, "afd%d", "ATAPI/IDE floppy device", 118, 65538, 8, 4 }, + { DEVICE_TYPE_DISK, "mlxd%d", "Mylex RAID disk", 131, 65538, 8, 4 }, + { DEVICE_TYPE_DISK, "amrd%d", "AMI MegaRAID drive", 133, 65538, 8, 4 }, + { DEVICE_TYPE_DISK, "idad%d", "Compaq RAID array", 109, 65538, 8, 4 }, + { DEVICE_TYPE_DISK, "twed%d", "3ware ATA RAID array", 147, 65538, 8, 4 }, + { DEVICE_TYPE_DISK, "aacd%d", "Adaptec FSA RAID array", 151, 65538, 8, 4 }, + { DEVICE_TYPE_DISK, "ipsd%d", "IBM ServeRAID RAID array", 176, 65538, 8, 4 }, + { DEVICE_TYPE_FLOPPY, "fd%d", "floppy drive unit A", 9, 0, 64, 4 }, + { DEVICE_TYPE_NETWORK, "an", "Aironet 4500/4800 802.11 wireless adapter" }, + { DEVICE_TYPE_NETWORK, "aue", "ADMtek USB ethernet adapter" }, + { DEVICE_TYPE_NETWORK, "axe", "ASIX Electronics USB ethernet adapter" }, + { DEVICE_TYPE_NETWORK, "bfe", "Broadcom BCM440x PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "bge", "Broadcom BCM570x PCI gigabit ethernet card" }, + { DEVICE_TYPE_NETWORK, "cue", "CATC USB ethernet adapter" }, + { DEVICE_TYPE_NETWORK, "fpa", "DEC DEFPA PCI FDDI card" }, + { DEVICE_TYPE_NETWORK, "sr", "SDL T1/E1 sync serial PCI card" }, + { DEVICE_TYPE_NETWORK, "cc3i", "SDL HSSI sync serial PCI card" }, + { DEVICE_TYPE_NETWORK, "en", "Efficient Networks ATM PCI card" }, + { DEVICE_TYPE_NETWORK, "dc", "DEC/Intel 21143 (and clones) PCI fast ethernet card" }, + { DEVICE_TYPE_NETWORK, "de", "DEC DE435 PCI NIC or other DC21040-AA based card" }, + { DEVICE_TYPE_NETWORK, "fxp", "Intel EtherExpress Pro/100B PCI Fast Ethernet card" }, + { DEVICE_TYPE_NETWORK, "ed", "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA" }, + { DEVICE_TYPE_NETWORK, "ep", "3Com 3C509 ethernet card/3C589 PCMCIA" }, + { DEVICE_TYPE_NETWORK, "el", "3Com 3C501 ethernet card" }, + { DEVICE_TYPE_NETWORK, "em", "Intel(R) PRO/1000 ethernet card" }, + { DEVICE_TYPE_NETWORK, "ex", "Intel EtherExpress Pro/10 ethernet card" }, + { DEVICE_TYPE_NETWORK, "fe", "Fujitsu MB86960A/MB86965A ethernet card" }, + { DEVICE_TYPE_NETWORK, "ie", "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210" }, + { DEVICE_TYPE_NETWORK, "ix", "Intel Etherexpress ethernet card" }, + { DEVICE_TYPE_NETWORK, "kue", "Kawasaki LSI USB ethernet adapter" }, + { DEVICE_TYPE_NETWORK, "le", "DEC EtherWorks 2 or 3 ethernet card" }, + { DEVICE_TYPE_NETWORK, "lnc", "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) ethernet" }, + { DEVICE_TYPE_NETWORK, "lge", "Level 1 LXT1001 gigabit ethernet card" }, + { DEVICE_TYPE_NETWORK, "nge", "NatSemi PCI gigabit ethernet card" }, + { DEVICE_TYPE_NETWORK, "pcn", "AMD Am79c79x PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "ray", "Raytheon Raylink 802.11 wireless adaptor" }, + { DEVICE_TYPE_NETWORK, "re", "RealTek 8139C+/8169/8169S/8110S PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "rl", "RealTek 8129/8139 PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "rue", "RealTek USB ethernet card" }, + { DEVICE_TYPE_NETWORK, "sf", "Adaptec AIC-6915 PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "sis", "SiS 900/SiS 7016 PCI ethernet card" }, +#ifdef PC98 + { DEVICE_TYPE_NETWORK, "snc", "SONIC ethernet card" }, +#endif + { DEVICE_TYPE_NETWORK, "sn", "SMC/Megahertz ethernet card" }, + { DEVICE_TYPE_NETWORK, "ste", "Sundance ST201 PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "sk", "SysKonnect PCI gigabit ethernet card" }, + { DEVICE_TYPE_NETWORK, "tx", "SMC 9432TX ethernet card" }, + { DEVICE_TYPE_NETWORK, "txp", "3Com 3cR990 ethernet card" }, + { DEVICE_TYPE_NETWORK, "ti", "Alteon Networks PCI gigabit ethernet card" }, + { DEVICE_TYPE_NETWORK, "tl", "Texas Instruments ThunderLAN PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "vge", "VIA VT612x PCI gigabit ethernet card" }, + { DEVICE_TYPE_NETWORK, "vr", "VIA VT3043/VT86C100A Rhine PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "vlan", "IEEE 802.1Q VLAN network interface" }, + { DEVICE_TYPE_NETWORK, "vx", "3COM 3c590 / 3c595 ethernet card" }, + { DEVICE_TYPE_NETWORK, "wb", "Winbond W89C840F PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "wi", "Lucent WaveLAN/IEEE 802.11 wireless adapter" }, + { DEVICE_TYPE_NETWORK, "wx", "Intel Gigabit Ethernet (82452) card" }, + { DEVICE_TYPE_NETWORK, "xe", "Xircom/Intel EtherExpress Pro100/16 ethernet card" }, + { DEVICE_TYPE_NETWORK, "xl", "3COM 3c90x / 3c90xB PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "cuaa%d", "%s on device %s (COM%d)", 28, 128, 1, 16 }, + { DEVICE_TYPE_NETWORK, "fwe", "FireWire Ethernet emulation" }, + { DEVICE_TYPE_NETWORK, "lp", "Parallel Port IP (PLIP) peer connection" }, + { DEVICE_TYPE_NETWORK, "lo", "Loop-back (local) network interface" }, + { DEVICE_TYPE_NETWORK, "disc", "Software discard network interface" }, +#ifdef PC98 + { DEVICE_TYPE_DISK, "wd%d", "IDE disk device", 3, 65538, 8, 16 }, + { DEVICE_TYPE_CDROM, "wcd%dc", "ATAPI IDE CDROM", 69, 2, 8, 4 }, + { DEVICE_TYPE_FLOPPY, "wfd%d", "ATAPI floppy drive unit A", 87, 0, 8, 4 }, + { DEVICE_TYPE_DISK, "wfd%d", "ATAPI floppy device", 87, 65538, 8, 4 }, +#endif + { 0 }, +}; + +Device * +new_device(char *name) +{ + Device *dev; + + dev = safe_malloc(sizeof(Device)); + bzero(dev, sizeof(Device)); + if (name) + SAFE_STRCPY(dev->name, name); + return dev; +} + +/* Stubs for unimplemented strategy routines */ +Boolean +dummyInit(Device *dev) +{ + return TRUE; +} + +FILE * +dummyGet(Device *dev, char *dist, Boolean probe) +{ + return NULL; +} + +void +dummyShutdown(Device *dev) +{ + return; +} + +static int +deviceTry(struct _devname dev, char *try, int i) +{ + int fd; + char unit[80]; + mode_t m; + dev_t d; + int fail; + + snprintf(unit, sizeof unit, dev.name, i); + snprintf(try, FILENAME_MAX, "/dev/%s", unit); + if (isDebug()) + msgDebug("deviceTry: attempting to open %s\n", try); + fd = open(try, O_RDONLY); + if (fd >= 0) { + if (isDebug()) + msgDebug("deviceTry: open of %s succeeded on first try.\n", try); + return fd; + } + m = 0640 | S_IFCHR; + d = makedev(dev.major, dev.minor + (i * dev.delta)); + if (isDebug()) + msgDebug("deviceTry: Making %s device for %s [%d, %d]\n", m & S_IFCHR ? "raw" : "block", try, dev.major, dev.minor + (i * dev.delta)); + fail = mknod(try, m, d); + fd = open(try, O_RDONLY); + if (fd >= 0) { + if (isDebug()) + msgDebug("deviceTry: open of %s succeeded on second try.\n", try); + return fd; + } + else if (!fail) + (void)unlink(try); + /* Don't try a "make-under" here since we're using a fixit floppy in this case */ + snprintf(try, FILENAME_MAX, "/mnt/dev/%s", unit); + fd = open(try, O_RDONLY); + if (isDebug()) + msgDebug("deviceTry: final attempt for %s returns %d\n", try, fd); + return fd; +} + +/* Register a new device in the devices array */ +Device * +deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled, + Boolean (*init)(Device *), FILE * (*get)(Device *, char *, Boolean), + void (*shutdown)(Device *), void *private) +{ + Device *newdev = NULL; + + if (numDevs == DEV_MAX) + msgFatal("Too many devices found!"); + else { + newdev = new_device(name); + newdev->description = desc; + newdev->devname = devname; + newdev->type = type; + newdev->enabled = enabled; + newdev->init = init ? init : dummyInit; + newdev->get = get ? get : dummyGet; + newdev->shutdown = shutdown ? shutdown : dummyShutdown; + newdev->private = private; + Devices[numDevs] = newdev; + Devices[++numDevs] = NULL; + } + return newdev; +} + +/* Reset the registered device chain */ +void +deviceReset(void) +{ + int i; + + for (i = 0; i < numDevs; i++) { + DEVICE_SHUTDOWN(Devices[i]); + + /* XXX this potentially leaks Devices[i]->private if it's being + * used to point to something dynamic, but you're not supposed + * to call this routine at such times that some open instance + * has its private ptr pointing somewhere anyway. XXX + */ + free(Devices[i]); + } + Devices[numDevs = 0] = NULL; +} + +/* Get all device information for devices we have attached */ +void +deviceGetAll(void) +{ + int i, j, fd, s; + struct ifconf ifc; + struct ifreq *ifptr, *end; + int ifflags; + char buffer[INTERFACE_MAX * sizeof(struct ifreq)]; + char **names; + + msgNotify("Probing devices, please wait (this can take a while)..."); + /* First go for the network interfaces. Stolen shamelessly from ifconfig! */ + ifc.ifc_len = sizeof(buffer); + ifc.ifc_buf = buffer; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + goto skipif; /* Jump over network iface probing */ + + if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) + goto skipif; /* Jump over network iface probing */ + + close(s); + ifflags = ifc.ifc_req->ifr_flags; + end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + for (ifptr = ifc.ifc_req; ifptr < end; ifptr++) { + char *descr; + + /* If it's not a link entry, forget it */ + if (ifptr->ifr_ifru.ifru_addr.sa_family != AF_LINK) + goto loopend; + + /* Eliminate network devices that don't make sense */ + if (!strncmp(ifptr->ifr_name, "lo", 2)) + goto loopend; + + /* If we have a slip device, don't register it */ + if (!strncmp(ifptr->ifr_name, "sl", 2)) { + goto loopend; + } + /* And the same for ppp */ + if (!strncmp(ifptr->ifr_name, "tun", 3) || !strncmp(ifptr->ifr_name, "ppp", 3)) { + goto loopend; + } + /* Try and find its description */ + for (i = 0, descr = NULL; device_names[i].name; i++) { + int len = strlen(device_names[i].name); + + if (!ifptr->ifr_name || !ifptr->ifr_name[0]) + continue; + else if (!strncmp(ifptr->ifr_name, device_names[i].name, len)) { + descr = device_names[i].description; + break; + } + } + if (!descr) + descr = "<unknown network interface type>"; + + deviceRegister(ifptr->ifr_name, descr, strdup(ifptr->ifr_name), DEVICE_TYPE_NETWORK, TRUE, + mediaInitNetwork, NULL, mediaShutdownNetwork, NULL); + if (isDebug()) + msgDebug("Found a network device named %s\n", ifptr->ifr_name); + close(s); + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + continue; + +loopend: + if (ifptr->ifr_addr.sa_len) /* I'm not sure why this is here - it's inherited */ + ifptr = (struct ifreq *)((caddr_t)ifptr + ifptr->ifr_addr.sa_len - sizeof(struct sockaddr)); + close(s); + } + +skipif: + /* Next, try to find all the types of devices one might need + * during the second stage of the installation. + */ + for (i = 0; device_names[i].name; i++) { + for (j = 0; j < device_names[i].max; j++) { + char try[FILENAME_MAX]; + + switch(device_names[i].type) { + case DEVICE_TYPE_CDROM: + fd = deviceTry(device_names[i], try, j); + if (fd >= 0 || errno == EBUSY) { /* EBUSY if already mounted */ + char n[BUFSIZ]; + + if (fd >= 0) close(fd); + snprintf(n, sizeof n, device_names[i].name, j); + deviceRegister(strdup(n), device_names[i].description, strdup(try), + DEVICE_TYPE_CDROM, TRUE, mediaInitCDROM, mediaGetCDROM, + mediaShutdownCDROM, NULL); + if (isDebug()) + msgDebug("Found a CDROM device for %s\n", try); + } + break; + + case DEVICE_TYPE_TAPE: + fd = deviceTry(device_names[i], try, j); + if (fd >= 0) { + char n[BUFSIZ]; + + close(fd); + snprintf(n, sizeof n, device_names[i].name, j); + deviceRegister(strdup(n), device_names[i].description, strdup(try), + DEVICE_TYPE_TAPE, TRUE, mediaInitTape, mediaGetTape, mediaShutdownTape, NULL); + if (isDebug()) + msgDebug("Found a TAPE device for %s\n", try); + } + break; + + case DEVICE_TYPE_DISK: + fd = deviceTry(device_names[i], try, j); + if (fd >= 0 && RunningAsInit) { + dev_t d; + mode_t m; + int s, fail; + char unit[80], slice[80]; + + close(fd); + /* Make associated slice entries */ + for (s = 1; s < 8; s++) { + snprintf(unit, sizeof unit, device_names[i].name, j); + snprintf(slice, sizeof slice, "/dev/%ss%d", unit, s); + d = makedev(device_names[i].major, device_names[i].minor + + (j * device_names[i].delta) + (s * SLICE_DELTA)); + m = 0640 | S_IFCHR; + fail = mknod(slice, m, d); + fd = open(slice, O_RDONLY); + if (fd >= 0) + close(fd); + else if (!fail) + (void)unlink(slice); + } + } + break; + + case DEVICE_TYPE_FLOPPY: + fd = deviceTry(device_names[i], try, j); + if (fd >= 0) { + char n[BUFSIZ]; + + close(fd); + snprintf(n, sizeof n, device_names[i].name, j); + deviceRegister(strdup(n), device_names[i].description, strdup(try), + DEVICE_TYPE_FLOPPY, TRUE, mediaInitFloppy, mediaGetFloppy, + mediaShutdownFloppy, NULL); + if (isDebug()) + msgDebug("Found a floppy device for %s\n", try); + } + break; + + case DEVICE_TYPE_NETWORK: + fd = deviceTry(device_names[i], try, j); + /* The only network devices that you can open this way are serial ones */ + if (fd >= 0) { + char *newdesc, *cp; + + close(fd); + cp = device_names[i].description; + /* Serial devices get a slip and ppp device each, if supported */ + newdesc = safe_malloc(strlen(cp) + 40); + sprintf(newdesc, cp, "SLIP interface", try, j + 1); + deviceRegister("sl0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork, + NULL, mediaShutdownNetwork, NULL); + msgDebug("Add mapping for %s to sl0\n", try); + newdesc = safe_malloc(strlen(cp) + 50); + sprintf(newdesc, cp, "PPP interface", try, j + 1); + deviceRegister("ppp0", newdesc, strdup(try), DEVICE_TYPE_NETWORK, TRUE, mediaInitNetwork, + NULL, mediaShutdownNetwork, NULL); + if (isDebug()) + msgDebug("Add mapping for %s to ppp0\n", try); + } + break; + + default: + break; + } + } + } + + /* Finally, go get the disks and look for DOS partitions to register */ + if ((names = Disk_Names()) != NULL) { + int i; + + for (i = 0; names[i]; i++) { + Chunk *c1; + Disk *d; + + /* Ignore memory disks */ + if (!strncmp(names[i], "md", 2)) + continue; + + /* + * XXX + * Due to unknown reasons, Disk_Names() returns SCSI CDROM as a + * valid disk. This is main reason why sysinstall presents SCSI + * CDROM to available disks in Fdisk/Label menu. In addition, + * adding a blank SCSI CDROM to the menu generates floating point + * exception in sparc64. Disk_Names() just extracts sysctl + * "kern.disks". Why GEOM treats SCSI CDROM as a disk is beyond + * me and that should be investigated. + * For temporary workaround, ignore SCSI CDROM device. + */ + if (!strncmp(names[i], "cd", 2)) + continue; + + d = Open_Disk(names[i]); + if (!d) { + msgDebug("Unable to open disk %s\n", names[i]); + continue; + } + + deviceRegister(names[i], names[i], d->name, DEVICE_TYPE_DISK, FALSE, + dummyInit, dummyGet, dummyShutdown, d); + if (isDebug()) + msgDebug("Found a disk device named %s\n", names[i]); + + /* Look for existing DOS partitions to register as "DOS media devices" */ + for (c1 = d->chunks->part; c1; c1 = c1->next) { + if (c1->type == fat || c1->type == efi || c1->type == extended) { + Device *dev; + char devname[80]; + + /* Got one! */ + snprintf(devname, sizeof devname, "/dev/%s", c1->name); + dev = deviceRegister(c1->name, c1->name, strdup(devname), DEVICE_TYPE_DOS, TRUE, + mediaInitDOS, mediaGetDOS, mediaShutdownDOS, NULL); + dev->private = c1; + if (isDebug()) + msgDebug("Found a DOS partition %s on drive %s\n", c1->name, d->name); + } + } + } + free(names); + } + dialog_clear_norefresh(); +} + +/* Rescan all devices, after closing previous set - convenience function */ +void +deviceRescan(void) +{ + deviceReset(); + deviceGetAll(); +} + +/* + * Find all devices that match the criteria, allowing "wildcarding" as well + * by allowing NULL or ANY values to match all. The array returned is static + * and may be used until the next invocation of deviceFind(). + */ +Device ** +deviceFind(char *name, DeviceType class) +{ + static Device *found[DEV_MAX]; + int i, j; + + j = 0; + for (i = 0; i < numDevs; i++) { + if ((!name || !strcmp(Devices[i]->name, name)) + && (class == DEVICE_TYPE_ANY || class == Devices[i]->type)) + found[j++] = Devices[i]; + } + found[j] = NULL; + return j ? found : NULL; +} + +Device ** +deviceFindDescr(char *name, char *desc, DeviceType class) +{ + static Device *found[DEV_MAX]; + int i, j; + + j = 0; + for (i = 0; i < numDevs; i++) { + if ((!name || !strcmp(Devices[i]->name, name)) && + (!desc || !strcmp(Devices[i]->description, desc)) && + (class == DEVICE_TYPE_ANY || class == Devices[i]->type)) + found[j++] = Devices[i]; + } + found[j] = NULL; + return j ? found : NULL; +} + +int +deviceCount(Device **devs) +{ + int i; + + if (!devs) + return 0; + for (i = 0; devs[i]; i++); + return i; +} + +/* + * Create a menu listing all the devices of a certain type in the system. + * The passed-in menu is expected to be a "prototype" from which the new + * menu is cloned. + */ +DMenu * +deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d)) +{ + Device **devs; + int numdevs; + DMenu *tmp = NULL; + int i, j; + + devs = deviceFind(NULL, type); + numdevs = deviceCount(devs); + if (!numdevs) + return NULL; + tmp = (DMenu *)safe_malloc(sizeof(DMenu) + (sizeof(dialogMenuItem) * (numdevs + 1))); + bcopy(menu, tmp, sizeof(DMenu)); + for (i = 0; devs[i]; i++) { + tmp->items[i].prompt = devs[i]->name; + for (j = 0; j < numDevs; j++) { + if (devs[i] == Devices[j]) { + tmp->items[i].title = Devices[j]->description; + break; + } + } + if (j == numDevs) + tmp->items[i].title = "<unknown device type>"; + tmp->items[i].fire = hook; + tmp->items[i].checked = check; + } + tmp->items[i].title = NULL; + return tmp; +} diff --git a/usr.sbin/sysinstall/dhcp.c b/usr.sbin/sysinstall/dhcp.c new file mode 100644 index 0000000000000..fa35580e12359 --- /dev/null +++ b/usr.sbin/sysinstall/dhcp.c @@ -0,0 +1,158 @@ +/* + * $FreeBSD$ + * + * Copyright (c) 1999 + * C. Stone. 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 C. STONE ``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 C STONE OR HIS BODILY PARASITES 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 BY THE VOICES IN YOUR HEAD BEFOREHAND. + * + */ + +#include "sysinstall.h" + +#include <ctype.h> + +int +dhcpParseLeases(char *file, char *hostname, char *domain, char *nameserver, + char *ipaddr, char *gateway, char *netmask) +{ + char tempbuf[1024]; + char optbuf[1024], *optname = NULL; + char *tptr; + int endedflag = 0; + int leaseflag = 0; + FILE *fp; + enum { P_NOSTMT, P_NOSTMT1, P_STMT, P_STMTLINE } state; + + if ((fp = fopen(file, "r")) == NULL) { + msgDebug("error opening file %s: %s\n", file, strerror(errno)); + return -1; + } + + state = P_NOSTMT; + while (fscanf(fp, "%1023s", tempbuf) > 0) { + switch (state) { + case P_NOSTMT: + state = P_NOSTMT1; + if (!strncasecmp(tempbuf, "lease", 5)) { + if (!leaseflag) + leaseflag = 1; + else { + fclose(fp); + return 0; + } + } + break; + + case P_NOSTMT1: + if (tempbuf[0] != '{') { + msgWarn("dhcpParseLeases: '{' expected"); + fclose(fp); + return -1; + } + state = P_STMT; + break; + + case P_STMT: + if (!strncasecmp("option", tempbuf, 6)) + continue; + if (tempbuf[0] == '}') { + state = P_NOSTMT; + leaseflag = 0; + continue; + } + if (!leaseflag) + break; + if (tempbuf[0] == ';') { /* play it safe */ + state = P_STMT; + continue; + } + if ((tptr = (char *)strchr(tempbuf, ';')) && (*(tptr + 1) == 0)) { + *tptr = '\0'; + endedflag = 1; + } + if (!isalnum(tempbuf[0])) { + msgWarn("dhcpParseLeases: bad option"); + fclose(fp); + return -1; + } + if (optname) + free(optname); + optname = strdup(tempbuf); + if (endedflag) { + state = P_STMT; + endedflag = 0; + continue; + } + state = P_STMTLINE; + break; + + case P_STMTLINE: + if (tempbuf[0] == ';') { + state = P_STMT; + continue; + } + if ((tptr = (char *)strchr(tempbuf, ';')) && (*(tptr + 1) == 0)) { + *tptr = '\0'; + endedflag = 1; + } + if (tempbuf[0] == '"') { + if (sscanf(tempbuf, "\"%[^\" ]\"", optbuf) < 1) { + msgWarn("dhcpParseLeases: bad option value"); + fclose(fp); + return -1; + } + } + else + strcpy(optbuf, tempbuf); + + if (!strcasecmp("host-name", optname)) { + strcpy(hostname, optbuf); + } else if (!strcasecmp("domain-name", optname)) { + strcpy(domain, optbuf); + } else if (!strcasecmp("fixed-address", optname)) { + strcpy(ipaddr, optbuf); + } else if (!strcasecmp("routers", optname)) { + if((tptr = (char *)strchr(optbuf, ','))) + *tptr = '\0'; + strcpy(gateway, optbuf); + } else if (!strcasecmp("subnet-mask", optname)) { + strcpy(netmask, optbuf); + } else if (!strcasecmp("domain-name-servers", optname)) { + /* <jkh> ...one value per property */ + if((tptr = (char *)strchr(optbuf, ','))) + *tptr = '\0'; + strcpy(nameserver, optbuf); + } + if (endedflag) { + state = P_STMT; + endedflag = 0; + continue; + } + break; + } + } + fclose(fp); + return 0; +} diff --git a/usr.sbin/sysinstall/disks.c b/usr.sbin/sysinstall/disks.c new file mode 100644 index 0000000000000..1e35c7b3a11c3 --- /dev/null +++ b/usr.sbin/sysinstall/disks.c @@ -0,0 +1,1001 @@ +/* + * 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 <ctype.h> +#include <fcntl.h> +#include <inttypes.h> +#include <libdisk.h> +#include <sys/stat.h> +#include <sys/disklabel.h> + +#ifdef WITH_SLICES +enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE }; + +#ifdef PC98 +#define SUBTYPE_FREEBSD 50324 +#define SUBTYPE_FAT 37218 +#else +#define SUBTYPE_FREEBSD 165 +#define SUBTYPE_FAT 6 +#endif +#define SUBTYPE_EFI 239 + +#ifdef PC98 +#define OTHER_SLICE_VALUES \ + "Other popular values are 37218 for a\n" \ + "DOS FAT partition.\n\n" +#else +#define OTHER_SLICE_VALUES \ + "Other popular values are 6 for a\n" \ + "DOS FAT partition, 131 for a Linux ext2fs partition, or\n" \ + "130 for a Linux swap partition.\n\n" +#endif +#define NON_FREEBSD_NOTE \ + "Note: If you choose a non-FreeBSD partition type, it will not\n" \ + "be formatted or otherwise prepared, it will simply reserve space\n" \ + "for you to use another tool, such as DOS format, to later format\n" \ + "and actually use the partition." + +/* Where we start displaying chunk information on the screen */ +#define CHUNK_START_ROW 5 + +/* Where we keep track of MBR chunks */ +#define CHUNK_INFO_ENTRIES 16 +static struct chunk *chunk_info[CHUNK_INFO_ENTRIES]; +static int current_chunk; + +static void diskPartitionNonInteractive(Device *dev); +static u_char * bootalloc(char *name, size_t *size); + +static void +record_chunks(Disk *d) +{ + struct chunk *c1 = NULL; + int i = 0; + daddr_t last_free = 0; + + if (!d->chunks) + msgFatal("No chunk list found for %s!", d->name); + + for (c1 = d->chunks->part; c1; c1 = c1->next) { + if (c1->type == unused && c1->size > last_free) { + last_free = c1->size; + current_chunk = i; + } + chunk_info[i++] = c1; + } + chunk_info[i] = NULL; + if (current_chunk >= i) + current_chunk = i - 1; +} + +static daddr_t Total; + +static void +print_chunks(Disk *d, int u) +{ + int row; + int i; + daddr_t sz; + char *szstr; + + szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" : + (u == UNIT_KILO ? "KB" : "ST"))); + + Total = 0; + for (i = 0; chunk_info[i]; i++) + Total += chunk_info[i]->size; +#ifdef PC98 + if (d->bios_cyl >= 65536 || d->bios_hd > 16 || d->bios_sect >= 256) { +#else + if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { +#endif + dialog_clear_norefresh(); + msgConfirm("WARNING: A geometry of %lu/%lu/%lu for %s is incorrect. Using\n" + "a more likely geometry. If this geometry is incorrect or you\n" + "are unsure as to whether or not it's correct, please consult\n" + "the Hardware Guide in the Documentation submenu or use the\n" + "(G)eometry command to change it now.\n\n" + "Remember: you need to enter whatever your BIOS thinks the\n" + "geometry is! For IDE, it's what you were told in the BIOS\n" + "setup. For SCSI, it's the translation mode your controller is\n" + "using. Do NOT use a ``physical geometry''.", + d->bios_cyl, d->bios_hd, d->bios_sect, d->name); + Sanitize_Bios_Geom(d); + } + attrset(A_NORMAL); + mvaddstr(0, 0, "Disk name:\t"); + clrtobot(); + attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); + attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); + mvprintw(1, 0, + "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %jd sectors (%jdMB)", + d->bios_cyl, d->bios_hd, d->bios_sect, + (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect, + (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); + mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", + "Offset", "Size", szstr, "End", "Name", "PType", "Desc", + "Subtype", "Flags"); + for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { + switch(u) { + default: /* fall thru */ + case UNIT_BLOCKS: + sz = chunk_info[i]->size; + break; + case UNIT_KILO: + sz = chunk_info[i]->size / (1024/512); + break; + case UNIT_MEG: + sz = chunk_info[i]->size / (1024/512) / 1024; + break; + case UNIT_GIG: + sz = chunk_info[i]->size / (1024/512) / 1024 / 1024; + break; + } + if (i == current_chunk) + attrset(ATTR_SELECTED); + mvprintw(row, 0, "%10jd %10jd %10jd %8s %6d %10s %8d\t%-6s", + (intmax_t)chunk_info[i]->offset, (intmax_t)sz, + (intmax_t)chunk_info[i]->end, chunk_info[i]->name, + chunk_info[i]->type, + slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), + chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); + if (i == current_chunk) + attrset(A_NORMAL); + } +} + +static void +print_command_summary() +{ + mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); + mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice F = `DD' mode"); + mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable | = Wizard m."); + mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); + if (!RunningAsInit) + mvprintw(18, 47, "W = Write Changes"); + mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); + move(0, 0); +} + +#ifdef PC98 +static void +getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, + u_char **bootmenu, size_t *bootmenu_size) +{ + static u_char *boot0; + static size_t boot0_size; + static u_char *boot05; + static size_t boot05_size; + + char str[80]; + char *cp; + int i = 0; + + cp = variable_get(VAR_BOOTMGR); + if (!cp) { + /* Figure out what kind of IPL the user wants */ + sprintf(str, "Install Boot Manager for drive %s?", dname); + MenuIPLType.title = str; + i = dmenuOpenSimple(&MenuIPLType, FALSE); + } else { + if (!strncmp(cp, "boot", 4)) + BootMgr = 0; + else + BootMgr = 1; + } + if (cp || i) { + switch (BootMgr) { + case 0: + if (!boot0) boot0 = bootalloc("boot0", &boot0_size); + *bootipl = boot0; + *bootipl_size = boot0_size; + if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size); + *bootmenu = boot05; + *bootmenu_size = boot05_size; + return; + case 1: + default: + break; + } + } + *bootipl = NULL; + *bootipl_size = 0; + *bootmenu = NULL; + *bootmenu_size = 0; +} +#else +static void +getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) +{ +#if defined(__i386__) || defined(__amd64__) /* only meaningful on x86 */ + static u_char *mbr, *boot0; + static size_t mbr_size, boot0_size; + char str[80]; + char *cp; + int i = 0; + + cp = variable_get(VAR_BOOTMGR); + if (!cp) { + /* Figure out what kind of MBR the user wants */ + sprintf(str, "Install Boot Manager for drive %s?", dname); + MenuMBRType.title = str; + i = dmenuOpenSimple(&MenuMBRType, FALSE); + } + else { + if (!strncmp(cp, "boot", 4)) + BootMgr = 0; + else if (!strcmp(cp, "standard")) + BootMgr = 1; + else + BootMgr = 2; + } + if (cp || i) { + switch (BootMgr) { + case 0: + if (!boot0) boot0 = bootalloc("boot0", &boot0_size); + *bootCode = boot0; + *bootCodeSize = boot0_size; + return; + case 1: + if (!mbr) mbr = bootalloc("mbr", &mbr_size); + *bootCode = mbr; + *bootCodeSize = mbr_size; + return; + case 2: + default: + break; + } + } +#endif + *bootCode = NULL; + *bootCodeSize = 0; +} +#endif +#endif /* WITH_SLICES */ + +int +diskGetSelectCount(Device ***devs) +{ + int i, cnt, enabled; + char *cp; + Device **dp; + + cp = variable_get(VAR_DISK); + dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); + cnt = deviceCount(dp); + if (!cnt) + return -1; + for (i = 0, enabled = 0; i < cnt; i++) { + if (dp[i]->enabled) + ++enabled; + } + return enabled; +} + +#ifdef WITH_SLICES +void +diskPartition(Device *dev) +{ + char *cp, *p; + int rv, key = 0; + int i; + Boolean chunking; + char *msg = NULL; +#ifdef PC98 + u_char *bootipl; + size_t bootipl_size; + u_char *bootmenu; + size_t bootmenu_size; +#else + u_char *mbrContents; + size_t mbrSize; +#endif + WINDOW *w = savescr(); + Disk *d = (Disk *)dev->private; + int size_unit; + + size_unit = UNIT_BLOCKS; + chunking = TRUE; + keypad(stdscr, TRUE); + + /* Flush both the dialog and curses library views of the screen + since we don't always know who called us */ + dialog_clear_norefresh(), clear(); + current_chunk = 0; + + /* Set up the chunk array */ + record_chunks(d); + + while (chunking) { + char *val, geometry[80]; + + /* Now print our overall state */ + if (d) + print_chunks(d, size_unit); + print_command_summary(); + if (msg) { + attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); + beep(); + msg = NULL; + } + else { + move(23, 0); + clrtoeol(); + } + + /* Get command character */ + key = getch(); + switch (toupper(key)) { + case '\014': /* ^L (redraw) */ + clear(); + msg = NULL; + break; + + case '\020': /* ^P */ + case KEY_UP: + case '-': + if (current_chunk != 0) + --current_chunk; + break; + + case '\016': /* ^N */ + case KEY_DOWN: + case '+': + case '\r': + case '\n': + if (chunk_info[current_chunk + 1]) + ++current_chunk; + break; + + case KEY_HOME: + current_chunk = 0; + break; + + case KEY_END: + while (chunk_info[current_chunk + 1]) + ++current_chunk; + break; + + case KEY_F(1): + case '?': + systemDisplayHelp("slice"); + clear(); + break; + + case 'A': + case 'F': /* Undocumented magic Dangerously Dedicated mode */ +#if !defined(__i386__) && !defined(__amd64__) + rv = 1; +#else /* The rest is only relevant on x86 */ + cp = variable_get(VAR_DEDICATE_DISK); + if (cp && !strcasecmp(cp, "always")) + rv = 1; + else if (toupper(key) == 'A') + rv = 0; + else { + rv = msgYesNo("Do you want to do this with a true partition entry\n" + "so as to remain cooperative with any future possible\n" + "operating systems on the drive(s)?\n" + "(See also the section about ``dangerously dedicated''\n" + "disks in the FreeBSD FAQ.)"); + if (rv == -1) + rv = 0; + } +#endif + All_FreeBSD(d, rv); + variable_set2(DISK_PARTITIONED, "yes", 0); + record_chunks(d); + clear(); + break; + + case 'C': + if (chunk_info[current_chunk]->type != unused) + msg = "Slice in use, delete it first or move to an unused one."; + else { + char *val, tmp[20], name[16], *cp; + daddr_t size; + int subtype; + chunk_e partitiontype; +#ifdef PC98 + snprintf(name, sizeof (name), "%s", "FreeBSD"); + val = msgGetInput(name, + "Please specify the name for new FreeBSD slice."); + if (val) + strncpy(name, val, sizeof (name)); +#else + name[0] = '\0'; +#endif + snprintf(tmp, 20, "%jd", (intmax_t)chunk_info[current_chunk]->size); + val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" + "or append a trailing `M' for megabytes (e.g. 20M)."); + if (val && (size = strtoimax(val, &cp, 0)) > 0) { + if (*cp && toupper(*cp) == 'M') + size *= ONE_MEG; + else if (*cp && toupper(*cp) == 'G') + size *= ONE_GIG; + sprintf(tmp, "%d", SUBTYPE_FREEBSD); + val = msgGetInput(tmp, "Enter type of partition to create:\n\n" + "Pressing Enter will choose the default, a native FreeBSD\n" + "slice (type %u). " + OTHER_SLICE_VALUES + NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); + if (val && (subtype = strtol(val, NULL, 0)) > 0) { + if (subtype == SUBTYPE_FREEBSD) + partitiontype = freebsd; + else if (subtype == SUBTYPE_FAT) + partitiontype = fat; + else if (subtype == SUBTYPE_EFI) + partitiontype = efi; + else +#ifdef PC98 + partitiontype = pc98; +#else + partitiontype = mbr; +#endif + Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, + (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); + variable_set2(DISK_PARTITIONED, "yes", 0); + record_chunks(d); + } + } + clear(); + } + break; + + case KEY_DC: + case 'D': + if (chunk_info[current_chunk]->type == unused) + msg = "Slice is already unused!"; + else { + Delete_Chunk(d, chunk_info[current_chunk]); + variable_set2(DISK_PARTITIONED, "yes", 0); + record_chunks(d); + } + break; + + case 'T': + if (chunk_info[current_chunk]->type == unused) + msg = "Slice is currently unused (use create instead)"; + else { + char *val, tmp[20]; + int subtype; + chunk_e partitiontype; + + sprintf(tmp, "%d", chunk_info[current_chunk]->subtype); + val = msgGetInput(tmp, "New partition type:\n\n" + "Pressing Enter will use the current type. To choose a native\n" + "FreeBSD slice enter %u. " + OTHER_SLICE_VALUES + NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); + if (val && (subtype = strtol(val, NULL, 0)) > 0) { + if (subtype == SUBTYPE_FREEBSD) + partitiontype = freebsd; + else if (subtype == SUBTYPE_FAT) + partitiontype = fat; + else if (subtype == SUBTYPE_EFI) + partitiontype = efi; + else +#ifdef PC98 + partitiontype = pc98; +#else + partitiontype = mbr; +#endif + chunk_info[current_chunk]->type = partitiontype; + chunk_info[current_chunk]->subtype = subtype; + } + } + break; + + case 'G': + snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); + val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" + "Don't forget to use the two slash (/) separator characters!\n" + "It's not possible to parse the field without them."); + if (val) { + long nc, nh, ns; + nc = strtol(val, &val, 0); + nh = strtol(val + 1, &val, 0); + ns = strtol(val + 1, 0, 0); + Set_Bios_Geom(d, nc, nh, ns); + } + clear(); + break; + + case 'S': + /* Clear active states so we won't have two */ + for (i = 0; (chunk_info[i] != NULL) && (i < CHUNK_INFO_ENTRIES); i++) + chunk_info[i]->flags &= !CHUNK_ACTIVE; + + /* Set Bootable */ + chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; + break; + + case 'U': + if (!variable_cmp(DISK_LABELLED, "written")) { + msgConfirm("You've already written this information out - you\n" + "can't undo it."); + } + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { + char cp[BUFSIZ]; + + sstrncpy(cp, d->name, sizeof cp); + Free_Disk(dev->private); + d = Open_Disk(cp); + if (!d) + msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); + dev->private = d; + variable_unset(DISK_PARTITIONED); + variable_unset(DISK_LABELLED); + if (d) + record_chunks(d); + } + clear(); + break; + + case 'W': + if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" + "installation. If you are installing FreeBSD for the first time\n" + "then you should simply type Q when you're finished here and your\n" + "changes will be committed in one batch automatically at the end of\n" + "these questions. If you're adding a disk, you should NOT write\n" + "from this screen, you should do it from the label editor.\n\n" + "Are you absolutely sure you want to do this now?")) { + variable_set2(DISK_PARTITIONED, "yes", 0); + +#ifdef PC98 + /* + * Don't trash the IPL if the first (and therefore only) chunk + * is marked for a truly dedicated disk (i.e., the disklabel + * starts at sector 0), even in cases where the user has + * requested a FreeBSD Boot Manager -- both would be fatal in + * this case. + */ + /* + * Don't offer to update the IPL on this disk if the first + * "real" chunk looks like a FreeBSD "all disk" partition, + * or the disk is entirely FreeBSD. + */ + if ((d->chunks->part->type != freebsd) || + (d->chunks->part->offset > 1)) + getBootMgr(d->name, &bootipl, &bootipl_size, + &bootmenu, &bootmenu_size); + else { + bootipl = NULL; + bootipl_size = 0; + bootmenu = NULL; + bootmenu_size = 0; + } + Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); +#else + /* + * Don't trash the MBR if the first (and therefore only) chunk + * is marked for a truly dedicated disk (i.e., the disklabel + * starts at sector 0), even in cases where the user has + * requested booteasy or a "standard" MBR -- both would be + * fatal in this case. + */ + /* + * Don't offer to update the MBR on this disk if the first + * "real" chunk looks like a FreeBSD "all disk" partition, + * or the disk is entirely FreeBSD. + */ + if ((d->chunks->part->type != freebsd) || + (d->chunks->part->offset > 1)) + getBootMgr(d->name, &mbrContents, &mbrSize); + else { + mbrContents = NULL; + mbrSize = 0; + } + Set_Boot_Mgr(d, mbrContents, mbrSize); +#endif + + if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) + msgConfirm("Disk partition write returned an error status!"); + else + msgConfirm("Wrote FDISK partition information out successfully."); + } + clear(); + break; + + case '|': + if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" + "No seat belts whatsoever are provided!")) { + clear(); + refresh(); + slice_wizard(d); + variable_set2(DISK_PARTITIONED, "yes", 0); + record_chunks(d); + } + else + msg = "Wise choice!"; + clear(); + break; + + case '\033': /* ESC */ + case 'Q': + chunking = FALSE; +#ifdef PC98 + /* + * Don't trash the IPL if the first (and therefore only) chunk + * is marked for a truly dedicated disk (i.e., the disklabel + * starts at sector 0), even in cases where the user has requested + * a FreeBSD Boot Manager -- both would be fatal in this case. + */ + /* + * Don't offer to update the IPL on this disk if the first "real" + * chunk looks like a FreeBSD "all disk" partition, or the disk is + * entirely FreeBSD. + */ + if ((d->chunks->part->type != freebsd) || + (d->chunks->part->offset > 1)) { + if (variable_cmp(DISK_PARTITIONED, "written")) { + getBootMgr(d->name, &bootipl, &bootipl_size, + &bootmenu, &bootmenu_size); + if (bootipl != NULL && bootmenu != NULL) + Set_Boot_Mgr(d, bootipl, bootipl_size, + bootmenu, bootmenu_size); + } + } +#else + /* + * Don't trash the MBR if the first (and therefore only) chunk + * is marked for a truly dedicated disk (i.e., the disklabel + * starts at sector 0), even in cases where the user has requested + * booteasy or a "standard" MBR -- both would be fatal in this case. + */ + /* + * Don't offer to update the MBR on this disk if the first "real" + * chunk looks like a FreeBSD "all disk" partition, or the disk is + * entirely FreeBSD. + */ + if ((d->chunks->part->type != freebsd) || + (d->chunks->part->offset > 1)) { + if (variable_cmp(DISK_PARTITIONED, "written")) { + getBootMgr(d->name, &mbrContents, &mbrSize); + if (mbrContents != NULL) + Set_Boot_Mgr(d, mbrContents, mbrSize); + } + } +#endif + break; + + case 'Z': + size_unit = (size_unit + 1) % UNIT_SIZE; + break; + + default: + beep(); + msg = "Type F1 or ? for help"; + break; + } + } + p = CheckRules(d); + if (p) { + char buf[FILENAME_MAX]; + + use_helpline("Press F1 to read more about disk slices."); + use_helpfile(systemHelpFile("partition", buf)); + if (!variable_get(VAR_NO_WARN)) + dialog_mesgbox("Disk slicing warning:", p, -1, -1); + free(p); + } + restorescr(w); +} +#endif /* WITH_SLICES */ + +static u_char * +bootalloc(char *name, size_t *size) +{ + char buf[FILENAME_MAX]; + struct stat sb; + + snprintf(buf, sizeof buf, "/boot/%s", name); + if (stat(buf, &sb) != -1) { + int fd; + + fd = open(buf, O_RDONLY); + if (fd != -1) { + u_char *cp; + + cp = malloc(sb.st_size); + if (read(fd, cp, sb.st_size) != sb.st_size) { + free(cp); + close(fd); + msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); + return NULL; + } + close(fd); + if (size != NULL) + *size = sb.st_size; + return cp; + } + msgDebug("bootalloc: couldn't open %s\n", buf); + } + else + msgDebug("bootalloc: can't stat %s\n", buf); + return NULL; +} + +#ifdef WITH_SLICES +static int +partitionHook(dialogMenuItem *selected) +{ + Device **devs = NULL; + + devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); + if (!devs) { + msgConfirm("Unable to find disk %s!", selected->prompt); + return DITEM_FAILURE; + } + /* Toggle enabled status? */ + if (!devs[0]->enabled) { + devs[0]->enabled = TRUE; + diskPartition(devs[0]); + } + else + devs[0]->enabled = FALSE; + return DITEM_SUCCESS; +} + +static int +partitionCheck(dialogMenuItem *selected) +{ + Device **devs = NULL; + + devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); + if (!devs || devs[0]->enabled == FALSE) + return FALSE; + return TRUE; +} + +int +diskPartitionEditor(dialogMenuItem *self) +{ + DMenu *menu; + Device **devs; + int i, cnt, devcnt; + + cnt = diskGetSelectCount(&devs); + devcnt = deviceCount(devs); + if (cnt == -1) { + 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 if (cnt) { + /* Some are already selected */ + for (i = 0; i < devcnt; i++) { + if (devs[i]->enabled) { + if (variable_get(VAR_NONINTERACTIVE) && + !variable_get(VAR_DISKINTERACTIVE)) + diskPartitionNonInteractive(devs[i]); + else + diskPartition(devs[i]); + } + } + } + else { + /* No disks are selected, fall-back case now */ + if (devcnt == 1) { + devs[0]->enabled = TRUE; + if (variable_get(VAR_NONINTERACTIVE) && + !variable_get(VAR_DISKINTERACTIVE)) + diskPartitionNonInteractive(devs[0]); + else + diskPartition(devs[0]); + return DITEM_SUCCESS; + } + else { + menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); + if (!menu) { + msgConfirm("No devices suitable for installation found!\n\n" + "Please verify that your disk controller (and attached drives)\n" + "were detected properly. This can be done by pressing the\n" + "[Scroll Lock] key and using the Arrow keys to move back to\n" + "the boot messages. Press [Scroll Lock] again to return."); + return DITEM_FAILURE; + } + else { + i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; + free(menu); + } + return i; + } + } + return DITEM_SUCCESS; +} +#endif /* WITH_SLICES */ + +int +diskPartitionWrite(dialogMenuItem *self) +{ + Device **devs; + int i; + + if (!variable_cmp(DISK_PARTITIONED, "written")) + return DITEM_SUCCESS; + + devs = deviceFind(NULL, DEVICE_TYPE_DISK); + if (!devs) { + msgConfirm("Unable to find any disks to write to??"); + return DITEM_FAILURE; + } + if (isDebug()) + msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); + for (i = 0; devs[i]; i++) { + Disk *d = (Disk *)devs[i]->private; + static u_char *boot1; +#if defined(__i386__) || defined(__amd64__) + static u_char *boot2; +#endif + + if (!devs[i]->enabled) + continue; + +#if defined(__i386__) || defined(__amd64__) + if (!boot1) boot1 = bootalloc("boot1", NULL); + if (!boot2) boot2 = bootalloc("boot2", NULL); + Set_Boot_Blocks(d, boot1, boot2); +#elif !defined(__ia64__) + if (!boot1) boot1 = bootalloc("boot1", NULL); + Set_Boot_Blocks(d, boot1, NULL); +#endif + + msgNotify("Writing partition information to drive %s", d->name); + if (!Fake && Write_Disk(d)) { + msgConfirm("ERROR: Unable to write data to disk %s!", d->name); + return DITEM_FAILURE; + } + } + /* Now it's not "yes", but "written" */ + variable_set2(DISK_PARTITIONED, "written", 0); + return DITEM_SUCCESS | DITEM_RESTORE; +} + +#ifdef WITH_SLICES +/* Partition a disk based wholly on which variables are set */ +static void +diskPartitionNonInteractive(Device *dev) +{ + char *cp; + int i, all_disk = 0; + daddr_t sz; +#ifdef PC98 + u_char *bootipl; + size_t bootipl_size; + u_char *bootmenu; + size_t bootmenu_size; +#else + u_char *mbrContents; + size_t mbrSize; +#endif + Disk *d = (Disk *)dev->private; + + record_chunks(d); + cp = variable_get(VAR_GEOMETRY); + if (cp) { + msgDebug("Setting geometry from script to: %s\n", cp); + d->bios_cyl = strtol(cp, &cp, 0); + d->bios_hd = strtol(cp + 1, &cp, 0); + d->bios_sect = strtol(cp + 1, 0, 0); + } + + cp = variable_get(VAR_PARTITION); + if (cp) { + if (!strcmp(cp, "free")) { + /* Do free disk space case */ + for (i = 0; chunk_info[i]; i++) { + /* If a chunk is at least 10MB in size, use it. */ + if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { + Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, + freebsd, 3, + (chunk_info[i]->flags & CHUNK_ALIGN), + "FreeBSD"); + variable_set2(DISK_PARTITIONED, "yes", 0); + break; + } + } + if (!chunk_info[i]) { + msgConfirm("Unable to find any free space on this disk!"); + return; + } + } + else if (!strcmp(cp, "all")) { + /* Do all disk space case */ + msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); + + All_FreeBSD(d, FALSE); + } + else if (!strcmp(cp, "exclusive")) { + /* Do really-all-the-disk-space case */ + msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); + + All_FreeBSD(d, all_disk = TRUE); + } + else if ((sz = strtoimax(cp, &cp, 0))) { + /* Look for sz bytes free */ + if (*cp && toupper(*cp) == 'M') + sz *= ONE_MEG; + else if (*cp && toupper(*cp) == 'G') + sz *= ONE_GIG; + for (i = 0; chunk_info[i]; i++) { + /* If a chunk is at least sz MB, use it. */ + if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { + Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, + (chunk_info[i]->flags & CHUNK_ALIGN), + "FreeBSD"); + variable_set2(DISK_PARTITIONED, "yes", 0); + break; + } + } + if (!chunk_info[i]) { + msgConfirm("Unable to find %jd free blocks on this disk!", + (intmax_t)sz); + return; + } + } + else if (!strcmp(cp, "existing")) { + /* Do existing FreeBSD case */ + for (i = 0; chunk_info[i]; i++) { + if (chunk_info[i]->type == freebsd) + break; + } + if (!chunk_info[i]) { + msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); + return; + } + } + else { + msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); + return; + } + if (!all_disk) { +#ifdef PC98 + getBootMgr(d->name, &bootipl, &bootipl_size, + &bootmenu, &bootmenu_size); + Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); +#else + getBootMgr(d->name, &mbrContents, &mbrSize); + Set_Boot_Mgr(d, mbrContents, mbrSize); +#endif + } + variable_set2(DISK_PARTITIONED, "yes", 0); + } +} +#endif /* WITH_SLICES */ diff --git a/usr.sbin/sysinstall/dispatch.c b/usr.sbin/sysinstall/dispatch.c new file mode 100644 index 0000000000000..4896b235c1460 --- /dev/null +++ b/usr.sbin/sysinstall/dispatch.c @@ -0,0 +1,440 @@ +/* + * 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 <ctype.h> +#include <errno.h> +#include <sys/signal.h> +#include <sys/fcntl.h> + +#include "list.h" + +static int dispatch_shutdown(dialogMenuItem *unused); +static int dispatch_systemExecute(dialogMenuItem *unused); +static int dispatch_msgConfirm(dialogMenuItem *unused); +static int dispatch_mediaClose(dialogMenuItem *unused); + +static struct _word { + char *name; + int (*handler)(dialogMenuItem *self); +} resWords[] = { + { "configAnonFTP", configAnonFTP }, + { "configRouter", configRouter }, + { "configInetd", configInetd }, + { "configNFSServer", configNFSServer }, + { "configNTP", configNTP }, + { "configPCNFSD", configPCNFSD }, + { "configPackages", configPackages }, + { "configUsers", configUsers }, +#ifdef WITH_SLICES + { "diskPartitionEditor", diskPartitionEditor }, +#endif + { "diskPartitionWrite", diskPartitionWrite }, + { "diskLabelEditor", diskLabelEditor }, + { "diskLabelCommit", diskLabelCommit }, + { "distReset", distReset }, + { "distSetCustom", distSetCustom }, + { "distUnsetCustom", distUnsetCustom }, + { "distSetDeveloper", distSetDeveloper }, + { "distSetXDeveloper", distSetXDeveloper }, + { "distSetKernDeveloper", distSetKernDeveloper }, + { "distSetUser", distSetUser }, + { "distSetXUser", distSetXUser }, + { "distSetMinimum", distSetMinimum }, + { "distSetEverything", distSetEverything }, + { "distSetSrc", distSetSrc }, + { "distExtractAll", distExtractAll }, + { "docBrowser", docBrowser }, + { "docShowDocument", docShowDocument }, + { "installCommit", installCommit }, + { "installExpress", installExpress }, + { "installStandard", installStandard }, + { "installUpgrade", installUpgrade }, + { "installFixupBase", installFixupBase }, + { "installFixitHoloShell", installFixitHoloShell }, + { "installFixitCDROM", installFixitCDROM }, + { "installFixitFloppy", installFixitFloppy }, + { "installFilesystems", installFilesystems }, + { "installVarDefaults", installVarDefaults }, + { "loadConfig", dispatch_load_file }, + { "loadFloppyConfig", dispatch_load_floppy }, + { "mediaClose", dispatch_mediaClose }, + { "mediaSetCDROM", mediaSetCDROM }, + { "mediaSetFloppy", mediaSetFloppy }, + { "mediaSetDOS", mediaSetDOS }, + { "mediaSetTape", mediaSetTape }, + { "mediaSetFTP", mediaSetFTP }, + { "mediaSetFTPActive", mediaSetFTPActive }, + { "mediaSetFTPPassive", mediaSetFTPPassive }, + { "mediaSetHTTP", mediaSetHTTP }, + { "mediaSetUFS", mediaSetUFS }, + { "mediaSetNFS", mediaSetNFS }, + { "mediaSetFTPUserPass", mediaSetFTPUserPass }, + { "mediaSetCPIOVerbosity", mediaSetCPIOVerbosity }, + { "mediaGetType", mediaGetType }, + { "msgConfirm", dispatch_msgConfirm }, + { "optionsEditor", optionsEditor }, + { "packageAdd", packageAdd }, + { "addGroup", userAddGroup }, + { "addUser", userAddUser }, + { "shutdown", dispatch_shutdown }, + { "system", dispatch_systemExecute }, + { "dumpVariables", dump_variables }, + { "tcpMenuSelect", tcpMenuSelect }, + { NULL, NULL }, +}; + +/* + * Helper routines for buffering data. + * + * We read an entire configuration into memory before executing it + * so that we are truely standalone and can do things like nuke the + * file or disk we're working on. + */ + +typedef struct command_buffer_ { + qelement queue; + char * string; +} command_buffer; + +static void +dispatch_free_command(command_buffer *item) +{ + REMQUE(item); + free(item->string); + free(item); +} + +static void +dispatch_free_all(qelement *head) +{ + command_buffer *item; + + while (!EMPTYQUE(*head)) { + item = (command_buffer *) head->q_forw; + dispatch_free_command(item); + } +} + +static command_buffer * +dispatch_add_command(qelement *head, char *string) +{ + command_buffer *new; + + new = malloc(sizeof(command_buffer)); + + if (!new) + return NULL; + + new->string = strdup(string); + INSQUEUE(new, head->q_back); + + return new; +} + +/* + * Command processing + */ + +/* Just convenience */ +static int +dispatch_shutdown(dialogMenuItem *unused) +{ + systemShutdown(0); + return DITEM_FAILURE; +} + +static int +dispatch_systemExecute(dialogMenuItem *unused) +{ + char *cmd = variable_get(VAR_COMMAND); + + if (cmd) + return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS; + else + msgDebug("_systemExecute: No command passed in `command' variable.\n"); + return DITEM_FAILURE; +} + +static int +dispatch_msgConfirm(dialogMenuItem *unused) +{ + char *msg = variable_get(VAR_COMMAND); + + if (msg) { + msgConfirm("%s", msg); + return DITEM_SUCCESS; + } + + msgDebug("_msgConfirm: No message passed in `command' variable.\n"); + return DITEM_FAILURE; +} + +static int +dispatch_mediaClose(dialogMenuItem *unused) +{ + mediaClose(); + return DITEM_SUCCESS; +} + +static int +call_possible_resword(char *name, dialogMenuItem *value, int *status) +{ + int i, rval; + + rval = 0; + for (i = 0; resWords[i].name; i++) { + if (!strcmp(name, resWords[i].name)) { + *status = resWords[i].handler(value); + rval = 1; + break; + } + } + return rval; +} + +/* For a given string, call it or spit out an undefined command diagnostic */ +int +dispatchCommand(char *str) +{ + int i; + char *cp; + + if (!str || !*str) { + msgConfirm("Null or zero-length string passed to dispatchCommand"); + return DITEM_FAILURE; + } + /* If it's got a newline, trim it */ + if ((cp = index(str, '\n')) != NULL) + *cp = '\0'; + + /* If it's got a `=' sign in there, assume it's a variable setting */ + if (index(str, '=')) { + if (isDebug()) + msgDebug("dispatch: setting variable `%s'\n", str); + variable_set(str, 0); + i = DITEM_SUCCESS; + } + else { + /* A command might be a pathname if it's encoded in argv[0], which + we also support */ + if ((cp = rindex(str, '/')) != NULL) + str = cp + 1; + if (isDebug()) + msgDebug("dispatch: calling resword `%s'\n", str); + if (!call_possible_resword(str, NULL, &i)) { + msgNotify("Warning: No such command ``%s''", str); + i = DITEM_FAILURE; + } + /* + * Allow a user to prefix a command with "noError" to cause + * us to ignore any errors for that one command. + */ + if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR)) + i = DITEM_SUCCESS; + variable_unset(VAR_NO_ERROR); + } + return i; +} + + +/* + * File processing + */ + +static qelement * +dispatch_load_fp(FILE *fp) +{ + qelement *head; + char buf[BUFSIZ], *cp; + + head = malloc(sizeof(qelement)); + + if (!head) + return NULL; + + INITQUE(*head); + + while (fgets(buf, sizeof buf, fp)) { + + if ((cp = strchr(buf, '\n')) != NULL) + *cp = '\0'; + if (*buf == '\0' || *buf == '#') + continue; + + if (!dispatch_add_command(head, buf)) + return NULL; + } + + return head; +} + +static int +dispatch_execute(qelement *head) +{ + int result = DITEM_SUCCESS; + command_buffer *item; + char *old_interactive; + + if (!head) + return result | DITEM_FAILURE; + + old_interactive = variable_get(VAR_NONINTERACTIVE); + if (old_interactive) + old_interactive = strdup(old_interactive); /* save copy */ + + /* Hint to others that we're running from a script, should they care */ + variable_set2(VAR_NONINTERACTIVE, "yes", 0); + + while (!EMPTYQUE(*head)) { + item = (command_buffer *) head->q_forw; + + if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) { + msgConfirm("Command `%s' failed - rest of script aborted.\n", + item->string); + result |= DITEM_FAILURE; + break; + } + dispatch_free_command(item); + } + + dispatch_free_all(head); + + if (!old_interactive) + variable_unset(VAR_NONINTERACTIVE); + else { + variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); + free(old_interactive); + } + + return result; +} + +int +dispatch_load_file_int(int quiet) +{ + FILE *fp; + char *cp; + int i; + qelement *list; + + static const char *names[] = { + "install.cfg", + "/stand/install.cfg", + "/tmp/install.cfg", + NULL + }; + + fp = NULL; + cp = variable_get(VAR_CONFIG_FILE); + if (!cp) { + for (i = 0; names[i]; i++) + if ((fp = fopen(names[i], "r")) != NULL) + break; + } else + fp = fopen(cp, "r"); + + if (!fp) { + if (!quiet) + msgConfirm("Unable to open %s: %s", cp, strerror(errno)); + return DITEM_FAILURE; + } + + list = dispatch_load_fp(fp); + fclose(fp); + + return dispatch_execute(list); +} + +int +dispatch_load_file(dialogMenuItem *self) +{ + return dispatch_load_file_int(FALSE); +} + +int +dispatch_load_floppy(dialogMenuItem *self) +{ + int what = DITEM_SUCCESS; + extern char *distWanted; + char *cp; + FILE *fp; + qelement *list; + + mediaClose(); + cp = variable_get_value(VAR_INSTALL_CFG, + "Specify the name of a configuration file\n" + "residing on a MSDOS or UFS floppy.", 0); + if (!cp || !*cp) { + variable_unset(VAR_INSTALL_CFG); + what |= DITEM_FAILURE; + return what; + } + + distWanted = cp; + /* Try to open the floppy drive */ + if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { + msgConfirm("Unable to set media device to floppy."); + what |= DITEM_FAILURE; + mediaClose(); + return what; + } + + if (!DEVICE_INIT(mediaDevice)) { + msgConfirm("Unable to mount floppy filesystem."); + what |= DITEM_FAILURE; + mediaClose(); + return what; + } + + fp = DEVICE_GET(mediaDevice, cp, TRUE); + if (fp) { + list = dispatch_load_fp(fp); + fclose(fp); + mediaClose(); + + what |= dispatch_execute(list); + } + else { + if (!variable_get(VAR_NO_ERROR)) + msgConfirm("Configuration file '%s' not found.", cp); + variable_unset(VAR_INSTALL_CFG); + what |= DITEM_FAILURE; + mediaClose(); + } + return what; +} + diff --git a/usr.sbin/sysinstall/dist.c b/usr.sbin/sysinstall/dist.c new file mode 100644 index 0000000000000..72f43d87d9768 --- /dev/null +++ b/usr.sbin/sysinstall/dist.c @@ -0,0 +1,825 @@ +/* + * 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 <sys/param.h> +#include <sys/mount.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <signal.h> +#include <libutil.h> + +unsigned int Dists; +unsigned int SrcDists; +unsigned int XOrgDists; + +enum _disttype { DT_TARBALL, DT_SUBDIST, DT_PACKAGE }; + +typedef struct _dist { + char *my_name; + unsigned int *my_mask; + unsigned int my_bit; + enum _disttype my_type; + union { + char *my_string; /* DT_TARBALL & DT_PACKAGE */ + struct _dist *my_dist; /* DT_SUBDIST */ + } my_data; +} Distribution; + +extern Distribution DistTable[]; +extern Distribution SrcDistTable[]; +extern Distribution XOrgDistTable[]; + +#define DTE_TARBALL(name, mask, flag, directory) \ + { name, mask, DIST_ ## flag, DT_TARBALL, { directory } } +#define DTE_PACKAGE(name, mask, flag, package) \ + { name, mask, DIST_ ## flag, DT_PACKAGE, { package } } +#define DTE_SUBDIST(name, mask, flag, subdist) \ + { name, mask, DIST_ ## flag, DT_SUBDIST, { .my_dist = subdist } } + +#define BASE_DIST (&DistTable[0]) + +/* The top-level distribution categories */ +static Distribution DistTable[] = { + DTE_TARBALL("base", &Dists, BASE, "/"), + DTE_TARBALL("doc", &Dists, DOC, "/"), + DTE_TARBALL("games", &Dists, GAMES, "/"), + DTE_TARBALL("manpages", &Dists, MANPAGES, "/"), + DTE_TARBALL("catpages", &Dists, CATPAGES, "/"), + DTE_TARBALL("proflibs", &Dists, PROFLIBS, "/"), + DTE_TARBALL("dict", &Dists, DICT, "/"), + DTE_TARBALL("info", &Dists, INFO, "/"), + DTE_SUBDIST("src", &Dists, SRC, SrcDistTable), +#ifdef __i386__ + DTE_TARBALL("compat1x", &Dists, COMPAT1X, "/"), + DTE_TARBALL("compat20", &Dists, COMPAT20, "/"), + DTE_TARBALL("compat21", &Dists, COMPAT21, "/"), + DTE_TARBALL("compat22", &Dists, COMPAT22, "/"), + DTE_TARBALL("compat3x", &Dists, COMPAT3X, "/"), +#endif +#if defined(__i386__) || defined(__alpha__) + DTE_TARBALL("compat4x", &Dists, COMPAT4X, "/"), +#endif + DTE_TARBALL("ports", &Dists, PORTS, "/usr"), + DTE_TARBALL("local", &Dists, LOCAL, "/"), + DTE_PACKAGE("perl", &Dists, PERL, "perl"), + DTE_SUBDIST("X.Org", &Dists, XORG, XOrgDistTable), + { NULL }, +}; + +/* The /usr/src distribution */ +static Distribution SrcDistTable[] = { + DTE_TARBALL("sbase", &SrcDists, SRC_BASE, "/usr/src"), + DTE_TARBALL("scontrib", &SrcDists, SRC_CONTRIB, "/usr/src"), + DTE_TARBALL("scrypto", &SrcDists, SRC_SCRYPTO, "/usr/src"), + DTE_TARBALL("sgnu", &SrcDists, SRC_GNU, "/usr/src"), + DTE_TARBALL("setc", &SrcDists, SRC_ETC, "/usr/src"), + DTE_TARBALL("sgames", &SrcDists, SRC_GAMES, "/usr/src"), + DTE_TARBALL("sinclude", &SrcDists, SRC_INCLUDE, "/usr/src"), + DTE_TARBALL("skrb5", &SrcDists, SRC_SKERBEROS5, "/usr/src"), + DTE_TARBALL("slib", &SrcDists, SRC_LIB, "/usr/src"), + DTE_TARBALL("slibexec", &SrcDists, SRC_LIBEXEC, "/usr/src"), + DTE_TARBALL("srelease", &SrcDists, SRC_RELEASE, "/usr/src"), + DTE_TARBALL("sbin", &SrcDists, SRC_BIN, "/usr/src"), + DTE_TARBALL("ssecure", &SrcDists, SRC_SSECURE, "/usr/src"), + DTE_TARBALL("ssbin", &SrcDists, SRC_SBIN, "/usr/src"), + DTE_TARBALL("sshare", &SrcDists, SRC_SHARE, "/usr/src"), + DTE_TARBALL("ssys", &SrcDists, SRC_SYS, "/usr/src"), + DTE_TARBALL("subin", &SrcDists, SRC_UBIN, "/usr/src"), + DTE_TARBALL("susbin", &SrcDists, SRC_USBIN, "/usr/src"), + DTE_TARBALL("stools", &SrcDists, SRC_TOOLS, "/usr/src"), + DTE_TARBALL("srescue", &SrcDists, SRC_RESCUE, "/usr/src"), + { NULL }, +}; + +/* The X.Org distribution */ +static Distribution XOrgDistTable[] = { + DTE_PACKAGE("Xbin", &XOrgDists, XORG_CLIENTS, "xorg-clients"), + DTE_PACKAGE("Xlib", &XOrgDists, XORG_LIB, "xorg-libraries"), + DTE_PACKAGE("Xman", &XOrgDists, XORG_MAN, "xorg-manpages"), + DTE_PACKAGE("Xdoc", &XOrgDists, XORG_DOC, "xorg-documents"), + DTE_PACKAGE("Xprog", &XOrgDists, XORG_IMAKE, "imake"), + + DTE_PACKAGE("Xsrv", &XOrgDists, XORG_SERVER, "xorg-server"), + DTE_PACKAGE("Xnest", &XOrgDists, XORG_NESTSERVER, "xorg-nestserver"), + DTE_PACKAGE("Xprt", &XOrgDists, XORG_PRINTSERVER, "xorg-printserver"), + DTE_PACKAGE("Xvfb", &XOrgDists, XORG_VFBSERVER, "xorg-vfbserver"), + + DTE_PACKAGE("Xfmsc", &XOrgDists, XORG_FONTS_MISC, "xorg-fonts-miscbitmaps"), + DTE_PACKAGE("Xf75", &XOrgDists, XORG_FONTS_75, "xorg-fonts-75dpi"), + DTE_PACKAGE("Xf100", &XOrgDists, XORG_FONTS_100, "xorg-fonts-100dpi"), + DTE_PACKAGE("Xfcyr", &XOrgDists, XORG_FONTS_CYR, "xorg-fonts-cyrillic"), + DTE_PACKAGE("Xft1", &XOrgDists, XORG_FONTS_T1, "xorg-fonts-type1"), + DTE_PACKAGE("Xftt", &XOrgDists, XORG_FONTS_TT, "xorg-fonts-truetype"), + DTE_PACKAGE("Xfs", &XOrgDists, XORG_FONTSERVER, "xorg-fontserver"), + { NULL }, +}; + +static int distMaybeSetPorts(dialogMenuItem *self); + +static void +distVerifyFlags(void) +{ + if (SrcDists) + Dists |= DIST_SRC; + if (XOrgDists) + Dists |= DIST_XORG; + if (isDebug()) { + msgDebug("Dist Masks: Dists: %0x, Srcs: %0x\n", Dists, + SrcDists); + msgDebug("XServer: %0x\n", XOrgDists); + } +} + +int +distReset(dialogMenuItem *self) +{ + Dists = 0; + SrcDists = 0; + XOrgDists = 0; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +int +distConfig(dialogMenuItem *self) +{ + char *cp; + + distReset(NULL); + + if ((cp = variable_get(VAR_DIST_MAIN)) != NULL) + Dists = atoi(cp); + + if ((cp = variable_get(VAR_DIST_SRC)) != NULL) + SrcDists = atoi(cp); + + if ((cp = variable_get(VAR_DIST_X11)) != NULL) + XOrgDists = atoi(cp); + + distVerifyFlags(); + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +distSetX(void) +{ + Dists |= DIST_XORG; + XOrgDists = DIST_XORG_MISC_ALL | DIST_XORG_SERVER | _DIST_XORG_FONTS_BASE; + return distSetXOrg(NULL); +} + +int +distSetDeveloper(dialogMenuItem *self) +{ + int i; + + distReset(NULL); + Dists = _DIST_DEVELOPER; + SrcDists = DIST_SRC_ALL; + i = distMaybeSetPorts(self); + distVerifyFlags(); + return i; +} + +int +distSetXDeveloper(dialogMenuItem *self) +{ + int i; + + i = distSetDeveloper(self); + i |= distSetX(); + distVerifyFlags(); + return i; +} + +int +distSetKernDeveloper(dialogMenuItem *self) +{ + int i; + + distReset(NULL); + Dists = _DIST_DEVELOPER; + SrcDists = DIST_SRC_SYS; + i = distMaybeSetPorts(self); + distVerifyFlags(); + return i; +} + +int +distSetXKernDeveloper(dialogMenuItem *self) +{ + int i; + + i = distSetKernDeveloper(self); + i |= distSetX(); + distVerifyFlags(); + return i; +} + +int +distSetUser(dialogMenuItem *self) +{ + int i; + + distReset(NULL); + Dists = _DIST_USER; + i = distMaybeSetPorts(self); + distVerifyFlags(); + return i; +} + +int +distSetXUser(dialogMenuItem *self) +{ + int i; + + i = distSetUser(self); + i |= distSetX(); + distVerifyFlags(); + return i; +} + +int +distSetMinimum(dialogMenuItem *self) +{ + distReset(NULL); + Dists = DIST_BASE; + distVerifyFlags(); + return DITEM_SUCCESS | DITEM_REDRAW; +} + +int +distSetEverything(dialogMenuItem *self) +{ + int i; + + Dists = DIST_ALL; + SrcDists = DIST_SRC_ALL; + XOrgDists = DIST_XORG_ALL; + i = distMaybeSetPorts(self); + distVerifyFlags(); + return i | DITEM_REDRAW; +} + +static int +distMaybeSetPorts(dialogMenuItem *self) +{ + dialog_clear_norefresh(); + if (!msgYesNo("Would you like to install the FreeBSD ports collection?\n\n" + "This will give you ready access to over 10500 ported software packages,\n" + "at a cost of around 300MB of disk space when \"clean\" and possibly\n" + "much more than that when a lot of the distribution tarballs are loaded\n" + "(unless you have the extra discs available from a FreeBSD CD/DVD distribution\n" + "and can mount them on /cdrom, in which case this is far less of a problem).\n\n" + "The ports collection is a very valuable resource and well worth having\n" + "on your /usr partition, so it is advisable to say Yes to this option.\n\n" + "For more information on the ports collection & the latest ports, visit:\n" + " http://www.freebsd.org/ports\n")) + Dists |= DIST_PORTS; + else + Dists &= ~DIST_PORTS; + return DITEM_SUCCESS | DITEM_RESTORE; +} + +static Boolean +distSetByName(Distribution *dist, char *name) +{ + int i, status = FALSE; + + /* Loop through current set */ + for (i = 0; dist[i].my_name; i++) { + switch (dist[i].my_type) { + case DT_TARBALL: + case DT_PACKAGE: + if (!strcmp(dist[i].my_name, name)) { + *(dist[i].my_mask) |= dist[i].my_bit; + status = TRUE; + } + break; + case DT_SUBDIST: + if (distSetByName(dist[i].my_data.my_dist, name)) { + status = TRUE; + } + break; + } + } + distVerifyFlags(); + return status; +} + +static Boolean +distUnsetByName(Distribution *dist, char *name) +{ + int i, status = FALSE; + + /* Loop through current set */ + for (i = 0; dist[i].my_name; i++) { + switch (dist[i].my_type) { + case DT_TARBALL: + case DT_PACKAGE: + if (!strcmp(dist[i].my_name, name)) { + *(dist[i].my_mask) &= ~(dist[i].my_bit); + status = TRUE; + } + break; + case DT_SUBDIST: + if (distUnsetByName(dist[i].my_data.my_dist, name)) { + status = TRUE; + } + break; + } + } + return status; +} + +/* Just for the dispatch stuff */ +int +distSetCustom(dialogMenuItem *self) +{ + char *cp, *cp2, *tmp; + + if (!(tmp = variable_get(VAR_DISTS))) { + msgDebug("distSetCustom() called without %s variable set.\n", VAR_DISTS); + return DITEM_FAILURE; + } + + cp = alloca(strlen(tmp) + 1); + if (!cp) + msgFatal("Couldn't alloca() %d bytes!\n", (int)(strlen(tmp) + 1)); + strcpy(cp, tmp); + while (cp) { + if ((cp2 = index(cp, ' ')) != NULL) + *(cp2++) = '\0'; + if (!distSetByName(DistTable, cp)) + msgDebug("distSetCustom: Warning, no such release \"%s\"\n", cp); + cp = cp2; + } + distVerifyFlags(); + return DITEM_SUCCESS; +} + +/* Just for the dispatch stuff */ +int +distUnsetCustom(dialogMenuItem *self) +{ + char *cp, *cp2, *tmp; + + if (!(tmp = variable_get(VAR_DISTS))) { + msgDebug("distUnsetCustom() called without %s variable set.\n", VAR_DISTS); + return DITEM_FAILURE; + } + + cp = alloca(strlen(tmp) + 1); + if (!cp) + msgFatal("Couldn't alloca() %d bytes!\n", (int)(strlen(tmp) + 1)); + strcpy(cp, tmp); + while (cp) { + if ((cp2 = index(cp, ' ')) != NULL) + *(cp2++) = '\0'; + if (!distUnsetByName(DistTable, cp)) + msgDebug("distUnsetCustom: Warning, no such release \"%s\"\n", cp); + cp = cp2; + } + return DITEM_SUCCESS; +} + +int +distSetSrc(dialogMenuItem *self) +{ + int i; + + dialog_clear_norefresh(); + if (!dmenuOpenSimple(&MenuSrcDistributions, FALSE)) + i = DITEM_FAILURE; + else + i = DITEM_SUCCESS; + distVerifyFlags(); + return i | DITEM_RESTORE; +} + +int +distSetXOrg(dialogMenuItem *self) +{ + int i = DITEM_SUCCESS; + + dialog_clear_norefresh(); + if (!dmenuOpenSimple(&MenuXOrgSelect, FALSE)) + i = DITEM_FAILURE; + distVerifyFlags(); + return i | DITEM_RESTORE; +} + +static Boolean got_intr = 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; +} + +/* + * Try to get distribution as multiple pieces, locating and parsing an + * info file which tells us how many we need for this distribution. + */ +static Boolean +distExtractTarball(char *path, char *dist, char *my_dir, int is_base) +{ + char *buf = NULL, fname[PATH_MAX]; + struct timeval start, stop; + int j, status, total, intr; + int cpid, zpid, fd2, chunk, numchunks; + properties dist_attr = NULL; + const char *tmp; + FILE *fp; + + status = TRUE; + numchunks = 0; + snprintf(fname, sizeof (fname), "%s/%s.inf", path, dist); + +getinfo: + fp = DEVICE_GET(mediaDevice, fname, TRUE); + intr = check_for_interrupt(); + if (fp == (FILE *)IO_ERROR || intr || !mediaDevice) { + /* Hard error, can't continue */ + if (!msgYesNo("Unable to open %s: %s.\nReinitialize media?", + fname, !intr ? "I/O error." : "User interrupt.")) { + DEVICE_SHUTDOWN(mediaDevice); + if (!DEVICE_INIT(mediaDevice)) + return (FALSE); + goto getinfo; + } else + return (FALSE); + } else if (fp == NULL) { + /* No attributes file, so try as a single file. */ + snprintf(fname, sizeof(fname), "%s/%s.%s", path, dist, + USE_GZIP ? "tgz" : "tbz"); + /* + * Passing TRUE as 3rd parm to get routine makes this a "probing" + * get, for which errors are not considered too significant. + */ + getsingle: + fp = DEVICE_GET(mediaDevice, fname, TRUE); + intr = check_for_interrupt(); + if (fp == (FILE *)IO_ERROR || intr || !mediaDevice) { + /* Hard error, can't continue */ + msgConfirm("Unable to open %s: %s", fname, + !intr ? "I/O error" : "User interrupt"); + DEVICE_SHUTDOWN(mediaDevice); + if (!DEVICE_INIT(mediaDevice)) + return (FALSE); + goto getsingle; + } else if (fp != NULL) { + char *dir = root_bias(my_dir); + + dialog_clear_norefresh(); + msgNotify("Extracting %s into %s directory...", dist, dir); + status = mediaExtractDist(dir, dist, fp); + fclose(fp); + return (status); + } else + return (FALSE); + } + + if (isDebug()) + msgDebug("Parsing attributes file for distribution %s\n", dist); + + dist_attr = properties_read(fileno(fp)); + intr = check_for_interrupt(); + if (intr || !dist_attr) { + msgConfirm("Cannot parse information file for the %s distribution: %s\n" + "Please verify that your media is valid and try again.", + dist, !intr ? "I/O error" : "User interrupt"); + } else { + tmp = property_find(dist_attr, "Pieces"); + if (tmp) + numchunks = strtol(tmp, 0, 0); + } + fclose(fp); + if (!numchunks) + return (TRUE); + + if (isDebug()) + msgDebug("Attempting to extract distribution from %u chunks.\n", + numchunks); + + total = 0; + (void)gettimeofday(&start, (struct timezone *)NULL); + + /* We have one or more chunks, initialize unpackers... */ + mediaExtractDistBegin(root_bias(my_dir), &fd2, &zpid, &cpid); + + /* And go for all the chunks */ + dialog_clear_norefresh(); + for (chunk = 0; chunk < numchunks; chunk++) { + int n, retval, last_msg, chunksize, realsize; + char prompt[80]; + + last_msg = 0; + + getchunk: + snprintf(fname, sizeof(fname), "cksum.%c%c", (chunk / 26) + 'a', + (chunk % 26) + 'a'); + tmp = property_find(dist_attr, fname); + chunksize = 0; + if (tmp) { + tmp = index(tmp, ' '); + chunksize = strtol(tmp, 0, 0); + } + snprintf(fname, sizeof(fname), "%s/%s.%c%c", path, dist, (chunk / 26) + 'a', + (chunk % 26) + 'a'); + if (isDebug()) + msgDebug("trying for piece %d of %d: %s\n", chunk + 1, numchunks, + fname); + fp = DEVICE_GET(mediaDevice, fname, FALSE); + intr = check_for_interrupt(); + /* XXX: this can't work if we get an I/O error */ + if (fp <= (FILE *)NULL || intr) { + if (fp == NULL) + msgConfirm("Failed to find %s on this media. Reinitializing media.", fname); + else + msgConfirm("Failed to retreive piece file %s.\n" + "%s: Reinitializing media.", + fname, !intr ? "I/O error" : "User interrupt"); + DEVICE_SHUTDOWN(mediaDevice); + if (!DEVICE_INIT(mediaDevice)) + goto punt; + else + goto getchunk; + } + + snprintf(prompt, sizeof(prompt), "Extracting %s into %s directory...", + dist, root_bias(my_dir)); + dialog_gauge("Progress", prompt, 8, 15, 6, 50, + (chunk + 1) * 100 / numchunks); + + buf = safe_realloc(buf, chunksize); + realsize = 0; + while (1) { + int seconds; + + n = fread(buf + realsize, 1, BUFSIZ, fp); + if (check_for_interrupt()) { + msgConfirm("Media read error: User interrupt."); + fclose(fp); + goto punt; + } else if (n <= 0) + break; + total += n; + realsize += n; + + /* Print statistics about how we're doing */ + (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; + + if (seconds != last_msg) { + last_msg = seconds; + msgInfo("%10d bytes read from %s dist, chunk %2d of %2d @ %.1f KBytes/sec.", + total, dist, chunk + 1, numchunks, + (total / seconds) / 1000.0); + } + } + fclose(fp); + + if (!chunksize || (realsize == chunksize)) { + /* No substitution necessary */ + retval = write(fd2, buf, realsize); + if (retval != realsize) { + fclose(fp); + dialog_clear_norefresh(); + msgConfirm("Write failure on transfer! (wrote %d bytes of %d bytes)", retval, realsize); + goto punt; + } + } else { + for (j = 0; j < realsize; j++) { + /* On finding CRLF, skip the CR; don't exceed end of buffer. */ + if ((buf[j] != 0x0d) || (j == total - 1) || (buf[j + 1] != 0x0a)) { + retval = write(fd2, buf + j, 1); + if (retval != 1) { + fclose(fp); + dialog_clear_norefresh(); + msgConfirm("Write failure on transfer! (wrote %d bytes of %d bytes)", j, chunksize); + goto punt; + } + } + } + } + } + goto done; + +punt: + status = FALSE; +done: + properties_free(dist_attr); + close(fd2); + if (status != FALSE) + status = mediaExtractDistEnd(zpid, cpid); + else + (void)mediaExtractDistEnd(zpid, cpid); + + safe_free(buf); + return (status); +} + +static Boolean +distExtract(char *parent, Distribution *me) +{ + int i, status; + char *path, *dist; + WINDOW *w = savescr(); + struct sigaction old, new; + + status = TRUE; + if (isDebug()) + msgDebug("distExtract: parent: %s, me: %s\n", parent ? parent : "(none)", me->my_name); + + /* Make ^C fake a sudden timeout */ + new.sa_handler = handle_intr; + new.sa_flags = 0; + (void)sigemptyset(&new.sa_mask); + dialog_clear_norefresh(); + dialog_msgbox("Please Wait", "Extracting all requested distributions...", -1, -1, 0); + sigaction(SIGINT, &new, &old); + + /* Loop through to see if we're in our parent's plans */ + for (i = 0; me[i].my_name; i++) { + dist = me[i].my_name; + path = parent ? parent : dist; + + /* If our bit isn't set, go to the next */ + if (!(me[i].my_bit & *(me[i].my_mask))) + continue; + + switch (me[i].my_type) { + case DT_SUBDIST: + /* Recurse if we actually have a sub-distribution */ + status = distExtract(dist, me[i].my_data.my_dist); + if (!status) { + dialog_clear_norefresh(); + msgConfirm("Unable to transfer all components of the %s distribution.\n" + "You may wish to switch media types and try again.\n", + me[i].my_name); + } + break; + case DT_PACKAGE: + dialog_clear_norefresh(); + msgNotify("Installing %s distribution...", dist); + status = (package_add(me[i].my_data.my_string) == DITEM_SUCCESS); + if (!status) + dialog_clear_norefresh(); + break; + case DT_TARBALL: + status = distExtractTarball(path, dist, me[i].my_data.my_string, + &me[i] == BASE_DIST); + if (!status) { + dialog_clear_norefresh(); + if (me[i].my_bit != DIST_LOCAL) { + status = msgYesNo("Unable to transfer the %s distribution from\n%s.\n\n" + "Do you want to try to retrieve it again?", + me[i].my_name, mediaDevice->name); + if (!status) + --i; + status = FALSE; + } + } + break; + } + + /* + * If extract was successful, remove ourselves from further + * consideration. + */ + if (status) + *(me[i].my_mask) &= ~(me[i].my_bit); + } + sigaction(SIGINT, &old, NULL); /* Restore signal handler */ + restorescr(w); + return status; +} + +static void +printSelected(char *buf, int selected, Distribution *me, int *col) +{ + int i; + + /* Loop through to see if we're in our parent's plans */ + for (i = 0; me[i].my_name; i++) { + + /* If our bit isn't set, go to the next */ + if (!(me[i].my_bit & selected)) + continue; + + *col += strlen(me[i].my_name); + if (*col > 50) { + *col = 0; + strcat(buf, "\n"); + } + sprintf(&buf[strlen(buf)], " %s", me[i].my_name); + + /* Recurse if have a sub-distribution */ + if (me[i].my_type == DT_SUBDIST) + printSelected(buf, *(me[i].my_mask), me[i].my_data.my_dist, col); + } +} + +int +distExtractAll(dialogMenuItem *self) +{ + int old_dists, retries = 0, status = DITEM_SUCCESS; + char buf[512]; + WINDOW *w; + + /* paranoia */ + if (!Dists) { + if (!dmenuOpenSimple(&MenuSubDistributions, FALSE) || !Dists) + return DITEM_FAILURE; + } + + if (!mediaVerify() || !DEVICE_INIT(mediaDevice)) + return DITEM_FAILURE; + + old_dists = Dists; + distVerifyFlags(); + + dialog_clear_norefresh(); + w = savescr(); + msgNotify("Attempting to install all selected distributions.."); + + /* Try for 3 times around the loop, then give up. */ + while (Dists && ++retries < 3) + distExtract(NULL, DistTable); + + dialog_clear_norefresh(); + /* Only do base fixup if base dist was successfully extracted */ + if ((old_dists & DIST_BASE) && !(Dists & DIST_BASE)) + status |= installFixupBase(self); + + /* Clear any local dist flags now */ + Dists &= ~DIST_LOCAL; + + if (Dists) { + int col = 0; + + buf[0] = '\0'; + dialog_clear_norefresh(); + printSelected(buf, Dists, DistTable, &col); + dialog_clear_norefresh(); + if (col) { + msgConfirm("Couldn't extract the following distributions. This may\n" + "be because they were not available on the installation\n" + "media you've chosen:\n\n\t%s", buf); + } + } + restorescr(w); + return status; +} diff --git a/usr.sbin/sysinstall/dist.h b/usr.sbin/sysinstall/dist.h new file mode 100644 index 0000000000000..08cb302831254 --- /dev/null +++ b/usr.sbin/sysinstall/dist.h @@ -0,0 +1,93 @@ +/* $FreeBSD$ */ + +#ifndef _DIST_H_INCLUDE +#define _DIST_H_INCLUDE + +/* Bitfields for distributions - hope we never have more than 32! :-) */ +#define DIST_BASE 0x00001 +#define DIST_GAMES 0x00002 +#define DIST_MANPAGES 0x00004 +#define DIST_PROFLIBS 0x00008 +#define DIST_DICT 0x00010 +#define DIST_SRC 0x00020 +#define DIST_DOC 0x00040 +#define DIST_INFO 0x00080 +#ifdef __i386__ /* only applicable on x86 */ +#define DIST_COMPAT1X 0x00100 +#define DIST_COMPAT20 0x00200 +#define DIST_COMPAT21 0x00400 +#define DIST_COMPAT22 0x00800 +#define DIST_COMPAT3X 0x01000 +#endif +#if defined(__i386__) || defined(__alpha__) +#define DIST_COMPAT4X 0x02000 +#endif +#define DIST_XORG 0x04000 +#define DIST_CATPAGES 0x10000 +#define DIST_PORTS 0x20000 +#define DIST_LOCAL 0x40000 +#define DIST_PERL 0x80000 +#define DIST_ALL 0xFFFFF + +/* Subtypes for SRC distribution */ +#define DIST_SRC_BASE 0x00001 +#define DIST_SRC_CONTRIB 0x00002 +#define DIST_SRC_GNU 0x00004 +#define DIST_SRC_ETC 0x00008 +#define DIST_SRC_GAMES 0x00010 +#define DIST_SRC_INCLUDE 0x00020 +#define DIST_SRC_LIB 0x00040 +#define DIST_SRC_LIBEXEC 0x00080 +#define DIST_SRC_TOOLS 0x00100 +#define DIST_SRC_RELEASE 0x00200 +#define DIST_SRC_SBIN 0x00400 +#define DIST_SRC_SHARE 0x00800 +#define DIST_SRC_SYS 0x01000 +#define DIST_SRC_UBIN 0x02000 +#define DIST_SRC_USBIN 0x04000 +#define DIST_SRC_BIN 0x08000 +#define DIST_SRC_SCRYPTO 0x10000 +#define DIST_SRC_SSECURE 0x20000 +#define DIST_SRC_SKERBEROS5 0x40000 +#define DIST_SRC_RESCUE 0x80000 +#define DIST_SRC_ALL 0xFFFFF + +/* Subtypes for X.Org packages */ +#define DIST_XORG_CLIENTS 0x000001 +#define DIST_XORG_LIB 0x000002 +#define DIST_XORG_MAN 0x000004 +#define DIST_XORG_DOC 0x000008 +#define DIST_XORG_IMAKE 0x000010 + +#define DIST_XORG_SERVER 0x000100 +#define DIST_XORG_NESTSERVER 0x000200 +#define DIST_XORG_PRINTSERVER 0x000400 +#define DIST_XORG_VFBSERVER 0x000800 + +#define DIST_XORG_FONTS_MISC 0x010000 +#define DIST_XORG_FONTS_75 0x020000 +#define DIST_XORG_FONTS_100 0x040000 +#define DIST_XORG_FONTS_CYR 0x080000 +#define DIST_XORG_FONTS_T1 0x100000 +#define DIST_XORG_FONTS_TT 0x200000 +#define DIST_XORG_FONTSERVER 0x400000 + +#define DIST_XORG_MISC_ALL 0x00001f +#define DIST_XORG_SERVER_ALL 0x000f00 +#define DIST_XORG_FONTS_ALL 0x7f0000 +#define DIST_XORG_ALL \ + (DIST_XORG_MISC_ALL | DIST_XORG_SERVER_ALL | DIST_XORG_FONTS_ALL) + +/* Canned distribution sets */ + +#define _DIST_XORG_FONTS_BASE \ + (DIST_XORG_FONTS_MISC | DIST_XORG_FONTS_75 | DIST_XORG_FONTS_100 | \ + DIST_XORG_FONTS_TT) + +#define _DIST_USER \ + ( DIST_BASE | DIST_DOC | DIST_MANPAGES | DIST_DICT | DIST_PERL ) + +#define _DIST_DEVELOPER \ + ( _DIST_USER | DIST_PROFLIBS | DIST_INFO | DIST_SRC ) + +#endif /* _DIST_H_INCLUDE */ diff --git a/usr.sbin/sysinstall/dmenu.c b/usr.sbin/sysinstall/dmenu.c new file mode 100644 index 0000000000000..d89f8ce2265cd --- /dev/null +++ b/usr.sbin/sysinstall/dmenu.c @@ -0,0 +1,319 @@ +/* + * The new sysinstall program. + * + * This is probably the last attempt in the `sysinstall' line, the next + * generation being slated for what's 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 <errno.h> + +#define MAX_MENU 15 + +static Boolean exited; + +int +dmenuDisplayFile(dialogMenuItem *tmp) +{ + systemDisplayHelp((char *)tmp->data); + return DITEM_SUCCESS; +} + +int +dmenuSubmenu(dialogMenuItem *tmp) +{ + return (dmenuOpenSimple((DMenu *)(tmp->data), FALSE) ? DITEM_SUCCESS : DITEM_FAILURE); +} + +int +dmenuSystemCommand(dialogMenuItem *self) +{ + WINDOW *w = NULL; /* Keep lint happy */ + + /* If aux is set, the command is known not to produce any screen-spoiling output */ + if (!self->aux) + w = savescr(); + systemExecute((char *)self->data); + if (!self->aux) + restorescr(w); + return DITEM_SUCCESS; +} + +int +dmenuSystemCommandBox(dialogMenuItem *tmp) +{ + WINDOW *w = savescr(); + + use_helpfile(NULL); + use_helpline("Select OK to dismiss this dialog"); + dialog_prgbox(tmp->title, (char *)tmp->data, 22, 76, 1, 1); + restorescr(w); + return DITEM_SUCCESS; +} + +int +dmenuExit(dialogMenuItem *tmp) +{ + exited = TRUE; + return DITEM_LEAVE_MENU; +} + +int +dmenuSetVariable(dialogMenuItem *tmp) +{ + variable_set((char *)tmp->data, *((char *)tmp->data) != '_'); + return DITEM_SUCCESS; +} + +int +dmenuSetVariables(dialogMenuItem *tmp) +{ + char *cp1, *cp2; + char *copy = strdup((char *)tmp->data); + + for (cp1 = copy; cp1 != NULL;) { + cp2 = index(cp1, ','); + if (cp2 != NULL) *cp2++ = '\0'; + variable_set(cp1, *cp1 != '_'); + cp1 = cp2; + } + free(copy); + return DITEM_SUCCESS; +} + +int +dmenuSetKmapVariable(dialogMenuItem *tmp) +{ + char *lang; + int err; + + variable_set((char *)tmp->data, TRUE); + lang = variable_get(VAR_KEYMAP); + if (lang != NULL) + { + err = loadKeymap(lang); + if (err == -1) + msgConfirm("No appropriate keyboard map found, sorry."); + else if (err == -2) + msgConfirm("Error installing keyboard map, errno = %d.", errno); + } + return DITEM_SUCCESS; +} + +int +dmenuToggleVariable(dialogMenuItem *tmp) +{ + char *var, *cp; + int status; + + if (!(var = strdup((char *)tmp->data))) { + msgConfirm("Incorrect data field for `%s'!", tmp->title); + return DITEM_FAILURE; + } + if (!(cp = index(var, '='))) { + msgConfirm("Data field for %s is not in var=value format!", tmp->title); + return DITEM_FAILURE; + } + status = variable_check(var); + *cp = '\0'; + variable_set2(var, status ? "NO" : "YES", *var != '_'); + free(var); + return DITEM_SUCCESS; +} + +int +dmenuISetVariable(dialogMenuItem *tmp) +{ + char *ans, *var; + + if (!(var = (char *)tmp->data)) { + msgConfirm("Incorrect data field for `%s'!", tmp->title); + return DITEM_FAILURE; + } + ans = msgGetInput(variable_get(var), tmp->title, 1); + if (!ans) + return DITEM_FAILURE; + else if (!*ans) + variable_unset(var); + else + variable_set2(var, ans, *var != '_'); + return DITEM_SUCCESS; +} + +int +dmenuSetFlag(dialogMenuItem *tmp) +{ + if (*((unsigned int *)tmp->data) & tmp->aux) + *((unsigned int *)tmp->data) &= ~tmp->aux; + else + *((unsigned int *)tmp->data) |= tmp->aux; + return DITEM_SUCCESS; +} + +int +dmenuSetValue(dialogMenuItem *tmp) +{ + *((unsigned int *)tmp->data) = tmp->aux; + return DITEM_SUCCESS; +} + +/* Traverse menu but give user no control over positioning */ +Boolean +dmenuOpenSimple(DMenu *menu, Boolean buttons) +{ + int choice, scroll, curr, max; + + choice = scroll = curr = max = 0; + return dmenuOpen(menu, &choice, &scroll, &curr, &max, buttons); +} + +/* Work functions for the state hook */ +int +dmenuFlagCheck(dialogMenuItem *item) +{ + return (*((unsigned int *)item->data) & item->aux); +} + +int +dmenuVarCheck(dialogMenuItem *item) +{ + char *w; + + w = (char *)item->aux; + if (!w) + w = (char *)item->data; + return variable_check(w); +} + +int +dmenuVarsCheck(dialogMenuItem *item) +{ + int res, init; + char *w, *cp1, *cp2; + char *copy; + + w = (char *)item->aux; + if (!w) + w = (char *)item->data; + if (!w) + return FALSE; + + copy = strdup(w); + res = TRUE; + init = FALSE; + for (cp1 = copy; cp1 != NULL;) { + init = TRUE; + cp2 = index(cp1, ','); + if (cp2 != NULL) + *cp2++ = '\0'; + res = res && variable_check(cp1); + cp1 = cp2; + } + free(copy); + return res && init; +} + +int +dmenuRadioCheck(dialogMenuItem *item) +{ + return (*((unsigned int *)item->data) == item->aux); +} + +static int +menu_height(DMenu *menu, int n) +{ + int max; + char *t; + + max = MAX_MENU; + if (StatusLine > 24) + max += StatusLine - 24; + for (t = menu->prompt; *t; t++) { + if (*t == '\n') + --max; + } + return n > max ? max : n; +} + +/* Traverse over an internal menu */ +Boolean +dmenuOpen(DMenu *menu, int *choice, int *scroll, int *curr, int *max, Boolean buttons) +{ + int n, rval = 0; + dialogMenuItem *items; + + items = menu->items; + if (buttons) + items += 2; + /* Count up all the items */ + for (n = 0; items[n].title; n++); + + while (1) { + char buf[FILENAME_MAX]; + WINDOW *w = savescr(); + + /* Any helpful hints, put 'em up! */ + use_helpline(menu->helpline); + use_helpfile(systemHelpFile(menu->helpfile, buf)); + dialog_clear_norefresh(); + /* Pop up that dialog! */ + if (menu->type & DMENU_NORMAL_TYPE) + rval = dialog_menu((u_char *)menu->title, (u_char *)menu->prompt, + -1, -1, menu_height(menu, n), -n, items, + (char *)(uintptr_t)buttons, choice, scroll); + + else if (menu->type & DMENU_RADIO_TYPE) + rval = dialog_radiolist((u_char *)menu->title, + (u_char *)menu->prompt, -1, -1, menu_height(menu, n), -n, + items, (char *)(uintptr_t)buttons); + + else if (menu->type & DMENU_CHECKLIST_TYPE) + rval = dialog_checklist((u_char *)menu->title, + (u_char *)menu->prompt, -1, -1, menu_height(menu, n), -n, + items, (char *)(uintptr_t)buttons); + else + msgFatal("Menu: `%s' is of an unknown type\n", menu->title); + if (exited) { + exited = FALSE; + restorescr(w); + return TRUE; + } + else if (rval) { + restorescr(w); + return FALSE; + } + else if (menu->type & DMENU_SELECTION_RETURNS) { + restorescr(w); + return TRUE; + } + } +} diff --git a/usr.sbin/sysinstall/doc.c b/usr.sbin/sysinstall/doc.c new file mode 100644 index 0000000000000..5294972f09226 --- /dev/null +++ b/usr.sbin/sysinstall/doc.c @@ -0,0 +1,123 @@ +/* + * The new sysinstall program. + * + * This is probably the last attempt in the `sysinstall' line, the next + * generation being slated for what's essentially a complete rewrite. + * + * 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. + * + * $FreeBSD$ + */ + +#include "sysinstall.h" + +/* + * This is called from the main menu. Try to find a copy of Lynx from somewhere + * and fire it up on the first copy of the handbook we can find. + */ +int +docBrowser(dialogMenuItem *self) +{ + int ret; + char *browser = variable_get(VAR_BROWSER_PACKAGE); + + if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) { + msgConfirm("This option may only be used after the system is installed, sorry!"); + return DITEM_FAILURE; + } + + /* First, make sure we have whatever browser we've chosen is here */ + if (!package_installed(browser)) { + ret = package_add(browser); + if (DITEM_STATUS(ret) != DITEM_SUCCESS) { + msgConfirm("Unable to install the %s HTML browser package. You may\n" + "wish to verify that your media is configured correctly and\n" + "try again.", browser); + return ret; + } + } + + if (!file_executable(variable_get(VAR_BROWSER_BINARY))) { + if (!msgYesNo("Hmmm. The %s package claims to have installed, but I can't\n" + "find its binary in %s! You may wish to try a different\n" + "location to load the package from (go to Media menu) and see if that\n" + "makes a difference.\n\n" + "I suggest that we remove the version that was extracted since it does\n" + "not appear to be correct. Would you like me to do that now?", + browser, variable_get(VAR_BROWSER_BINARY))) + vsystem("pkg_delete %s %s", !strcmp(variable_get(VAR_CPIO_VERBOSITY), "high") ? "-v" : "", browser); + return DITEM_FAILURE; + } + + /* Run browser on the appropriate doc */ + if (dmenuOpenSimple(&MenuHTMLDoc, FALSE)) + return DITEM_SUCCESS; + else + return DITEM_FAILURE; +} + +/* Try to show one of the documents requested from the HTML doc menu */ +int +docShowDocument(dialogMenuItem *self) +{ + char tmp[512], target[512]; + char *where, *browser = variable_get(VAR_BROWSER_BINARY); + char *str = self->prompt; + + if (!file_executable(browser)) { + msgConfirm("Can't find the browser in %s! Please ensure that it's\n" + "properly set in the Options editor.", browser); + return DITEM_FAILURE; + } + /* Default to Home */ + where = strcpy(target, "http://www.freebsd.org"); + if (strstr(str, "Other")) { + where = msgGetInput("http://www.freebsd.org", "Please enter the URL of the location you wish to visit."); + if (where) + strcpy(target, where); + } + else if (strstr(str, "FAQ")) { + where = strcpy(target, "/usr/share/doc/faq/index.html"); + if (!file_readable(target)) + where = strcpy(target, "http://www.freebsd.org/doc/en_US.ISO8859-1/books/faq"); + } + else if (strstr(str, "Handbook")) { + where = strcpy(target, "/usr/share/doc/handbook/index.html"); + if (!file_readable(target)) + where = strcpy(target, "http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook"); + } + if (where) { + sprintf(tmp, "%s %s", browser, target); + systemExecute(tmp); + return DITEM_SUCCESS; + } + else { + msgConfirm("Hmmmmm! I can't seem to access the documentation you selected!\n" + "Have you loaded the base distribution? Is your network connected?"); + return DITEM_FAILURE; + } +} diff --git a/usr.sbin/sysinstall/dos.c b/usr.sbin/sysinstall/dos.c new file mode 100644 index 0000000000000..564e33ff43747 --- /dev/null +++ b/usr.sbin/sysinstall/dos.c @@ -0,0 +1,94 @@ +/* + * 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. + * Copyright (c) 1995 + * Gary J Palmer. 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 <sys/stat.h> +#include <sys/errno.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <unistd.h> +#include <fcntl.h> +#include <grp.h> +#define MSDOSFS +#include <sys/mount.h> +#include <fs/msdosfs/msdosfsmount.h> +#undef MSDOSFS + +static Boolean DOSMounted; +static char mountpoint[] = "/dist"; + +Boolean +mediaInitDOS(Device *dev) +{ + struct msdosfs_args args; + + if (DOSMounted) + return TRUE; + + Mkdir(mountpoint); + memset(&args, 0, sizeof(args)); + args.fspec = dev->devname; + args.uid = args.gid = 0; + args.mask = 0777; + + if (mount("msdosfs", mountpoint, MNT_RDONLY, (caddr_t)&args) == -1) { + msgConfirm("Error mounting %s on %s: %s (%u)", args.fspec, mountpoint, strerror(errno), errno); + return FALSE; + } + DOSMounted = TRUE; + return TRUE; +} + +FILE * +mediaGetDOS(Device *dev, char *file, Boolean probe) +{ + return mediaGenericGet(mountpoint, file); +} + +void +mediaShutdownDOS(Device *dev) +{ + if (!DOSMounted) + return; + if (unmount(mountpoint, MNT_FORCE) != 0) + msgConfirm("Could not unmount the DOS partition from %s: %s", + mountpoint, strerror(errno)); + else + DOSMounted = FALSE; + return; +} diff --git a/usr.sbin/sysinstall/floppy.c b/usr.sbin/sysinstall/floppy.c new file mode 100644 index 0000000000000..0101bde3ce016 --- /dev/null +++ b/usr.sbin/sysinstall/floppy.c @@ -0,0 +1,158 @@ +/* + * 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. + * Copyright (c) 1995 + * Gary J Palmer. 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. + * + */ + +/* These routines deal with getting things off of floppy media */ + +#include "sysinstall.h" +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/errno.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <unistd.h> +#include <grp.h> + +#define MSDOSFS +#include <sys/mount.h> +#include <fs/msdosfs/msdosfsmount.h> +#undef MSDOSFS + +#include <ufs/ufs/ufsmount.h> +static Boolean floppyMounted; + +char *distWanted; +static char mountpoint[] = "/dist"; + +Boolean +mediaInitFloppy(Device *dev) +{ + struct msdosfs_args dosargs; + struct ufs_args u_args; + char *mp; + + if (floppyMounted) + return TRUE; + + mp = dev->private ? (char *)dev->private : mountpoint; + if (Mkdir(mp)) { + msgConfirm("Unable to make %s directory mountpoint for %s!", mp, dev->devname); + return FALSE; + } + + msgDebug("Init floppy called for %s distribution.\n", distWanted ? distWanted : "some"); + + if (!variable_get(VAR_NONINTERACTIVE)) { + if (!distWanted) + msgConfirm("Please insert floppy in %s", dev->description); + else + msgConfirm("Please insert floppy containing %s in %s", + distWanted, dev->description); + } + + memset(&dosargs, 0, sizeof dosargs); + dosargs.fspec = dev->devname; + dosargs.uid = dosargs.gid = 0; + dosargs.mask = 0777; + + memset(&u_args, 0, sizeof(u_args)); + u_args.fspec = dev->devname; + + if (mount("msdosfs", mp, MNT_RDONLY, (caddr_t)&dosargs) != -1) + goto success; + if (mount("ufs", mp, MNT_RDONLY, (caddr_t)&u_args) != -1) + goto success; + + msgConfirm("Error mounting floppy %s (%s) on %s : %s", + dev->name, dev->devname, mp, strerror(errno)); + return FALSE; + +success: + floppyMounted = TRUE; + distWanted = NULL; + return TRUE; +} + +FILE * +mediaGetFloppy(Device *dev, char *file, Boolean probe) +{ + char buf[PATH_MAX], *mp; + FILE *fp; + int nretries = 5; + + /* + * floppies don't use mediaGenericGet() because it's too expensive + * to speculatively open files on a floppy disk. Make user get it + * right or give up with floppies. + */ + mp = dev->private ? (char *)dev->private : mountpoint; + snprintf(buf, PATH_MAX, "%s/%s", mp, file); + if (!file_readable(buf)) { + if (probe) + return NULL; + else { + while (!file_readable(buf)) { + if (!--nretries) { + msgConfirm("GetFloppy: Failed to get %s after retries;\ngiving up.", buf); + return NULL; + } + distWanted = buf; + mediaShutdownFloppy(dev); + if (!mediaInitFloppy(dev)) + return NULL; + } + } + } + fp = fopen(buf, "r"); + return fp; +} + +void +mediaShutdownFloppy(Device *dev) +{ + if (floppyMounted) { + char *mp = dev->private ? (char *)dev->private : mountpoint; + + if (unmount(mp, MNT_FORCE) != 0) + msgDebug("Umount of floppy on %s failed: %s (%d)\n", mp, strerror(errno), errno); + else { + floppyMounted = FALSE; + if (!variable_get(VAR_NONINTERACTIVE) && variable_cmp(SYSTEM_STATE, "fixit")) + msgConfirm("You may remove the floppy from %s", dev->description); + } + } +} diff --git a/usr.sbin/sysinstall/ftp.c b/usr.sbin/sysinstall/ftp.c new file mode 100644 index 0000000000000..c971b79c05aa1 --- /dev/null +++ b/usr.sbin/sysinstall/ftp.c @@ -0,0 +1,288 @@ +/* + * 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 <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <netdb.h> +#include <pwd.h> +#include <ftpio.h> + +Boolean ftpInitted = FALSE; +static FILE *OpenConn; +int FtpPort; + +/* List of sub directories to look for under a given FTP server. */ +#ifdef PC98 +const char *ftp_dirs[] = { ".", "releases/pc98", "snapshots/pc98", + "pub/FreeBSD", "pub/FreeBSD/releases/pc98", + "pub/FreeBSD/snapshots/pc98", NULL }; +#else +const char *ftp_dirs[] = { ".", "releases/"MACHINE, "snapshots/"MACHINE, + "pub/FreeBSD", "pub/FreeBSD/releases/"MACHINE, + "pub/FreeBSD/snapshots/"MACHINE, NULL }; +#endif + +/* Brings up attached network device, if any - takes FTP device as arg */ +static Boolean +netUp(Device *dev) +{ + Device *netdev = (Device *)dev->private; + + if (netdev) + return DEVICE_INIT(netdev); + else + return TRUE; /* No net == happy net */ +} + +/* Brings down attached network device, if any - takes FTP device as arg */ +static void +netDown(Device *dev) +{ + Device *netdev = (Device *)dev->private; + + if (netdev) + DEVICE_SHUTDOWN(netdev); +} + +Boolean +mediaInitFTP(Device *dev) +{ + int i, code, af, fdir; + char *cp, *rel, *hostname, *dir; + char *user, *login_name, password[80]; + + if (ftpInitted) + return TRUE; + + if (OpenConn) { + fclose(OpenConn); + OpenConn = NULL; + } + + /* If we can't initialize the network, bag it! */ + if (!netUp(dev)) + return FALSE; + +try: + cp = variable_get(VAR_FTP_PATH); + if (!cp) { + if (DITEM_STATUS(mediaSetFTP(NULL)) == DITEM_FAILURE || (cp = variable_get(VAR_FTP_PATH)) == NULL) { + msgConfirm("Unable to get proper FTP path. FTP media not initialized."); + netDown(dev); + return FALSE; + } + } + + hostname = variable_get(VAR_FTP_HOST); + dir = variable_get(VAR_FTP_DIR); + if (!hostname || !dir) { + msgConfirm("Missing FTP host or directory specification. FTP media not initialized,"); + netDown(dev); + return FALSE; + } + user = variable_get(VAR_FTP_USER); + login_name = (!user || !*user) ? "anonymous" : user; + + if (variable_get(VAR_FTP_PASS)) + SAFE_STRCPY(password, variable_get(VAR_FTP_PASS)); + else if (RunningAsInit) + sprintf(password, "installer@%s", variable_get(VAR_HOSTNAME)); + else { + struct passwd *pw; + char *user; + + pw = getpwuid(getuid()); + user = pw ? pw->pw_name : "ftp"; + sprintf(password, "%s@%s", user, variable_get(VAR_HOSTNAME)); + } + af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC; + msgNotify("Logging in to %s@%s..", login_name, hostname); + if ((OpenConn = ftpLoginAf(hostname, af, login_name, password, FtpPort, isDebug(), &code)) == NULL) { + msgConfirm("Couldn't open FTP connection to %s:\n %s.", hostname, ftpErrString(code)); + goto punt; + } + + ftpPassive(OpenConn, !strcmp(variable_get(VAR_FTP_STATE), "passive")); + ftpBinary(OpenConn); + if (dir && *dir != '\0') { + if ((i = ftpChdir(OpenConn, dir)) != 0) { + if (i == 550) + msgConfirm("No such directory ftp://%s/%s\n" + "please check your URL and try again.", hostname, dir); + else + msgConfirm("FTP chdir to ftp://%s/%s returned error status:\n %s.", hostname, dir, ftpErrString(i)); + goto punt; + } + } + + /* + * Now that we've verified that the path we're given is ok, let's try to + * be a bit intelligent in locating the release we are looking for. First + * off, if the release is specified as "__RELEASE" or "any", then just + * assume that the current directory is the one we want and give up. + */ + rel = variable_get(VAR_RELNAME); + if (strcmp(rel, "__RELEASE") && strcmp(rel, "any")) { + /* + * Ok, since we have a release variable, let's walk through the list + * of directories looking for a release directory. The first one to + * match wins. For each case, we chdir to ftp_dirs[fdir] first. If + * that fails, we skip to the next one. Otherwise, we try to chdir to + * rel. If it succeeds we break out. If it fails, then we go back to + * the base directory and try again. Lots of chdirs, but oh well. :) + */ + for (fdir = 0; ftp_dirs[fdir]; fdir++) { + /* Avoid sending CWD . commands which confuse some ftp servers */ + if (strcmp(ftp_dirs[fdir], ".") && + (ftpChdir(OpenConn, (char *)ftp_dirs[fdir]) != 0)) + continue; + if (ftpChdir(OpenConn, rel) == 0) { + ftpInitted = TRUE; + return TRUE; + } + else /* reset to "root" dir for a fresh try */ + ftpChdir(OpenConn, "/"); + } + + /* + * If we get here, then all of the directories we tried failed, so + * print out the error message and ask the user if they want to try + * again. + */ + if (!msgYesNo("Warning: Can't find the `%s' distribution on this\n" + "FTP server. You may need to visit a different server for\n" + "the release you are trying to fetch or go to the Options\n" + "menu and to set the release name to explicitly match what's\n" + "available on %s (or set to \"any\").\n\n" + "Would you like to select another FTP server?", + rel, hostname)) { + variable_unset(VAR_FTP_PATH); + if (DITEM_STATUS(mediaSetFTP(NULL)) != DITEM_FAILURE) + goto try; + } + } else { + ftpInitted = TRUE; + return TRUE; + } + +punt: + ftpInitted = FALSE; + if (OpenConn != NULL) { + fclose(OpenConn); + OpenConn = NULL; + } + netDown(dev); + variable_unset(VAR_FTP_PATH); + return FALSE; +} + +FILE * +mediaGetFTP(Device *dev, char *file, Boolean probe) +{ + int nretries = 1; + FILE *fp; + char *try, buf[PATH_MAX]; + + if (!OpenConn) { + msgDebug("No FTP connection open, can't get file %s\n", file); + return NULL; + } + + try = file; + while ((fp = ftpGet(OpenConn, try, 0)) == NULL) { + int ftperr = ftpErrno(OpenConn); + + /* If a hard fail, try to "bounce" the ftp server to clear it */ + if (ftperr != 550) { + if (ftperr != 421) /* Timeout? */ + variable_unset(VAR_FTP_PATH); + /* If we can't re-initialize, just forget it */ + DEVICE_SHUTDOWN(dev); + if (!DEVICE_INIT(dev)) { + netDown(dev); + if (OpenConn) { + fclose(OpenConn); + OpenConn = NULL; + } + variable_unset(VAR_FTP_PATH); + return NULL; + } + } + else if (probe) + return NULL; + else { + /* Try some alternatives */ + switch (nretries++) { + case 1: + sprintf(buf, "releases/%s", file); + try = buf; + break; + + case 2: + sprintf(buf, "%s/%s", variable_get(VAR_RELNAME), file); + try = buf; + break; + + case 3: + sprintf(buf, "%s/releases/%s", variable_get(VAR_RELNAME), file); + try = buf; + break; + + case 4: + try = file; + break; + } + } + } + return fp; +} + +void +mediaShutdownFTP(Device *dev) +{ + if (!ftpInitted) + return; + + if (OpenConn != NULL) { + fclose(OpenConn); + OpenConn = NULL; + } + ftpInitted = FALSE; +} diff --git a/usr.sbin/sysinstall/globals.c b/usr.sbin/sysinstall/globals.c new file mode 100644 index 0000000000000..892d8528bc8a6 --- /dev/null +++ b/usr.sbin/sysinstall/globals.c @@ -0,0 +1,93 @@ +/* + * 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" + +/* + * Various global variables and an initialization hook to set them to + * whatever values we feel are appropriate. + */ + +int DebugFD; /* Where diagnostic output goes */ +Boolean Fake; /* Only pretend to be useful */ +Boolean RunningAsInit; /* Are we running as init? */ +Boolean DialogActive; /* Is libdialog initialized? */ +Boolean ColorDisplay; /* Are we on a color display? */ +Boolean OnVTY; /* Are we on a VTY? */ +Boolean Restarting; /* Are we restarting sysinstall? */ +Variable *VarHead; /* The head of the variable chain */ +Device *mediaDevice; /* Where we're installing from */ +int BootMgr; /* Which boot manager we're using */ +int StatusLine; /* Where to stick our status messages */ +jmp_buf BailOut; /* Beam me up, scotty! The natives are pissed! */ + +Chunk *HomeChunk; +Chunk *RootChunk; +Chunk *SwapChunk; +Chunk *TmpChunk; +Chunk *UsrChunk; +Chunk *VarChunk; +#ifdef __ia64__ +Chunk *EfiChunk; +#endif + +/* + * Yes, I know some of these are already automatically initialized as + * globals. I simply find it clearer to set everything explicitly. + */ +void +globalsInit(void) +{ + DebugFD = -1; + ColorDisplay = FALSE; + Fake = FALSE; + Restarting = FALSE; + OnVTY = FALSE; + DialogActive = FALSE; + VarHead = NULL; + mediaDevice = NULL; + RunningAsInit = FALSE; + + HomeChunk = NULL; + RootChunk = NULL; + SwapChunk = NULL; + TmpChunk = NULL; + UsrChunk = NULL; + VarChunk = NULL; +#ifdef __ia64__ + EfiChunk = NULL; +#endif +} diff --git a/usr.sbin/sysinstall/help/anonftp.hlp b/usr.sbin/sysinstall/help/anonftp.hlp new file mode 100644 index 0000000000000..e90985e235fe3 --- /dev/null +++ b/usr.sbin/sysinstall/help/anonftp.hlp @@ -0,0 +1,19 @@ +This screen allows you to configure the anonymous FTP user. + +The following configuration values are editable: + +UID: The user ID you wish to assign to the anonymous FTP user. + All files uploaded will be owned by this ID. + +Group: Which group you wish the anonymous FTP user to be in. + +Comment: String describing this user in /etc/passwd + + +FTP Root Directory: + + Where files available for anonymous FTP will be kept. + +Upload subdirectory: + + Where files uploaded by anonymous FTP users will go. diff --git a/usr.sbin/sysinstall/help/configure.hlp b/usr.sbin/sysinstall/help/configure.hlp new file mode 100644 index 0000000000000..65be877a3252c --- /dev/null +++ b/usr.sbin/sysinstall/help/configure.hlp @@ -0,0 +1,10 @@ +This menu allows you to configure your system after the installation +process is complete. At the minimum, you should probably set the +system manager's password and the system time zone. + +For extra goodies like bash, emacs, Pascal, etc., you should look at +the Packages item in this menu. + +For setting the timezone after the system is installed, type +``tzsetup''. For more information on the overall general system +configuration, see the ``/etc/defaults/rc.conf'' file. diff --git a/usr.sbin/sysinstall/help/distributions.hlp b/usr.sbin/sysinstall/help/distributions.hlp new file mode 100644 index 0000000000000..b6bae5c9d0585 --- /dev/null +++ b/usr.sbin/sysinstall/help/distributions.hlp @@ -0,0 +1,35 @@ +DISTRIBUTION INFORMATION +------------------------ + +An ``X-'' prefixed before a distribution set means that the XFree86 +base distribution, libraries, manual pages, SVGA server and a set +of default fonts will be selected in addition to the set itself. +If you select such a set, you will also be presented with a set of +menus for customizing the selections to your desired X Window System +setup. + +Any distribution may be further customized by selecting the `Custom' +item before leaving the menu. + +The current "canned" installations are provided: + +Developer: Base ("bin") distribution, man pages, dictionary + files, profiling libraries and the complete source tree. + +Kern-Developer: As above, but with only kernel sources instead of + the complete source tree. + +User: The base distribution, man pages, dictionary files and + the FreeBSD 1.x, 2.0, 2.1.x, 2.2.x and 3.x compatibility sets. + +Minimal: Only the base distribution. + +Everything: The base distribution, man pages, dictionary files, + profiling libraries, the FreeBSD compatibility libraries, + the complete source tree, games and your choice of XFree86 + distribution components. + +Custom: Allows you to create or modify your distribution set on + a piece-by-piece basis. + +Reset: Clear all currently selected distributions. diff --git a/usr.sbin/sysinstall/help/drives.hlp b/usr.sbin/sysinstall/help/drives.hlp new file mode 100644 index 0000000000000..946a1b211b7f0 --- /dev/null +++ b/usr.sbin/sysinstall/help/drives.hlp @@ -0,0 +1,92 @@ +Boot Manager Selection: +----------------------- + +If you wish to switch between multiple operating systems on your +machine, or if you are trying to install FreeBSD on a drive other than +your 1st drive, then you must install a boot manager. In the case +where you wish to boot off an alternate drive, it should also be noted +that you still need to install a boot manager on the FIRST drive! +Even if you do not intend to create a FreeBSD partition on that drive +(e.g. it's being wholly used by something else), the boot manager +still needs to reside on the first disk in order to function as a +"redirector" for the boot process. + +To do this, simply select your 1st drive in the drive selection menu +and when the partition editor comes up, don't make any changes - just +(Q)uit. At the boot manager menu which follows, select the first +option (install a boot manager) and then proceed to setup the other +drive(s) for FreeBSD as normal. + +It should also be noted that "operating systems" such as Windows 95 +will completely overwrite your boot manager without so much as a +polite "may I please destroy your boot manager?" prompt if you make +the mistake of installing them second. If this happens to you after +FreeBSD is already installed, all is not lost! Simply revisit your +FreeBSD distribution directory and look for a tools/ subdirectory, in +which you'll find "bootinst.exe" and "boot.bin". To reinstall, simply +say "bootinst boot.bin" while in the tools/ subdirectory. + + +If you see the boot manager displaying ``F?'' when you try to come up +for the first time and it refuses to change, no matter how often you +whap on the function key assigned to FreeBSD, then you have a geometry +mismatch problem and you should read the next section for important +information on how to prevent that exact problem from happening! + + +Geometry Translation / Sharing the disk(s) with another OS: +---------------------------------------------------------- + +If you are going to actually install some portion of FreeBSD on a +drive then PLEASE BE VERY CERTAIN that the Geometry reported in the +Partition Editor is the correct one for your drive and controller +combination! + +IDE drives often have a certain geometry set during the PC BIOS setup, +or (in the case of larger IDE drives) have their geometry "translated" +by either the IDE controller or a special boot-sector translation +utility such as that by OnTrack Systems. In these cases, knowing the +correct geometry gets even more complicated as it's not something you +can easily tell by looking at the drive or the PC BIOS setup. The +best way of verifying that your geometry is being correctly calculated +in such situations is to boot DOS (from the hard disk, not a floppy!) +and run the ``pfdisk'' utility provided in the tools/ subdirectory of +the FreeBSD CDROM or FTP site. It will report the geometry that DOS +sees, which is generally the correct one. + +If you have no DOS partition sharing the disk at all, then you may +find that you have better luck with Geometry detection if you create a +very small DOS partition first, before installing FreeBSD. Once +FreeBSD is installed you can always delete it again if you need the +space. + +It's actually not a bad idea (believe it or not) to have a small +bootable DOS partition on your FreeBSD machine anyway: Should the +machine become unstable or exhibit strange behavior at some point in +the future (which is not uncommon behavior for PC hardware!) you can +then at least use DOS for installing and running one of the +commercially available system diagnostic utilities. + +IMPORTANT NOTE: + +Any root partition you try to boot from must also reside below the +1024th cylinder. If you're using a translated geometry then this is +probably not a problem, but if you are using a native disk geometry +which exceeds 1024 cylinders then you could have a failure to boot if +you end up installing a root partition (or even just the kernel file +in a root partition) out past cylinder 1024. If you are trying to +share your first disk with FreeBSD and another OS which was installed +previously, you are particularly susceptible to this problem and should +check your disk addresses very carefully. + +If you find that you have insufficient space below cylinder 1024 to +make a root partition for FreeBSD (and again, this ONLY applies to the +root partition - once FreeBSD's kernel is loaded, it doesn't care +about the geometry issues) then you will probably need to install on a +completely different disk (see the boot manager section above) or +resize your existing partitions so that both operating systems can +have boot partitions below cylinder 1024. + +You may blame IBM for the limitations of a 10 bit cylinder address. +"No one will have a disk with more than 1024 cylinders." I'm sure +someone said. diff --git a/usr.sbin/sysinstall/help/fixit.hlp b/usr.sbin/sysinstall/help/fixit.hlp new file mode 100644 index 0000000000000..e47394ecb08c6 --- /dev/null +++ b/usr.sbin/sysinstall/help/fixit.hlp @@ -0,0 +1,7 @@ +A special shell will be launched by this option with a fixit floppy +(or 2nd CDROM) mounted as /mnt2. This provides access to extra +commands under /mnt2 as well as a more complete set of device files in +/mnt2/dev. Some device operations, like fsck and disklabel, may +therefore require you to go to /mnt2/dev and use the entries there +rather than assuming that they will be present in the default /dev +(which came from the boot floppy and is very minimal). diff --git a/usr.sbin/sysinstall/help/html.hlp b/usr.sbin/sysinstall/help/html.hlp new file mode 100644 index 0000000000000..e6f22c44ccb92 --- /dev/null +++ b/usr.sbin/sysinstall/help/html.hlp @@ -0,0 +1,20 @@ +In this screen, you can jump to remote or local HTML +resources such as the FreeBSD Handbook & FreeBSD FAQ +(Frequently Asked Questions) documents located in: + + file:/usr/share/doc/ + +If you've loaded the doc distribution. + +The default browser package used is links (a text based +browser which can render tables), which will be +automatically loaded from the installation media if it +is available. You may change the selection of browser +& browser package to auto-load by visiting the Options +editor. + +In order to visit remote URLs, you naturally must have +some sort of working Internet connection. If you have not +yet brought up any network interfaces, please visit +the ``Networking'' item in the Configuration menu +before attempting to reference any http://.. style URLs. diff --git a/usr.sbin/sysinstall/help/media.hlp b/usr.sbin/sysinstall/help/media.hlp new file mode 100644 index 0000000000000..57ab36fe39ba0 --- /dev/null +++ b/usr.sbin/sysinstall/help/media.hlp @@ -0,0 +1,54 @@ +You can install from the following types of media: + + CDROM requires one of the following supported CDROM drives: + ATAPI - Any standard ATAPI CDROM driver hooked to + a supported controller <see Hardware Guide). + SCSI - Any standard SCSI CDROM drive hooked to + a supported controller (see Hardware Guide). + + + DOS A DOS primary partition with the required FreeBSD + distribution files copied onto it (e.g. C:\FREEBSD\) + + + FS Assuming a disk or partition with an existing + FreeBSD file system and distribution set on it, + get the distribution files from there. + + + Floppy Get distribution files from one or more DOS or UFS + formatted floppies. Such floppies are assumed to + contain the appropriate distribution pieces - see + ABOUT.TXT for more information about making floppy + distribution media. + + + FTP Get the distribution files from an anonymous ftp server + (you will be presented with a list). Please note that + you may invoke FTP in "Active" mode, "Passive" mode, or + via an HTTP proxy. + + Active mode is the standard way of fetching files and + Passive mode is for use when you're behind a firewall or + some other security mechanism that blocks active FTP + connections. Using an HTTP proxy is sometimes necessary + for firewalls which block all FTP connections. + + If you chose to enter your own URL in the FTP menu, please + note that all paths are *relative* to the home directory + of the user being logged in as. By default, this is the + user "ftp" (anonymous ftp) but you may change this in the + Options screen. + + + NFS Get the distribution files from an NFS server somewhere + (make sure that permissions on the server allow this!). + If this install method hangs on you or refuses to work + properly, you may need to set some special options for + your NFS server. See the Options screen for more details. + + + Tape Extract distribution files from tape into a temporary + directory and install from there. If the tape was created + with blocksize other than 20, you may wish to change this + in the Options screen. diff --git a/usr.sbin/sysinstall/help/network_device.hlp b/usr.sbin/sysinstall/help/network_device.hlp new file mode 100644 index 0000000000000..a65467bf63944 --- /dev/null +++ b/usr.sbin/sysinstall/help/network_device.hlp @@ -0,0 +1,58 @@ +You can do network installations over 3 types of communications links: + + Serial port: SLIP / PPP + Parallel port: PLIP (laplink cable) + Ethernet: A standard Ethernet controller (includes some + PCMCIA networking cards). + +SLIP support is rather primitive and limited primarily to directly +connected links, such as a serial cable running between a laptop +computer and another PC. The link must be hard-wired as the SLIP +installation doesn't currently offer a dialing capability (that +facility is offered by the PPP utility, which should be used in +preference to SLIP whenever possible). When you choose the SLIP +option, you'll be given the option of later editing the slattach +command before it's run on the serial line. It is expected that +you'll run slattach (or some equivalent command) on the other end of +the link at that time and bring up the line. FreeBSD will then +install itself at serial speeds of up to 115.2K/baud (the recommended +speed for a hardwired cable). + +If you're using a modem then PPP is almost certainly your only choice. +Make sure that you have your service provider's information handy as +you'll need to know it fairly early in the installation process. You +will need to know your service provider's IP address, the IP address +of your provider's DNS server, and possibly your own IP address unless +your ISP supports dynamic negotiation, most do. If you do not choose +a PAP or CHAP login you will also need to know how to use the various +"AT commands" to dial the ISP with your particular brand of modem as +the PPP dialer provides only a very simple terminal emulator and has no +"modem capabilities database". If you choose a PAP or CHAP login you +can simply enter `dial' (without the quotes) at the ppp prompt if your +modem uses the Hayes compatible AT command set. + +If a hard-wired connection to another FreeBSD (2.0R or later) machine +is available, you might also consider installing over a "laplink" +parallel port cable. The data rate over the parallel port is much +higher than what is typically possible over a serial line, and speeds +of over 50KB/sec are not uncommon. + +Finally, for the fastest possible network installation, an Ethernet +adaptor is always a good choice! FreeBSD supports most common PC +Ethernet cards, a table of which is provided in the FreeBSD Hardware +Guide (see the Documentation menu on the boot floppy). If you are +using one of the supported PCMCIA Ethernet cards, also be sure that +it's plugged in _before_ the laptop is powered on! FreeBSD does not, +unfortunately, currently support "hot insertion" of PCMCIA cards. + +You will also need to know your IP address on the network, the +"netmask" value for your address class, and the name of your machine. +Your system administrator can tell you which values to use for your +particular network setup. If you will be referring to other hosts by +name rather than IP address, you'll also need a name server and +possibly the address of a gateway (if you're using PPP, it's your +provider's IP address) to use in talking to it. If you do not know +the answers to all or most of these questions then you should really +probably talk to your system administrator FIRST before trying this +type of installation! Choosing the wrong IP address on a busy network +will NOT make you popular with your systems administrator! :-) diff --git a/usr.sbin/sysinstall/help/options.hlp b/usr.sbin/sysinstall/help/options.hlp new file mode 100644 index 0000000000000..1f3217220cfcd --- /dev/null +++ b/usr.sbin/sysinstall/help/options.hlp @@ -0,0 +1,124 @@ +The following options may be set from this screen. Use the SPACE key +to toggle an option's value, Q to leave when you're done. + +NFS Secure: NFS server talks only on a secure port + + This is most commonly used when talking to Sun workstations, which + will not talk NFS over "non privileged" ports. + + +NFS Slow: User is using a slow PC or Ethernet card + + Use this option if you have a slow PC (386) or an Ethernet card + with poor performance being "fed" by NFS on a higher-performance + workstation. This will throttle the workstation back to prevent + the PC from becoming swamped with data. + + +Debugging: Turn on the extra debugging flag + + This turns on a lot of extra noise over on the second screen + (ALT-F2 to see it, ALT-F1 to switch back). If your installation + should fail for any reason, PLEASE turn this flag on when + attempting to reproduce the problem. It will provide a lot of + extra debugging at the failure point and may be very helpful to + the developers in tracking such problems down! + + +Yes To All: Assume "Yes" answers to all non-critical dialogs + + This flag should be used with caution. It will essentially + decide NOT to ask the user about any "boundary" conditions that + might not constitute actual errors but may be warnings indicative + of other problems. It's most useful to those who are doing unattended + installs. + + +FTP username: Specify username and password instead of anonymous. + + By default, the installation attempts to log in as the + anonymous user. If you wish to log in as someone else, + specify the username and password with this option. + + +Install Root: Specify some directory other than / as your "root". + + This should be left as / unless you have a really good reason to + change it. One good reason might be if you were installing to a + disk other than your own, as might happen if you needed to prepare a + disk for another machine which couldn't load FreeBSD directly + for some reason. + + Note: If you set this option, you will only be able to install + packages if the bin distribution is also installed (usually + the case anyway) since /usr/sbin/pkg_add will otherwise not be + found after the chroot() call. + + +Editor: Specify which screen editor to use. + + At various points during the installation it may be necessary + to customize some text file, at which point the user will be + thrown unceremoniously into a screen editor. A relatively + simplistic editor which shows its command set on-screen is + selected by default, but UNIX purists may wish to change this + setting to /usr/bin/vi + + +Tape Blocksize: Specify block size in 512 byte blocks of tape. + + This defaults to 20 blocks, which should work with most + tape drive + tar combinations. It may not allow your particular + drive to win any records for speed, however, and the more + adventurous among you might try experimenting with larger sizes. + + +Extract Detail: How to show filenames on debug screen as they're extracted. + + While a distribution is being extracted, the default detail level + of "high" will show the full file names as they're extracted. + If you would prefer a more terse form for this, namely dots, select + the "medium" detail level. If you want nothing to be printed + on the debugging screen during extraction, select "low". + + +Release Name: Which release to attempt to load from installation media. + + You should only change this option if you're really sure you know + what you are doing! This will change the release name used by + sysinstall when fetching components of any distributions, and + is a useful way of using a more recent installation boot floppy + with an older release (say, on CDROM). + + +Browser Package: Which package to load for an HTML browser. + + By default, this is set to links but may also be set to any other + text capable HTML browser for which a package exists. If you set this + to an X based browser, you will not be able to use it if you're running + in text mode! :) + + +Browser Exec: Which binary to run for the HTML browser. + + The full pathname to the main executable in Browser Package + + +Media Type: Which media type is being used. + + This is mostly informational and indicates which media type (if any) + was last selected in the Media menu. It's also a convenient short-cut + to the media menu itself. + + +Package Temp: Where package temporary files should go + + Some packages, like emacs, can use a LOT of temporary space - up to + 20 or 30MB. If you are going to configure a small / directory (and + hence a small /tmp) then you may wish to set this to point at another + location (say, /usr/tmp). + + +Use Defaults: Use default values. + + Reset all options back to their default values. diff --git a/usr.sbin/sysinstall/help/partition.hlp b/usr.sbin/sysinstall/help/partition.hlp new file mode 100644 index 0000000000000..1d62148e88f96 --- /dev/null +++ b/usr.sbin/sysinstall/help/partition.hlp @@ -0,0 +1,169 @@ +This is the FreeBSD DiskLabel Editor. + +NOTE: If you're entering this editor from the update procedure then +you probably shouldn't (C)reate anything at all but rather use only +the (M)ount command to check and mount existing partitions for +upgrading. + +If you would like the label editor to do most of the following for +you, simply type `A' for automatic partitioning of the disk. + +If you wish to create partitions manually you may do so by moving the +highlighted selection bar with the arrow keys over the FreeBSD +partition(s) displayed at the top of the screen. Typing (C)reate +while a partition with available free space is selected will allow you +to create a BSD partition inside of it using some or all of its +available space. + +Typing (M)ount over an existing partition entry (displayed in the +middle of the screen) will allow you to set a mount point for it +without initializing it. If you want it initialized, use the (T)oggle +command to flip the Newfs flag. When Newfs is set to "Y", the +filesystem in question will be ERASED and rebuilt from scratch! + + +You should use this editor to create at least the following +filesystems: + + Name Purpose Min Size? Optional? + ---- ------- --------- --------- + / Root filesystem 118MB No + swap Swap space 2 * MEM No + /usr System & user files 80MB or more Yes + +Note: If you do not create a /usr filesystem then your / filesystem +will need to be bigger - at least 200MB. This is not recommended as +any media errors that may occur during disk I/O to user files will +corrupt the filesystem containing vital system files as well. It is +for this reason that / is generally kept on its own filesystem, where +it should be considered essentially "read only" in your administration +of it. + +Swap space is a little tricker, and the rule of "2 * MEM" is simply a +best-guess approximation and not necessarily accurate for your +intended usage of the system. If you intend to use the system heavily +in a server or multi-user application, you may be well advised to +increase this size. You may also create swap space on multiple drives +for a larger "total" swap and this is, in fact, recommended if you +have multiple, fast drives for which such load-balancing can only help +overall I/O performance. + +The /usr filesystem should be sized according to what kind of +distributions you're trying to load and how many packages you intend +to install in locations like /usr/local. You can also make /usr/local +a separate filesystem if you don't want to risk filling up your /usr +by mistake. + +Another useful filesystem to create is /var, which contains mail, news +printer spool files and other temporary items. It is a popular +candidate for a separate partition and should be sized according to +your estimates of the amount of mail, news or spooled print jobs that +may be stored there. + +WARNING: If you do not create a separate filesystem for /var, space +for such files will be allocated out of the root (/) filesystem +instead. You may therefore wish to make the / partition bigger if you +expect a lot of mail or news and do not want to make /var its own +partition. + +If you're new to this installation, you might also want to read the +following explanation of how FreeBSD's new "slice" paradigm for +looking at disk storage works: + + +In FreeBSD's new system, a device name can be broken up into up to 3 +parts. Take a typical name like ``/dev/da0s1a'': + + The first three characters represent the drive name. If we had + a system with two SCSI drives on it then we'd see /dev/da0 and + /dev/da1 as the device entries representing the entire drives. + + Next you have the "slice" (or "FDISK Partition") number, + as seen in the Partition Editor. Assuming that our da0 + contained two slices, a FreeBSD slice and a DOS slice, that + would give us /dev/da0s1 and /dev/da0s2 as device entries pointing + to the entire slices. + + Next, if a slice is a FreeBSD slice, you can have a number of + (confusingly named) "partitions" inside of it. + + These partitions are where various filesystems or swap areas live, + and using our hypothetical two-SCSI-disk machine again, we might + have something like the following layout on da0: + + Name Mountpoint + ---- ---------- + da0s1a / + da0s1b <swap space> + da0s1e /usr + +Once you understand all this, then the purpose of the label editor +becomes fairly clear: You're carving up the FreeBSD slices displayed +at the top of the screen into smaller pieces, which are displayed in +the middle of the screen, and then assigning FreeBSD file system names +(mount points) to them. + +You can also use the label editor to mount existing partitions/slices +into your filesystem hierarchy, as is frequently done for DOS FAT +slices. For FreeBSD partitions, you can also toggle the "newfs" state +so that the partitions are either (re)created from scratch or simply +checked and mounted (the contents are preserved). + +If you set (S)oftUpdates on a filesystem, it will cause the +"Soft Updates" policy to be in effect for it. This basically causes +both metadata and data blocks to be written asynchronously to disk, +but with extra state information which causes the metadata and any +related data blocks to be committed in a single transaction. This +results in async metadata update speeds (which are considerably +faster than the default sync) without the potential for data loss +which could occur if you simply mounted the filesystem with purely +"async" update policy and then had a power failure. If you wish +to later turn the softupdates policy back off, use the command +"tunefs -n disable devicename". NOTE: It is probably not wise +to use this on your root filesystem unless you have a large +(e.g. non-standard size) root. The reason is that smaller filesystems +with significant activity can temporarily overflow if the soft updates +policy results in free'd blocks not being "garbage collected" as fast +as they're being requested. + +The UNIX File System (UFS) on FreeBSD supports two different on-disk +layouts: UFS1 and UFS2. UFS1 was the default file system in use +through FreeBSD 5.0-RELEASE; as of FreeBSD 5.1-RELEASE, the default +is now UFS2, with the exception of the PC98 platform. UFS2 provides +sparse inode allocation (faster fsck), 64-bit storage pointers (larger +maximum size), and native extended attributes (required for ACLs, MAC, +and other advanced security and file system services). The selection +of UFS1 or UFS2 must be made when the file system is created--later +conversion is not currently possible. UFS2 is the recommended file +system, but if disks are to be used on older FreeBSD systems, UFS1 +improves portability. When dual-booting between FreeBSD 4.x or +earlier and FreeBSD 5.x, UFS1 file systems will be accessible from +both. To toggle a file system to UFS1, press '1'. To restore it to +UFS2, press '2'. + +WARNING: FreeBSD on i386 is currently unable to boot from root file +systems larger than 1.5TB. + +To add additional flags to the newfs command line for UFS file +systems, press 'N'. These options will be specified before the +device argument of the command line, but after any other options +placed there by sysinstall, such as the UFS version and soft +updates flag; as such, arguments provided may override existing +settings. To completely replace the newfs command used by +sysinstall, press 'Z' to convert a partition to a Custom +partition type. Sysinstall will prompt you with the newfs +command line that it would have used based on existing settings +prior to the change, but allow you to modify any aspect of the +command line. Once a partition has been converted to a custom +partition in the label editor, you will need to restart the +labeling process or delete and recreate the partition to restore +it to a non-custom state. Custom partitions are represented by +the letters "CST" instead of "UFS" or "FAT. + +When you're done, type `Q' to exit. + +No actual changes will be made to the disk until you (C)ommit from the +Install menu or (W)rite directly from this one. You're working with +what is essentially a copy of the disk label(s), both here and in the +FDISK Partition Editor, and the actual on-disk labels won't be +affected by any changes you make until you explicitly say so. diff --git a/usr.sbin/sysinstall/help/register.hlp b/usr.sbin/sysinstall/help/register.hlp new file mode 100644 index 0000000000000..811f71d7394d2 --- /dev/null +++ b/usr.sbin/sysinstall/help/register.hlp @@ -0,0 +1,76 @@ +This screen allows you to register yourself with the FreeBSD Project's +user counter & statistics database. + +** IT IS VERY IMPORTANT THAT YOU DO THIS! ** + +Believe me, I hate filling out forms as much as anyone, and most +people's understandable reaction to a registration form is to say "Eh, +what's this? They want to send me junk mail and then on top of that +they expect me to go to *extra* trouble in order to make it easy for +them?! Forget it!" + +This is not that kind of registration, and I strongly urge you to take +just a few minutes to read this and find out how much the simple act +of registering can help both you and FreeBSD. + +1. It is very much in your best interest, as a FreeBSD user, to stand + up and be counted so that various software vendors will begin to + take you and your operating system seriously. There are numerous + ISVs (Independent Software Vendors) who would be only too happy + to port the kinds of applications that many FreeBSD users are + currently screaming for (everything from spreadsheets and word + processing packages to games) if they only had some idea that it + might be worth the trouble. The only way to convince the ISVs that + FreeBSD is worth their trouble is to show them how many users + we have, and to do that we need your registration! At this time + we literally do not know how many users FreeBSD has, and that's + hardly helpful when you're trying to convince someone to port + software to it. + + +2. We will not send you *anything* you do not ask for. Some people + are genuinely interested in new product announcements for FreeBSD + or want to hear about security issues & other important advisories + as they come up, and for such people we've added registration + options for selecting various types of additional material they + might be interested in receiving as a side-effect of registration. + + The default behavior is to NOT put the user on any special mailing + lists or provide their names in mailing list data sent to + (carefully screened) FreeBSD product advertisers - all of that must + be specifically requested during the registration. + +Most fields in the form are fairly self-explanatory. At the minimum, +you should enter your first and last name as well as your email +address so that we can weed obvious duplicates from the counter. You +will NOT be sent any mail at this address unless you also sign up for +one of the additional notification services, and it's only used to +provide us with a way of differentiating "John Smith <smith@foo.org>" +from "John Smith <jsm@bar.com>" in the simple, no-frills registration +case. If you do not have an email address, some sort of postal +address will serve the same purpose. + +If you also wish to receive the FreeBSD Newsletter, published and +distributed free of charge by Walnut Creek CDROM in printed form, +then you must specify some sort of postal address. Likewise, if you +elect to receive notification on the email version then you should +specify a valid Email address. Back-issues of the FreeBSD newsletter +are available at ftp://ftp.freebsd.org/pub/FreeBSD/doc/newsletter/ . + +Should you wish to unsubscribe to the FreeBSD Newsletter or otherwise +de-register yourself at a later time, you can simply send mail to +register-request@freebsd.org. If you subscribe to the announce +mailing list (and it's a good idea) then you can modify your +subscription at any time by sending mail to majordomo@freebsd.org + + +Your cooperation with this new registration service is greatly +appreciated, and by taking just 5 minutes to fill this out now you +will be helping us to gather data which will greatly assist FreeBSD in +firmly establishing a position as a serious UN*X operating system +contender. + +Regards, + + Jordan Hubbard, + FreeBSD PR Officer diff --git a/usr.sbin/sysinstall/help/securelevel.hlp b/usr.sbin/sysinstall/help/securelevel.hlp new file mode 100644 index 0000000000000..c0964e439d414 --- /dev/null +++ b/usr.sbin/sysinstall/help/securelevel.hlp @@ -0,0 +1,38 @@ +This menu allows you to configure the Securelevel mechanism in FreeBSD. + +Securelevels may be used to limit the privileges assigned to the +root user in multi-user mode, which in turn may limit the effects of +a root compromise, at the cost of reducing administrative functions. +Refer to the init(8) manual page for complete details. + + -1 Permanently insecure mode - always run the system in level 0 + mode. This is the default initial value. + + 0 Insecure mode - immutable and append-only flags may be turned + off. All devices may be read or written subject to their + permissions. + + 1 Secure mode - the system immutable and system append-only + flags may not be turned off; disks for mounted file systems, + /dev/mem, and /dev/kmem may not be opened for writing; kernel + modules (see kld(4)) may not be loaded or unloaded. + + 2 Highly secure mode - same as secure mode, plus disks may not + be opened for writing (except by mount(2)) whether mounted or + not. This level precludes tampering with file systems by + unmounting them, but also inhibits running newfs(8) while the + system is multi- user. + + In addition, kernel time changes are restricted to less than + or equal to one second. Attempts to change the time by more + than this will log the message ``Time adjustment clamped to +1 + second''. + + 3 Network secure mode - same as highly secure mode, plus IP + packet filter rules (see ipfw(8) and ipfirewall(4)) cannot be + changed and dummynet(4) configuration cannot be adjusted. + +Securelevels must be used in combination with careful system design and +application of protective mechanisms to prevent system configuration +files from being modified in a way that compromises the protections of +the securelevel variable upon reboot. diff --git a/usr.sbin/sysinstall/help/shortcuts.hlp b/usr.sbin/sysinstall/help/shortcuts.hlp new file mode 100644 index 0000000000000..8964ead9ff697 --- /dev/null +++ b/usr.sbin/sysinstall/help/shortcuts.hlp @@ -0,0 +1,114 @@ +/stand/sysinstall now supports command-line "shortcuts" which can +often replace outdated commands, like pkg_manage. Multiple commands +can be invoked in sequence, and variables may be set on-the-fly to +customize the installation program's behavior in various ways. + +Syntax: + +/stand/sysinstall [var=value ..] [command ..] + +Where "var" can be one or more of: + +blanktime Screen blank time setting in seconds +bootManager Select boot manager: booteasy, standard or none +browserBinary Which doc browser to use (default: links) +browserPackage Which package to get browser from (default: links) +cpioVerbose How verbose to be with cpio: high, medium or low +debug Extra debugging? +disk Which disk to operate on (wd0, da0, etc). +domainname Domain name +editor Which screen editor to use +ifconfig_<iface> For each <iface> in network_devices +ftpDirectory Root of the FreeBSD distribution tree on FTP server +ftpOnError Set to retry or abort +ftpPass Which password to use when logging into FTP server +ftp Which FTP site/dir to use (URL ftp://site/dir/..) +ftpPort Which FTP port to use (default: 21) +ftpRetryCount How many times to retry a fetch operation +ftpUser Which username to use when logging into FTP server +ftpHost Which FTP hostname to use (overrides ftp variable) +gated Use gated instead of routed +defaultrouter IP address of default route +geometry Geometry to use for selected disk ("cyl/hd/sec") +hostname Fully qualified domain name for host. +network_interfaces Which network interfaces to configure +ipaddr IP address for this host's primary interface +nameserver IP address of name server +netmask Netmask for this host's primary interface +nfs Full host:/path/ specification to NFS media +nfsHost Host portion of nfs path +nfsSecure Use NFS secure mount (-P flag) +nfs_server Configure this machine as an NFS server +noConfirm Don't ask for confirmation on non-fatal errors +ntpDate Which ntp clock synchronization server to use +pcnfsd Install the PCNFSD package +ports Path to the ports collection +releaseName Which FreeBSD release to install +rootSize Size of the root partition to create for Auto +routedflags Which flags to pass to routed, if enabled +serialSpeed How fast to run a SLIP/PPP connection +slowEthernetCard PC ethernet card is uncommonly slow +swapSize Size of the swap partition to create for Auto +tapeBlocksize Tape size in blocks +ufs Full path to UFS media directory +usrSize Size of the /usr partition to create for Auto +varSize Size of the /var partition to create for Auto + +And "command" can be one or more of: + +addUser Add a new user to the system +addGroup Add a new group to the system +configAnonFTP Configure system for anonymous FTP +configGated Configure and install gated +configNFSServer Configure host as an NFS server +configPackages Browse / install packages +diskPartitionEditor Partition a new or existing disk +diskPartitionWrite Write out any changed partition information +diskLabelEditor Label/Newfs/Mount new or existing filesystems +diskLabelCommit Write out any changed label information +distReset Reset distribution information +distSetDeveloper Select developer distribution +distSetXDeveloper Select X developer distribution +distSetKernDeveloper Select kernel developer distribution +distSetUser Select user distribution +distSetXUser Select X user distribution +distSetMinimum Select minimal distribution +distSetEverything Select all distributions +distSetDES Select DES sub-distributions +distSetSrc Select source sub-distributions +distSetXF86 Select XFree86 sub-distributions +distExtractAll Extract all selected distributions +docBrowser Browse documentation +installCommit Commit any pending installation operations +installExpress Express installation +installUpgrade Upgrade installation +installFixup Go into "fixit" mode +mediaSetCDROM Select CDROM media +mediaSetFloppy Select floppy media +mediaSetDOS Select DOS media +mediaSetTape Select tape media +mediaSetFTP Select FTP media +mediaSetFTPPassive Select FTP media in passive mode +mediaSetUFS Select UFS media +mediaSetNFS Select NFS media +mediaSetFtpUserPass Prompt for FTP username and password +mediaSetCPIOVerbosity Prompt for CPIO verbosity +mediaGetType Prompt for media type +optionsEditor Go to options editor +register Go to registration editor. + +Examples: + +/stand/sysinstall mediaSetFTP configPackages + +Selects an FTP site and then goes to the package configuration menu. + + +/stand/sysinstall disk=da0 diskPartitionEditor + +Invokes the disk partition editor on disk da0. + + +If /stand/sysinstall is linked to another filename, say +`/usr/local/bin/configPackages', then the basename will be used +as an implicit command name. diff --git a/usr.sbin/sysinstall/help/slice.hlp b/usr.sbin/sysinstall/help/slice.hlp new file mode 100644 index 0000000000000..b6f6a831ba032 --- /dev/null +++ b/usr.sbin/sysinstall/help/slice.hlp @@ -0,0 +1,65 @@ +This is the Main Slice (``FDISK'' or PC-style Partition) Editor. + +Possible commands are printed at the bottom and the Master Boot Record +contents are shown at the top. You can move up and down with the +arrow keys and (C)reate a new slice whenever the highlighted +selection bar is over a slice whose type is marked as "unused." + +You are expected to leave this screen with at least one slice +marked "FreeBSD." Note that unlike Linux, you don't need to create +multiple FreeBSD FDISK partition entries for different things like +swap, file systems, etc. The usual convention is to create ONE +FreeBSD slice (FDISK partition) per drive and then subsection this slice +into swap and file systems with the Label editor. + +No actual changes will be made to the disk until you (C)ommit from the +Install menu or use the (W)rite option here! You're working with what +is essentially a copy of the disk label(s), both here and in the Label +Editor. + +If you want to use the entire disk for FreeBSD, type `A'. You'll be +asked whether or not you wish to keep the disk (potentially) compatible +with other operating systems, i.e. the information in the FDISK table +should be kept valid. If you select the default of `Yes', slices will be +aligned to fictitious cylinder boundaries and space will be reserved +in front of the FreeBSD slice for a [future] possible boot manager. + +For the truly dedicated disk case, you can select `No' at the +compatibility prompt. In that case, all BIOS geometry considerations +will no longer be in effect and you can safely ignore any +``The detected geometry is invalid'' warning messages you may later +see. It is also not necessary in this case to set a slice bootable +or install an MBR boot manager as both things are then irrelevant. + +The FreeBSD slice will start at absolute sector 0 of the disk (so that +FreeBSD's disk label is identical to the Master Boot Record) and +extend to the very last sector of the disk medium. Needless to say, +such a disk cannot have any sort of a boot manager, `disk manager', +or anything else that has to interact with the BIOS. This option is +therefore only considered safe for SCSI disks and most IDE disks and +is primarily intended for people who are going to set up a dedicated +FreeBSD server or workstation, not a typical `home PC'. + +The flags field has the following legend: + + '=' -- This slice is properly aligned. + '>' -- This slice doesn't end before cylinder 1024 + 'R' -- This slice contains the root (/) filesystem + 'B' -- Slice employs BAD144 bad-spot handling + 'C' -- This is the FreeBSD 2.0-compatibility slice (default) + 'A' -- This slice is marked active. + +If you select a slice for Bad144 handling, it will be scanned +for bad blocks before any new filesystems are made on it. + +If no slice is marked Active, you will need to either install +a Boot Manager (the option for which will be presented later in the +installation) or set one Active before leaving this screen. + +To leave the slice editor, type `Q'. + +Final Note: If you're absolutely sure you know what you're doing + and you want to use the old "Dangerously Dedicated" mode + which is now deprecated by sysinstall, use the (purposely) + undocumented `F' key. + diff --git a/usr.sbin/sysinstall/help/tcp.hlp b/usr.sbin/sysinstall/help/tcp.hlp new file mode 100644 index 0000000000000..d79cf2732bc15 --- /dev/null +++ b/usr.sbin/sysinstall/help/tcp.hlp @@ -0,0 +1,34 @@ +This screen allows you to set up your general network parameters +(hostname, domain name, DNS server, etc) as well as the settings for a +given interface (which was selected from the menu before this screen). + +PLIP/SLIP users - please read through to the end of this doc! + +You can move through the fields with the TAB, BACK-TAB and ENTER +keys. To edit a field, use DELETE or BACKSPACE. You may also use ^A +(control-A) to go to the beginning of the line, ^E (control-E) to go +to the end, ^F (control-F) to go forward a character, ^B (control-B) +to go backward one character, ^D (control-D) to delete the character +under the cursor and ^K (control-K) to delete to the end of the line. +Basically, the standard EMACS motion sequences. + +The "Extra options to ifconfig" field is kind of special (read: a +hack :-): + +If you're running SLIP or PLIP, you also need to use it for specifying +the remote end of the link (simply type the foreign IP address in). +In the specific case where you're running PLIP with a Linux host peer +rather than a FreeBSD one, you also must add the "-link0" flag after the +foreign address. + + +If you're dealing with an ethernet adaptor with multiple media +connectors (e.g. AUI, 10BT, 10B2, etc), you can use this field to +specify which one to use. The following strings are recognized: + + "media 10base5/AUI" - Select the AUI port. + "media 10baseT/UTP" - Select the twisted pair port. + "media 10base2/BNC" - Select the BNC connector. + "media 100baseTX" - Select 100BaseT on a 100/10 dual adaptor. + +When you're done with this form, select OK. diff --git a/usr.sbin/sysinstall/help/usage.hlp b/usr.sbin/sysinstall/help/usage.hlp new file mode 100644 index 0000000000000..e67d548a54c3d --- /dev/null +++ b/usr.sbin/sysinstall/help/usage.hlp @@ -0,0 +1,65 @@ +HOW TO USE THIS SYSTEM +====================== + +[press the PageDown key to go to the next screen when you finish + reading this one] + +The following keys are recognized in most of the dialogs you'll +encounter during this installation: + +KEY ACTION +--- ------ +SPACE Select or toggle the current item. +ENTER Finish with a menu or item. +UP ARROW Move to previous item (or up, in a text display box). +DOWN ARROW Move to next item (or down, in a text display box). +TAB Move to next item or group. +RIGHT ARROW Move to next item or group (same as TAB). +SHIFT-TAB Move to previous item or group. +LEFT ARROW Move to previous item or group (same as SHIFT-TAB). +PAGE UP In text display boxes, scrolls up one page. +PAGE DOWN In text display boxes, scrolls down one page. +F1 Display associated help text. + +If you see small "^(-)" or "v(+)" symbols at the edges of a menu, it +means that there are more items above or below the current one that +aren't being shown (due to insufficient screen space). In text +display boxes, the amount of text above the current point will be +displayed as a percentage in the lower right corner. Using the +Up/Down arrow keys will cause the object to scroll by line. The +PageUp and PageDown keys will scroll by entire screens. + +Selecting OK in a menu will confirm whatever action it's controlling. +Selecting Cancel will cancel the operation and generally return you to +the previous menu. Use TAB to move the cursor around and select the +buttons. + +Most screens obey the Help key (F1) - USE IT! It generally offers useful +context-specific hints on what to do at each stage of the installation, +and if you're at all unsure about what to do at a given stage in the +installation, hit F1! + + +SPECIAL FEATURES: +================= + +It is possible to select a menu item by typing the first character of +its name, if unique. This will generally be an item number. + +The console driver contains a scroll-back buffer for reviewing things +that may have scrolled off the screen. To use scroll-back, press the +"Scroll Lock" key on your keyboard and use the arrow or Page Up/Page +Down keys to move through the saved text. To leave scroll-back mode, +press the Scroll Lock key again. This feature is most useful for +reading back through your boot messages (go ahead, try it now!) though +it's also useful when dealing with sub-shells or other "wizard modes" +that don't use menus and tend to scroll their output off the top of +the screen. + +FreeBSD also supports multiple "virtual consoles" which you can use to +in order to have several active sessions at once. Use ALT-F<n> to +switch between screens, where `F<n>' is the function key corresponding +to the screen you wish to see. By default, the system comes with 8 +virtual consoles enabled - you can enable more by editing the +/etc/ttys file and turning the "off" field to "on" in the relevant vty +entries (up to 12). diff --git a/usr.sbin/sysinstall/help/usermgmt.hlp b/usr.sbin/sysinstall/help/usermgmt.hlp new file mode 100644 index 0000000000000..d0819fe1df339 --- /dev/null +++ b/usr.sbin/sysinstall/help/usermgmt.hlp @@ -0,0 +1,89 @@ +These screens allow you to add groups and users to your system. + +You can move through the fields with the TAB, BACK-TAB and ENTER +keys. To edit a field, use DELETE or BACKSPACE. You may also use ^A +(control-A) to go to the beginning of the line, ^E (control-E) to go +to the end, ^F (control-F) to go forward a character, ^B (control-B) +to go backward one character, ^D (control-D) to delete the character +under the cursor and ^K (control-K) to delete to the end of the line. +Basically, the standard EMACS motion sequences. + +When you're done with this form, select OK. + +Many of the settings get reasonable defaults if you leave them blank. +The first time you have entered the name of the new group or user, the +system will show you what it would chose for most of these fields. +You are free to change them, of course. + + +User groups +=========== + +It's certainly almost generally a good idea to first create a new +group for your users. Common names for such a group are "users", or +even simply "other". Group names are used to control file access +permissions for users that belong to the same group. Several group +names are already used for system files. + +The numerical user or group IDs are often nothing you want to care for +explicitly. If you don't fill in these fields, the system will chose +reasonable defaults. However, these numbers (rather than the +associated names) are what the operating system actually uses to +distinguish users and groups -- hence they should normally be unique +to each person or group, respectively. + +(The initial membership list for a new group is currently +unimplemented, sorry.) + + +Users +===== + +The user's login ID is a short (up to 15 characters) alphanumeric ID +the user must enter when logging into the system. It's often the +initial letters of the user's name, and commonly used in lower case. +It's also the local mail name for this user (though it's possible to +also setup more descriptive mail alias names later). + +The user's login group determines which group access rights the user +will initially get when logging in. If an additional list of groups is +provided where the user will become a member of, (s)he will also be +able to access files of those groups later without providing any +additional password etc. Except for the "wheel" case mentioned below, +the additional group membership list should normally not contain the +login group again. + +The user's password can also be set here, and should be chosen with +care - 6 or more characters, intermixing punctuation and numerics, and +*not* a word from the dictionary or related to the username is a good +password choice. + +Some of the system's groups have a special meaning. In particular, +members of group "wheel" are the only people who are later allowed to +become superuser using the command su(1). So if you're going to add a +new user who should later perform administrative tasks, don't forget +to add him to this group! (Well, ``he'' will most likely be yourself +in the very first place. :) + +Also, members of group "operator" will by default get permissions for +minor administrative operations, like performing system backups, or +shutting down the system -- without first becoming superuser! So, +take care with adding people to this group. + +The ``full name'' field serves as a comment only. It is also used by +mail front ends to determine the real name of the user, hence you +should actually fill in the first and last name of this user. By +convention, this field can be divided into comma-separated subfields, +where the office location, the work phone number, and the home phone +number follow the full name of the user. + +The home directory is the directory in the filesystem where the user +is being logged into, and where his personalized setup files (``dot +files'', since they usually begin with a `.' and are not displayed by +the ls(1) command by default) will be looked up. It is often created +under /usr/home/ or /home/. + +Finally, the shell is the user's initial command interpreter. The +default shell is /bin/sh, some users prefer the more historic +/bin/csh. Other, often more user-friendly and comfortable shells can +be found in the ports and packages collection. diff --git a/usr.sbin/sysinstall/http.c b/usr.sbin/sysinstall/http.c new file mode 100644 index 0000000000000..19c826465e080 --- /dev/null +++ b/usr.sbin/sysinstall/http.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 1999 + * Philipp Mergenthaler <philipp.mergenthaler@stud.uni-karlsruhe.de> + * 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. + * 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 AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#include "sysinstall.h" +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/param.h> +#include <netdb.h> + +extern const char *ftp_dirs[]; /* defined in ftp.c */ + +Boolean +checkAccess(Boolean proxyCheckOnly) +{ +/* + * Some proxies fetch files with certain extensions in "ascii mode" instead + * of "binary mode" for FTP. The FTP server then translates all LF to CRLF. + * + * You can force Squid to use binary mode by appending ";type=i" to the URL, + * which is what I do here. For other proxies, the LF->CRLF substitution + * is reverted in distExtract(). + */ + + int rv, s, af; + bool el, found=FALSE; /* end of header line */ + char *cp, buf[PATH_MAX], req[BUFSIZ]; + struct addrinfo hints, *res, *res0; + + 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_protocol = 0; + if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST), + variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) { + msgConfirm("%s", gai_strerror(rv)); + variable_unset(VAR_HTTP_HOST); + return FALSE; + } + s = -1; + for (res = res0; res; res = res->ai_next) { + if ((s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + continue; + if (connect(s, res->ai_addr, res->ai_addrlen) >= 0) + break; + close(s); + s = -1; + } + freeaddrinfo(res0); + if (s == -1) { + msgConfirm("Couldn't connect to proxy %s:%s", + variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT)); + variable_unset(VAR_HTTP_HOST); + return FALSE; + } + if (proxyCheckOnly) { + close(s); + return TRUE; + } + + msgNotify("Checking access to\n %s", variable_get(VAR_HTTP_PATH)); + sprintf(req,"GET %s/ HTTP/1.0\r\n\r\n", variable_get(VAR_HTTP_PATH)); + write(s,req,strlen(req)); +/* + * scan the headers of the response + * this is extremely quick'n dirty + * + */ + bzero(buf, PATH_MAX); + cp=buf; + el=FALSE; + rv=read(s,cp,1); + variable_set2(VAR_HTTP_FTP_MODE,"",0); + while (rv>0) { + if ((*cp == '\012') && el) { + /* reached end of a header line */ + if (!strncmp(buf,"HTTP",4)) { + if (strtol((char *)(buf+9),0,0) == 200) { + found = TRUE; + } + } + + if (!strncmp(buf,"Server: ",8)) { + if (!strncmp(buf,"Server: Squid",13)) { + variable_set2(VAR_HTTP_FTP_MODE,";type=i",0); + } else { + variable_set2(VAR_HTTP_FTP_MODE,"",0); + } + } + /* ignore other headers */ + /* check for "\015\012" at beginning of line, i.e. end of headers */ + if ((cp-buf) == 1) + break; + cp=buf; + rv=read(s,cp,1); + } else { + el=FALSE; + if (*cp == '\015') + el=TRUE; + cp++; + rv=read(s,cp,1); + } + } + close(s); + return found; +} + +Boolean +mediaInitHTTP(Device *dev) +{ + bool found=FALSE; /* end of header line */ + char *rel, req[BUFSIZ]; + int fdir; + + /* + * First verify the proxy access + */ + checkAccess(TRUE); + while (variable_get(VAR_HTTP_HOST) == NULL) { + if (DITEM_STATUS(mediaSetHTTP(NULL)) == DITEM_FAILURE) + return FALSE; + checkAccess(TRUE); + } +again: + /* If the release is specified as "__RELEASE" or "any", then just + * assume that the path the user gave is ok. + */ + rel = variable_get(VAR_RELNAME); + /* + msgConfirm("rel: -%s-", rel); + */ + + if (strcmp(rel, "__RELEASE") && strcmp(rel, "any")) { + for (fdir = 0; ftp_dirs[fdir]; fdir++) { + sprintf(req, "%s/%s/%s", variable_get(VAR_FTP_PATH), + ftp_dirs[fdir], rel); + variable_set2(VAR_HTTP_PATH, req, 0); + if (checkAccess(FALSE)) { + found = TRUE; + break; + } + } + } else { + variable_set2(VAR_HTTP_PATH, variable_get(VAR_FTP_PATH), 0); + found = checkAccess(FALSE); + } + if (!found) { + msgConfirm("No such directory: %s\n" + "please check the URL and try again.", variable_get(VAR_HTTP_PATH)); + variable_unset(VAR_HTTP_PATH); + dialog_clear_norefresh(); + clear(); + if (DITEM_STATUS(mediaSetHTTP(NULL)) != DITEM_FAILURE) goto again; + } + return found; +} + +FILE * +mediaGetHTTP(Device *dev, char *file, Boolean probe) +{ + FILE *fp; + int rv, s, af; + bool el; /* end of header line */ + char *cp, buf[PATH_MAX], req[BUFSIZ]; + struct addrinfo hints, *res, *res0; + + 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_protocol = 0; + if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST), + variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) { + msgConfirm("%s", gai_strerror(rv)); + return NULL; + } + s = -1; + for (res = res0; res; res = res->ai_next) { + if ((s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + continue; + if (connect(s, res->ai_addr, res->ai_addrlen) >= 0) + break; + close(s); + s = -1; + } + freeaddrinfo(res0); + if (s == -1) { + msgConfirm("Couldn't connect to proxy %s:%s", + variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT)); + return NULL; + } + + sprintf(req,"GET %s/%s%s HTTP/1.0\r\n\r\n", + variable_get(VAR_HTTP_PATH), file, variable_get(VAR_HTTP_FTP_MODE)); + + if (isDebug()) { + msgDebug("sending http request: %s\n",req); + } + write(s,req,strlen(req)); + +/* + * scan the headers of the response + * this is extremely quick'n dirty + * + */ + cp=buf; + el=FALSE; + rv=read(s,cp,1); + while (rv>0) { + if ((*cp == '\012') && el) { + /* reached end of a header line */ + if (!strncmp(buf,"HTTP",4)) { + rv=strtol((char *)(buf+9),0,0); + *(cp-1)='\0'; /* chop the CRLF off */ + if (probe && (rv != 200)) { + return NULL; + } else if (rv >= 500) { + msgConfirm("Server error %s when sending %s, you could try an other server",buf, req); + return NULL; + } else if (rv == 404) { + msgConfirm("%s was not found, maybe directory or release-version are wrong?",req); + return NULL; + } else if (rv >= 400) { + msgConfirm("Client error %s, you could try an other server",buf); + return NULL; + } else if (rv >= 300) { + msgConfirm("Error %s,",buf); + return NULL; + } else if (rv != 200) { + msgConfirm("Error %s when sending %s, you could try an other server",buf, req); + return NULL; + } + } + /* ignore other headers */ + /* check for "\015\012" at beginning of line, i.e. end of headers */ + if ((cp-buf) == 1) + break; + cp=buf; + rv=read(s,cp,1); + } else { + el=FALSE; + if (*cp == '\015') + el=TRUE; + cp++; + rv=read(s,cp,1); + } + } + fp=fdopen(s,"r"); + return fp; +} diff --git a/usr.sbin/sysinstall/index.c b/usr.sbin/sysinstall/index.c new file mode 100644 index 0000000000000..ef685644a5672 --- /dev/null +++ b/usr.sbin/sysinstall/index.c @@ -0,0 +1,835 @@ +/* + * The new sysinstall program. + * + * This is probably the last program in the `sysinstall' line - the next + * generation being essentially a complete rewrite. + * + * 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. + * + * $FreeBSD$ + */ + +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ncurses.h> +#include <dialog.h> +#include "sysinstall.h" + +/* Macros and magic values */ +#define MAX_MENU 12 +#define _MAX_DESC 55 + +/* A structure holding the root, top and plist pointer at once */ +struct ListPtrs +{ + PkgNodePtr root; /* root of tree */ + PkgNodePtr top; /* part of tree we handle */ + PkgNodePtr plist; /* list of selected packages */ +}; +typedef struct ListPtrs* ListPtrsPtr; + +static void index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie); + +/* Shared between index_initialize() and the various clients of it */ +PkgNode Top, Plist; + +/* Smarter strdup */ +inline char * +_strdup(char *ptr) +{ + return ptr ? strdup(ptr) : NULL; +} + +static char *descrs[] = { + "Package Selection", "To mark a package, move to it and press SPACE. If the package is\n" + "already marked, it will be unmarked or deleted (if installed).\n" + "Items marked with a `D' are dependencies which will be auto-loaded.\n" + "To search for a package by name, press ESC. To select a category,\n" + "press RETURN. NOTE: The All category selection creates a very large\n" + "submenu! If you select it, please be patient while it comes up.", + "Package Targets", "These are the packages you've selected for extraction.\n\n" + "If you're sure of these choices, select OK.\n" + "If not, select Cancel to go back to the package selection menu.\n", + "All", "All available packages in all categories.", + "accessibility", "Ports to help disabled users.", + "afterstep", "Ports to support the AfterStep window manager.", + "applications", "User application software.", + "arabic", "Ported software for Arab countries.", + "archivers", "Utilities for archiving and unarchiving data.", + "astro", "Applications related to astronomy.", + "audio", "Audio utilities - most require a supported sound card.", + "benchmarks", "Utilities for measuring system performance.", + "biology", "Software related to biology.", + "cad", "Computer Aided Design utilities.", + "chinese", "Ported software for the Chinese market.", + "comms", "Communications utilities.", + "converters", "Format conversion utilities.", + "databases", "Database software.", + "deskutils", "Various Desktop utilities.", + "devel", "Software development utilities and libraries.", + "dns", "Domain Name Service tools.", + "documentation", "Document preparation utilities.", + "editors", "Common text editors.", + "elisp", "Things related to Emacs Lisp.", + "emulators", "Utilities for emulating other OS types.", + "finance", "Monetary, financial and related applications.", + "french", "Ported software for French countries.", + "ftp", "FTP client and server utilities.", + "games", "Various and sundry amusements.", + "german", "Ported software for Germanic countries.", + "gnome", "Components of the Gnome Desktop environment.", + "graphics", "Graphics libraries and utilities.", + "haskell", "Software related to the Haskell language.", + "hebrew", "Ported software for Hebrew language.", + "hungarian", "Ported software for the Hungarian market.", + "ipv6", "IPv6 related software.", + "irc", "Internet Relay Chat utilities.", + "japanese", "Ported software for the Japanese market.", + "java", "Java language support.", + "kde", "Software for the K Desktop Environment.", + "korean", "Ported software for the Korean market.", + "lang", "Computer languages.", + "languages", "Computer languages.", + "libraries", "Software development libraries.", + "linux", "Linux programs that can be run under binary compatibility.", + "mail", "Electronic mail packages and utilities.", + "math", "Mathematical computation software.", + "mbone", "Applications and utilities for the MBONE.", + "misc", "Miscellaneous utilities.", + "multimedia", "Multimedia software.", + "net", "Networking utilities.", + "net-mgmt", "Network Management", + "news", "USENET News support software.", + "numeric", "Mathematical computation software.", + "offix", "An office automation suite of sorts.", + "orphans", "Packages without a home elsewhere.", + "palm", "Software support for the Palm(tm) series.", + "parallel", "Applications dealing with parallelism in computing.", + "perl5", "Utilities/modules for the PERL5 language.", + "picobsd", "Ports to support PicoBSD.", + "pilot", "Software support for the 3Com Palm Pilot(tm) series.", + "plan9", "Software from the Plan9 operating system.", + "polish", "Ported software for the Polish market.", + "portuguese", "Ported software for the Portuguese market.", + "print", "Utilities for dealing with printing.", + "printing", "Utilities for dealing with printing.", + "programming", "Software development utilities and libraries.", + "python", "Software related to the Python language.", + "ruby", "Software related to the Ruby language.", + "russian", "Ported software for the Russian market.", + "science", "Scientific software.", + "scheme", "Software related to the Scheme language.", + "security", "System security software.", + "shells", "Various shells (tcsh, bash, etc).", + "sysutils", "Various system utilities.", + "tcl75", "TCL v7.5 and packages that depend on it.", + "tcl76", "TCL v7.6 and packages that depend on it.", + "tcl80", "TCL v8.0 and packages that depend on it.", + "tcl81", "TCL v8.1 and packages that depend on it.", + "tcl82", "TCL v8.2 and packages that depend on it.", + "tcl83", "TCL v8.3 and packages that depend on it.", + "tcl84", "TCL v8.4 and packages that depend on it.", + "textproc", "Text processing/search utilities.", + "tk41", "Tk4.1 and packages that depend on it.", + "tk42", "Tk4.2 and packages that depend on it.", + "tk80", "Tk8.0 and packages that depend on it.", + "tk81", "Tk8.1 and packages that depend on it.", + "tk82", "Tk8.2 and packages that depend on it.", + "tk83", "Tk8.3 and packages that depend on it.", + "tkstep80", "tkstep wm and packages that depend on it.", + "troff", "TROFF text formatting utilities.", + "ukrainian", "Ported software for the Ukrainian market.", + "vietnamese", "Ported software for the Vietnamese market.", + "windowmaker", "Ports to support the WindowMaker window manager.", + "www", "WEB utilities (browers, HTTP servers, etc).", + "x11", "X Window System based utilities.", + "x11-clocks", "X Window System based clocks.", + "x11-fm", "X Window System based file managers.", + "x11-fonts", "X Window System fonts and font utilities.", + "x11-servers", "X Window System servers.", + "x11-themes", "X Window System themes.", + "x11-toolkits", "X Window System based development toolkits.", + "x11-wm", "X Window System window managers.", + "zope", "Software related to the Zope platform.", + NULL, NULL, +}; + +static char * +fetch_desc(char *name) +{ + int i; + + for (i = 0; descrs[i]; i += 2) { + if (!strcmp(descrs[i], name)) + return descrs[i + 1]; + } + return "No description provided"; +} + +static PkgNodePtr +new_pkg_node(char *name, node_type type) +{ + PkgNodePtr tmp = safe_malloc(sizeof(PkgNode)); + + tmp->name = _strdup(name); + tmp->type = type; + return tmp; +} + +static char * +strip(char *buf) +{ + int i; + + for (i = 0; buf[i]; i++) + if (buf[i] == '\t' || buf[i] == '\n') + buf[i] = ' '; + return buf; +} + +static IndexEntryPtr +new_index(char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *deps, int volume) +{ + IndexEntryPtr tmp = safe_malloc(sizeof(IndexEntry)); + + tmp->name = _strdup(name); + tmp->path = _strdup(pathto); + tmp->prefix = _strdup(prefix); + tmp->comment = _strdup(comment); + tmp->descrfile = strip(_strdup(descr)); + tmp->maintainer = _strdup(maint); + tmp->deps = _strdup(deps); + tmp->depc = 0; + tmp->installed = package_installed(name); + tmp->volume = volume; + return tmp; +} + +static void +index_register(PkgNodePtr top, char *where, IndexEntryPtr ptr) +{ + PkgNodePtr p, q; + + for (q = NULL, p = top->kids; p; p = p->next) { + if (!strcmp(p->name, where)) { + q = p; + break; + } + } + if (!p) { + /* Add new category */ + q = new_pkg_node(where, PLACE); + q->desc = fetch_desc(where); + q->next = top->kids; + top->kids = q; + } + p = new_pkg_node(ptr->name, PACKAGE); + p->desc = ptr->comment; + p->data = ptr; + p->next = q->kids; + q->kids = p; +} + +static int +copy_to_sep(char *to, char *from, int sep) +{ + char *tok; + + tok = strchr(from, sep); + if (!tok) { + *to = '\0'; + return 0; + } + *tok = '\0'; + strcpy(to, from); + return tok + 1 - from; +} + +static int +readline(FILE *fp, char *buf, int max) +{ + int rv, i = 0; + char ch; + + while ((rv = fread(&ch, 1, 1, fp)) == 1 && ch != '\n' && i < max) + buf[i++] = ch; + if (i < max) + buf[i] = '\0'; + return rv; +} + +/* + * XXX - this function should do error checking, and skip corrupted INDEX + * lines without a set number of '|' delimited fields. + */ + +int +index_parse(FILE *fp, char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *cats, char *rdeps, int *volume) +{ + char line[10240 + 2048 * 7]; + char junk[2048]; + char volstr[2048]; + char *cp; + int i; + + i = readline(fp, line, sizeof line); + if (i <= 0) + return EOF; + cp = line; + cp += copy_to_sep(name, cp, '|'); /* package name */ + cp += copy_to_sep(pathto, cp, '|'); /* ports directory */ + cp += copy_to_sep(prefix, cp, '|'); /* prefix */ + cp += copy_to_sep(comment, cp, '|'); /* comment */ + cp += copy_to_sep(descr, cp, '|'); /* path to pkg-descr */ + cp += copy_to_sep(maint, cp, '|'); /* maintainer */ + cp += copy_to_sep(cats, cp, '|'); /* categories */ + cp += copy_to_sep(junk, cp, '|'); /* build deps - not used */ + cp += copy_to_sep(rdeps, cp, '|'); /* run deps */ + if (index(cp, '|')) + cp += copy_to_sep(junk, cp, '|'); /* url - not used */ + else { + strncpy(junk, cp, 1023); + *volume = 0; + return 0; + } + if (index(cp, '|')) + cp += copy_to_sep(junk, cp, '|'); /* extract deps - not used */ + if (index(cp, '|')) + cp += copy_to_sep(junk, cp, '|'); /* patch deps - not used */ + if (index(cp, '|')) + cp += copy_to_sep(junk, cp, '|'); /* fetch deps - not used */ + if (index(cp, '|')) + cp += copy_to_sep(volstr, cp, '|'); /* media volume */ + else { + strncpy(volstr, cp, 1023); + } + *volume = atoi(volstr); + return 0; +} + +int +index_read(FILE *fp, PkgNodePtr papa) +{ + char name[127], pathto[255], prefix[255], comment[255], descr[127], maint[127], cats[511], deps[2048 * 8]; + int volume; + PkgNodePtr i; + + while (index_parse(fp, name, pathto, prefix, comment, descr, maint, cats, deps, &volume) != EOF) { + char *cp, *cp2, tmp[1024]; + IndexEntryPtr idx; + + idx = new_index(name, pathto, prefix, comment, descr, maint, deps, volume); + /* For now, we only add things to menus if they're in categories. Keywords are ignored */ + for (cp = strcpy(tmp, cats); (cp2 = strchr(cp, ' ')) != NULL; cp = cp2 + 1) { + *cp2 = '\0'; + index_register(papa, cp, idx); + } + index_register(papa, cp, idx); + + /* Add to special "All" category */ + index_register(papa, "All", idx); + } + + /* Adjust dependency counts */ + for (i = papa->kids; i != NULL; i = i->next) + if (strcmp(i->name, "All") == 0) + break; + for (i = i->kids; i != NULL; i = i->next) + if (((IndexEntryPtr)i->data)->installed) + index_recorddeps(TRUE, papa, i->data); + + return 0; +} + +void +index_init(PkgNodePtr top, PkgNodePtr plist) +{ + if (top) { + top->next = top->kids = NULL; + top->name = "Package Selection"; + top->type = PLACE; + top->desc = fetch_desc(top->name); + top->data = NULL; + } + if (plist) { + plist->next = plist->kids = NULL; + plist->name = "Package Targets"; + plist->type = PLACE; + plist->desc = fetch_desc(plist->name); + plist->data = NULL; + } +} + +void +index_print(PkgNodePtr top, int level) +{ + int i; + + while (top) { + for (i = 0; i < level; i++) putchar('\t'); + printf("name [%s]: %s\n", top->type == PLACE ? "place" : "package", top->name); + for (i = 0; i < level; i++) putchar('\t'); + printf("desc: %s\n", top->desc); + if (top->kids) + index_print(top->kids, level + 1); + top = top->next; + } +} + +/* Swap one node for another */ +static void +swap_nodes(PkgNodePtr a, PkgNodePtr b) +{ + PkgNode tmp; + + tmp = *a; + *a = *b; + a->next = tmp.next; + tmp.next = b->next; + *b = tmp; +} + +/* Use a disgustingly simplistic bubble sort to put our lists in order */ +void +index_sort(PkgNodePtr top) +{ + PkgNodePtr p, q; + + /* Sort everything at the top level */ + for (p = top->kids; p; p = p->next) { + for (q = top->kids; q; q = q->next) { + if (q->next && strcmp(q->name, q->next->name) > 0) + swap_nodes(q, q->next); + } + } + + /* Now sub-sort everything n levels down */ + for (p = top->kids; p; p = p->next) { + if (p->kids) + index_sort(p); + } +} + +/* Delete an entry out of the list it's in (only the plist, at present) */ +void +index_delete(PkgNodePtr n) +{ + if (n->next) { + PkgNodePtr p = n->next; + + *n = *(n->next); + safe_free(p); + } + else /* Kludgy end sentinal */ + n->name = NULL; +} + +/* + * Search for a given node by name, returning the category in if + * tp is non-NULL. + */ +PkgNodePtr +index_search(PkgNodePtr top, char *str, PkgNodePtr *tp) +{ + PkgNodePtr p, sp; + + for (p = top->kids; p && p->name; p = p->next) { + if (p->type == PACKAGE) { + /* If tp == NULL, we're looking for an exact package match */ + if (!tp && !strcmp(p->name, str)) + return p; + + /* If tp, we're looking for both a package and a pointer to the place it's in */ + if (tp && !strncmp(p->name, str, strlen(str))) { + *tp = top; + return p; + } + } + else if (p->kids) { + /* The usual recursion-out-of-laziness ploy */ + if ((sp = index_search(p, str, tp)) != NULL) + return sp; + } + } + if (p && !p->name) + p = NULL; + return p; +} + +int +pkg_checked(dialogMenuItem *self) +{ + ListPtrsPtr lists = (ListPtrsPtr)self->aux; + PkgNodePtr kp = self->data, plist = lists->plist; + int i; + + i = index_search(plist, kp->name, NULL) ? TRUE : FALSE; + if (kp->type == PACKAGE && plist) { + IndexEntryPtr ie = kp->data; + int markD, markX; + + markD = ie->depc > 0; /* needed as dependency */ + markX = i || ie->installed; /* selected or installed */ + self->mark = markX ? 'X' : 'D'; + return markD || markX; + } else + return FALSE; +} + +int +pkg_fire(dialogMenuItem *self) +{ + int ret; + ListPtrsPtr lists = (ListPtrsPtr)self->aux; + PkgNodePtr sp, kp = self->data, plist = lists->plist; + + if (!plist) + ret = DITEM_FAILURE; + else if (kp->type == PACKAGE) { + IndexEntryPtr ie = kp->data; + + sp = index_search(plist, kp->name, NULL); + /* Not already selected? */ + if (!sp) { + if (!ie->installed) { + PkgNodePtr np = (PkgNodePtr)safe_malloc(sizeof(PkgNode)); + + *np = *kp; + np->next = plist->kids; + plist->kids = np; + index_recorddeps(TRUE, lists->root, ie); + msgInfo("Added %s to selection list", kp->name); + } + else if (ie->depc == 0) { + if (!msgNoYes("Do you really want to delete %s from the system?", kp->name)) { + if (vsystem("pkg_delete %s %s", isDebug() ? "-v" : "", kp->name)) { + msgConfirm("Warning: pkg_delete of %s failed.\n Check debug output for details.", kp->name); + } + else { + ie->installed = 0; + index_recorddeps(FALSE, lists->root, ie); + } + } + } + else + msgConfirm("Warning: Package %s is needed by\n %d other installed package%s.", + kp->name, ie->depc, (ie->depc != 1) ? "s" : ""); + } + else { + index_recorddeps(FALSE, lists->root, ie); + msgInfo("Removed %s from selection list", kp->name); + index_delete(sp); + } + ret = DITEM_SUCCESS; + /* Mark menu for redraw if we had dependencies */ + if (strlen(ie->deps) > 0) + ret |= DITEM_REDRAW; + } + else { /* Not a package, must be a directory */ + int p, s; + + p = s = 0; + index_menu(lists->root, kp, plist, &p, &s); + ret = DITEM_SUCCESS | DITEM_CONTINUE; + } + return ret; +} + +void +pkg_selected(dialogMenuItem *self, int is_selected) +{ + PkgNodePtr kp = self->data; + + if (!is_selected || kp->type != PACKAGE) + return; + msgInfo("%s", kp->desc); +} + +int +index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll) +{ + struct ListPtrs lists; + int n, rval, maxname; + int curr, max; + PkgNodePtr kp; + dialogMenuItem *nitems; + Boolean hasPackages; + WINDOW *w; + + lists.root = root; + lists.top = top; + lists.plist = plist; + + hasPackages = FALSE; + nitems = NULL; + n = maxname = 0; + + /* Figure out if this menu is full of "leaves" or "branches" */ + for (kp = top->kids; kp && kp->name; kp = kp->next) { + int len; + + ++n; + if (kp->type == PACKAGE && plist) { + hasPackages = TRUE; + if ((len = strlen(kp->name)) > maxname) + maxname = len; + } + } + if (!n && plist) { + msgConfirm("The %s menu is empty.", top->name); + return DITEM_LEAVE_MENU; + } + + w = savescr(); + while (1) { + n = 0; + curr = max = 0; + use_helpline(NULL); + use_helpfile(NULL); + kp = top->kids; + if (!hasPackages && plist) { + nitems = item_add(nitems, "OK", NULL, NULL, NULL, NULL, NULL, NULL, &curr, &max); + nitems = item_add(nitems, "Install", NULL, NULL, NULL, NULL, NULL, NULL, &curr, &max); + } + while (kp && kp->name) { + char buf[256]; + IndexEntryPtr ie = kp->data; + + /* Brutally adjust description to fit in menu */ + if (kp->type == PACKAGE) + snprintf(buf, sizeof buf, "[%s]", ie->path ? ie->path : "External vendor"); + else + SAFE_STRCPY(buf, kp->desc); + if (strlen(buf) > (_MAX_DESC - maxname)) + buf[_MAX_DESC - maxname] = '\0'; + nitems = item_add(nitems, kp->name, (char *)buf, pkg_checked, + pkg_fire, pkg_selected, kp, (int *)(&lists), + &curr, &max); + ++n; + kp = kp->next; + } + /* NULL delimiter so item_free() knows when to stop later */ + nitems = item_add(nitems, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &curr, &max); + +recycle: + dialog_clear_norefresh(); + if (hasPackages) + rval = dialog_checklist(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems, NULL); + else + rval = dialog_menu(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems + (plist ? 2 : 0), (char *)plist, pos, scroll); + if (rval == -1 && plist) { + static char *cp; + PkgNodePtr menu; + + /* Search */ + if ((cp = msgGetInput(cp, "Search by package name. Please enter search string:")) != NULL) { + PkgNodePtr p = index_search(top, cp, &menu); + + if (p) { + int pos, scroll; + + /* These need to be set to point at the found item, actually. Hmmm! */ + pos = scroll = 0; + index_menu(root, menu, plist, &pos, &scroll); + } + else + msgConfirm("Search string: %s yielded no hits.", cp); + } + goto recycle; + } + items_free(nitems, &curr, &max); + restorescr(w); + return rval ? DITEM_FAILURE : DITEM_SUCCESS; + } +} + +int +index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended) +{ + int status = DITEM_SUCCESS; + PkgNodePtr tmp2; + IndexEntryPtr id = who->data; + WINDOW *w = savescr(); + + /* + * Short-circuit the package dependency checks. We're already + * maintaining a data structure of installed packages, so if a + * package is already installed, don't try to check to make sure + * that all of its dependencies are installed. At best this + * wastes a ton of cycles and can cause minor delays between + * package extraction. At worst it can cause an infinite loop with + * a certain faulty INDEX file. + */ + + if (id->installed == 1) + return DITEM_SUCCESS; + + /* + * Prompt user if the package is not available on the current volume. + */ + + while (id->volume != dev->volume) { + if (!msgYesNo("This is disc #%d. Package %s is on disc #%d\n" + "Would you like to switch discs now?\n", dev->volume, + id->name, id->volume)) { + DEVICE_SHUTDOWN(mediaDevice); + msgConfirm("Please remove disc #%d from your drive, and add disc #%d\n", + dev->volume, id->volume); + DEVICE_INIT(mediaDevice); + } else { + return DITEM_FAILURE; + } + } + + if (id && id->deps && strlen(id->deps)) { + char t[2048 * 8], *cp, *cp2; + + SAFE_STRCPY(t, id->deps); + cp = t; + while (cp && DITEM_STATUS(status) == DITEM_SUCCESS) { + if ((cp2 = index(cp, ' ')) != NULL) + *cp2 = '\0'; + if ((tmp2 = index_search(top, cp, NULL)) != NULL) { + status = index_extract(dev, top, tmp2, TRUE); + if (DITEM_STATUS(status) != DITEM_SUCCESS) { + if (variable_get(VAR_NO_CONFIRM)) + msgNotify("Loading of dependent package %s failed", cp); + else + msgConfirm("Loading of dependent package %s failed", cp); + } + } + else if (!package_installed(cp)) { + if (variable_get(VAR_NO_CONFIRM)) + msgNotify("Warning: %s is a required package but was not found.", cp); + else + msgConfirm("Warning: %s is a required package but was not found.", cp); + } + if (cp2) + cp = cp2 + 1; + else + cp = NULL; + } + } + /* Done with the deps? Load the real m'coy */ + if (DITEM_STATUS(status) == DITEM_SUCCESS) { + status = package_extract(dev, who->name, depended); + if (DITEM_STATUS(status) == DITEM_SUCCESS) + id->installed = 1; + } + restorescr(w); + return status; +} + +static void +index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie) +{ + char depends[1024 * 16], *space, *todo; + PkgNodePtr found; + IndexEntryPtr found_ie; + + SAFE_STRCPY(depends, ie->deps); + for (todo = depends; todo != NULL; ) { + space = index(todo, ' '); + if (space != NULL) + *space = '\0'; + + if (strlen(todo) > 0) { /* only non-empty dependencies */ + found = index_search(root, todo, NULL); + if (found != NULL) { + found_ie = found->data; + if (add) + ++found_ie->depc; + else + --found_ie->depc; + } + } + + if (space != NULL) + todo = space + 1; + else + todo = NULL; + } +} + +static Boolean index_initted; + +/* Read and initialize global index */ +int +index_initialize(char *path) +{ + FILE *fp; + WINDOW *w = NULL; + + if (!index_initted) { + w = savescr(); + dialog_clear_norefresh(); + + /* Got any media? */ + if (!mediaVerify()) { + restorescr(w); + return DITEM_FAILURE; + } + + /* Does it move when you kick it? */ + if (!DEVICE_INIT(mediaDevice)) { + restorescr(w); + return DITEM_FAILURE; + } + + dialog_clear_norefresh(); + msgNotify("Attempting to fetch %s file from selected media.", path); + fp = DEVICE_GET(mediaDevice, path, TRUE); + if (!fp) { + msgConfirm("Unable to get packages/INDEX file from selected media.\n\n" + "This may be because the packages collection is not available\n" + "on the distribution media you've chosen, most likely an FTP site\n" + "without the packages collection mirrored. Please verify that\n" + "your media, or your path to the media, is correct and try again."); + DEVICE_SHUTDOWN(mediaDevice); + restorescr(w); + return DITEM_FAILURE; + } + dialog_clear_norefresh(); + msgNotify("Located INDEX, now reading package data from it..."); + index_init(&Top, &Plist); + if (index_read(fp, &Top)) { + msgConfirm("I/O or format error on packages/INDEX file.\n" + "Please verify media (or path to media) and try again."); + fclose(fp); + restorescr(w); + return DITEM_FAILURE; + } + fclose(fp); + index_sort(&Top); + index_initted = TRUE; + restorescr(w); + } + return DITEM_SUCCESS; +} diff --git a/usr.sbin/sysinstall/install.c b/usr.sbin/sysinstall/install.c new file mode 100644 index 0000000000000..bea2a57ae78c1 --- /dev/null +++ b/usr.sbin/sysinstall/install.c @@ -0,0 +1,1267 @@ +/* + * 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 <ctype.h> +#include <sys/consio.h> +#include <sys/disklabel.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <sys/wait.h> +#include <sys/uio.h> +#include <sys/param.h> +#define MSDOSFS +#include <sys/mount.h> +#include <ufs/ufs/ufsmount.h> +#include <fs/msdosfs/msdosfsmount.h> +#undef MSDOSFS +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <libdisk.h> +#include <limits.h> +#include <unistd.h> +#include <termios.h> + +/* Hack for rsaref package add, which displays interactive license. + * Used by package.c + */ +int _interactiveHack; +int FixItMode = 0; + +static void create_termcap(void); +static void fixit_common(void); + +#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(); + return DITEM_SUCCESS; + FixItMode = 0; +} + +int +installFixitCDROM(dialogMenuItem *self) +{ + struct stat sb; + int need_eject; + + if (!RunningAsInit) + return DITEM_SUCCESS; + + variable_set2(SYSTEM_STATE, "fixit", 0); + (void)unlink("/mnt2"); + (void)rmdir("/mnt2"); + + 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; + + /* Since the fixit code expects everything to be in /mnt2, and the CDROM mounting stuff /dist, do + * a little kludge dance here.. + */ + if (symlink("/dist", "/mnt2")) { + msgConfirm("Unable to symlink /mnt2 to the disc mount point. Please report this\n" + "unexpected failure to freebsd-bugs@FreeBSD.org."); + return DITEM_FAILURE; + } + + /* + * If /tmp points to /mnt2/tmp from a previous fixit floppy session, it's + * not very good for us if we point it to the CDROM now. Rather make it + * a directory in the root MFS then. Experienced admins will still be + * able to mount their disk's /tmp over this if they need. + */ + if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK) + (void)unlink("/tmp"); + Mkdir("/tmp"); + + /* + * Since setuid binaries ignore LD_LIBRARY_PATH, we indeed need the + * ld.so.hints file. Fortunately, it's fairly small (~ 3 KB). + */ + 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.\n" + "Dynamic executables from the disc likely won't work."); + } + } + + /* Yet more iggly hardcoded pathnames. */ + 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 - not necessarily a problem for ELF\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\n" + "Dynamic executables from the disc likely won't work."); + } + } + /* optional nicety */ + if (!file_readable("/usr/bin/vi")) + symlink("/mnt2/usr/bin/vi", "/usr/bin/vi"); + fixit_common(); + 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(); +} + + +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 (200MB 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 (200MB 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_LINUX + dialog_clear_norefresh(); + if (!msgYesNo("Would you like to enable Linux binary compatibility?")) + (void)configLinux(self); +#endif + +#ifdef __alpha__ + dialog_clear_norefresh(); + if (!msgYesNo("Would you like to enable OSF/1 binary compatibility?")) + (void)configOSF1(self); +#endif + +#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 (!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; + int kstat = 1; +#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 (!kstat || !OnVTY) + fprintf(fp, "# -- sysinstall generated deltas -- #\n"); + if (!kstat) + fprintf(fp, "userconfig_script_load=\"YES\"\n"); + if (!OnVTY) + 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 build for bin */ + vsystem("newaliases"); + + /* 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; +} + +#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. It will be assumed\n" + "that you have the appropriate device entries already in /dev."); + } + 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; +} + +static char * +getRelname(void) +{ + static char buf[64]; + size_t sz = (sizeof buf) - 1; + + if (sysctlbyname("kern.osrelease", buf, &sz, NULL, 0) != -1) { + buf[sz] = '\0'; + return buf; + } + else + return "<unknown>"; +} + +/* Initialize various user-settable values to their defaults */ +int +installVarDefaults(dialogMenuItem *self) +{ + char *cp; + + /* Set default startup options */ + variable_set2(VAR_RELNAME, getRelname(), 0); + variable_set2(VAR_CPIO_VERBOSITY, "high", 0); + variable_set2(VAR_TAPE_BLOCKSIZE, DEFAULT_TAPE_BLOCKSIZE, 0); + variable_set2(VAR_INSTALL_ROOT, "/", 0); + variable_set2(VAR_INSTALL_CFG, "install.cfg", 0); + variable_set2(VAR_SKIP_PCCARD, "NO", 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); + 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); + } +} diff --git a/usr.sbin/sysinstall/install.cfg b/usr.sbin/sysinstall/install.cfg new file mode 100644 index 0000000000000..fb7ad88597953 --- /dev/null +++ b/usr.sbin/sysinstall/install.cfg @@ -0,0 +1,99 @@ +# This is the installation configuration file for my test machine, +# crate.cdrom.com. +# It is included here merely as a sort-of-documented example. +# +# $FreeBSD$ + +# Turn on extra debugging. +debug=yes + +################################ +# My host specific data +hostname=crate.cdrom.com +domainname=cdrom.com +nameserver=204.216.27.3 +defaultrouter=204.216.27.228 +ipaddr=204.216.27.230 +netmask=255.255.255.240 +################################ + +################################ +# Which installation device to use - ftp is pointed directly at my local +# machine and the installation device is my WD8013 ethernet interface. +_ftpPath=ftp://time.cdrom.com/pub +netDev=ed0 +mediaSetFTP +################################ + +################################ +# Select which distributions we want. +dists=bin doc manpages info compat21 des src sbase ssys +distSetCustom +################################ + +################################ +# Now set the parameters for the partition editor on ad0. Set to use the +# disk exclusively (could also be "all" to use the whole disk but +# respecting the MBR or "free" to use only unallocated space for FreeBSD). +disk=ad0 +partition=exclusive +diskPartitionEditor + +# Uncomment this instead to use only the free space and install boot manager. +#partition=free +#bootManager=booteasy +#diskPartitionEditor +################################ + +################################ + +# This assumes that slice 1 is a DOS partition and mounts it as /dos, +# which is the case on my laptop. +# +# All sizes are expressed in 512 byte blocks! + +# A 20MB root partition +ad0s1-1=ufs 40960 / +# And a 20MB swap partition +ad0s1-2=swap 40960 none +# Followed by a /usr partition using all remaining space (size 0 = free space) +# and with softupdates enabled (non-zero arg following mountpoint). +ad0s1-3=ufs 0 /usr 1 +# Let's do it! +diskLabelEditor + +################################ + +################################ +# Now partition the 2nd disk. +disk=ad1 +partition=exclusive +diskPartitionEditor + +ad1s1-1=ufs 40960 /var +ad1s1-2=ufs 0 /usr/src +diskLabelEditor +################################ + +################################ +# And the 3rd. +disk=da0 +partition=exclusive +diskPartitionEditor + +da0s1-1=swap 40960 none +da0s1-2=ufs 0 /tmp +diskLabelEditor +################################ + + +# OK, everything is set. Do it! +installCommit + +# Install some packages at the end. +package=bash-1.14.7 +packageAdd +package=ncftp-2.4.2 +packageAdd +package=tcsh-6.07.02 +packageAdd diff --git a/usr.sbin/sysinstall/installUpgrade.c b/usr.sbin/sysinstall/installUpgrade.c new file mode 100644 index 0000000000000..aa7ec88a97423 --- /dev/null +++ b/usr.sbin/sysinstall/installUpgrade.c @@ -0,0 +1,498 @@ +/* + * 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 <sys/disklabel.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <sys/wait.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/mount.h> + +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, "dhclient.conf", TRUE, NULL }, + { JUST_COPY, "disktab", TRUE, NULL }, + { JUST_COPY, "dm.conf", 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, "make.conf", TRUE, NULL }, + { JUST_COPY, "manpath.config", TRUE, NULL }, + { JUST_COPY, "master.passwd", FALSE, 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, "pam.conf", TRUE, NULL }, + { JUST_COPY, "passwd", TRUE, NULL }, + { JUST_COPY, "periodic", TRUE, NULL }, + { JUST_COPY, "ppp", TRUE, NULL }, + { JUST_COPY, "printcap", TRUE, NULL }, + { JUST_COPY, "profile", 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, "spwd.db", TRUE, NULL }, + { JUST_COPY, "ssh", TRUE, NULL }, + { JUST_COPY, "syslog.conf", TRUE, NULL }, + { JUST_COPY, "ttys", TRUE, NULL }, + { JUST_COPY, "uucp", TRUE, NULL }, + { 0 }, +}; + +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 unless 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 /usr/sbin /usr/bin /usr/lib /usr/libexec /kernel*"); + + if (file_readable("/kernel")) { + msgNotify("Moving old kernel to /kernel.prev"); + if (system("mv /kernel /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 /kernel.prev should this upgrade\n" + "fail for any reason and you need to boot your old 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, 3)}' /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)) { + 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 befor 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; + } + + if (file_readable("/kernel")) { + msgNotify("Moving old kernel to /kernel.prev"); + if (!system("chflags noschg /kernel && mv /kernel /kernel.prev")) { + /* Give us a working kernel in case we crash and reboot */ + system("cp /kernel.prev /kernel"); + } + } + + 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; +} diff --git a/usr.sbin/sysinstall/keymap.c b/usr.sbin/sysinstall/keymap.c new file mode 100644 index 0000000000000..3c53a0070a173 --- /dev/null +++ b/usr.sbin/sysinstall/keymap.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1996 Joerg Wunsch + * + * 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. + * 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 DEVELOPERS ``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 DEVELOPERS 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, 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. + * + * $FreeBSD$ + * + */ + +#include "sysinstall.h" +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/kbio.h> + +struct keymapInfo { + const char *name; + const struct keymap *map; +}; + +#include "keymap.h" + +/* + * keymap.h is being automatically generated by the Makefile. It + * contains definitions for all desired keymaps. Note that since we + * don't support font loading nor screen mapping during installation, + * we simply don't care for any other keys than the ASCII subset. + * + * Therefore, if no keymap with the exact name has been found in the + * first pass, we make a second pass over the table looking just for + * the language name only. + */ + +/* + * Return values: + * + * 0: OK + * -1: no appropriate keymap found + * -2: error installing map (other than ENXIO which means we're not on syscons) + */ + +int +loadKeymap(const char *lang) +{ + int passno, err; + char *llang; + size_t l; + struct keymapInfo *kip; + + llang = strdup(lang); + if (llang == NULL) + abort(); + + for (passno = 0; passno < 2; passno++) + { + if (passno > 0) + { + /* make the match more fuzzy */ + l = strspn(llang, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + llang[l] = '\0'; + } + + l = strlen(llang); + + for (kip = keymapInfos; kip->name; kip++) + if (strncmp(kip->name, llang, l) == 0) + { + /* Yep, got it! */ + err = ioctl(0, PIO_KEYMAP, kip->map); + free(llang); + return (err == -1 && errno != ENOTTY)? -2: 0; + } + } + free(llang); + return -1; +} diff --git a/usr.sbin/sysinstall/label.c b/usr.sbin/sysinstall/label.c new file mode 100644 index 0000000000000..c752f736c1a44 --- /dev/null +++ b/usr.sbin/sysinstall/label.c @@ -0,0 +1,1692 @@ +/* + * 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 <ctype.h> +#include <inttypes.h> +#include <libdisk.h> +#include <sys/disklabel.h> +#include <sys/param.h> +#include <sys/sysctl.h> + +#define AUTO_HOME 0 /* do not create /home automatically */ + +/* + * Everything to do with editing the contents of disk labels. + */ + +/* A nice message we use a lot in the disklabel editor */ +#define MSG_NOT_APPLICABLE "That option is not applicable here" + +/* Where to start printing the freebsd slices */ +#define CHUNK_SLICE_START_ROW 2 +#define CHUNK_PART_START_ROW 11 + +/* The smallest filesystem we're willing to create */ +#define FS_MIN_SIZE ONE_MEG + +/* + * Minimum partition sizes + */ +#if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__) || defined(__amd64__) +#define ROOT_MIN_SIZE 128 +#else +#define ROOT_MIN_SIZE 118 +#endif +#define SWAP_MIN_SIZE 32 +#define USR_MIN_SIZE 80 +#define VAR_MIN_SIZE 20 +#define TMP_MIN_SIZE 20 +#define HOME_MIN_SIZE 20 + +/* + * Swap size limit for auto-partitioning (4G). + */ +#define SWAP_AUTO_LIMIT_SIZE 4096 + +/* + * Default partition sizes. If we do not have sufficient disk space + * for this configuration we scale things relative to the NOM vs DEFAULT + * sizes. If the disk is larger then /home will get any remaining space. + */ +#define ROOT_DEFAULT_SIZE 256 +#define USR_DEFAULT_SIZE 3072 +#define VAR_DEFAULT_SIZE 256 +#define TMP_DEFAULT_SIZE 256 +#define HOME_DEFAULT_SIZE USR_DEFAULT_SIZE + +/* + * Nominal partition sizes. These are used to scale the default sizes down + * when we have insufficient disk space. If this isn't sufficient we scale + * down using the MIN sizes instead. + */ +#define ROOT_NOMINAL_SIZE 192 +#define USR_NOMINAL_SIZE 512 +#define VAR_NOMINAL_SIZE 64 +#define TMP_NOMINAL_SIZE 64 +#define HOME_NOMINAL_SIZE USR_NOMINAL_SIZE + +/* The bottom-most row we're allowed to scribble on */ +#define CHUNK_ROW_MAX 16 + + +/* All the chunks currently displayed on the screen */ +static struct { + struct chunk *c; + PartType type; +} label_chunk_info[MAX_CHUNKS + 1]; +static int here; + +/*** with this value we try to track the most recently added label ***/ +static int label_focus = 0, pslice_focus = 0; + +static int diskLabel(Device *dev); +static int diskLabelNonInteractive(Device *dev); +static char *try_auto_label(Device **devs, Device *dev, int perc, int *req); + +static int +labelHook(dialogMenuItem *selected) +{ + Device **devs = NULL; + + devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); + if (!devs) { + msgConfirm("Unable to find disk %s!", selected->prompt); + return DITEM_FAILURE; + } + /* Toggle enabled status? */ + if (!devs[0]->enabled) { + devs[0]->enabled = TRUE; + diskLabel(devs[0]); + } + else + devs[0]->enabled = FALSE; + return DITEM_SUCCESS; +} + +static int +labelCheck(dialogMenuItem *selected) +{ + Device **devs = NULL; + + devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); + if (!devs || devs[0]->enabled == FALSE) + return FALSE; + return TRUE; +} + +int +diskLabelEditor(dialogMenuItem *self) +{ + DMenu *menu; + Device **devs; + int i, cnt; + + i = 0; + cnt = diskGetSelectCount(&devs); + if (cnt == -1) { + 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 if (cnt) { + /* Some are already selected */ + if (variable_get(VAR_NONINTERACTIVE) && + !variable_get(VAR_DISKINTERACTIVE)) + i = diskLabelNonInteractive(NULL); + else + i = diskLabel(NULL); + } + else { + /* No disks are selected, fall-back case now */ + cnt = deviceCount(devs); + if (cnt == 1) { + devs[0]->enabled = TRUE; + if (variable_get(VAR_NONINTERACTIVE) && + !variable_get(VAR_DISKINTERACTIVE)) + i = diskLabelNonInteractive(devs[0]); + else + i = diskLabel(devs[0]); + } + else { + menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); + if (!menu) { + msgConfirm("No devices suitable for installation found!\n\n" + "Please verify that your disk controller (and attached drives)\n" + "were detected properly. This can be done by pressing the\n" + "[Scroll Lock] key and using the Arrow keys to move back to\n" + "the boot messages. Press [Scroll Lock] again to return."); + i = DITEM_FAILURE; + } + else { + i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; + free(menu); + } + } + } + if (DITEM_STATUS(i) != DITEM_FAILURE) { + if (variable_cmp(DISK_LABELLED, "written")) + variable_set2(DISK_LABELLED, "yes", 0); + } + return i; +} + +int +diskLabelCommit(dialogMenuItem *self) +{ + char *cp; + int i; + + /* Already done? */ + if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) + i = DITEM_SUCCESS; + else if (!cp) { + msgConfirm("You must assign disk labels before this option can be used."); + i = DITEM_FAILURE; + } + /* The routine will guard against redundant writes, just as this one does */ + else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) + i = DITEM_FAILURE; + else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) + i = DITEM_FAILURE; + else { + msgInfo("All filesystem information written successfully."); + variable_set2(DISK_LABELLED, "written", 0); + i = DITEM_SUCCESS; + } + return i; +} + +/* See if we're already using a desired partition name */ +static Boolean +check_conflict(char *name) +{ + int i; + + for (i = 0; label_chunk_info[i].c; i++) + if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT + || label_chunk_info[i].type == PART_EFI) && label_chunk_info[i].c->private_data + && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) + return TRUE; + return FALSE; +} + +/* How much space is in this FreeBSD slice? */ +static daddr_t +space_free(struct chunk *c) +{ + struct chunk *c1; + daddr_t sz = c->size; + + for (c1 = c->part; c1; c1 = c1->next) { + if (c1->type != unused) + sz -= c1->size; + } + if (sz < 0) + msgFatal("Partitions are larger than actual chunk??"); + return sz; +} + +/* Snapshot the current situation into the displayed chunks structure */ +static void +record_label_chunks(Device **devs, Device *dev) +{ + int i, j, p; + struct chunk *c1, *c2; + Disk *d; + + j = p = 0; + /* First buzz through and pick up the FreeBSD slices */ + for (i = 0; devs[i]; i++) { + if ((dev && devs[i] != dev) || !devs[i]->enabled) + continue; + d = (Disk *)devs[i]->private; + if (!d->chunks) + msgFatal("No chunk list found for %s!", d->name); + +#ifdef __ia64__ + label_chunk_info[j].type = PART_SLICE; + label_chunk_info[j].c = d->chunks; + j++; +#endif + + /* Put the slice entries first */ + for (c1 = d->chunks->part; c1; c1 = c1->next) { + if (c1->type == freebsd) { + label_chunk_info[j].type = PART_SLICE; + label_chunk_info[j].c = c1; + ++j; + } +#ifdef __powerpc__ + if (c1->type == apple) { + label_chunk_info[j].type = PART_SLICE; + label_chunk_info[j].c = c1; + ++j; + } +#endif + } + } + + /* Now run through again and get the FreeBSD partition entries */ + for (i = 0; devs[i]; i++) { + if (!devs[i]->enabled) + continue; + d = (Disk *)devs[i]->private; + /* Then buzz through and pick up the partitions */ + for (c1 = d->chunks->part; c1; c1 = c1->next) { + if (c1->type == freebsd) { + for (c2 = c1->part; c2; c2 = c2->next) { + if (c2->type == part) { + if (c2->subtype == FS_SWAP) + label_chunk_info[j].type = PART_SWAP; + else + label_chunk_info[j].type = PART_FILESYSTEM; + label_chunk_info[j].c = c2; + ++j; + } + } + } + else if (c1->type == fat) { + label_chunk_info[j].type = PART_FAT; + label_chunk_info[j].c = c1; + ++j; + } +#ifdef __ia64__ + else if (c1->type == efi) { + label_chunk_info[j].type = PART_EFI; + label_chunk_info[j].c = c1; + ++j; + } + else if (c1->type == part) { + if (c1->subtype == FS_SWAP) + label_chunk_info[j].type = PART_SWAP; + else + label_chunk_info[j].type = PART_FILESYSTEM; + label_chunk_info[j].c = c1; + ++j; + } +#endif +#ifdef __powerpc__ + else if (c1->type == apple) { + for (c2 = c1->part; c2; c2 = c2->next) { + if (c2->type == part) { + if (c2->subtype == FS_SWAP) + label_chunk_info[j].type = PART_SWAP; + else + label_chunk_info[j].type = PART_FILESYSTEM; + label_chunk_info[j].c = c2; + ++j; + } + } + } +#endif + } + } + label_chunk_info[j].c = NULL; + if (here >= j) { + here = j ? j - 1 : 0; + } +} + +/* A new partition entry */ +static PartInfo * +new_part(PartType type, char *mpoint, Boolean newfs) +{ + PartInfo *pi; + + if (!mpoint) + mpoint = (type == PART_EFI) ? "/efi" : "/change_me"; + + pi = (PartInfo *)safe_malloc(sizeof(PartInfo)); + sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX); + + pi->do_newfs = newfs; + + if (type == PART_EFI) { + pi->newfs_type = NEWFS_MSDOS; + } else { + pi->newfs_type = NEWFS_UFS; + strcpy(pi->newfs_data.newfs_ufs.user_options, ""); + pi->newfs_data.newfs_ufs.acls = FALSE; + pi->newfs_data.newfs_ufs.multilabel = FALSE; + pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/"); +#ifdef PC98 + pi->newfs_data.newfs_ufs.ufs1 = TRUE; +#else + pi->newfs_data.newfs_ufs.ufs1 = FALSE; +#endif + } + + return pi; +} + +/* Get the mountpoint for a partition and save it away */ +static PartInfo * +get_mountpoint(PartType type, struct chunk *old) +{ + char *val; + PartInfo *tmp; + Boolean newfs; + + if (old && old->private_data) + tmp = old->private_data; + else + tmp = NULL; + val = (tmp != NULL) ? tmp->mountpoint : (type == PART_EFI) ? "/efi" : NULL; + val = msgGetInput(val, "Please specify a mount point for the partition"); + if (!val || !*val) { + if (!old) + return NULL; + else { + free(old->private_data); + old->private_data = NULL; + } + return NULL; + } + + /* Is it just the same value? */ + if (tmp && !strcmp(tmp->mountpoint, val)) + return NULL; + + /* Did we use it already? */ + if (check_conflict(val)) { + msgConfirm("You already have a mount point for %s assigned!", val); + return NULL; + } + + /* Is it bogus? */ + if (*val != '/') { + msgConfirm("Mount point must start with a / character"); + return NULL; + } + + /* Is it going to be mounted on root? */ + if (!strcmp(val, "/")) { + if (old) + old->flags |= CHUNK_IS_ROOT; + } + else if (old) + old->flags &= ~CHUNK_IS_ROOT; + + newfs = TRUE; + if (tmp) { + newfs = tmp->do_newfs; + safe_free(tmp); + } + val = string_skipwhite(string_prune(val)); + tmp = new_part(type, val, newfs); + if (old) { + old->private_data = tmp; + old->private_free = safe_free; + } + return tmp; +} + +/* Get the type of the new partiton */ +static PartType +get_partition_type(void) +{ + char selection[20]; + int i; + static unsigned char *fs_types[] = { +#ifdef __ia64__ + "EFI", "An EFI system partition", +#endif + "FS", "A file system", + "Swap", "A swap partition.", + }; + WINDOW *w = savescr(); + + i = dialog_menu("Please choose a partition type", + "If you want to use this partition for swap space, select Swap.\n" + "If you want to put a filesystem on it, choose FS.", + -1, -1, +#ifdef __ia64__ + 3, 3, +#else + 2, 2, +#endif + fs_types, selection, NULL, NULL); + restorescr(w); + if (!i) { +#ifdef __ia64__ + if (!strcmp(selection, "EFI")) + return PART_EFI; +#endif + if (!strcmp(selection, "FS")) + return PART_FILESYSTEM; + else if (!strcmp(selection, "Swap")) + return PART_SWAP; + } + return PART_NONE; +} + +/* If the user wants a special newfs command for this, set it */ +static void +getNewfsCmd(PartInfo *p) +{ + char buffer[NEWFS_CMD_ARGS_MAX]; + char *val; + + switch (p->newfs_type) { + case NEWFS_UFS: + snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s", + NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ? "-U" : "", + p->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2", + p->newfs_data.newfs_ufs.user_options); + break; + case NEWFS_MSDOS: + snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD); + break; + case NEWFS_CUSTOM: + strcpy(buffer, p->newfs_data.newfs_custom.command); + break; + } + + val = msgGetInput(buffer, + "Please enter the newfs command and options you'd like to use in\n" + "creating this file system."); + if (val != NULL) { + p->newfs_type = NEWFS_CUSTOM; + strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX); + } +} + +static void +getNewfsOptionalArguments(PartInfo *p) +{ + char buffer[NEWFS_CMD_ARGS_MAX]; + char *val; + + /* Must be UFS, per argument checking in I/O routines. */ + + strlcpy(buffer, p->newfs_data.newfs_ufs.user_options, + NEWFS_CMD_ARGS_MAX); + val = msgGetInput(buffer, + "Please enter any additional UFS newfs options you'd like to\n" + "use in creating this file system."); + if (val != NULL) + strlcpy(p->newfs_data.newfs_ufs.user_options, val, + NEWFS_CMD_ARGS_MAX); +} + +#define MAX_MOUNT_NAME 9 + +#define PART_PART_COL 0 +#define PART_MOUNT_COL 10 +#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) +#define PART_NEWFS_COL (PART_SIZE_COL + 8) +#define PART_OFF 38 + +#define TOTAL_AVAIL_LINES (10) +#define PSLICE_SHOWABLE (4) + + +/* stick this all up on the screen */ +static void +print_label_chunks(void) +{ + int i, j, srow, prow, pcol; + daddr_t sz; + char clrmsg[80]; + int ChunkPartStartRow; + WINDOW *ChunkWin; + + /********************************************************/ + /*** These values are for controling screen resources ***/ + /*** Each label line holds up to 2 labels, so beware! ***/ + /*** strategy will be to try to always make sure the ***/ + /*** highlighted label is in the active display area. ***/ + /********************************************************/ + int pslice_max, label_max; + int pslice_count, label_count, label_focus_found, pslice_focus_found; + + attrset(A_REVERSE); + mvaddstr(0, 25, "FreeBSD Disklabel Editor"); + attrset(A_NORMAL); + + /*** Count the number of parition slices ***/ + pslice_count = 0; + for (i = 0; label_chunk_info[i].c ; i++) { + if (label_chunk_info[i].type == PART_SLICE) + ++pslice_count; + } + pslice_max = pslice_count; + + /*** 4 line max for partition slices ***/ + if (pslice_max > PSLICE_SHOWABLE) { + pslice_max = PSLICE_SHOWABLE; + } + ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; + + /*** View partition slices modulo pslice_max ***/ + label_max = TOTAL_AVAIL_LINES - pslice_max; + + for (i = 0; i < 2; i++) { + mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); + mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); + + mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); + mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); + + mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); + mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); + + mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); + mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); + } + srow = CHUNK_SLICE_START_ROW; + prow = 0; + pcol = 0; + + /*** these variables indicate that the focused item is shown currently ***/ + label_focus_found = 0; + pslice_focus_found = 0; + + label_count = 0; + pslice_count = 0; + mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); + mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); + + ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); + + wclear(ChunkWin); + /*** wrefresh(ChunkWin); ***/ + + for (i = 0; label_chunk_info[i].c; i++) { + /* Is it a slice entry displayed at the top? */ + if (label_chunk_info[i].type == PART_SLICE) { + /*** This causes the new pslice to replace the previous display ***/ + /*** focus must remain on the most recently active pslice ***/ + if (pslice_count == pslice_max) { + if (pslice_focus_found) { + /*** This is where we can mark the more following ***/ + attrset(A_BOLD); + mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); + attrset(A_NORMAL); + continue; + } + else { + /*** this is where we set the more previous ***/ + attrset(A_BOLD); + mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); + attrset(A_NORMAL); + pslice_count = 0; + srow = CHUNK_SLICE_START_ROW; + } + } + + sz = space_free(label_chunk_info[i].c); + if (i == here) + attrset(ATTR_SELECTED); + if (i == pslice_focus) + pslice_focus_found = -1; + + if (label_chunk_info[i].c->type == whole) { + if (sz >= 100 * ONE_GIG) + mvprintw(srow++, 0, + "Disk: %s\t\tFree: %jd blocks (%jdGB)", + label_chunk_info[i].c->disk->name, (intmax_t)sz, + (intmax_t)(sz / ONE_GIG)); + else + mvprintw(srow++, 0, + "Disk: %s\t\tFree: %jd blocks (%jdMB)", + label_chunk_info[i].c->disk->name, (intmax_t)sz, + (intmax_t)(sz / ONE_MEG)); + } else { + if (sz >= 100 * ONE_GIG) + mvprintw(srow++, 0, + "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdGB)", + label_chunk_info[i].c->disk->name, + label_chunk_info[i].c->name, + (intmax_t)sz, (intmax_t)(sz / ONE_GIG)); + else + mvprintw(srow++, 0, + "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdMB)", + label_chunk_info[i].c->disk->name, + label_chunk_info[i].c->name, + (intmax_t)sz, (intmax_t)(sz / ONE_MEG)); + } + attrset(A_NORMAL); + clrtoeol(); + move(0, 0); + /*** refresh(); ***/ + ++pslice_count; + } + /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ + else { + char onestr[PART_OFF], num[10], *mountpoint, newfs[12]; + + /* + * We copy this into a blank-padded string so that it looks like + * a solid bar in reverse-video + */ + memset(onestr, ' ', PART_OFF - 1); + onestr[PART_OFF - 1] = '\0'; + + /*** Track how many labels have been displayed ***/ + if (label_count == ((label_max - 1 ) * 2)) { + if (label_focus_found) { + continue; + } + else { + label_count = 0; + prow = 0; + pcol = 0; + } + } + + /* Go for two columns if we've written one full columns worth */ + /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ + if (label_count == label_max - 1) { + pcol = PART_OFF; + prow = 0; + } + memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); + /* If it's a filesystem, display the mountpoint */ + if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM + || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI)) + mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; + else if (label_chunk_info[i].type == PART_SWAP) + mountpoint = "swap"; + else + mountpoint = "<none>"; + + /* Now display the newfs field */ + if (label_chunk_info[i].type == PART_FAT) + strcpy(newfs, "DOS"); +#if defined(__ia64__) + else if (label_chunk_info[i].type == PART_EFI) { + strcpy(newfs, "EFI"); + if (label_chunk_info[i].c->private_data) { + strcat(newfs, " "); + PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; + strcat(newfs, pi->do_newfs ? " Y" : " N"); + } + } +#endif + else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { + PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; + + switch (pi->newfs_type) { + case NEWFS_UFS: + strcpy(newfs, NEWFS_UFS_STRING); + if (pi->newfs_data.newfs_ufs.ufs1) + strcat(newfs, "1"); + else + strcat(newfs, "2"); + if (pi->newfs_data.newfs_ufs.softupdates) + strcat(newfs, "+S"); + else + strcat(newfs, " "); + + break; + case NEWFS_MSDOS: + strcpy(newfs, "FAT"); + break; + case NEWFS_CUSTOM: + strcpy(newfs, "CUST"); + break; + } + strcat(newfs, pi->do_newfs ? " Y" : " N "); + } + else if (label_chunk_info[i].type == PART_SWAP) + strcpy(newfs, "SWAP"); + else + strcpy(newfs, "*"); + for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) + onestr[PART_MOUNT_COL + j] = mountpoint[j]; + if (label_chunk_info[i].c->size == 0) + snprintf(num, 10, "%5dMB", 0); + else if (label_chunk_info[i].c->size < (100 * ONE_GIG)) + snprintf(num, 10, "%5jdMB", + (intmax_t)label_chunk_info[i].c->size / ONE_MEG); + else + snprintf(num, 10, "%5jdGB", + (intmax_t)label_chunk_info[i].c->size / ONE_GIG); + memcpy(onestr + PART_SIZE_COL, num, strlen(num)); + memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); + onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; + if (i == label_focus) { + label_focus_found = -1; + wattrset(ChunkWin, A_BOLD); + } + if (i == here) + wattrset(ChunkWin, ATTR_SELECTED); + + /*** lazy man's way of expensively padding this string ***/ + while (strlen(onestr) < 37) + strcat(onestr, " "); + + mvwaddstr(ChunkWin, prow, pcol, onestr); + wattrset(ChunkWin, A_NORMAL); + move(0, 0); + ++prow; + ++label_count; + } + } + + /*** this will erase all the extra stuff ***/ + memset(clrmsg, ' ', 37); + clrmsg[37] = '\0'; + + while (pslice_count < pslice_max) { + mvprintw(srow++, 0, clrmsg); + clrtoeol(); + ++pslice_count; + } + while (label_count < (2 * (label_max - 1))) { + mvwaddstr(ChunkWin, prow++, pcol, clrmsg); + ++label_count; + if (prow == (label_max - 1)) { + prow = 0; + pcol = PART_OFF; + } + } + refresh(); + wrefresh(ChunkWin); +} + +static void +print_command_summary(void) +{ + mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); + mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); + if (!RunningAsInit) + mvprintw(18, 56, "W = Write"); + mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates Z = Custom Newfs"); + mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge"); + mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); + move(0, 0); +} + +static void +clear_wins(void) +{ + extern void print_label_chunks(); + clear(); + print_label_chunks(); +} + +static int +diskLabel(Device *dev) +{ + daddr_t sz; + int key = 0; + Boolean labeling; + char *msg = NULL; + PartInfo *p, *oldp; + PartType type; + Device **devs; + WINDOW *w = savescr(); + + label_focus = 0; + pslice_focus = 0; + here = 0; + + devs = deviceFind(NULL, DEVICE_TYPE_DISK); + if (!devs) { + msgConfirm("No disks found!"); + restorescr(w); + return DITEM_FAILURE; + } + labeling = TRUE; + keypad(stdscr, TRUE); + record_label_chunks(devs, dev); + + clear(); + while (labeling) { + char *cp; + int rflags = DELCHUNK_NORMAL; + + print_label_chunks(); + print_command_summary(); + if (msg) { + attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); + clrtoeol(); + beep(); + msg = NULL; + } + else { + move(23, 0); + clrtoeol(); + } + + refresh(); + key = getch(); + switch (toupper(key)) { + int i; + static char _msg[40]; + + case '\014': /* ^L */ + clear_wins(); + break; + + case '\020': /* ^P */ + case KEY_UP: + case '-': + if (here != 0) + --here; + else + while (label_chunk_info[here + 1].c) + ++here; + break; + + case '\016': /* ^N */ + case KEY_DOWN: + case '+': + case '\r': + case '\n': + if (label_chunk_info[here + 1].c) + ++here; + else + here = 0; + break; + + case KEY_HOME: + here = 0; + break; + + case KEY_END: + while (label_chunk_info[here + 1].c) + ++here; + break; + + case KEY_F(1): + case '?': + systemDisplayHelp("partition"); + clear_wins(); + break; + + case '1': + if (label_chunk_info[here].type == PART_FILESYSTEM) { + PartInfo *pi = + ((PartInfo *)label_chunk_info[here].c->private_data); + + if ((pi != NULL) && + (pi->newfs_type == NEWFS_UFS)) { + pi->newfs_data.newfs_ufs.ufs1 = true; + } else + msg = MSG_NOT_APPLICABLE; + } else + msg = MSG_NOT_APPLICABLE; + break; + break; + + case '2': + if (label_chunk_info[here].type == PART_FILESYSTEM) { + PartInfo *pi = + ((PartInfo *)label_chunk_info[here].c->private_data); + + if ((pi != NULL) && + (pi->newfs_type == NEWFS_UFS)) { + pi->newfs_data.newfs_ufs.ufs1 = false; + } else + msg = MSG_NOT_APPLICABLE; + } else + msg = MSG_NOT_APPLICABLE; + break; + break; + + case 'A': + if (label_chunk_info[here].type != PART_SLICE) { + msg = "You can only do this in a disk slice (at top of screen)"; + break; + } + /* + * Generate standard partitions automatically. If we do not + * have sufficient space we attempt to scale-down the size + * of the partitions within certain bounds. + */ + { + int perc; + int req = 0; + + for (perc = 100; perc > 0; perc -= 5) { + req = 0; /* reset for each loop */ + if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL) + break; + } + if (msg) { + if (req) { + msgConfirm(msg); + clear_wins(); + msg = NULL; + } + } + } + break; + + case 'C': + if (label_chunk_info[here].type != PART_SLICE) { + msg = "You can only do this in a master partition (see top of screen)"; + break; + } + sz = space_free(label_chunk_info[here].c); + if (sz <= FS_MIN_SIZE) { + msg = "Not enough space to create an additional FreeBSD partition"; + break; + } + else { + char *val; + daddr_t size; + struct chunk *tmp; + char osize[80]; + u_long flags = 0; + +#ifdef __powerpc__ + /* Always use the maximum size for apple partitions */ + if (label_chunk_info[here].c->type == apple) + size = sz; + else { +#endif + sprintf(osize, "%jd", (intmax_t)sz); + val = msgGetInput(osize, + "Please specify the partition size in blocks or append a trailing G for\n" +#ifdef __ia64__ + "gigabytes, M for megabytes.\n" +#else + "gigabytes, M for megabytes, or C for cylinders.\n" +#endif + "%jd blocks (%jdMB) are free.", + (intmax_t)sz, (intmax_t)sz / ONE_MEG); + if (!val || (size = strtoimax(val, &cp, 0)) <= 0) { + clear_wins(); + break; + } + + if (*cp) { + if (toupper(*cp) == 'M') + size *= ONE_MEG; + else if (toupper(*cp) == 'G') + size *= ONE_GIG; +#ifndef __ia64__ + else if (toupper(*cp) == 'C') + size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); +#endif + } + if (size <= FS_MIN_SIZE) { + msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); + clear_wins(); + break; + } +#ifdef __powerpc__ + } +#endif + type = get_partition_type(); + if (type == PART_NONE) { + clear_wins(); + beep(); + break; + } + + if (type == PART_FILESYSTEM || type == PART_EFI) { + if ((p = get_mountpoint(type, NULL)) == NULL) { + clear_wins(); + beep(); + break; + } + else if (!strcmp(p->mountpoint, "/")) { + if (type != PART_FILESYSTEM) { + clear_wins(); + beep(); + break; + } + else + flags |= CHUNK_IS_ROOT; + } + else + flags &= ~CHUNK_IS_ROOT; + } + else + p = NULL; + + if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { + msgConfirm("Warning: This is smaller than the recommended size for a\n" + "root partition. For a variety of reasons, root\n" + "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); + } + tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, size, +#ifdef __ia64__ + (type == PART_EFI) ? efi : part, + (type == PART_EFI) ? 0 : (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, +#else + part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, +#endif + flags); + if (!tmp) { + msgConfirm("Unable to create the partition. Too big?"); + clear_wins(); + break; + } + +#ifdef __alpha__ + /* + * SRM requires that the root partition is at the + * begining of the disk and cannot boot otherwise. + * Warn Alpha users if they are about to shoot themselves in + * the foot in this way. + * + * Since partitions may not start precisely at offset 0 we + * check for a "close to 0" instead. :-( + */ + if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) { + msgConfirm("Your root partition `a' does not seem to be the first\n" + "partition. The Alpha's firmware can only boot from the\n" + "first partition. So it is unlikely that your current\n" + "disk layout will be bootable boot after installation.\n" + "\n" + "Please allocate the root partition before allocating\n" + "any others.\n"); + } +#endif /* alpha */ + + tmp->private_data = p; + tmp->private_free = safe_free; + if (variable_cmp(DISK_LABELLED, "written")) + variable_set2(DISK_LABELLED, "yes", 0); + record_label_chunks(devs, dev); + clear_wins(); + /* This is where we assign focus to new label so it shows. */ + { + int i; + label_focus = -1; + for (i = 0; label_chunk_info[i].c; ++i) { + if (label_chunk_info[i].c == tmp) { + label_focus = i; + break; + } + } + if (label_focus == -1) + label_focus = i - 1; + } + } + break; + + case KEY_DC: + case 'R': /* recover space (delete w/ recover) */ + /* + * Delete the partition w/ space recovery. + */ + rflags = DELCHUNK_RECOVER; + /* fall through */ + case 'D': /* delete */ + if (label_chunk_info[here].type == PART_SLICE) { + msg = MSG_NOT_APPLICABLE; + break; + } + else if (label_chunk_info[here].type == PART_FAT) { + msg = "Use the Disk Partition Editor to delete DOS partitions"; + break; + } + Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags); + if (variable_cmp(DISK_LABELLED, "written")) + variable_set2(DISK_LABELLED, "yes", 0); + record_label_chunks(devs, dev); + break; + + case 'M': /* mount */ + switch(label_chunk_info[here].type) { + case PART_SLICE: + msg = MSG_NOT_APPLICABLE; + break; + + case PART_SWAP: + msg = "You don't need to specify a mountpoint for a swap partition."; + break; + + case PART_FAT: + case PART_EFI: + case PART_FILESYSTEM: + oldp = label_chunk_info[here].c->private_data; + p = get_mountpoint(label_chunk_info[here].type, label_chunk_info[here].c); + if (p) { + if (!oldp) + p->do_newfs = FALSE; + if ((label_chunk_info[here].type == PART_FAT || + label_chunk_info[here].type == PART_EFI) && + (!strcmp(p->mountpoint, "/") || + !strcmp(p->mountpoint, "/usr") || + !strcmp(p->mountpoint, "/var"))) { + msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); + strcpy(p->mountpoint, "/bogus"); + } + } + if (variable_cmp(DISK_LABELLED, "written")) + variable_set2(DISK_LABELLED, "yes", 0); + record_label_chunks(devs, dev); + clear_wins(); + break; + + default: + msgFatal("Bogus partition under cursor???"); + break; + } + break; + + case 'N': /* Set newfs options */ + if (label_chunk_info[here].c->private_data && + ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) + getNewfsOptionalArguments( + label_chunk_info[here].c->private_data); + else + msg = MSG_NOT_APPLICABLE; + clear_wins(); + break; + + case 'S': /* Toggle soft updates flag */ + if (label_chunk_info[here].type == PART_FILESYSTEM) { + PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); + if (pi != NULL && + pi->newfs_type == NEWFS_UFS) + pi->newfs_data.newfs_ufs.softupdates = + !pi->newfs_data.newfs_ufs.softupdates; + else + msg = MSG_NOT_APPLICABLE; + } + else + msg = MSG_NOT_APPLICABLE; + break; + + case 'T': /* Toggle newfs state */ + if ((label_chunk_info[here].type == PART_FILESYSTEM || + label_chunk_info[here].type == PART_EFI) && + (label_chunk_info[here].c->private_data)) { + PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); + if (!pi->do_newfs) + label_chunk_info[here].c->flags |= CHUNK_NEWFS; + else + label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; + + label_chunk_info[here].c->private_data = + new_part(label_chunk_info[here].type, pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs + : TRUE); + if (pi != NULL && + pi->newfs_type == NEWFS_UFS) { + PartInfo *pi_new = label_chunk_info[here].c->private_data; + + pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs; + } + safe_free(pi); + label_chunk_info[here].c->private_free = safe_free; + if (variable_cmp(DISK_LABELLED, "written")) + variable_set2(DISK_LABELLED, "yes", 0); + } + else + msg = MSG_NOT_APPLICABLE; + break; + + case 'U': + clear(); + if (!variable_cmp(DISK_LABELLED, "written")) { + msgConfirm("You've already written out your changes -\n" + "it's too late to undo!"); + } + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { + variable_unset(DISK_PARTITIONED); + variable_unset(DISK_LABELLED); + for (i = 0; devs[i]; i++) { + Disk *d; + + if (!devs[i]->enabled) + continue; + else if ((d = Open_Disk(devs[i]->name)) != NULL) { + Free_Disk(devs[i]->private); + devs[i]->private = d; +#ifdef WITH_SLICES + diskPartition(devs[i]); +#endif + } + } + record_label_chunks(devs, dev); + } + clear_wins(); + break; + + case 'W': + if (!variable_cmp(DISK_LABELLED, "written")) { + msgConfirm("You've already written out your changes - if you\n" + "wish to overwrite them, you'll have to restart\n" + "sysinstall first."); + } + else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" + "installation. If you are installing FreeBSD for the first time\n" + "then you should simply type Q when you're finished here and your\n" + "changes will be committed in one batch automatically at the end of\n" + "these questions.\n\n" + "Are you absolutely sure you want to do this now?")) { + variable_set2(DISK_LABELLED, "yes", 0); + diskLabelCommit(NULL); + } + clear_wins(); + break; + + case 'Z': /* Set newfs command line */ + if (label_chunk_info[here].c->private_data && + ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) + getNewfsCmd(label_chunk_info[here].c->private_data); + else + msg = MSG_NOT_APPLICABLE; + clear_wins(); + break; + +#ifndef __ia64__ + case '|': + if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" + "This is an entirely undocumented feature which you are not\n" + "expected to understand!")) { + int i; + Device **devs; + + dialog_clear(); + end_dialog(); + DialogActive = FALSE; + devs = deviceFind(NULL, DEVICE_TYPE_DISK); + if (!devs) { + msgConfirm("Can't find any disk devices!"); + break; + } + for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { + if (devs[i]->enabled) + slice_wizard(((Disk *)devs[i]->private)); + } + if (variable_cmp(DISK_LABELLED, "written")) + variable_set2(DISK_LABELLED, "yes", 0); + DialogActive = TRUE; + record_label_chunks(devs, dev); + clear_wins(); + } + else + msg = "A most prudent choice!"; + break; +#endif + + case '\033': /* ESC */ + case 'Q': + labeling = FALSE; + break; + + default: + beep(); + sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); + msg = _msg; + break; + } + if (label_chunk_info[here].type == PART_SLICE) + pslice_focus = here; + else + label_focus = here; + } + restorescr(w); + return DITEM_SUCCESS; +} + +static __inline daddr_t +requested_part_size(char *varName, daddr_t nom, int def, int perc) +{ + char *cp; + daddr_t sz; + + if ((cp = variable_get(varName)) != NULL) + sz = strtoimax(cp, NULL, 0); + else + sz = nom + (def - nom) * perc / 100; + return(sz * ONE_MEG); +} + +/* + * Attempt to auto-label the disk. 'perc' (0-100) scales + * the size of the various partitions within appropriate + * bounds (NOMINAL through DEFAULT sizes). The procedure + * succeeds of NULL is returned. A non-null return message + * is either a failure-status message (*req == 0), or + * a confirmation requestor (*req == 1). *req is 0 on + * entry to this call. + * + * We autolabel the following partitions: /, swap, /var, /tmp, /usr, + * and /home. /home receives any extra left over disk space. + */ +static char * +try_auto_label(Device **devs, Device *dev, int perc, int *req) +{ + daddr_t sz; + Chunk *AutoHome, *AutoRoot, *AutoSwap; + Chunk *AutoTmp, *AutoUsr, *AutoVar; +#ifdef __ia64__ + Chunk *AutoEfi; +#endif + int mib[2]; + unsigned long physmem; + size_t size; + char *msg = NULL; + + sz = space_free(label_chunk_info[here].c); + if (sz <= FS_MIN_SIZE) + return("Not enough free space to create a new partition in the slice"); + + (void)checkLabels(FALSE); + AutoHome = AutoRoot = AutoSwap = NULL; + AutoTmp = AutoUsr = AutoVar = NULL; + +#ifdef __ia64__ + AutoEfi = NULL; + if (EfiChunk == NULL) { + sz = 100 * ONE_MEG; + AutoEfi = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, sz, efi, 0, 0); + if (AutoEfi == NULL) { + *req = 1; + msg = "Unable to create the EFI system partition. Too big?"; + goto done; + } + AutoEfi->private_data = new_part(PART_EFI, "/efi", TRUE); + AutoEfi->private_free = safe_free; + AutoEfi->flags |= CHUNK_NEWFS; + record_label_chunks(devs, dev); + } +#endif + + if (RootChunk == NULL) { + sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc); + + AutoRoot = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, sz, part, + FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE); + if (!AutoRoot) { + *req = 1; + msg = "Unable to create the root partition. Too big?"; + goto done; + } + AutoRoot->private_data = new_part(PART_FILESYSTEM, "/", TRUE); + AutoRoot->private_free = safe_free; + AutoRoot->flags |= CHUNK_NEWFS; + record_label_chunks(devs, dev); + } + if (SwapChunk == NULL) { + sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc); + if (sz == 0) { + daddr_t nom; + daddr_t def; + + mib[0] = CTL_HW; + mib[1] = HW_PHYSMEM; + size = sizeof physmem; + sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); + def = 2 * (int)(physmem / 512); + if (def < SWAP_MIN_SIZE * ONE_MEG) + def = SWAP_MIN_SIZE * ONE_MEG; + if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG) + def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG; + nom = (int)(physmem / 512) / 8; + sz = nom + (def - nom) * perc / 100; + } + AutoSwap = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, sz, part, + FS_SWAP, CHUNK_AUTO_SIZE); + if (!AutoSwap) { + *req = 1; + msg = "Unable to create the swap partition. Too big?"; + goto done; + } + AutoSwap->private_data = 0; + AutoSwap->private_free = safe_free; + record_label_chunks(devs, dev); + } + if (VarChunk == NULL) { + sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc); + + AutoVar = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, sz, part, + FS_BSDFFS, CHUNK_AUTO_SIZE); + if (!AutoVar) { + *req = 1; + msg = "Not enough free space for /var - you will need to\n" + "partition your disk manually with a custom install!"; + goto done; + } + AutoVar->private_data = new_part(PART_FILESYSTEM, "/var", TRUE); + AutoVar->private_free = safe_free; + AutoVar->flags |= CHUNK_NEWFS; + record_label_chunks(devs, dev); + } + if (TmpChunk == NULL && !variable_get(VAR_NO_TMP)) { + sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc); + + AutoTmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, sz, part, + FS_BSDFFS, CHUNK_AUTO_SIZE); + if (!AutoTmp) { + *req = 1; + msg = "Not enough free space for /tmp - you will need to\n" + "partition your disk manually with a custom install!"; + goto done; + } + AutoTmp->private_data = new_part(PART_FILESYSTEM, "/tmp", TRUE); + AutoTmp->private_free = safe_free; + AutoTmp->flags |= CHUNK_NEWFS; + record_label_chunks(devs, dev); + } + if (UsrChunk == NULL && !variable_get(VAR_NO_USR)) { + sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc); +#if AUTO_HOME == 0 + sz = space_free(label_chunk_info[here].c); +#endif + if (sz) { + if (sz < (USR_MIN_SIZE * ONE_MEG)) { + *req = 1; + msg = "Not enough free space for /usr - you will need to\n" + "partition your disk manually with a custom install!"; + } + + AutoUsr = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, sz, part, + FS_BSDFFS, CHUNK_AUTO_SIZE); + if (!AutoUsr) { + msg = "Unable to create the /usr partition. Not enough space?\n" + "You will need to partition your disk manually with a custom install!"; + goto done; + } + AutoUsr->private_data = new_part(PART_FILESYSTEM, "/usr", TRUE); + AutoUsr->private_free = safe_free; + AutoUsr->flags |= CHUNK_NEWFS; + record_label_chunks(devs, dev); + } + } +#if AUTO_HOME == 1 + if (HomeChunk == NULL && !variable_get(VAR_NO_HOME)) { + sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc); + if (sz < space_free(label_chunk_info[here].c)) + sz = space_free(label_chunk_info[here].c); + if (sz) { + if (sz < (HOME_MIN_SIZE * ONE_MEG)) { + *req = 1; + msg = "Not enough free space for /home - you will need to\n" + "partition your disk manually with a custom install!"; + goto done; + } + + AutoHome = Create_Chunk_DWIM(label_chunk_info[here].c->disk, + label_chunk_info[here].c, sz, part, + FS_BSDFFS, CHUNK_AUTO_SIZE); + if (!AutoHome) { + msg = "Unable to create the /home partition. Not enough space?\n" + "You will need to partition your disk manually with a custom install!"; + goto done; + } + AutoHome->private_data = new_part(PART_FILESYSTEM, "/home", TRUE); + AutoHome->private_free = safe_free; + AutoHome->flags |= CHUNK_NEWFS; + record_label_chunks(devs, dev); + } + } +#endif + + /* At this point, we're reasonably "labelled" */ + if (variable_cmp(DISK_LABELLED, "written")) + variable_set2(DISK_LABELLED, "yes", 0); + +done: + if (msg) { + if (AutoRoot != NULL) + Delete_Chunk(AutoRoot->disk, AutoRoot); + if (AutoSwap != NULL) + Delete_Chunk(AutoSwap->disk, AutoSwap); + if (AutoVar != NULL) + Delete_Chunk(AutoVar->disk, AutoVar); + if (AutoTmp != NULL) + Delete_Chunk(AutoTmp->disk, AutoTmp); + if (AutoUsr != NULL) + Delete_Chunk(AutoUsr->disk, AutoUsr); + if (AutoHome != NULL) + Delete_Chunk(AutoHome->disk, AutoHome); + record_label_chunks(devs, dev); + } + return(msg); +} + +static int +diskLabelNonInteractive(Device *dev) +{ + char *cp; + PartType type; + PartInfo *p; + u_long flags; + int i, status; + Device **devs; + Disk *d; + + status = DITEM_SUCCESS; + cp = variable_get(VAR_DISK); + if (!cp) { + msgConfirm("diskLabel: No disk selected - can't label automatically."); + return DITEM_FAILURE; + } + devs = deviceFind(cp, DEVICE_TYPE_DISK); + if (!devs) { + msgConfirm("diskLabel: No disk device %s found!", cp); + return DITEM_FAILURE; + } + if (dev) + d = dev->private; + else + d = devs[0]->private; + record_label_chunks(devs, dev); + for (i = 0; label_chunk_info[i].c; i++) { + Chunk *c1 = label_chunk_info[i].c; + + if (label_chunk_info[i].type == PART_SLICE) { + char name[512]; + char typ[10], mpoint[50]; + int entries; + + for (entries = 1;; entries++) { + intmax_t sz; + int soft = 0; + snprintf(name, sizeof name, "%s-%d", c1->name, entries); + if ((cp = variable_get(name)) == NULL) + break; + if (sscanf(cp, "%s %jd %s %d", typ, &sz, mpoint, &soft) < 3) { + msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); + status = DITEM_FAILURE; + break; + } else { + Chunk *tmp; + + flags = 0; + if (!strcmp(typ, "swap")) { + type = PART_SWAP; + strcpy(mpoint, "SWAP"); + } else { + type = PART_FILESYSTEM; + if (!strcmp(mpoint, "/")) + flags |= CHUNK_IS_ROOT; + } + if (!sz) + sz = space_free(c1); + if (sz > space_free(c1)) { + msgConfirm("Not enough free space to create partition: %s", mpoint); + status = DITEM_FAILURE; + break; + } + if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, + (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { + msgConfirm("Unable to create from partition spec: %s. Too big?", cp); + status = DITEM_FAILURE; + break; + } else { + PartInfo *pi; + pi = tmp->private_data = new_part(PART_FILESYSTEM, mpoint, TRUE); + tmp->private_free = safe_free; + pi->newfs_data.newfs_ufs.softupdates = soft; + } + } + } + } else { + /* Must be something we can set a mountpoint for */ + cp = variable_get(c1->name); + if (cp) { + char mpoint[50], do_newfs[8]; + Boolean newfs = FALSE; + + do_newfs[0] = '\0'; + if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { + msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); + status = DITEM_FAILURE; + break; + } + newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; + if (c1->private_data) { + p = c1->private_data; + p->do_newfs = newfs; + strcpy(p->mountpoint, mpoint); + } + else { + c1->private_data = new_part(PART_FILESYSTEM, mpoint, newfs); + c1->private_free = safe_free; + } + if (!strcmp(mpoint, "/")) + c1->flags |= CHUNK_IS_ROOT; + else + c1->flags &= ~CHUNK_IS_ROOT; + } + } + } + if (status == DITEM_SUCCESS) + variable_set2(DISK_LABELLED, "yes", 0); + return status; +} diff --git a/usr.sbin/sysinstall/list.h b/usr.sbin/sysinstall/list.h new file mode 100644 index 0000000000000..8300173e0660a --- /dev/null +++ b/usr.sbin/sysinstall/list.h @@ -0,0 +1,60 @@ +/* + * The new sysinstall program. + * + * This is probably the last attempt in the `sysinstall' line, the next + * generation being slated for what's essentially a complete rewrite. + * + * $FreeBSD$ + * + * Copyright (c) 1997 FreeBSD, Inc. + * 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 PAUL TRAINA ``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 PAUL TRAINA OR HIS KILLER RATS 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. + * + */ + +/* The structure */ +typedef struct _qelement { + struct _qelement *q_forw; + struct _qelement *q_back; +} qelement; + +#define INITQUE(Xhead) { \ + (Xhead).q_forw = &(Xhead); \ + (Xhead).q_back = &(Xhead); \ +} + +#define EMPTYQUE(Xhead) \ + ((Xhead).q_forw == &(Xhead)) + +#define INSQUEUE(elem, pred) { \ + register qelement *Xe = (qelement *) (elem); \ + register qelement *Xp = (qelement *) (pred); \ + Xp->q_forw = (Xe->q_forw = (Xe->q_back = Xp)->q_forw)->q_back = Xe; \ +} + +#define REMQUE(elem) { \ + register qelement *Xe = (qelement *) (elem); \ + (Xe->q_back->q_forw = Xe->q_forw)->q_back = Xe->q_back; \ +} diff --git a/usr.sbin/sysinstall/main.c b/usr.sbin/sysinstall/main.c new file mode 100644 index 0000000000000..695754b074fc7 --- /dev/null +++ b/usr.sbin/sysinstall/main.c @@ -0,0 +1,187 @@ +/* + * The new sysinstall program. + * + * This is probably the last attempt in the `sysinstall' line, the next + * generation being slated for what's 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 <sys/signal.h> +#include <sys/fcntl.h> + +const char *StartName; /* Initial contents of argv[0] */ + +static void +screech(int sig) +{ + msgDebug("\007Signal %d caught! That's bad!\n", sig); + longjmp(BailOut, sig); +} + +int +main(int argc, char **argv) +{ + int choice, scroll, curr, max, status; + + /* Record name to be able to restart */ + StartName = argv[0]; + + /* Catch fatal signals and complain about them if running as init */ + if (getpid() == 1) { + signal(SIGBUS, screech); + signal(SIGSEGV, screech); + } + signal(SIGPIPE, SIG_IGN); + + /* We don't work too well when running as non-root anymore */ + if (geteuid() != 0) { + fprintf(stderr, "Error: This utility should only be run as root.\n"); + return 1; + } + +#ifdef PC98 + { + /* XXX */ + char *p = getenv("TERM"); + if (p && strcmp(p, "cons25") == 0) + putenv("TERM=cons25w"); + } +#endif + + /* Set up whatever things need setting up */ + systemInitialize(argc, argv); + + /* Set default flag and variable values */ + installVarDefaults(NULL); + /* only when multi-user is it reasonable to do this here */ + if (!RunningAsInit) + installEnvironment(); + + if (argc > 1 && !strcmp(argv[1], "-fake")) { + variable_set2(VAR_DEBUG, "YES", 0); + Fake = TRUE; + msgConfirm("I'll be just faking it from here on out, OK?"); + } + if (argc > 1 && !strcmp(argv[1], "-restart")) + Restarting = TRUE; + + /* Try to preserve our scroll-back buffer */ + if (OnVTY) { + for (curr = 0; curr < 25; curr++) + putchar('\n'); + } + /* Move stderr aside */ + if (DebugFD) + dup2(DebugFD, 2); + + /* Initialize driver modules, if we haven't already done so (ie, + the user hit Ctrl-C -> Restart. */ + if (!pvariable_get("modulesInitialize")) { + moduleInitialize(); + pvariable_set("modulesInitialize=1"); + } + + /* Initialize PC Card, if we haven't already done so. */ +#ifdef PCCARD_ARCH + if (!variable_cmp(VAR_SKIP_PCCARD, "YES") && + variable_get(VAR_SKIP_PCCARD)!=1 && + !pvariable_get("pccardInitialize")) { + pccardInitialize(); + pvariable_set("pccardInitialize=1"); + } +#endif + + /* Initialize USB, if we haven't already done so. */ + if (!pvariable_get("usbInitialize")) { + usbInitialize(); + pvariable_set("usbInitialize=1"); + } + + /* Probe for all relevant devices on the system */ + deviceGetAll(); + + /* Prompt for the driver floppy if appropriate. */ + if (!pvariable_get("driverFloppyCheck")) { + driverFloppyCheck(); + pvariable_set("driverFloppyCheck=1"); + } + + /* First, see if we have any arguments to process (and argv[0] counts if it's not "sysinstall") */ + if (!RunningAsInit) { + int i, start_arg; + + if (!strstr(argv[0], "sysinstall")) + start_arg = 0; + else if (Fake || Restarting) + start_arg = 2; + else + start_arg = 1; + for (i = start_arg; i < argc; i++) { + if (DITEM_STATUS(dispatchCommand(argv[i])) != DITEM_SUCCESS) + systemShutdown(1); + } + if (argc > start_arg) + systemShutdown(0); + } + else + dispatch_load_file_int(TRUE); + + status = setjmp(BailOut); + if (status) { + msgConfirm("A signal %d was caught - I'm saving what I can and shutting\n" + "down. If you can reproduce the problem, please turn Debug on\n" + "in the Options menu for the extra information it provides\n" + "in debugging problems like this.", status); + systemShutdown(status); + } + + /* Begin user dialog at outer menu */ + dialog_clear(); + while (1) { + choice = scroll = curr = max = 0; + dmenuOpen(&MenuInitial, &choice, &scroll, &curr, &max, TRUE); + if (getpid() != 1 +#if defined(__alpha__) || defined(__sparc64__) + || !msgNoYes("Are you sure you wish to exit? The system will halt.") +#else + || !msgNoYes("Are you sure you wish to exit? The system will reboot\n" + "(be sure to remove any floppies/CDs/DVDs from the drives).") +#endif + ) + break; + } + + /* Say goodnight, Gracie */ + systemShutdown(0); + + return 0; /* We should never get here */ +} diff --git a/usr.sbin/sysinstall/media.c b/usr.sbin/sysinstall/media.c new file mode 100644 index 0000000000000..cbdc01c04ed40 --- /dev/null +++ b/usr.sbin/sysinstall/media.c @@ -0,0 +1,882 @@ +/* + * 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 <signal.h> +#include <netdb.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/errno.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <resolv.h> + +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 ""; +} + +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 +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); +} + +static int +tapeHook(dialogMenuItem *self) +{ + return genericHook(self, DEVICE_TYPE_TAPE); +} + +/* + * Return 1 if we successfully found and set the installation type to + * be a tape drive. + */ +int +mediaSetTape(dialogMenuItem *self) +{ + Device **devs; + int cnt; + + mediaClose(); + devs = deviceFind(NULL, DEVICE_TYPE_TAPE); + cnt = deviceCount(devs); + if (!cnt) { + msgConfirm("No tape drive 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(&MenuMediaTape, DEVICE_TYPE_TAPE, tapeHook, NULL); + if (!menu) + msgFatal("Unable to create tape drive menu! Something is seriously wrong."); + status = dmenuOpenSimple(menu, FALSE); + free(menu); + if (!status) + return DITEM_FAILURE; + } + else + mediaDevice = devs[0]; + if (mediaDevice) { + char *val; + + val = msgGetInput("/var/tmp", "Please enter the name of a temporary directory containing\n" + "sufficient space for holding the contents of this tape (or\n" + "tapes). The contents of this directory will be removed\n" + "after installation, so be sure to specify a directory that\n" + "can be erased afterwards!\n"); + if (!val) + mediaDevice = NULL; + else + mediaDevice->private = strdup(val); + } + 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, 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://<hostname>/<path>\n" + "Where <path> 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.", + 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]; + int 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.", + 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(), "--block-size", mediaTapeBlocksize(), (char *)0); + else + i = execl(cpio, cpio, "-idum", "--block-size", mediaTapeBlocksize(), (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", + USE_GZIP ? "gunzip" : "bunzip2", 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(), "--block-size", mediaTapeBlocksize(), (char *)0); + else + i = execl(cpio, cpio, "-idum", "--block-size", mediaTapeBlocksize(), (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", + USE_GZIP ? "gunzip" : "bunzip2", 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"); +} + diff --git a/usr.sbin/sysinstall/menus.c b/usr.sbin/sysinstall/menus.c new file mode 100644 index 0000000000000..d38476ecf534f --- /dev/null +++ b/usr.sbin/sysinstall/menus.c @@ -0,0 +1,2300 @@ +/* + * The new sysinstall program. + * + * This is probably the last program in the `sysinstall' line - the next + * generation being essentially a complete rewrite. + * + * 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. + * + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif + +#include "sysinstall.h" + +/* Miscellaneous work routines for menus */ +static int +setSrc(dialogMenuItem *self) +{ + Dists |= DIST_SRC; + SrcDists = DIST_SRC_ALL; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +clearSrc(dialogMenuItem *self) +{ + Dists &= ~DIST_SRC; + SrcDists = 0; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +setX11Misc(dialogMenuItem *self) +{ + XOrgDists |= DIST_XORG_MISC_ALL; + Dists |= DIST_XORG; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +clearX11Misc(dialogMenuItem *self) +{ + XOrgDists &= ~DIST_XORG_MISC_ALL; + if (!XOrgDists) + Dists &= ~DIST_XORG; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +setX11Servers(dialogMenuItem *self) +{ + XOrgDists |= DIST_XORG_SERVER_ALL; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +clearX11Servers(dialogMenuItem *self) +{ + XOrgDists &= ~DIST_XORG_SERVER_ALL; + if (!XOrgDists) + Dists &= ~DIST_XORG; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +setX11Fonts(dialogMenuItem *self) +{ + XOrgDists |= DIST_XORG_FONTS_ALL; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +clearX11Fonts(dialogMenuItem *self) +{ + XOrgDists &= ~DIST_XORG_FONTS_ALL; + if (!XOrgDists) + Dists &= ~DIST_XORG; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +#define _IS_SET(dist, set) (((dist) & (set)) == (set)) + +#define IS_DEVELOPER(dist, extra) (_IS_SET(dist, _DIST_DEVELOPER | extra) || \ + _IS_SET(dist, _DIST_DEVELOPER | extra)) + +#define IS_USER(dist, extra) (_IS_SET(dist, _DIST_USER | extra) || \ + _IS_SET(dist, _DIST_USER | extra)) + +static int +checkDistDeveloper(dialogMenuItem *self) +{ + return IS_DEVELOPER(Dists, 0) && _IS_SET(SrcDists, DIST_SRC_ALL); +} + +static int +checkDistXDeveloper(dialogMenuItem *self) +{ + return IS_DEVELOPER(Dists, DIST_XORG) && _IS_SET(SrcDists, DIST_SRC_ALL); +} + +static int +checkDistKernDeveloper(dialogMenuItem *self) +{ + return IS_DEVELOPER(Dists, 0) && _IS_SET(SrcDists, DIST_SRC_SYS); +} + +static int +checkDistXKernDeveloper(dialogMenuItem *self) +{ + return IS_DEVELOPER(Dists, DIST_XORG) && _IS_SET(SrcDists, DIST_SRC_SYS); +} + +static int +checkDistUser(dialogMenuItem *self) +{ + return IS_USER(Dists, 0); +} + +static int +checkDistXUser(dialogMenuItem *self) +{ + return IS_USER(Dists, DIST_XORG); +} + +static int +checkDistMinimum(dialogMenuItem *self) +{ + return Dists == (DIST_BASE); +} + +static int +checkDistEverything(dialogMenuItem *self) +{ + return Dists == DIST_ALL && + _IS_SET(SrcDists, DIST_SRC_ALL) && + _IS_SET(XOrgDists, DIST_XORG_ALL); +} + +static int +srcFlagCheck(dialogMenuItem *item) +{ + return SrcDists; +} + +static int +x11FlagCheck(dialogMenuItem *item) +{ + if (XOrgDists != 0) + Dists |= DIST_XORG; + else + Dists &= ~DIST_XORG; + + return Dists & DIST_XORG; +} + +static int +checkTrue(dialogMenuItem *item) +{ + return TRUE; +} + +/* All the system menus go here. + * + * Hardcoded things like version number strings will disappear from + * these menus just as soon as I add the code for doing inline variable + * expansion. + */ + +DMenu MenuIndex = { + DMENU_NORMAL_TYPE, + "Glossary of functions", + "This menu contains an alphabetized index of the top level functions in\n" + "this program (sysinstall). Invoke an option by pressing [SPACE] or\n" + "[ENTER]. To exit, use [TAB] to move to the Cancel button.", + "Use PageUp or PageDown to move through this menu faster!", + NULL, + { { " Anon FTP", "Configure anonymous FTP logins.", dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, + { " Commit", "Commit any pending actions (dangerous!)", NULL, installCustomCommit }, +#ifdef WITH_SYSCONS + { " Console settings", "Customize system console behavior.", NULL, dmenuSubmenu, NULL, &MenuSyscons }, +#endif + { " Configure", "The system configuration menu.", NULL, dmenuSubmenu, NULL, &MenuConfigure }, + { " Defaults, Load", "Load default settings.", NULL, dispatch_load_floppy }, +#ifdef WITH_MICE + { " Device, Mouse", "The mouse configuration menu.", NULL, dmenuSubmenu, NULL, &MenuMouse }, +#endif + { " Disklabel", "The disk Label editor", NULL, diskLabelEditor }, + { " Dists, All", "Root of the distribution tree.", NULL, dmenuSubmenu, NULL, &MenuDistributions }, + { " Dists, Basic", "Basic FreeBSD distribution menu.", NULL, dmenuSubmenu, NULL, &MenuSubDistributions }, + { " Dists, Developer", "Select developer's distribution.", checkDistDeveloper, distSetDeveloper }, + { " Dists, Src", "Src distribution menu.", NULL, dmenuSubmenu, NULL, &MenuSrcDistributions }, + { " Dists, X Developer", "Select X developer's distribution.", checkDistXDeveloper, distSetXDeveloper }, + { " Dists, Kern Developer", "Select kernel developer's distribution.", checkDistKernDeveloper, distSetKernDeveloper }, + { " Dists, User", "Select average user distribution.", checkDistUser, distSetUser }, + { " Dists, X User", "Select average X user distribution.", checkDistXUser, distSetXUser }, + { " Distributions, Adding", "Installing additional distribution sets", NULL, distExtractAll }, + { " Distributions, X.Org","X.Org distribution menu.", NULL, distSetXOrg }, + { " Documentation", "Installation instructions, README, etc.", NULL, dmenuSubmenu, NULL, &MenuDocumentation }, + { " Doc, README", "The distribution README file.", NULL, dmenuDisplayFile, NULL, "README" }, + { " Doc, Migration Guide", "Migration Guide to FreeBSD 5.X.", NULL, dmenuDisplayFile, NULL, "MIGRATE5" }, + { " Doc, Errata", "The distribution errata.", NULL, dmenuDisplayFile, NULL, "ERRATA" }, + { " Doc, Hardware", "The distribution hardware guide.", NULL, dmenuDisplayFile, NULL, "HARDWARE" }, + { " Doc, Install", "The distribution installation guide.", NULL, dmenuDisplayFile, NULL, "INSTALL" }, + { " Doc, Copyright", "The distribution copyright notices.", NULL, dmenuDisplayFile, NULL, "COPYRIGHT" }, + { " Doc, Release", "The distribution release notes.", NULL, dmenuDisplayFile, NULL, "RELNOTES" }, + { " Doc, HTML", "The HTML documentation menu.", NULL, docBrowser }, + { " Dump Vars", "(debugging) dump out internal variables.", NULL, dump_variables }, + { " Emergency shell", "Start an Emergency Holographic shell.", NULL, installFixitHoloShell }, +#ifdef WITH_SLICES + { " Fdisk", "The disk Partition Editor", NULL, diskPartitionEditor }, +#endif + { " Fixit", "Repair mode with CDROM or fixit floppy.", NULL, dmenuSubmenu, NULL, &MenuFixit }, + { " FTP sites", "The FTP mirror site listing.", NULL, dmenuSubmenu, NULL, &MenuMediaFTP }, + { " Gateway", "Set flag to route packets between interfaces.", dmenuVarCheck, dmenuToggleVariable, NULL, "gateway=YES" }, + { " HTML Docs", "The HTML documentation menu", NULL, docBrowser }, + { " inetd Configuration", "Configure inetd and simple internet services.", dmenuVarCheck, configInetd, NULL, "inetd_enable=YES" }, + { " Install, Standard", "A standard system installation.", NULL, installStandard }, + { " Install, Express", "An express system installation.", NULL, installExpress }, + { " Install, Custom", "The custom installation menu", NULL, dmenuSubmenu, NULL, &MenuInstallCustom }, + { " Label", "The disk Label editor", NULL, diskLabelEditor }, + { " Media", "Top level media selection menu.", NULL, dmenuSubmenu, NULL, &MenuMedia }, + { " Media, Tape", "Select tape installation media.", NULL, mediaSetTape }, + { " Media, NFS", "Select NFS installation media.", NULL, mediaSetNFS }, + { " Media, Floppy", "Select floppy installation media.", NULL, mediaSetFloppy }, + { " Media, CDROM/DVD", "Select CDROM/DVD installation media.", NULL, mediaSetCDROM }, + { " Media, DOS", "Select DOS installation media.", NULL, mediaSetDOS }, + { " Media, UFS", "Select UFS installation media.", NULL, mediaSetUFS }, + { " Media, FTP", "Select FTP installation media.", NULL, mediaSetFTP }, + { " Media, FTP Passive", "Select passive FTP installation media.", NULL, mediaSetFTPPassive }, + { " Media, HTTP", "Select FTP via HTTP proxy installation media.", NULL, mediaSetHTTP }, + { " Network Interfaces", "Configure network interfaces", NULL, tcpMenuSelect }, + { " Networking Services", "The network services menu.", NULL, dmenuSubmenu, NULL, &MenuNetworking }, + { " NFS, client", "Set NFS client flag.", dmenuVarCheck, dmenuToggleVariable, NULL, "nfs_client_enable=YES" }, + { " NFS, server", "Set NFS server flag.", dmenuVarCheck, configNFSServer, NULL, "nfs_server_enable=YES" }, + { " NTP Menu", "The NTP configuration menu.", NULL, dmenuSubmenu, NULL, &MenuNTP }, + { " Options", "The options editor.", NULL, optionsEditor }, + { " Packages", "The packages collection", NULL, configPackages }, +#ifdef WITH_SLICES + { " Partition", "The disk Slice (PC-style partition) Editor", NULL, diskPartitionEditor }, +#endif + { " PCNFSD", "Run authentication server for PC-NFS.", dmenuVarCheck, configPCNFSD, NULL, "pcnfsd" }, + { " Root Password", "Set the system manager's password.", NULL, dmenuSystemCommand, NULL, "passwd root" }, + { " Router", "Select routing daemon (default: routed)", NULL, configRouter, NULL, "router_enable" }, + { " Security", "Configure system security options", NULL, dmenuSubmenu, NULL, &MenuSecurity }, +#ifdef WITH_SYSCONS + { " Syscons", "The system console configuration menu.", NULL, dmenuSubmenu, NULL, &MenuSyscons }, +#ifndef PC98 + { " Syscons, Font", "The console screen font.", NULL, dmenuSubmenu, NULL, &MenuSysconsFont }, +#endif + { " Syscons, Keymap", "The console keymap configuration menu.", NULL, dmenuSubmenu, NULL, &MenuSysconsKeymap }, + { " Syscons, Keyrate", "The console key rate configuration menu.", NULL, dmenuSubmenu, NULL, &MenuSysconsKeyrate }, + { " Syscons, Saver", "The console screen saver configuration menu.", NULL, dmenuSubmenu, NULL, &MenuSysconsSaver }, +#ifndef PC98 + { " Syscons, Screenmap", "The console screenmap configuration menu.", NULL, dmenuSubmenu, NULL, &MenuSysconsScrnmap }, + { " Syscons, Ttys", "The console terminal type menu.", NULL, dmenuSubmenu, NULL, &MenuSysconsTtys }, +#endif +#endif /* WITH_SYSCONS */ + { " Time Zone", "Set the system's time zone.", NULL, dmenuSystemCommand, NULL, "tzsetup" }, + { " TTYs", "Configure system ttys.", NULL, configEtcTtys, NULL, "ttys" }, + { " Upgrade", "Upgrade an existing system.", NULL, installUpgrade }, + { " Usage", "Quick start - How to use this menu system.", NULL, dmenuDisplayFile, NULL, "usage" }, + { " User Management", "Add user and group information.", NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, + { " X.Org, Fonts", "X.Org Font selection menu.", NULL, dmenuSubmenu, NULL, &MenuXOrgSelectFonts }, + { " X.Org, Server", "X.Org Server selection menu.", NULL, dmenuSubmenu, NULL, &MenuXOrgSelectServer }, + { NULL } }, +}; + +/* The initial installation menu */ +DMenu MenuInitial = { + DMENU_NORMAL_TYPE, + "sysinstall Main Menu", /* title */ + "Welcome to the FreeBSD installation and configuration tool. Please\n" /* prompt */ + "select one of the options below by using the arrow keys or typing the\n" + "first character of the option name you're interested in. Invoke an\n" + "option with [SPACE] or [ENTER]. To exit, use [TAB] to move to Exit.", + "Press F1 for Installation Guide", /* help line */ + "INSTALL", /* help file */ + { { " Select " }, + { "X Exit Install", NULL, NULL, dmenuExit }, + { " Usage", "Quick start - How to use this menu system", NULL, dmenuDisplayFile, NULL, "usage" }, + { "Standard", "Begin a standard installation (recommended)", NULL, installStandard }, + { "Express", "Begin a quick installation (for experts)", NULL, installExpress }, + { " Custom", "Begin a custom installation (for experts)", NULL, dmenuSubmenu, NULL, &MenuInstallCustom }, + { "Configure", "Do post-install configuration of FreeBSD", NULL, dmenuSubmenu, NULL, &MenuConfigure }, + { "Doc", "Installation instructions, README, etc.", NULL, dmenuSubmenu, NULL, &MenuDocumentation }, +#ifdef WITH_SYSCONS + { "Keymap", "Select keyboard type", NULL, dmenuSubmenu, NULL, &MenuSysconsKeymap }, +#endif + { "Options", "View/Set various installation options", NULL, optionsEditor }, + { "Fixit", "Repair mode with CDROM/DVD/floppy or start shell", NULL, dmenuSubmenu, NULL, &MenuFixit }, + { "Upgrade", "Upgrade an existing system", NULL, installUpgrade }, + { "Load Config","Load default install configuration", NULL, dispatch_load_floppy }, + { "Index", "Glossary of functions", NULL, dmenuSubmenu, NULL, &MenuIndex }, + { NULL } }, +}; + +/* The main documentation menu */ +DMenu MenuDocumentation = { + DMENU_NORMAL_TYPE, + "FreeBSD Documentation Menu", + "If you are at all unsure about the configuration of your hardware\n" + "or are looking to build a system specifically for FreeBSD, read the\n" + "Hardware guide! New users should also read the Install document for\n" + "a step-by-step tutorial on installing FreeBSD. For general information,\n" + "consult the README file.", + "Confused? Press F1 for help.", + "usage", + { { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { "1 README", "A general description of FreeBSD. Read this!", NULL, dmenuDisplayFile, NULL, "README" }, + { "2 Migration", "Migration Guide to FreeBSD 5.X.", NULL, dmenuDisplayFile, NULL, "MIGRATE5" }, + { "3 Errata", "Late-breaking, post-release news.", NULL, dmenuDisplayFile, NULL, "ERRATA" }, + { "4 Hardware", "The FreeBSD survival guide for PC hardware.", NULL, dmenuDisplayFile, NULL, "HARDWARE" }, + { "5 Install", "A step-by-step guide to installing FreeBSD.", NULL, dmenuDisplayFile, NULL, "INSTALL" }, + { "6 Copyright", "The FreeBSD Copyright notices.", NULL, dmenuDisplayFile, NULL, "COPYRIGHT" }, + { "7 Release" ,"The release notes for this version of FreeBSD.", NULL, dmenuDisplayFile, NULL, "RELNOTES" }, + { "8 Shortcuts", "Creating shortcuts to sysinstall.", NULL, dmenuDisplayFile, NULL, "shortcuts" }, + { "9 HTML Docs", "Go to the HTML documentation menu (post-install).", NULL, docBrowser }, + { NULL } }, +}; + +#ifdef WITH_MICE +DMenu MenuMouseType = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, +#ifdef PC98 + "Select a protocol type for your mouse", + "If your mouse is attached to the bus mouse port, you should always choose\n" + "\"Auto\", regardless of the model and the brand of the mouse. All other\n" + "protocol types are for serial mice and should not be used with the bus\n" + "mouse. If you have a serial mouse and are not sure about its protocol,\n" + "you should also try \"Auto\". It may not work for the serial mouse if the\n" + "mouse does not support the PnP standard. But, it won't hurt. Many\n" + "2-button serial mice are compatible with \"Microsoft\" or \"MouseMan\".\n" + "3-button serial mice may be compatible with \"MouseSystems\" or \"MouseMan\".\n" + "If the serial mouse has a wheel, it may be compatible with \"IntelliMouse\".", + NULL, + NULL, + { { "1 Auto", "Bus mouse or PnP serial mouse", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=auto" }, +#else + "Select a protocol type for your mouse", + "If your mouse is attached to the PS/2 mouse port or the bus mouse port,\n" + "you should always choose \"Auto\", regardless of the model and the brand\n" + "of the mouse. All other protocol types are for serial mice and should\n" + "not be used with the PS/2 port mouse or the bus mouse. If you have\n" + "a serial mouse and are not sure about its protocol, you should also try\n" + "\"Auto\". It may not work for the serial mouse if the mouse does not\n" + "support the PnP standard. But, it won't hurt. Many 2-button serial mice\n" + "are compatible with \"Microsoft\" or \"MouseMan\". 3-button serial mice\n" + "may be compatible with \"MouseSystems\" or \"MouseMan\". If the serial\n" + "mouse has a wheel, it may be compatible with \"IntelliMouse\".", + NULL, + NULL, + { { "1 Auto", "Bus mouse, PS/2 style mouse or PnP serial mouse", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=auto" }, +#endif /* PC98 */ + { "2 GlidePoint", "ALPS GlidePoint pad (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=glidepoint" }, + { "3 Hitachi","Hitachi tablet (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=mmhittab" }, + { "4 IntelliMouse", "Microsoft IntelliMouse (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=intellimouse" }, + { "5 Logitech", "Logitech protocol (old models) (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=logitech" }, + { "6 Microsoft", "Microsoft protocol (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=microsoft" }, + { "7 MM Series","MM Series protocol (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=mmseries" }, + { "8 MouseMan", "Logitech MouseMan/TrackMan models (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=mouseman" }, + { "9 MouseSystems", "MouseSystems protocol (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=mousesystems" }, + { "A ThinkingMouse","Kensington ThinkingMouse (serial)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_TYPE "=thinkingmouse" }, + { NULL } }, +}; + +#ifdef PC98 +DMenu MenuMousePort = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Select your mouse port from the following menu", + "The built-in pointing device of laptop/notebook computers is usually\n" + "a BusMouse style device.", + NULL, + NULL, + { + { "1 BusMouse", "PC-98x1 bus mouse (/dev/mse0)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/mse0" }, + { "2 COM1", "Serial mouse on COM1 (/dev/cuaa0)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/cuaa0" }, + { "3 COM2", "Serial mouse on COM2 (/dev/cuaa1)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/cuaa1" }, + { NULL } }, +}; +#else +DMenu MenuMousePort = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Select your mouse port from the following menu", + "The built-in pointing device of laptop/notebook computers is usually\n" + "a PS/2 style device.", + NULL, + NULL, + { { "1 PS/2", "PS/2 style mouse (/dev/psm0)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/psm0" }, + { "2 COM1", "Serial mouse on COM1 (/dev/cuaa0)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/cuaa0" }, + { "3 COM2", "Serial mouse on COM2 (/dev/cuaa1)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/cuaa1" }, + { "4 COM3", "Serial mouse on COM3 (/dev/cuaa2)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/cuaa2" }, + { "5 COM4", "Serial mouse on COM4 (/dev/cuaa3)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/cuaa3" }, + { "6 BusMouse", "Logitech, ATI or MS bus mouse (/dev/mse0)", + dmenuVarCheck, dmenuSetVariable, NULL, VAR_MOUSED_PORT "=/dev/mse0" }, + { NULL } }, +}; +#endif /* PC98 */ + +DMenu MenuMouse = { + DMENU_NORMAL_TYPE, + "Please configure your mouse", + "You can cut and paste text in the text console by running the mouse\n" + "daemon. Specify a port and a protocol type of your mouse and enable\n" + "the mouse daemon. If you don't want this feature, select 6 to disable\n" + "the daemon.\n" + "Once you've enabled the mouse daemon, you can specify \"/dev/sysmouse\"\n" + "as your mouse device and \"SysMouse\" or \"MouseSystems\" as mouse\n" + "protocol when running the X configuration utility (see Configuration\n" + "menu).", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { "2 Enable", "Test and run the mouse daemon", NULL, mousedTest, NULL, NULL }, + { "3 Type", "Select mouse protocol type", NULL, dmenuSubmenu, NULL, &MenuMouseType }, + { "4 Port", "Select mouse port", NULL, dmenuSubmenu, NULL, &MenuMousePort }, + { "5 Flags", "Set additional flags", dmenuVarCheck, setMouseFlags, + NULL, VAR_MOUSED_FLAGS "=" }, + { "6 Disable", "Disable the mouse daemon", NULL, mousedDisable, NULL, NULL }, + { NULL } }, +}; +#endif /* WITH_MICE */ + +DMenu MenuMediaCDROM = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Choose a CD/DVD type", + "FreeBSD can be installed directly from a CD/DVD containing a valid\n" + "FreeBSD distribution. If you are seeing this menu it is because\n" + "more than one CD/DVD drive was found on your system. Please select one\n" + "of the following CD/DVD drives as your installation drive.", + "Press F1 to read the installation guide", + "INSTALL", + { { NULL } }, +}; + +DMenu MenuMediaFloppy = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Choose a Floppy drive", + "You have more than one floppy drive. Please choose which drive\n" + "you would like to use.", + NULL, + NULL, + { { NULL } }, +}; + +DMenu MenuMediaDOS = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Choose a DOS partition", + "FreeBSD can be installed directly from a DOS partition\n" + "assuming, of course, that you have copied the relevant\n" + "distributions into your DOS partition before starting this\n" + "installation. If this is not the case then you should reboot\n" + "DOS at this time and copy the distributions you wish to install\n" + "into a \"FREEBSD\" subdirectory on one of your DOS partitions.\n" + "Otherwise, please select the DOS partition containing the FreeBSD\n" + "distribution files.", + "Press F1 to read the installation guide", + "INSTALL", + { { NULL } }, +}; + +DMenu MenuMediaFTP = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Please select a FreeBSD FTP distribution site", + "Please select the site closest to you or \"other\" if you'd like to\n" + "specify a different choice. Also note that not every site listed here\n" + "carries more than the base distribution kits. Only Primary sites are\n" + "guaranteed to carry the full range of possible distributions.", + "Select a site that's close!", + "INSTALL", + { { "Main Site", "ftp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.freebsd.org" }, + { "URL", "Specify some other ftp site by URL", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=other" }, + { "Snapshots Server Japan", "snapshots.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://snapshots.jp.freebsd.org" }, + { "Snapshots Server Sweden", "snapshots.se.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://snapshots.se.freebsd.org" }, + + { "IPv6 Ireland", "ftp3.ie.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.ie.freebsd.org" }, + { " IPv6 Japan", "ftp2.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.jp.freebsd.org" }, + { " IPv6 USA", "ftp4.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.us.freebsd.org" }, + + { "Primary", "ftp1.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp1.freebsd.org" }, + { " Primary #2", "ftp2.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.freebsd.org" }, + { " Primary #3", "ftp3.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.freebsd.org" }, + { " Primary #4", "ftp4.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.freebsd.org" }, + { " Primary #5", "ftp5.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.freebsd.org" }, + { " Primary #6", "ftp6.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.freebsd.org" }, + { " Primary #7", "ftp7.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp7.freebsd.org" }, + { " Primary #8", "ftp8.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp8.freebsd.org" }, + { " Primary #9", "ftp9.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp9.freebsd.org" }, + { " Primary #10", "ftp10.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp10.freebsd.org" }, + { " Primary #11", "ftp11.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp11.freebsd.org" }, + { " Primary #12", "ftp12.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp12.freebsd.org" }, + { " Primary #13", "ftp13.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp13.freebsd.org" }, + { " Primary #14", "ftp14.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp14.freebsd.org" }, + + { "Argentina", "ftp.ar.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ar.freebsd.org" }, + + { "Australia", "ftp.au.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.au.freebsd.org" }, + { " Australia #2","ftp2.au.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.au.freebsd.org" }, + { " Australia #3","ftp3.au.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.au.freebsd.org" }, + + { "Austria","ftp.at.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.at.freebsd.org" }, + { " Austria #2","ftp2.at.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.at.freebsd.org" }, + + { "Brazil", "ftp.br.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.br.freebsd.org" }, + { " Brazil #2", "ftp2.br.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.br.freebsd.org" }, + { " Brazil #3", "ftp3.br.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.br.freebsd.org" }, + { " Brazil #4", "ftp4.br.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.br.freebsd.org" }, + { " Brazil #5", "ftp5.br.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.br.freebsd.org" }, + { " Brazil #6", "ftp6.br.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.br.freebsd.org" }, + { " Brazil #7", "ftp7.br.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp7.br.freebsd.org" }, + + { "Canada", "ftp.ca.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ca.freebsd.org" }, + + { "China", "ftp.cn.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.cn.freebsd.org" }, + { " China #2", "ftp2.cn.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.cn.freebsd.org" }, + + { "Croatia", "ftp.hr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.hr.freebsd.org" }, + + { "Czech Republic", "ftp.cz.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.cz.freebsd.org" }, + + { "Denmark", "ftp.dk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.dk.freebsd.org" }, + { " Denmark #2", "ftp2.dk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.dk.freebsd.org" }, + + { "Estonia", "ftp.ee.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ee.freebsd.org" }, + + { "Finland", "ftp.fi.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.fi.freebsd.org" }, + + { "France", "ftp.fr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.fr.freebsd.org" }, + { " France #2", "ftp2.fr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.fr.freebsd.org" }, + { " France #3", "ftp3.fr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.fr.freebsd.org" }, + { " France #5", "ftp5.fr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.fr.freebsd.org" }, + { " France #6", "ftp6.fr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.fr.freebsd.org" }, + { " France #8", "ftp8.fr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp8.fr.freebsd.org" }, + + { "Germany", "ftp.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.de.freebsd.org" }, + { " Germany #2", "ftp2.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.de.freebsd.org" }, + { " Germany #3", "ftp3.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.de.freebsd.org" }, + { " Germany #4", "ftp4.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.de.freebsd.org" }, + { " Germany #5", "ftp5.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.de.freebsd.org" }, + { " Germany #6", "ftp6.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.de.freebsd.org" }, + { " Germany #7", "ftp7.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp7.de.freebsd.org" }, + { " Germany #8", "ftp8.de.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp8.de.freebsd.org" }, + + { "Greece", "ftp.gr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.gr.freebsd.org" }, + { " Greece #2", "ftp2.gr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.gr.freebsd.org" }, + + { "Hong Kong", "ftp.hk.super.net", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.hk.super.net" }, + + { "Hungary", "ftp.hu.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.hu.freebsd.org" }, + + { "Iceland", "ftp.is.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.is.freebsd.org" }, + + { "Ireland", "ftp.ie.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ie.freebsd.org" }, + { " Ireland #2", "ftp2.ie.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.ie.freebsd.org" }, + { " Ireland #3", "ftp3.ie.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.ie.freebsd.org" }, + + { "Italy", "ftp.it.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.it.freebsd.org" }, + + { "Japan", "ftp.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.jp.freebsd.org" }, + { " Japan #2", "ftp2.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.jp.freebsd.org" }, + { " Japan #3", "ftp3.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.jp.freebsd.org" }, + { " Japan #4", "ftp4.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.jp.freebsd.org" }, + { " Japan #5", "ftp5.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.jp.freebsd.org" }, + { " Japan #6", "ftp6.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.jp.freebsd.org" }, + { " Japan #7", "ftp7.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp7.jp.freebsd.org" }, + { " Japan #8", "ftp8.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp8.jp.freebsd.org" }, + { " Japan #9", "ftp9.jp.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp9.jp.freebsd.org" }, + + { "Korea", "ftp.kr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.kr.freebsd.org" }, + { " Korea #2", "ftp2.kr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.kr.freebsd.org" }, + + { "Lithuania", "ftp.lt.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.lt.freebsd.org" }, + + { "Netherlands", "ftp.nl.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.nl.freebsd.org" }, + { " Netherlands #2", "ftp2.nl.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.nl.freebsd.org" }, + + { "Norway", "ftp.no.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.no.freebsd.org" }, + { " Norway #3", "ftp3.no.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.no.freebsd.org" }, + + { "Poland", "ftp.pl.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.pl.freebsd.org" }, + { " Poland #2", "ftp2.pl.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.pl.freebsd.org" }, + { " Poland #5", "ftp5.pl.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.pl.freebsd.org" }, + + { "Portugal", "ftp.pt.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.pt.freebsd.org" }, + { " Portugal #2", "ftp2.pt.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.pt.freebsd.org" }, + { " Portugal #4", "ftp4.pt.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.pt.freebsd.org" }, + + { "Romania", "ftp.ro.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ro.freebsd.org" }, + + { "Russia", "ftp.ru.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ru.freebsd.org" }, + { " Russia #2", "ftp2.ru.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.ru.freebsd.org" }, + { " Russia #3", "ftp3.ru.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.ru.freebsd.org" }, + { " Russia #4", "ftp4.ru.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.ru.freebsd.org" }, + + { "Singapore", "ftp.sg.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.sg.freebsd.org" }, + + { "Slovak Republic", "ftp.sk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.sk.freebsd.org" }, + + { "Slovenia", "ftp.si.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.si.freebsd.org" }, + { " Slovenia #2", "ftp2.si.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.si.freebsd.org" }, + + { "South Africa", "ftp.za.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.za.freebsd.org" }, + { " South Africa #2", "ftp2.za.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.za.freebsd.org" }, + { " South Africa #3", "ftp3.za.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.za.freebsd.org" }, + { " South Africa #4", "ftp4.za.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.za.freebsd.org" }, + + { "Spain", "ftp.es.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.es.freebsd.org" }, + { " Spain #2", "ftp2.es.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.es.freebsd.org" }, + { " Spain #3", "ftp3.es.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.es.freebsd.org" }, + + { "Sweden", "ftp.se.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.se.freebsd.org" }, + { " Sweden #2", "ftp2.se.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.se.freebsd.org" }, + { " Sweden #3", "ftp3.se.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.se.freebsd.org" }, + { " Sweden #5", "ftp5.se.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.se.freebsd.org" }, + + { "Switzerland", "ftp.ch.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ch.freebsd.org" }, + { " Switzerland #2", "ftp2.ch.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.ch.freebsd.org" }, + + { "Taiwan", "ftp.tw.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.tw.freebsd.org" }, + { " Taiwan #2", "ftp2.tw.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.tw.freebsd.org" }, + { " Taiwan #3", "ftp3.tw.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.tw.freebsd.org" }, + { " Taiwan #4", "ftp4.tw.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.tw.freebsd.org" }, + { " Taiwan #6", "ftp6.tw.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.tw.freebsd.org" }, + { " Taiwan #11", "ftp11.tw.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp11.tw.freebsd.org" }, + + { "Turkey", "ftp.tr.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.tr.freebsd.org" }, + + { "UK", "ftp.uk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.uk.freebsd.org" }, + { " UK #2", "ftp2.uk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.uk.freebsd.org" }, + { " UK #3", "ftp3.uk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.uk.freebsd.org" }, + { " UK #4", "ftp4.uk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.uk.freebsd.org" }, + { " UK #5", "ftp5.uk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.uk.freebsd.org" }, + { " UK #6", "ftp6.uk.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.uk.freebsd.org" }, + + { "Ukraine", "ftp.ua.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp.ua.freebsd.org" }, + { " Ukraine #2", "ftp2.ua.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.ua.freebsd.org" }, + { " Ukraine #5", "ftp5.ua.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.ua.freebsd.org" }, + { " Ukraine #6", "ftp6.ua.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.ua.freebsd.org" }, + { " Ukraine #7", "ftp7.ua.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp7.ua.freebsd.org" }, + { " Ukraine #8", "ftp8.ua.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp8.ua.freebsd.org" }, + + { "USA #1", "ftp1.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp1.us.freebsd.org" }, + { " USA #2", "ftp2.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp2.us.freebsd.org" }, + { " USA #3", "ftp3.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp3.us.freebsd.org" }, + { " USA #4", "ftp4.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp4.us.freebsd.org" }, + { " USA #5", "ftp5.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp5.us.freebsd.org" }, + { " USA #6", "ftp6.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp6.us.freebsd.org" }, + { " USA #7", "ftp7.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp7.us.freebsd.org" }, + { " USA #8", "ftp8.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp8.us.freebsd.org" }, + { " USA #9", "ftp9.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp9.us.freebsd.org" }, + { " USA #10", "ftp10.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp10.us.freebsd.org" }, + { " USA #11", "ftp11.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp11.us.freebsd.org" }, + { " USA #12", "ftp12.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp12.us.freebsd.org" }, + { " USA #13", "ftp13.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp13.us.freebsd.org" }, + { " USA #14", "ftp14.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp14.us.freebsd.org" }, + { " USA #15", "ftp15.us.freebsd.org", NULL, dmenuSetVariable, NULL, + VAR_FTP_PATH "=ftp://ftp15.us.freebsd.org" }, + + { NULL } } +}; + +DMenu MenuMediaTape = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Choose a tape drive type", + "FreeBSD can be installed from tape drive, though this installation\n" + "method requires a certain amount of temporary storage in addition\n" + "to the space required by the distribution itself (tape drives make\n" + "poor random-access devices, so we extract _everything_ on the tape\n" + "in one pass). If you have sufficient space for this, then you should\n" + "select one of the following tape devices detected on your system.", + "Press F1 to read the installation guide", + "INSTALL", + { { NULL } }, +}; + +DMenu MenuNetworkDevice = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Network interface information required", + "If you are using PPP over a serial device, as opposed to a direct\n" + "ethernet connection, then you may first need to dial your Internet\n" + "Service Provider using the ppp utility we provide for that purpose.\n" + "If you're using SLIP over a serial device then the expectation is\n" + "that you have a HARDWIRED connection.\n\n" + "You can also install over a parallel port using a special \"laplink\"\n" + "cable to another machine running FreeBSD.", + "Press F1 to read network configuration manual", + "network_device", + { { NULL } }, +}; + +/* Prototype KLD load menu */ +DMenu MenuKLD = { + DMENU_NORMAL_TYPE, + "KLD Menu", + "Load a KLD from a floppy\n", + NULL, + NULL, + { { NULL } }, +}; + +/* The media selection menu */ +DMenu MenuMedia = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Choose Installation Media", + "FreeBSD can be installed from a variety of different installation\n" + "media, ranging from floppies to an Internet FTP server. If you're\n" + "installing FreeBSD from a supported CD/DVD drive then this is generally\n" + "the best media to use if you have no overriding reason for using other\n" + "media.", + "Press F1 for more information on the various media types", + "media", + { { "1 CD/DVD", "Install from a FreeBSD CD/DVD", NULL, mediaSetCDROM }, + { "2 FTP", "Install from an FTP server", NULL, mediaSetFTPActive }, + { "3 FTP Passive", "Install from an FTP server through a firewall", NULL, mediaSetFTPPassive }, + { "4 HTTP", "Install from an FTP server through a http proxy", NULL, mediaSetHTTP }, + { "5 DOS", "Install from a DOS partition", NULL, mediaSetDOS }, + { "6 NFS", "Install over NFS", NULL, mediaSetNFS }, + { "7 File System", "Install from an existing filesystem", NULL, mediaSetUFS }, + { "8 Floppy", "Install from a floppy disk set", NULL, mediaSetFloppy }, + { "9 Tape", "Install from SCSI or QIC tape", NULL, mediaSetTape }, + { "X Options", "Go to the Options screen", NULL, optionsEditor }, + { NULL } }, +}; + +/* The distributions menu */ +DMenu MenuDistributions = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "Choose Distributions", + "As a convenience, we provide several \"canned\" distribution sets.\n" + "These select what we consider to be the most reasonable defaults for the\n" + "type of system in question. If you would prefer to pick and choose the\n" + "list of distributions yourself, simply select \"Custom\". You can also\n" + "pick a canned distribution set and then fine-tune it with the Custom item.\n\n" + "Choose an item by pressing [SPACE] or [ENTER]. When finished, choose the\n" + "Exit item or move to the OK button with [TAB].", + "Press F1 for more information on these options.", + "distributions", + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "All", "All system sources, binaries and X Window System", + checkDistEverything, distSetEverything, NULL, NULL, ' ', ' ', ' ' }, + { "Reset", "Reset selected distribution list to nothing", + NULL, distReset, NULL, NULL, ' ', ' ', ' ' }, + { "4 Developer", "Full sources, binaries and doc but no games", + checkDistDeveloper, distSetDeveloper }, + { "5 X-Developer", "Same as above + X Window System", + checkDistXDeveloper, distSetXDeveloper }, + { "6 Kern-Developer", "Full binaries and doc, kernel sources only", + checkDistKernDeveloper, distSetKernDeveloper }, + { "7 X-Kern-Developer", "Same as above + X Window System", + checkDistXKernDeveloper, distSetXKernDeveloper }, + { "8 User", "Average user - binaries and doc only", + checkDistUser, distSetUser }, + { "9 X-User", "Same as above + X Window System", + checkDistXUser, distSetXUser }, + { "A Minimal", "The smallest configuration possible", + checkDistMinimum, distSetMinimum }, + { "B Custom", "Specify your own distribution set", + NULL, dmenuSubmenu, NULL, &MenuSubDistributions, '>', '>', '>' }, + { NULL } }, +}; + +DMenu MenuSubDistributions = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "Select the distributions you wish to install.", + "Please check off the distributions you wish to install. At the\n" + "very minimum, this should be \"base\".", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "All", "All system sources, binaries and X Window System", + NULL, distSetEverything, NULL, NULL, ' ', ' ', ' ' }, + { "Reset", "Reset all of the below", + NULL, distReset, NULL, NULL, ' ', ' ', ' ' }, + { " base", "Binary base distribution (required)", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_BASE }, +#ifdef __i386__ + { " compat1x", "FreeBSD 1.x binary compatibility", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_COMPAT1X }, + { " compat20", "FreeBSD 2.0 binary compatibility", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_COMPAT20 }, + { " compat21", "FreeBSD 2.1 binary compatibility", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_COMPAT21 }, + { " compat22", "FreeBSD 2.2.x and 3.0 a.out binary compatibility", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_COMPAT22 }, + { " compat3x", "FreeBSD 3.x binary compatibility", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_COMPAT3X }, +#endif +#if __FreeBSD__ >= 4 && (defined(__i386__) || defined(__alpha__)) + { " compat4x", "FreeBSD 4.x binary compatibility", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_COMPAT4X }, +#endif + { " dict", "Spelling checker dictionary files", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_DICT }, + { " doc", "Miscellaneous FreeBSD online docs", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_DOC }, + { " games", "Games (non-commercial)", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_GAMES }, + { " info", "GNU info files", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_INFO }, + { " man", "System manual pages - recommended", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_MANPAGES }, + { " catman", "Preformatted system manual pages", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_CATPAGES }, + { " proflibs", "Profiled versions of the libraries", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_PROFLIBS }, + { " src", "Sources for everything", + srcFlagCheck, distSetSrc }, + { " ports", "The FreeBSD Ports collection", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_PORTS }, + { " local", "Local additions collection", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_LOCAL}, + { " perl", "The Perl distribution", + dmenuFlagCheck, dmenuSetFlag, NULL, &Dists, '[', 'X', ']', DIST_PERL }, + { " X.Org", "The X.Org distribution", + x11FlagCheck, distSetXOrg }, + { NULL } }, +}; + +DMenu MenuSrcDistributions = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "Select the sub-components of src you wish to install.", + "Please check off those portions of the FreeBSD source tree\n" + "you wish to install.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "All", "Select all of the below", + NULL, setSrc, NULL, NULL, ' ', ' ', ' ' }, + { "Reset", "Reset all of the below", + NULL, clearSrc, NULL, NULL, ' ', ' ', ' ' }, + { " base", "top-level files in /usr/src", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_BASE }, + { " contrib", "/usr/src/contrib (contributed software)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_CONTRIB }, + { " crypto", "/usr/src/crypto (contrib encryption sources)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_SCRYPTO }, + { " gnu", "/usr/src/gnu (software from the GNU Project)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_GNU }, + { " etc", "/usr/src/etc (miscellaneous system files)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_ETC }, + { " games", "/usr/src/games (the obvious!)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_GAMES }, + { " include", "/usr/src/include (header files)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_INCLUDE }, + { " krb5", "/usr/src/kerberos5 (sources for Kerberos5)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_SKERBEROS5 }, + { " lib", "/usr/src/lib (system libraries)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_LIB }, + { " libexec", "/usr/src/libexec (system programs)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_LIBEXEC }, + { " release", "/usr/src/release (release-generation tools)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_RELEASE }, + { " rescue", "/usr/src/rescue (static rescue tools)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_RESCUE }, + { " bin", "/usr/src/bin (system binaries)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_BIN }, + { " sbin", "/usr/src/sbin (system binaries)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_SBIN }, + { " secure", "/usr/src/secure (BSD encryption sources)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_SSECURE }, + { " share", "/usr/src/share (documents and shared files)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_SHARE }, + { " sys", "/usr/src/sys (FreeBSD kernel)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_SYS }, + { " tools", "/usr/src/tools (miscellaneous tools)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_TOOLS }, + { " ubin", "/usr/src/usr.bin (user binaries)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_UBIN }, + { " usbin", "/usr/src/usr.sbin (aux system binaries)", + dmenuFlagCheck, dmenuSetFlag, NULL, &SrcDists, '[', 'X', ']', DIST_SRC_USBIN }, + { NULL } }, +}; + +DMenu MenuXOrgConfig = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Please select the X.Org configuration tool you want to use.", + "The first option, xorgcfg, is fully graphical.\n" + "The second option provides a menu-based interface similar to\n" + "what you are currently using. " + "The third option, xorgconfig, is\n" + "a more simplistic shell-script based tool and less friendly to\n" + "new users, but it may work in situations where the other options\n" + "do not.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + NULL, dmenuExit }, + { "2 xorgcfg", "Fully graphical X.Org configuration tool.", + NULL, dmenuSetVariable, NULL, VAR_XORG_CONFIG "=xorgcfg" }, + { "3 xorgcfg -textmode", "ncurses-based X.Org configuration tool.", + NULL, dmenuSetVariable, NULL, VAR_XORG_CONFIG "=xorgcfg -textmode" }, + { "4 xorgconfig", "Shell-script based X.Org configuration tool.", + NULL, dmenuSetVariable, NULL, VAR_XORG_CONFIG "=xorgconfig" }, + { "D XDesktop", "X already set up, just do desktop configuration.", + NULL, dmenuSubmenu, NULL, &MenuXDesktops }, + { NULL } }, +}; + +DMenu MenuXDesktops = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Please select the default X desktop to use.", + "By default, X.Org comes with a fairly vanilla desktop which\n" + "is based around the twm(1) window manager and does not offer\n" + "much in the way of features. It does have the advantage of\n" + "being a standard part of X so you don't need to load anything\n" + "extra in order to use it. If, however, you have access to a\n" + "reasonably full packages collection on your installation media,\n" + "you can choose any one of the following desktops as alternatives.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + NULL, dmenuExit }, + { "2 KDE", "The K Desktop Environment (Lite Edition)", + NULL, dmenuSetVariable, NULL, VAR_DESKSTYLE "=kde" }, + { "3 GNOME 2", "The GNOME 2 Desktop Environment (Lite Edition)", + NULL, dmenuSetVariable, NULL, VAR_DESKSTYLE "=gnome2" }, + { "4 Afterstep", "The Afterstep window manager", + NULL, dmenuSetVariable, NULL, VAR_DESKSTYLE "=afterstep" }, + { "5 Windowmaker", "The Windowmaker window manager", + NULL, dmenuSetVariable, NULL, VAR_DESKSTYLE "=windowmaker" }, + { "6 fvwm", "The fvwm window manager", + NULL, dmenuSetVariable, NULL, VAR_DESKSTYLE "=fvwm2" }, + { NULL } }, +}; + +DMenu MenuXOrgSelect = { + DMENU_NORMAL_TYPE, + "X.Org Distribution", + "Please select the components you need from the X.Org\n" + "distribution sets.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { "Basic", "Basic component menu (required)", NULL, dmenuSubmenu, NULL, &MenuXOrgSelectCore }, + { "Server", "X server menu", NULL, dmenuSubmenu, NULL, &MenuXOrgSelectServer }, + { "Fonts", "Font set menu", NULL, dmenuSubmenu, NULL, &MenuXOrgSelectFonts }, + { NULL } }, +}; + +DMenu MenuXOrgSelectCore = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "X.Org base distribution types", + "Please check off the basic X.Org components you wish to install.\n" + "Bin, lib, and set are recommended for a minimum installaion.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "All", "Select all below", + NULL, setX11Misc, NULL, NULL, ' ', ' ', ' ' }, + { "Reset", "Reset all below", + NULL, clearX11Misc, NULL, NULL, ' ', ' ', ' ' }, + { " lib", "Shared libraries and data files needed at runtime", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_LIB }, + { " bin", "Client applications", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_CLIENTS }, + { " man", "Manual pages", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_MAN }, + { " doc", "Documentation", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_DOC }, + { " prog", "Programming tools", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_IMAKE }, + { NULL } }, +}; + +DMenu MenuXOrgSelectFonts = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "X.Org Font distribution selection.", + "Please check off the individual font distributions you wish to\n\ +install. At the minimum, you should install the standard\n\ +75 DPI and misc fonts if you're also installing an X server\n\ +(these are selected by default). The TrueType set is also \n\ +highly recommended. The font server is unnecessary in most\n\ +configurations.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "All", "All fonts", + NULL, setX11Fonts, NULL, NULL, ' ', ' ', ' ' }, + { "Reset", "Reset font selections", + NULL, clearX11Fonts, NULL, NULL, ' ', ' ', ' ' }, + { " fmsc", "Standard miscellaneous fonts", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_FONTS_MISC }, + { " f75", "75 DPI fonts", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_FONTS_75 }, + { " f100", "100 DPI fonts", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_FONTS_100 }, + { " fcyr", "Cyrillic Fonts", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_FONTS_CYR }, + { " ft1", "Type1 scalable fonts", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_FONTS_T1 }, + { " ftt", "TrueType scalable fonts", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_FONTS_TT }, + { " fs", "Font server", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_FONTSERVER }, + { NULL } }, +}; + +DMenu MenuXOrgSelectServer = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "X.Org X Server selection.", + "Please check off the types of X servers you wish to install.\n", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "All", "Select all of the above", + NULL, setX11Servers, NULL, NULL, ' ', ' ', ' ' }, + { "Reset", "Reset all of the above", + NULL, clearX11Servers, NULL, NULL, ' ', ' ', ' ' }, + { " srv", "Standard Graphics Framebuffer", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_SERVER }, + { " nest", "Nested X Server", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_NESTSERVER }, + { " prt", "X Print Server", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_PRINTSERVER }, + { " vfb", "Virtual Framebuffer", + dmenuFlagCheck, dmenuSetFlag, NULL, &XOrgDists, '[', 'X', ']', DIST_XORG_VFBSERVER }, + { NULL } }, +}; + +DMenu MenuDiskDevices = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "Select Drive(s)", + "Please select the drive, or drives, on which you wish to perform\n" + "this operation. If you are attempting to install a boot partition\n" + "on a drive other than the first one or have multiple operating\n" + "systems on your machine, you will have the option to install a boot\n" + "manager later. To select a drive, use the arrow keys to move to it\n" + "and press [SPACE] or [ENTER]. To de-select it, press it again.\n\n" + "Use [TAB] to get to the buttons and leave this menu.", + "Press F1 for important information regarding disk geometry!", + "drives", + { { NULL } }, +}; + +DMenu MenuHTMLDoc = { + DMENU_NORMAL_TYPE, + "Select HTML Documentation pointer", + "Please select the body of documentation you're interested in, the main\n" + "ones right now being the FAQ and the Handbook. You can also choose \"other\"\n" + "to enter an arbitrary URL for browsing.", + "Press F1 for more help on what you see here.", + "html", + { { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { "2 Handbook", "The FreeBSD Handbook.", NULL, docShowDocument }, + { "3 FAQ", "The Frequently Asked Questions guide.", NULL, docShowDocument }, + { "4 Home", "The Home Pages for the FreeBSD Project (requires net)", NULL, docShowDocument }, + { "5 Other", "Enter a URL.", NULL, docShowDocument }, + { NULL } }, +}; + +/* The main installation menu */ +DMenu MenuInstallCustom = { + DMENU_NORMAL_TYPE, + "Choose Custom Installation Options", + "This is the custom installation menu. You may use this menu to specify\n" + "details on the type of distribution you wish to have, where you wish\n" + "to install it from and how you wish to allocate disk storage to FreeBSD.", + "Press F1 to read the installation guide", + "INSTALL", + { { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { "2 Options", "View/Set various installation options", NULL, optionsEditor }, +#ifndef WITH_SLICES + { "3 Label", "Label disk partitions", NULL, diskLabelEditor }, + { "4 Distributions", "Select distribution(s) to extract", NULL, dmenuSubmenu, NULL, &MenuDistributions }, + { "5 Media", "Choose the installation media type", NULL, dmenuSubmenu, NULL, &MenuMedia }, + { "6 Commit", "Perform any pending Partition/Label/Extract actions", NULL, installCustomCommit }, +#else + { "3 Partition", "Allocate disk space for FreeBSD", NULL, diskPartitionEditor }, + { "4 Label", "Label allocated disk partitions", NULL, diskLabelEditor }, + { "5 Distributions", "Select distribution(s) to extract", NULL, dmenuSubmenu, NULL, &MenuDistributions }, + { "6 Media", "Choose the installation media type", NULL, dmenuSubmenu, NULL, &MenuMedia }, + { "7 Commit", "Perform any pending Partition/Label/Extract actions", NULL, installCustomCommit }, +#endif + { NULL } }, +}; + +#if defined(__i386__) || defined(__amd64__) +#ifdef PC98 +/* IPL type menu */ +DMenu MenuIPLType = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "overwrite me", /* will be disk specific label */ + "If you want a FreeBSD Boot Manager, select \"BootMgr\". If you would\n" + "prefer your Boot Manager to remain untouched then select \"None\".\n\n", + "Press F1 to read about drive setup", + "drives", + { { "BootMgr", "Install the FreeBSD Boot Manager", + dmenuRadioCheck, dmenuSetValue, NULL, &BootMgr }, + { "None", "Leave the IPL untouched", + dmenuRadioCheck, dmenuSetValue, NULL, &BootMgr, '(', '*', ')', 1 }, + { NULL } }, +}; +#else +/* MBR type menu */ +DMenu MenuMBRType = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "overwrite me", /* will be disk specific label */ + "FreeBSD comes with a boot selector that allows you to easily\n" + "select between FreeBSD and any other operating systems on your machine\n" + "at boot time. If you have more than one drive and want to boot\n" + "from the second one, the boot selector will also make it possible\n" + "to do so (limitations in the PC BIOS usually prevent this otherwise).\n" + "If you do not want a boot selector, or wish to replace an existing\n" + "one, select \"standard\". If you would prefer your Master Boot\n" + "Record to remain untouched then select \"None\".\n\n" + " NOTE: PC-DOS users will almost certainly require \"None\"!", + "Press F1 to read about drive setup", + "drives", + { { "BootMgr", "Install the FreeBSD Boot Manager", + dmenuRadioCheck, dmenuSetValue, NULL, &BootMgr }, + { "Standard", "Install a standard MBR (no boot manager)", + dmenuRadioCheck, dmenuSetValue, NULL, &BootMgr, '(', '*', ')', 1 }, + { "None", "Leave the Master Boot Record untouched", + dmenuRadioCheck, dmenuSetValue, NULL, &BootMgr, '(', '*', ')', 2 }, + { NULL } }, +}; +#endif /* PC98 */ +#endif /* __i386__ */ + +/* Final configuration menu */ +DMenu MenuConfigure = { + DMENU_NORMAL_TYPE, + "FreeBSD Configuration Menu", /* title */ + "If you've already installed FreeBSD, you may use this menu to customize\n" + "it somewhat to suit your particular configuration. Most importantly,\n" + "you can use the Packages utility to load extra \"3rd party\"\n" + "software not provided in the base distributions.", + "Press F1 for more information on these options", + "configure", + { { "X Exit", "Exit this menu (returning to previous)", + NULL, dmenuExit }, + { " Distributions", "Install additional distribution sets", + NULL, distExtractAll }, + { " Packages", "Install pre-packaged software for FreeBSD", + NULL, configPackages }, + { " Root Password", "Set the system manager's password", + NULL, dmenuSystemCommand, NULL, "passwd root" }, +#ifdef WITH_SLICES + { " Fdisk", "The disk Slice (PC-style partition) Editor", + NULL, diskPartitionEditor }, +#endif + { " Label", "The disk Label editor", + NULL, diskLabelEditor }, + { " User Management", "Add user and group information", + NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, +#ifdef WITH_SYSCONS + { " Console", "Customize system console behavior", + NULL, dmenuSubmenu, NULL, &MenuSyscons }, +#endif + { " Time Zone", "Set which time zone you're in", + NULL, dmenuSystemCommand, NULL, "tzsetup" }, + { " Media", "Change the installation media type", + NULL, dmenuSubmenu, NULL, &MenuMedia }, +#ifdef WITH_MICE + { " Mouse", "Configure your mouse", + NULL, dmenuSubmenu, NULL, &MenuMouse }, +#endif + { " Networking", "Configure additional network services", + NULL, dmenuSubmenu, NULL, &MenuNetworking }, + { " Security", "Configure system security options", + NULL, dmenuSubmenu, NULL, &MenuSecurity }, + { " Startup", "Configure system startup options", + NULL, dmenuSubmenu, NULL, &MenuStartup }, + { " TTYs", "Configure system ttys.", + NULL, configEtcTtys, NULL, "ttys" }, + { " Options", "View/Set various installation options", + NULL, optionsEditor }, + { " HTML Docs", "Go to the HTML documentation menu (post-install)", + NULL, docBrowser }, + { " Load KLD", "Load a KLD from a floppy", + NULL, kldBrowser }, + { NULL } }, +}; + +DMenu MenuStartup = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "Startup Services Menu", + "This menu allows you to configure various aspects of your system's\n" + "startup configuration. Use [SPACE] or [ENTER] to select items, and\n" + "[TAB] to move to the buttons. Select Exit to leave this menu.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, +#ifdef __i386__ + { " APM", "Auto-power management services (typically laptops)", + dmenuVarCheck, dmenuToggleVariable, NULL, "apm_enable=YES" }, +#endif +#ifdef PCCARD_ARCH + { " pccard", "Enable PCCARD (AKA PCMCIA) services (also laptops)", + dmenuVarCheck, dmenuToggleVariable, NULL, "pccard_enable=YES" }, + { " pccard mem", "Set PCCARD memory address (if enabled)", + dmenuVarCheck, dmenuISetVariable, NULL, "pccard_mem" }, + { " pccard ifconfig", "List of PCCARD ethernet devices to configure", + dmenuVarCheck, dmenuISetVariable, NULL, "pccard_ifconfig" }, +#endif + { " usbd", "Enable USB daemon (detect USB attach / detach)", + dmenuVarCheck, dmenuToggleVariable, NULL, "usbd_enable=YES" }, + { " usbd flags", "Set default flags to usbd (if enabled)", + dmenuVarCheck, dmenuISetVariable, NULL, "usbd_flags" }, + { " ", " -- ", NULL, NULL, NULL, NULL, ' ', ' ', ' ' }, + { " Startup dirs", "Set the list of dirs to look for startup scripts", + dmenuVarCheck, dmenuISetVariable, NULL, "local_startup" }, + { " named", "Run a local name server on this host", + dmenuVarCheck, dmenuToggleVariable, NULL, "named_enable=YES" }, + { " named flags", "Set default flags to named (if enabled)", + dmenuVarCheck, dmenuISetVariable, NULL, "named_flags" }, + { " NIS client", "This host wishes to be an NIS client.", + dmenuVarCheck, configRpcBind, NULL, "nis_client_enable=YES" }, + { " NIS domainname", "Set NIS domainname (if enabled)", + dmenuVarCheck, dmenuISetVariable, NULL, "nisdomainname" }, + { " NIS server", "This host wishes to be an NIS server.", + dmenuVarCheck, configRpcBind, NULL, "nis_server_enable=YES" }, + { " ", " -- ", NULL, NULL, NULL, NULL, ' ', ' ', ' ' }, + { " Accounting", "This host wishes to run process accounting.", + dmenuVarCheck, dmenuToggleVariable, NULL, "accounting_enable=YES" }, + { " lpd", "This host has a printer and wants to run lpd.", + dmenuVarCheck, dmenuToggleVariable, NULL, "lpd_enable=YES" }, +#ifdef WITH_LINUX + { " Linux", "This host wants to be able to run Linux binaries.", + dmenuVarCheck, configLinux, NULL, VAR_LINUX_ENABLE "=YES" }, +#endif +#ifdef __i386__ + { " SCO", "This host wants to be able to run IBCS2 binaries.", + dmenuVarCheck, dmenuToggleVariable, NULL, "ibcs2_enable=YES" }, + { " SVR4", "This host wants to be able to run SVR4 binaries.", + dmenuVarCheck, dmenuToggleVariable, NULL, "svr4_enable=YES" }, +#endif +#ifdef __alpha__ + { " OSF/1", "This host wants to be able to run DEC OSF/1 binaries.", + dmenuVarCheck, configOSF1, NULL, VAR_OSF1_ENABLE "=YES" }, +#endif + { " quotas", "This host wishes to check quotas on startup.", + dmenuVarCheck, dmenuToggleVariable, NULL, "check_quotas=YES" }, + { NULL } }, +}; + +DMenu MenuNetworking = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "Network Services Menu", + "You may have already configured one network device (and the other\n" + "various hostname/gateway/name server parameters) in the process\n" + "of installing FreeBSD. This menu allows you to configure other\n" + "aspects of your system's network configuration.", + NULL, + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { " Interfaces", "Configure additional network interfaces", + NULL, tcpMenuSelect }, + { " AMD", "This machine wants to run the auto-mounter service", + dmenuVarCheck, configRpcBind, NULL, "amd_enable=YES" }, + { " AMD Flags", "Set flags to AMD service (if enabled)", + dmenuVarCheck, dmenuISetVariable, NULL, "amd_flags" }, + { " Anon FTP", "This machine wishes to allow anonymous FTP.", + dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, + { " Gateway", "This machine will route packets between interfaces", + dmenuVarCheck, dmenuToggleVariable, NULL, "gateway_enable=YES" }, + { " inetd", "This machine wants to run the inet daemon", + dmenuVarCheck, configInetd, NULL, "inetd_enable=YES" }, + { " Mail", "This machine wants to run a Mail Transfer Agent", + NULL, dmenuSubmenu, NULL, &MenuMTA }, + { " NFS client", "This machine will be an NFS client", + dmenuVarCheck, dmenuToggleVariable, NULL, "nfs_client_enable=YES" }, + { " NFS server", "This machine will be an NFS server", + dmenuVarCheck, configNFSServer, NULL, "nfs_server_enable=YES" }, + { " Ntpdate", "Select a clock-synchronization server", + dmenuVarCheck, dmenuSubmenu, NULL, &MenuNTP, '[', 'X', ']', + (uintptr_t)"ntpdate_enable=YES" }, + { " PCNFSD", "Run authentication server for clients with PC-NFS.", + dmenuVarCheck, configPCNFSD, NULL, "pcnfsd" }, + { " rpcbind", "RPC port mapping daemon (formerly portmapper)", + dmenuVarCheck, dmenuToggleVariable, NULL, "rpcbind_enable=YES" }, + { " rpc.statd", "NFS status monitoring daemon", + dmenuVarCheck, configRpcBind, NULL, "rpc_statd_enable=YES" }, + { " rpc.lockd", "NFS file locking daemon", + dmenuVarCheck, configRpcBind, NULL, "rpc_lockd_enable=YES" }, + { " Routed", "Select routing daemon (default: routed)", + dmenuVarCheck, configRouter, NULL, "router_enable=YES" }, + { " Rwhod", "This machine wants to run the rwho daemon", + dmenuVarCheck, dmenuToggleVariable, NULL, "rwhod_enable=YES" }, + { " sshd", "This machine wants to run the SSH daemon", + dmenuVarCheck, dmenuToggleVariable, NULL, "sshd_enable=YES" }, + { " TCP Extensions", "Allow RFC1323 and RFC1644 TCP extensions?", + dmenuVarCheck, dmenuToggleVariable, NULL, "tcp_extensions=YES" }, + { NULL } }, +}; + +DMenu MenuMTA = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Mail Transfer Agent Selection", + "You can choose which Mail Transfer Agent (MTA) you wish to install and run.\n" + "Selecting Sendmail local disables sendmail's network socket for\n" + "incoming mail, but still enables sendmail for local and outbound mail.\n" + "The Postfix option will install the Postfix MTA from the ports\n" + "collection. The Exim option will install the Exim MTA from the ports\n" + "collection. To return to the previous menu, select Exit.", + NULL, + NULL, + { + { "Sendmail", "Use sendmail", + dmenuVarCheck, dmenuSetVariable, NULL, "sendmail_enable=YES" }, + { "Sendmail local", "Use sendmail, but do not listen on the network", + dmenuVarCheck, dmenuSetVariable, NULL, "sendmail_enable=NO" }, + { "Postfix", "Use the Postfix MTA", + NULL, configMTAPostfix, NULL, NULL }, + { "Exim", "Use the Exim MTA", + NULL, configMTAExim, NULL, NULL }, + { "None", "Do not install an MTA", + dmenuVarCheck, dmenuSetVariable, NULL, "sendmail_enable=NONE" }, + { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { NULL } }, +}; + +DMenu MenuNTP = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "NTPDATE Server Selection", + "There are a number of time synchronization servers available\n" + "for public use around the Internet. Please select one reasonably\n" + "close to you to have your system time synchronized accordingly.", + "These are the primary open-access NTP servers", + NULL, + { { "None", "No NTP server", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=NO,ntpdate_flags=none" }, + { "Other", "Select a site not on this list", + dmenuVarsCheck, configNTP, NULL, NULL }, + { "Worldwide", "pool.ntp.org", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=pool.ntp.org" }, + { "Asia", "asia.pool.ntp.org", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=asia.pool.ntp.org" }, + { "Europe", "europe.pool.ntp.org", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=europe.pool.ntp.org" }, + { "Oceania", "oceania.pool.ntp.org", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=oceania.pool.ntp.org" }, + { "North America", "north-america.pool.ntp.org", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=north-america.pool.ntp.org" }, + { "Argentina", "tick.nap.com.ar", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tick.nap.com.ar" }, + { "Argentina #2", "time.sinectis.com.ar", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.sinectis.com.ar" }, + { "Argentina #3", "tock.nap.com.ar", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tock.nap.com.ar" }, + { "Australia", "augean.eleceng.adelaide.edu.au", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=augean.eleceng.adelaide.edu.au" }, + { "Australia #2", "ntp.adelaide.edu.au", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.adelaide.edu.au" }, + { "Australia #3", "ntp.saard.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.saard.net" }, + { "Australia #4", "time.deakin.edu.au", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.deakin.edu.au" }, + { "Australia #5", "time.esec.com.au", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.esec.com.au" }, + { "Belgium", "ntp1.belbone.be", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.belbone.be" }, + { "Belgium #2", "ntp2.belbone.be", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.belbone.be" }, + { "Brazil", "ntp.cais.rnp.br", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.cais.rnp.br" }, + { "Brazil #2", "ntp.pop-df.rnp.br", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.pop-df.rnp.br" }, + { "Brazil #3", "ntp.ufes.br", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.ufes.br" }, + { "Brazil #4", "ntp1.pucpr.br", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.pucpr.br" }, + { "Canada", "ntp.cpsc.ucalgary.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.cpsc.ucalgary.ca" }, + { "Canada #2", "ntp1.cmc.ec.gc.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.cmc.ec.gc.ca" }, + { "Canada #3", "ntp2.cmc.ec.gc.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.cmc.ec.gc.ca" }, + { "Canada #4", "tick.utoronto.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tick.utoronto.ca" }, + { "Canada #5", "time.chu.nrc.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.chu.nrc.ca" }, + { "Canada #6", "time.nrc.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.nrc.ca" }, + { "Canada #7", "timelord.uregina.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=timelord.uregina.ca" }, + { "Canada #8", "tock.utoronto.ca", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tock.utoronto.ca" }, + { "Czech", "ntp.karpo.cz", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.karpo.cz" }, + { "Denmark", "clock.netcetera.dk", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock.netcetera.dk" }, + { "Denmark", "clock2.netcetera.dk", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock2.netcetera.dk" }, + { "Spain", "slug.ctv.es", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=slug.ctv.es" }, + { "Finland", "tick.keso.fi", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tick.keso.fi" }, + { "Finland #2", "tock.keso.fi", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tock.keso.fi" }, + { "France", "ntp.obspm.fr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.obspm.fr" }, + { "France #2", "ntp.univ-lyon1.fr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.univ-lyon1.fr" }, + { "France #3", "ntp.via.ecp.fr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.via.ecp.fr" }, + { "Croatia", "zg1.ntp.carnet.hr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=zg1.ntp.carnet.hr" }, + { "Croatia #2", "zg2.ntp.carnet.hr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=zg2.ntp.carnet.hr" }, + { "Croatia #3", "st.ntp.carnet.hr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=st.ntp.carnet.hr" }, + { "Croatia #4", "ri.ntp.carnet.hr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ri.ntp.carnet.hr" }, + { "Croatia #5", "os.ntp.carnet.hr", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=os.ntp.carnet.hr" }, + { "Hungary", "time.kfki.hu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.kfki.hu" }, + { "Indonesia", "ntp.incaf.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.incaf.net" }, + { "Ireland", "ntp.maths.tcd.ie", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.maths.tcd.ie" }, + { "Italy", "ntps.net4u.it", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=" }, + { "Korea", "time.nuri.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.nuri.net" }, + { "Mexico", "ntp2a.audiotel.com.mx", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2a.audiotel.com.mx" }, + { "Mexico #2", "ntp2b.audiotel.com.mx", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2b.audiotel.com.mx" }, + { "Mexico #3", "ntp2c.audiotel.com.mx", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2c.audiotel.com.mx" }, + { "Nigeria", "ntp.supernet300.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.supernet300.com" }, + { "Netherlands", "ntp1.theinternetone.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.theinternetone.net" }, + { "Netherlands #2", "ntp2.theinternetone.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.theinternetone.net" }, + { "Netherlands #3", "ntp3.theinternetone.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp3.theinternetone.net" }, + { "Norway", "fartein.ifi.uio.no", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=fartein.ifi.uio.no" }, + { "Norway #2", "time.alcanet.no", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.alcanet.no" }, + { "New Zealand", "ntp.massey.ac.nz", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.massey.ac.nz" }, + { "New Zealand #2", "ntp.public.otago.ac.nz", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.public.otago.ac.nz" }, + { "New Zealand #3", "tk1.ihug.co.nz", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tk1.ihug.co.nz" }, + { "New Zealand #4", "ntp.waikato.ac.nz", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.waikato.ac.nz" }, + { "Poland", "info.cyf-kr.edu.pl", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=info.cyf-kr.edu.pl" }, + { "Portugal", "bug.fe.up.pt", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=bug.fe.up.pt" }, + { "Romania", "ticks.roedu.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ticks.roedu.net" }, + { "Russia", "ntp.psn.ru", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.psn.ru" }, + { "Russia #2", "sign.chg.ru", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=sign.chg.ru" }, + { "Sweden", "ntp.lth.se", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.lth.se" }, + { "Singapore", "ntp.shim.org", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.shim.org" }, + { "Slovenia", "calvus.rzs-hm.si", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=calvus.rzs-hm.si" }, + { "Slovenia #2", "sizif.mf.uni-lj.si", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=sizif.mf.uni-lj.si" }, + { "Slovenia #3", "ntp1.arnes.si", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.arnes.si" }, + { "Slovenia #4", "ntp2.arnes.si", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.arnes.si" }, + { "Slovenia #5", "time.ijs.si", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.ijs.si" }, + { "Scotland", "ntp.cs.strath.ac.uk", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.cs.strath.ac.uk" }, + { "United Kingdom", "ntp.exnet.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.exnet.com" }, + { "United Kingdom #2", "ntp0.uk.uu.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp0.uk.uu.net" }, + { "United Kingdom #3", "ntp1.uk.uu.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.uk.uu.net" }, + { "United Kingdom #4", "ntp2.uk.uu.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.uk.uu.net" }, + { "United Kingdom #5", "ntp2a.mcc.ac.uk", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2a.mcc.ac.uk" }, + { "United Kingdom #6", "ntp2b.mcc.ac.uk", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2b.mcc.ac.uk" }, + { "United Kingdom #7", "ntp2c.mcc.ac.uk", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2c.mcc.ac.uk" }, + { "United Kingdom #8", "ntp2d.mcc.ac.uk", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2d.mcc.ac.uk" }, + { "United Kingdom #9", "tick.tanac.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tick.tanac.net" }, + { "U.S. AR", "sushi.compsci.lyon.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=sushi.compsci.lyon.edu" }, + { "U.S. AZ", "ntp.drydog.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.drydog.com" }, + { "U.S. CA", "ntp.ucsd.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.ucsd.edu" }, + { "U.S. CA #2", "ntp1.mainecoon.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.mainecoon.com" }, + { "U.S. CA #3", "ntp2.mainecoon.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.mainecoon.com" }, + { "U.S. CA #4", "reloj.kjsl.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=reloj.kjsl.com" }, + { "U.S. CA #5", "time.five-ten-sg.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time.five-ten-sg.com" }, + { "U.S. DE", "louie.udel.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=louie.udel.edu" }, + { "U.S. GA", "ntp.shorty.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.shorty.com" }, + { "U.S. GA #2", "rolex.usg.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=rolex.usg.edu" }, + { "U.S. GA #3", "timex.usg.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=timex.usg.edu" }, + { "U.S. IL", "ntp-0.cso.uiuc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-0.cso.uiuc.edu" }, + { "U.S. IL #2", "ntp-1.cso.uiuc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-1.cso.uiuc.edu" }, + { "U.S. IL #3", "ntp-1.mcs.anl.gov", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-1.mcs.anl.gov" }, + { "U.S. IL #4", "ntp-2.cso.uiuc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-2.cso.uiuc.edu" }, + { "U.S. IL #5", "ntp-2.mcs.anl.gov", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-2.mcs.anl.gov" }, + { "U.S. IN", "gilbreth.ecn.purdue.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=gilbreth.ecn.purdue.edu" }, + { "U.S. IN #2", "harbor.ecn.purdue.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=harbor.ecn.purdue.edu" }, + { "U.S. IN #3", "molecule.ecn.purdue.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=molecule.ecn.purdue.edu" }, + { "U.S. KS", "ntp1.kansas.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.kansas.net" }, + { "U.S. KS #2", "ntp2.kansas.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.kansas.net" }, + { "U.S. MA", "ntp.ourconcord.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.ourconcord.net" }, + { "U.S. MA #2", "timeserver.cs.umb.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=timeserver.cs.umb.edu" }, + { "U.S. MN", "ns.nts.umn.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ns.nts.umn.edu" }, + { "U.S. MN #2", "nss.nts.umn.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=nss.nts.umn.edu" }, + { "U.S. MO", "time-ext.missouri.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=time-ext.missouri.edu" }, + { "U.S. MT", "chronos1.umt.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=chronos1.umt.edu" }, + { "U.S. MT #2", "chronos2.umt.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=chronos2.umt.edu" }, + { "U.S. MT #3", "chronos3.umt.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=chronos3.umt.edu" }, + { "U.S. NC", "clock1.unc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock1.unc.edu" }, + { "U.S. NV", "cuckoo.nevada.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=cuckoo.nevada.edu" }, + { "U.S. NV #2", "tick.cs.unlv.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tick.cs.unlv.edu" }, + { "U.S. NV #3", "tock.cs.unlv.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tock.cs.unlv.edu" }, + { "U.S. NY", "clock.linuxshell.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock.linuxshell.net" }, + { "U.S. NY #2", "ntp.ctr.columbia.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.ctr.columbia.edu" }, + { "U.S. NY #3", "ntp0.cornell.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp0.cornell.edu" }, + { "U.S. NY #4", "ntp1.mpis.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.mpis.net" }, + { "U.S. NY #5", "ntp2.mpis.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.mpis.net" }, + { "U.S. NY #6", "sundial.columbia.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=sundial.columbia.edu" }, + { "U.S. NY #7", "timex.cs.columbia.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=timex.cs.columbia.edu" }, + { "U.S. OK", "constellation.ecn.uoknor.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=constellation.ecn.uoknor.edu" }, + { "U.S. PA", "clock-1.cs.cmu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock-1.cs.cmu.edu" }, + { "U.S. PA #2", "clock-2.cs.cmu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock-2.cs.cmu.edu" }, + { "U.S. PA #3", "clock.psu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock.psu.edu" }, + { "U.S. PA #4", "fuzz.psc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=fuzz.psc.edu" }, + { "U.S. PA #5", "ntp-1.ece.cmu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-1.ece.cmu.edu" }, + { "U.S. PA #6", "ntp-2.ece.cmu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-2.ece.cmu.edu" }, + { "U.S. TX", "ntp.cox.smu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.cox.smu.edu" }, + { "U.S. TX #2", "ntp.fnbhs.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.fnbhs.com" }, + { "U.S. TX #3", "ntp.tmc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.tmc.edu" }, + { "U.S. TX #4", "ntp5.tamu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp5.tamu.edu" }, + { "U.S. TX #5", "tick.greyware.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tick.greyware.com" }, + { "U.S. TX #6", "tock.greyware.com", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=tock.greyware.com" }, + { "U.S. VA", "ntp-1.vt.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-1.vt.edu" }, + { "U.S. VA #2", "ntp-2.vt.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp-2.vt.edu" }, + { "U.S. VA #3", "ntp.cmr.gov", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.cmr.gov" }, + { "U.S. VT", "ntp0.state.vt.us", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp0.state.vt.us" }, + { "U.S. VT #2", "ntp1.state.vt.us", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.state.vt.us" }, + { "U.S. VT #3", "ntp2.state.vt.us", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp2.state.vt.us" }, + { "U.S. WA", "clock.tricity.wsu.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=clock.tricity.wsu.edu" }, + { "U.S. WA #2", "ntp.tcp-udp.net", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.tcp-udp.net" }, + { "U.S. WI", "ntp1.cs.wisc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp1.cs.wisc.edu" }, + { "U.S. WI #2", "ntp3.cs.wisc.edu", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp3.cs.wisc.edu" }, + { "Venezuela", "ntp.linux.org.ve", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.linux.org.ve" }, + { "South Africa", "ntp.cs.unp.ac.za", + dmenuVarsCheck, dmenuSetVariables, NULL, + "ntpdate_enable=YES,ntpdate_flags=ntp.cs.unp.ac.za" }, + { NULL } }, +}; + +#ifdef WITH_SYSCONS +DMenu MenuSyscons = { + DMENU_NORMAL_TYPE, + "System Console Configuration", + "The default system console driver for FreeBSD (syscons) has a\n" + "number of configuration options which may be set according to\n" + "your preference.\n\n" + "When you are done setting configuration options, select Cancel.", + "Configure your system console settings", + NULL, + { { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, +#ifdef PC98 + { "2 Keymap", "Choose an alternate keyboard map", NULL, dmenuSubmenu, NULL, &MenuSysconsKeymap }, + { "3 Repeat", "Set the rate at which keys repeat", NULL, dmenuSubmenu, NULL, &MenuSysconsKeyrate }, + { "4 Saver", "Configure the screen saver", NULL, dmenuSubmenu, NULL, &MenuSysconsSaver }, +#else + { "2 Font", "Choose an alternate screen font", NULL, dmenuSubmenu, NULL, &MenuSysconsFont }, + { "3 Keymap", "Choose an alternate keyboard map", NULL, dmenuSubmenu, NULL, &MenuSysconsKeymap }, + { "4 Repeat", "Set the rate at which keys repeat", NULL, dmenuSubmenu, NULL, &MenuSysconsKeyrate }, + { "5 Saver", "Configure the screen saver", NULL, dmenuSubmenu, NULL, &MenuSysconsSaver }, + { "6 Screenmap", "Choose an alternate screenmap", NULL, dmenuSubmenu, NULL, &MenuSysconsScrnmap }, + { "7 Ttys", "Choose console terminal type", NULL, dmenuSubmenu, NULL, &MenuSysconsTtys }, +#endif + { NULL } }, +}; + +#ifdef PC98 +DMenu MenuSysconsKeymap = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "System Console Keymap", + "The default system console driver for FreeBSD (syscons) defaults\n" + "to a standard \"PC-98x1\" keyboard map. Users may wish to choose\n" + "one of the other keymaps below.\n" + "Note that sysinstall itself only uses the part of the keyboard map\n" + "which is required to generate the ANSI character subset, but your\n" + "choice of keymap will also be saved for later (fuller) use.", + "Choose a keyboard map", + NULL, + { { "Japanese PC-98x1", "Japanese PC-98x1 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=jp.pc98" }, + { " Japanese PC-98x1 (ISO)", "Japanese PC-98x1 (ISO) keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=jp.pc98.iso" }, + { NULL } }, +}; +#else +DMenu MenuSysconsKeymap = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "System Console Keymap", + "The default system console driver for FreeBSD (syscons) defaults\n" + "to a standard \"American\" keyboard map. Users in other countries\n" + "(or with different keyboard preferences) may wish to choose one of\n" + "the other keymaps below.\n" + "Note that sysinstall itself only uses the part of the keyboard map\n" + "which is required to generate the ANSI character subset, but your\n" + "choice of keymap will also be saved for later (fuller) use.", + "Choose a keyboard map", + NULL, + { { "Belgian", "Belgian ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=be.iso" }, + { " Brazil CP850", "Brazil CP850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=br275.cp850" }, + { " Brazil ISO (accent)", "Brazil ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=br275.iso.acc" }, + { " Brazil ISO", "Brazil ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=br275.iso" }, + { " Bulgarian BDS", "Bulgarian BDS keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=bg.bds.ctrlcaps" }, + { " Bulgarian Phonetic", "Bulgarian Phonetic keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=bg.phonetic.ctrlcaps" }, + { "Central European ISO", "Central European ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=ce.iso2" }, + { " Croatian ISO", "Croatian ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=hr.iso" }, + { " Czech ISO (accent)", "Czech ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=cs.latin2.qwertz" }, + { "Danish CP865", "Danish Code Page 865 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=danish.cp865" }, + { " Danish ISO", "Danish ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=danish.iso" }, + { "Estonian ISO", "Estonian ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=estonian.iso" }, + { " Estonian ISO 15", "Estonian ISO 8859-15 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=estonian.iso15" }, + { " Estonian CP850", "Estonian Code Page 850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=estonian.cp850" }, + { "Finnish CP850","Finnish Code Page 850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=finnish.cp850" }, + { " Finnish ISO", "Finnish ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=finnish.iso" }, + { " French ISO (accent)", "French ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=fr.iso.acc" }, + { " French ISO", "French ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=fr.iso" }, + { "German CP850", "German Code Page 850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=german.cp850" }, + { " German ISO", "German ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=german.iso" }, + { " Greek 101", "Greek ISO keymap (101 keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=gr.us101.acc" }, + { " Greek 104", "Greek ISO keymap (104 keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=el.iso07" }, + { " Greek ELOT", "Greek ISO keymap (ELOT 1000)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=gr.elot.acc" }, + { "Hungarian 101", "Hungarian ISO keymap (101 key)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=hu.iso2.101keys" }, + { " Hungarian 102", "Hungarian ISO keymap (102 key)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=hu.iso2.102keys" }, + { "Icelandic (accent)", "Icelandic ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=icelandic.iso.acc" }, + { " Icelandic", "Icelandic ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=icelandic.iso" }, + { " Italian", "Italian ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=it.iso" }, + { "Japanese 106", "Japanese 106 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=jp.106" }, + { "Latin American (accent)", "Latin American ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=latinamerican.iso.acc" }, + { " Latin American", "Latin American ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=latinamerican" }, + { "Norway ISO", "Norwegian ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=norwegian.iso" }, + { "Polish ISO", "Polish ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=pl_PL.ISO8859-2" }, + { " Portuguese (accent)", "Portuguese ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=pt.iso.acc" }, + { " Portuguese", "Portuguese ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=pt.iso" }, + { "Russia KOI8-R", "Russian KOI8-R keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=ru.koi8-r" }, + { "Slovak", "Slovak ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=sk.iso2" }, + { "Slovenian", "Slovenian ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=si.iso" }, + { " Spanish (accent)", "Spanish ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=spanish.iso.acc" }, + { " Spanish", "Spanish ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=spanish.iso" }, + { " Swedish CP850", "Swedish Code Page 850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swedish.cp850" }, + { " Swedish ISO", "Swedish ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swedish.iso" }, + { " Swiss French ISO (accent)", "Swiss French ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swissfrench.iso.acc" }, + { " Swiss French ISO", "Swiss French ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swissfrench.iso" }, + { " Swiss French CP850", "Swiss French Code Page 850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swissfrench.cp850" }, + { " Swiss German ISO (accent)", "Swiss German ISO keymap (accent keys)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swissgerman.iso.acc" }, + { " Swiss German ISO", "Swiss German ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swissgerman.iso" }, + { " Swiss German CP850", "Swiss German Code Page 850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=swissgerman.cp850" }, + { "UK CP850", "UK Code Page 850 keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=uk.cp850" }, + { " UK ISO", "UK ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=uk.iso" }, + { " Ukrainian KOI8-U", "Ukrainian KOI8-U keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=ua.koi8-u" }, + { " Ukrainian KOI8-U+KOI8-R", "Ukrainian KOI8-U+KOI8-R keymap (alter)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=ua.koi8-u.shift.alt" }, + { " USA CapsLock->Ctrl", "US standard (Caps as L-Control)", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=us.pc-ctrl" }, + { " USA Dvorak", "US Dvorak keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=us.dvorak" }, + { " USA Dvorak (left)", "US left handed Dvorak keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=us.dvorakl" }, + { " USA Dvorak (right)", "US right handed Dvorak keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=us.dvorakr" }, + { " USA Emacs", "US standard optimized for EMACS", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=us.emacs" }, + { " USA ISO", "US ISO keymap", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=us.iso" }, + { " USA UNIX", "US traditional UNIX-workstation", dmenuVarCheck, dmenuSetKmapVariable, NULL, "keymap=us.unix" }, + { NULL } }, +}; +#endif /* PC98 */ + +DMenu MenuSysconsKeyrate = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "System Console Keyboard Repeat Rate", + "This menu allows you to set the speed at which keys repeat\n" + "when held down.", + "Choose a keyboard repeat rate", + NULL, + { { "Slow", "Slow keyboard repeat rate", dmenuVarCheck, dmenuSetVariable, NULL, "keyrate=slow" }, + { "Normal", "\"Normal\" keyboard repeat rate", dmenuVarCheck, dmenuSetVariable, NULL, "keyrate=normal" }, + { "Fast", "Fast keyboard repeat rate", dmenuVarCheck, dmenuSetVariable, NULL, "keyrate=fast" }, + { "Default", "Use default keyboard repeat rate", dmenuVarCheck, dmenuSetVariable, NULL, "keyrate=NO" }, + { NULL } }, +}; + +DMenu MenuSysconsSaver = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "System Console Screen Saver", + "By default, the console driver will not attempt to do anything\n" + "special with your screen when it's idle. If you expect to leave your\n" + "monitor switched on and idle for long periods of time then you should\n" + "probably enable one of these screen savers to prevent phosphor burn-in.", + "Choose a nifty-looking screen saver", + NULL, + { { "1 Blank", "Simply blank the screen", + dmenuVarCheck, configSaver, NULL, "saver=blank" }, + { "2 Daemon", "\"BSD Daemon\" animated screen saver (text)", + dmenuVarCheck, configSaver, NULL, "saver=daemon" }, + { "3 Fade", "Fade out effect screen saver", + dmenuVarCheck, configSaver, NULL, "saver=fade" }, + { "4 Fire", "Flames effect screen saver", + dmenuVarCheck, configSaver, NULL, "saver=fire" }, + { "5 Green", "\"Green\" power saving mode (if supported by monitor)", + dmenuVarCheck, configSaver, NULL, "saver=green" }, + { "6 Logo", "\"BSD Daemon\" animated screen saver (graphics)", + dmenuVarCheck, configSaver, NULL, "saver=logo" }, + { "7 Rain", "Rain drops screen saver", + dmenuVarCheck, configSaver, NULL, "saver=rain" }, + { "8 Snake", "Draw a FreeBSD \"snake\" on your screen", + dmenuVarCheck, configSaver, NULL, "saver=snake" }, + { "9 Star", "A \"twinkling stars\" effect", + dmenuVarCheck, configSaver, NULL, "saver=star" }, + { "Warp", "A \"stars warping\" effect", + dmenuVarCheck, configSaver, NULL, "saver=warp" }, + { "Dragon", "Dragon screensaver (graphics)", + dmenuVarCheck, configSaver, NULL, "saver=dragon" }, + { "Timeout", "Set the screen saver timeout interval", + NULL, configSaverTimeout, NULL, NULL, ' ', ' ', ' ' }, + { NULL } }, +}; + +#ifndef PC98 +DMenu MenuSysconsScrnmap = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "System Console Screenmap", + "Unless you load a specific font, most PC hardware defaults to\n" + "displaying characters in the IBM 437 character set. However,\n" + "in the Unix world, this character set is very rarely used. Most\n" + "Western European countries, for example, prefer ISO 8859-1.\n" + "American users won't notice the difference since the bottom half\n" + "of all these character sets is ANSI anyway.\n" + "If your hardware is capable of downloading a new display font,\n" + "you should probably choose that option. However, for hardware\n" + "where this is not possible (e.g. monochrome adapters), a screen\n" + "map will give you the best approximation that your hardware can\n" + "display at all.", + "Choose a screen map", + NULL, + { { "1 None", "No screenmap, don't touch font", dmenuVarCheck, dmenuSetVariable, NULL, "scrnmap=NO" }, + { "2 ISO 8859-1 to IBM437", "W-Europe ISO 8859-1 to IBM 437 screenmap", dmenuVarCheck, dmenuSetVariable, NULL, "scrnmap=iso-8859-1_to_cp437" }, + { "3 ISO 8859-7 to IBM437", "Greek ISO 8859-7 to IBM 437 screenmap", dmenuVarCheck, dmenuSetVariable, NULL, "scrnmap=iso-8859-7_to_cp437" }, + { "4 US-ASCII to IBM437", "US-ASCII to IBM 437 screenmap", dmenuVarCheck, dmenuSetVariable, NULL, "scrnmap=us-ascii_to_cp437" }, + { "5 KOI8-R to IBM866", "Russian KOI8-R to IBM 866 screenmap", dmenuVarCheck, dmenuSetVariable, NULL, "scrnmap=koi8-r2cp866" }, + { "6 KOI8-U to IBM866u", "Ukrainian KOI8-U to IBM 866u screenmap", dmenuVarCheck, dmenuSetVariable, NULL, "scrnmap=koi8-u2cp866u" }, + { NULL } }, +}; + +DMenu MenuSysconsTtys = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "System Console Terminal Type", + "For various console encodings, a corresponding terminal type\n" + "must be chosen in /etc/ttys.\n\n" + "WARNING: For compatibility reasons, only entries starting with\n" + "ttyv and terminal types starting with cons[0-9] can be changed\n" + "via this menu.\n", + "Choose a terminal type", + NULL, + { { "1 None", "Don't touch anything", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=NO" }, + { "2 IBM437 (VGA default)", "cons25", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=cons25" }, + { "3 ISO 8859-1", "cons25l1", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=cons25l1" }, + { "4 ISO 8859-2", "cons25l2", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=cons25l2" }, + { "5 ISO 8859-7", "cons25l7", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=cons25l7" }, + { "6 KOI8-R", "cons25r", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=cons25r" }, + { "7 KOI8-U", "cons25u", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=cons25u" }, + { "8 US-ASCII", "cons25w", dmenuVarCheck, dmenuSetVariable, NULL, VAR_CONSTERM "=cons25w" }, + { NULL } }, +}; + +DMenu MenuSysconsFont = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "System Console Font", + "Most PC hardware defaults to displaying characters in the\n" + "IBM 437 character set. However, in the Unix world, this\n" + "character set is very rarely used. Most Western European\n" + "countries, for example, prefer ISO 8859-1.\n" + "American users won't notice the difference since the bottom half\n" + "of all these charactersets is ANSI anyway. However, they might\n" + "want to load a font anyway to use the 30- or 50-line displays.\n" + "If your hardware is capable of downloading a new display font,\n" + "you can select the appropriate font below.", + "Choose a font", + NULL, + { { "1 None", "Use hardware default font", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=NO,font8x14=NO,font8x16=NO" }, + { "2 IBM 437", "English and others, VGA default", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=cp437-8x8,font8x14=cp437-8x14,font8x16=cp437-8x16" }, + { "3 IBM 850", "Western Europe, IBM encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=cp850-8x8,font8x14=cp850-8x14,font8x16=cp850-8x16" }, + { "4 IBM 865", "Norwegian, IBM encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=cp865-8x8,font8x14=cp865-8x14,font8x16=cp865-8x16" }, + { "5 IBM 866", "Russian, IBM encoding (use with KOI8-R screenmap)", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=cp866-8x8,font8x14=cp866-8x14,font8x16=cp866b-8x16,mousechar_start=3" }, + { "6 IBM 866u", "Ukrainian, IBM encoding (use with KOI8-U screenmap)", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=cp866u-8x8,font8x14=cp866u-8x14,font8x16=cp866u-8x16,mousechar_start=3" }, + { "7 IBM 1251", "Cyrillic, MS Windows encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=cp1251-8x8,font8x14=cp1251-8x14,font8x16=cp1251-8x16,mousechar_start=3" }, + { "8 ISO 8859-1", "Western Europe, ISO encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=iso-8x8,font8x14=iso-8x14,font8x16=iso-8x16" }, + { "9 ISO 8859-2", "Eastern Europe, ISO encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=iso02-8x8,font8x14=iso02-8x14,font8x16=iso02-8x16" }, + { "a ISO 8859-4", "Baltic, ISO encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=iso04-8x8,font8x14=iso04-8x14,font8x16=iso04-8x16" }, + { "b ISO 8859-7", "Greek, ISO encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=iso07-8x8,font8x14=iso07-8x14,font8x16=iso07-8x16" }, + { "c ISO 8859-8", "Hebrew, ISO encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=iso08-8x8,font8x14=iso08-8x14,font8x16=iso08-8x16" }, + { "d ISO 8859-15", "Europe, ISO encoding", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=iso15-8x8,font8x14=iso15-8x14,font8x16=iso15-8x16" }, + { "e SWISS", "English, better resolution", dmenuVarCheck, dmenuSetVariables, NULL, + "font8x8=swiss-8x8,font8x14=NO,font8x16=swiss-8x16" }, + { NULL } }, +}; +#endif /* PC98 */ +#endif /* WITH_SYSCONS */ + +DMenu MenuUsermgmt = { + DMENU_NORMAL_TYPE, + "User and group management", + "The submenus here allow to manipulate user groups and\n" + "login accounts.\n", + "Configure your user groups and users", + NULL, + { { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { "User", "Add a new user to the system.", NULL, userAddUser }, + { "Group", "Add a new user group to the system.", NULL, userAddGroup }, + { NULL } }, +}; + +DMenu MenuSecurity = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "System Security Options Menu", + "This menu allows you to configure aspects of the operating system security\n" + "policy. Please read the system documentation carefully before modifying\n" + "these settings, as they may cause service disruption if used improperly.\n" + "\n" + "Most settings will take affect only following a system reboot.", + "Configure system security options", + NULL, + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { " Securelevel", "Configure securelevels for the system", + NULL, configSecurelevel }, +#if 0 + { " LOMAC", "Use Low Watermark Mandatory Access Control at boot", + dmenuVarCheck, dmenuToggleVariable, NULL, "lomac_enable=YES" }, +#endif + { " NFS port", "Require that the NFS clients used reserved ports", + dmenuVarCheck, dmenuToggleVariable, NULL, "nfs_reserved_port_only=YES" }, + { NULL } }, +}; + +DMenu MenuSecurelevel = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Securelevel Configuration Menu", + "This menu allows you to select the securelevel your system runs with.\n" + "When operating at a securelevel, certain root privileges are disabled,\n" + "which may increase resistance to exploits and protect system integrity.\n" + "In secure mode system flags may not be overriden by the root user,\n" + "access to direct kernel memory is limited, and kernel modules may not\n" + "be changed. In highly secure mode, mounted file systems may not be\n" + "modified on-disk, tampering with the system clock is prohibited. In\n" + "network secure mode configuration changes to firwalling are prohibited.\n", + "Select a securelevel to operate at - F1 for help", + "securelevel", + { { "X Exit", "Exit this menu (returning to previous)", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "Disabled", "Disable securelevels", NULL, configSecurelevelDisabled, }, + { "Secure", "Secure mode", NULL, configSecurelevelSecure }, + { "Highly Secure", "Highly secure mode", NULL, configSecurelevelHighlySecure }, + { "Network Secure", "Network secure mode", NULL, configSecurelevelNetworkSecure }, + { NULL } } +}; + +DMenu MenuFixit = { + DMENU_NORMAL_TYPE, + "Please choose a fixit option", + "There are three ways of going into \"fixit\" mode:\n" + "- you can use the live filesystem CDROM/DVD, in which case there will be\n" + " full access to the complete set of FreeBSD commands and utilities,\n" + "- you can use the more limited (but perhaps customized) fixit floppy,\n" + "- or you can start an Emergency Holographic Shell now, which is\n" + " limited to the subset of commands that is already available right now.", + "Press F1 for more detailed repair instructions", + "fixit", +{ { "X Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { "2 CDROM/DVD", "Use the \"live\" filesystem CDROM/DVD", NULL, installFixitCDROM }, + { "3 Floppy", "Use a floppy generated from the fixit image", NULL, installFixitFloppy }, + { "4 Shell", "Start an Emergency Holographic Shell", NULL, installFixitHoloShell }, + { NULL } }, +}; diff --git a/usr.sbin/sysinstall/misc.c b/usr.sbin/sysinstall/misc.c new file mode 100644 index 0000000000000..07cbc81751d18 --- /dev/null +++ b/usr.sbin/sysinstall/misc.c @@ -0,0 +1,529 @@ +/* + * Miscellaneous support routines.. + * + * $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 <ctype.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/errno.h> +#include <sys/file.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/wait.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <ufs/ufs/ufsmount.h> +#include <sys/reboot.h> +#include <sys/disklabel.h> +#include <fs/msdosfs/msdosfsmount.h> + +/* Quick check to see if a file is readable */ +Boolean +file_readable(char *fname) +{ + if (!access(fname, F_OK)) + return TRUE; + return FALSE; +} + +/* Quick check to see if a file is executable */ +Boolean +file_executable(char *fname) +{ + if (!access(fname, X_OK)) + return TRUE; + return FALSE; +} + +/* Concatenate two strings into static storage */ +char * +string_concat(char *one, char *two) +{ + static char tmp[FILENAME_MAX]; + + /* Yes, we're deliberately cavalier about not checking for overflow */ + strcpy(tmp, one); + strcat(tmp, two); + return tmp; +} + +/* sane strncpy() function */ +char * +sstrncpy(char *dst, const char *src, int size) +{ + dst[size] = '\0'; + return strncpy(dst, src, size); +} + +/* Concatenate three strings into static storage */ +char * +string_concat3(char *one, char *two, char *three) +{ + static char tmp[FILENAME_MAX]; + + /* Yes, we're deliberately cavalier about not checking for overflow */ + strcpy(tmp, one); + strcat(tmp, two); + strcat(tmp, three); + return tmp; +} + +/* Clip the whitespace off the end of a string */ +char * +string_prune(char *str) +{ + int len = str ? strlen(str) : 0; + + while (len && isspace(str[len - 1])) + str[--len] = '\0'; + return str; +} + +/* run the whitespace off the front of a string */ +char * +string_skipwhite(char *str) +{ + while (*str && isspace(*str)) + ++str; + return str; +} + +/* copy optionally and allow second arg to be null */ +char * +string_copy(char *s1, char *s2) +{ + if (!s1) + return NULL; + if (!s2) + s1[0] = '\0'; + else + strcpy(s1, s2); + return s1; +} + +/* convert an integer to a string, using a static buffer */ +char * +itoa(int value) +{ + static char buf[13]; + + snprintf(buf, 12, "%d", value); + return buf; +} + +Boolean +directory_exists(const char *dirname) +{ + DIR *tptr; + + if (!dirname) + return FALSE; + if (!strlen(dirname)) + return FALSE; + + tptr = opendir(dirname); + if (!tptr) + return (FALSE); + + closedir(tptr); + return (TRUE); +} + +char * +pathBaseName(const char *path) +{ + char *pt; + char *ret = (char *)path; + + pt = strrchr(path,(int)'/'); + + if (pt != 0) /* if there is a slash */ + { + ret = ++pt; /* start the file after it */ + } + + return(ret); +} + +/* A free guaranteed to take NULL ptrs */ +void +safe_free(void *ptr) +{ + if (ptr) + free(ptr); +} + +/* A malloc that checks errors */ +void * +safe_malloc(size_t size) +{ + void *ptr; + + if (size <= 0) + msgFatal("Invalid malloc size of %ld!", (long)size); + ptr = malloc(size); + if (!ptr) + msgFatal("Out of memory!"); + bzero(ptr, size); + return ptr; +} + +/* A realloc that checks errors */ +void * +safe_realloc(void *orig, size_t size) +{ + void *ptr; + + if (size <= 0) + msgFatal("Invalid realloc size of %ld!", (long)size); + ptr = reallocf(orig, size); + if (!ptr) + msgFatal("Out of memory!"); + return ptr; +} + +/* Create a path biased from the VAR_INSTALL_ROOT variable (if not /) */ +char * +root_bias(char *path) +{ + static char tmp[FILENAME_MAX]; + char *cp = variable_get(VAR_INSTALL_ROOT); + + if (!strcmp(cp, "/")) + return path; + strcpy(tmp, variable_get(VAR_INSTALL_ROOT)); + strcat(tmp, path); + return tmp; +} + +/* + * These next routines are kind of specialized just for building item lists + * for dialog_menu(). + */ + +/* Add an item to an item list */ +dialogMenuItem * +item_add(dialogMenuItem *list, char *prompt, char *title, + int (*checked)(dialogMenuItem *self), + int (*fire)(dialogMenuItem *self), + void (*selected)(dialogMenuItem *self, int is_selected), + void *data, int *aux, int *curr, int *max) +{ + dialogMenuItem *d; + + if (*curr == *max) { + *max += 20; + list = (dialogMenuItem *)safe_realloc(list, sizeof(dialogMenuItem) * *max); + } + d = &list[(*curr)++]; + bzero(d, sizeof(*d)); + d->prompt = prompt ? strdup(prompt) : NULL; + d->title = title ? strdup(title) : NULL; + d->checked = checked; + d->fire = fire; + d->selected = selected; + d->data = data; + d->aux = (long)aux; + return list; +} + +/* Toss the items out */ +void +items_free(dialogMenuItem *list, int *curr, int *max) +{ + int i; + + for (i = 0; list[i].prompt; i++) { + safe_free(list[i].prompt); + safe_free(list[i].title); + } + safe_free(list); + *curr = *max = 0; +} + +int +Mkdir(char *ipath) +{ + struct stat sb; + int final; + char *p, *path; + + if (file_readable(ipath) || Fake) + return DITEM_SUCCESS; + + path = strcpy(alloca(strlen(ipath) + 1), ipath); + if (isDebug()) + msgDebug("mkdir(%s)\n", path); + p = path; + if (p[0] == '/') /* Skip leading '/'. */ + ++p; + for (final = FALSE; !final; ++p) { + if (p[0] == '\0' || (p[0] == '/' && p[1] == '\0')) + final = TRUE; + else if (p[0] != '/') + continue; + *p = '\0'; + if (stat(path, &sb)) { + if (errno != ENOENT) { + msgConfirm("Couldn't stat directory %s: %s", path, strerror(errno)); + return DITEM_FAILURE; + } + if (isDebug()) + msgDebug("mkdir(%s..)\n", path); + if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { + msgConfirm("Couldn't create directory %s: %s", path,strerror(errno)); + return DITEM_FAILURE; + } + } + *p = '/'; + } + return DITEM_SUCCESS; +} + +int +Mkdir_command(char *key, void *dir) +{ + return (Mkdir((char*)dir)); +} + +int +Mount(char *mountp, void *dev) +{ + struct ufs_args ufsargs; + char device[80]; + char mountpoint[FILENAME_MAX]; + + if (Fake) + return DITEM_SUCCESS; + + if (*((char *)dev) != '/') { + sprintf(device, "%s/dev/%s", RunningAsInit ? "/mnt" : "", (char *)dev); + sprintf(mountpoint, "%s%s", RunningAsInit ? "/mnt" : "", mountp); + } + else { + strcpy(device, dev); + strcpy(mountpoint, mountp); + } + memset(&ufsargs,0,sizeof ufsargs); + + if (Mkdir(mountpoint)) { + msgConfirm("Unable to make directory mountpoint for %s!", mountpoint); + return DITEM_FAILURE; + } + if (isDebug()) + msgDebug("mount %s %s\n", device, mountpoint); + + ufsargs.fspec = device; + if (mount("ufs", mountpoint, RunningAsInit ? MNT_ASYNC | MNT_NOATIME : 0, + (caddr_t)&ufsargs) == -1) { + msgConfirm("Error mounting %s on %s : %s", device, mountpoint, strerror(errno)); + return DITEM_FAILURE; + } + return DITEM_SUCCESS; +} + +int +Mount_msdosfs(char *mountp, void *dev) +{ + struct msdosfs_args mount_args; + char device[80]; + char mountpoint[FILENAME_MAX]; + + if (Fake) + return DITEM_SUCCESS; + + if (*((char *)dev) != '/') { + sprintf(device, "%s/dev/%s", RunningAsInit ? "/mnt" : "", (char *)dev); + sprintf(mountpoint, "%s%s", RunningAsInit ? "/mnt" : "", mountp); + } + else { + strcpy(device, dev); + strcpy(mountpoint, mountp); + } + + if (Mkdir(mountpoint)) { + msgConfirm("Unable to make directory mountpoint for %s!", mountpoint); + return DITEM_FAILURE; + } + if (isDebug()) + msgDebug("mount %s %s\n", device, mountpoint); + + memset(&mount_args, 0, sizeof(mount_args)); + mount_args.fspec = device; + mount_args.magic = MSDOSFS_ARGSMAGIC; + mount_args.mask = S_IRWXU | S_IRWXG | S_IRWXO; + if (mount("msdosfs", mountpoint, RunningAsInit ? MNT_ASYNC|MNT_NOATIME : 0, + (caddr_t)&mount_args) == -1) { + msgConfirm("Error mounting %s on %s : %s", device, mountpoint, strerror(errno)); + return DITEM_FAILURE; + } + return DITEM_SUCCESS; +} + +WINDOW * +openLayoutDialog(char *helpfile, char *title, int x, int y, int width, int height) +{ + WINDOW *win; + static char help[FILENAME_MAX]; + + /* We need a curses window */ + win = newwin(LINES, COLS, 0, 0); + if (win) { + /* Say where our help comes from */ + if (helpfile) { + use_helpline("Press F1 for more information on this screen."); + use_helpfile(systemHelpFile(helpfile, help)); + } + /* Setup a nice screen for us to splat stuff onto */ + draw_box(win, y, x, height, width, dialog_attr, border_attr); + wattrset(win, dialog_attr); + mvwaddstr(win, y, x + (COLS - strlen(title)) / 2, title); + } + return win; +} + +ComposeObj * +initLayoutDialog(WINDOW *win, Layout *layout, int x, int y, int *max) +{ + ComposeObj *obj = NULL, *first; + int n; + + /* Loop over the layout list, create the objects, and add them + onto the chain of objects that dialog uses for traversal*/ + + n = 0; + while (layout[n].help != NULL) { + int t = TYPE_OF_OBJ(layout[n].type); + + switch (t) { + case STRINGOBJ: + layout[n].obj = NewStringObj(win, layout[n].prompt, layout[n].var, + layout[n].y + y, layout[n].x + x, layout[n].len, layout[n].maxlen); + ((StringObj *)layout[n].obj)->attr_mask = ATTR_OF_OBJ(layout[n].type); + break; + + case BUTTONOBJ: + layout[n].obj = NewButtonObj(win, layout[n].prompt, layout[n].var, layout[n].y + y, layout[n].x + x); + break; + + default: + msgFatal("Don't support this object yet!"); + } + AddObj(&obj, t, (void *) layout[n].obj); + n++; + } + *max = n - 1; + /* Find the first object in the list */ + for (first = obj; first->prev; first = first->prev); + return first; +} + +int +layoutDialogLoop(WINDOW *win, Layout *layout, ComposeObj **obj, int *n, int max, int *cbutton, int *cancel) +{ + char help_line[80]; + int ret, i, len = strlen(layout[*n].help); + + /* Display the help line at the bottom of the screen */ + for (i = 0; i < 79; i++) + help_line[i] = (i < len) ? layout[*n].help[i] : ' '; + help_line[i] = '\0'; + use_helpline(help_line); + display_helpline(win, LINES - 1, COLS - 1); + wrefresh(win); + + /* Ask for libdialog to do its stuff */ + ret = PollObj(obj); + /* Handle special case stuff that libdialog misses. Sigh */ + switch (ret) { + case SEL_ESC: /* Bail out */ + *cancel = TRUE; + return FALSE; + + /* This doesn't work for list dialogs. Oh well. Perhaps + should special case the move from the OK button ``up'' + to make it go to the interface list, but then it gets + awkward for the user to go back and correct screw up's + in the per-interface section */ + case KEY_DOWN: + case SEL_CR: + case SEL_TAB: + if (*n < max) + ++*n; + else + *n = 0; + break; + + /* The user has pressed enter over a button object */ + case SEL_BUTTON: + if (cbutton && *cbutton) + *cancel = TRUE; + else + *cancel = FALSE; + return FALSE; + + case KEY_UP: + case SEL_BACKTAB: + if (*n) + --*n; + else + *n = max; + break; + + case KEY_F(1): + display_helpfile(); + + /* They tried some key combination we don't support - tootle them forcefully! */ + default: + beep(); + } + return TRUE; +} + +WINDOW * +savescr(void) +{ + WINDOW *w; + + w = dupwin(newscr); + return w; +} + +void +restorescr(WINDOW *w) +{ + touchwin(w); + wrefresh(w); + delwin(w); +} + diff --git a/usr.sbin/sysinstall/modules.c b/usr.sbin/sysinstall/modules.c new file mode 100644 index 0000000000000..859994a26e890 --- /dev/null +++ b/usr.sbin/sysinstall/modules.c @@ -0,0 +1,229 @@ +/*- + * Copyright (c) 2000 "HOSOKAWA, Tatsumi" <hosokawa@FreeBSD.org> + * 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. + * 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 AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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, 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. + * + * $FreeBSD$ + */ + +#include "sysinstall.h" +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/linker.h> +#include <fcntl.h> +#include <dirent.h> +#include <fcntl.h> +#include <fnmatch.h> +#include <kenv.h> + +/* Prototypes */ +static int kldModuleFire(dialogMenuItem *self); + +#define MODULESDIR "/modules" +#define DISTMOUNT "/dist" + +void +moduleInitialize(void) +{ + int fd, len; + DIR *dirp; + struct dirent *dp; + char module[MAXPATHLEN], desc[MAXPATHLEN]; + char desc_str[BUFSIZ]; + + if (!RunningAsInit && !Fake) { + /* It's not my job... */ + return; + } + + dirp = opendir(MODULESDIR); + if (dirp) { + while ((dp = readdir(dirp))) { + if (dp->d_namlen < (sizeof(".ko") - 1)) continue; + if (strcmp(dp->d_name + dp->d_namlen - (sizeof(".ko") - 1), ".ko") == 0) { + strcpy(module, MODULESDIR); + strcat(module, "/"); + strcat(module, dp->d_name); + strcpy(desc, module); + len = strlen(desc); + strcpy(desc + (len - (sizeof(".ko") - 1)), ".dsc"); + fd = open(module, O_RDONLY); + if (fd < 0) continue; + close(fd); + fd = open(desc, O_RDONLY); + if (fd < 0) { + desc_str[0] = 0; + } + else { + len = read(fd, desc_str, BUFSIZ); + close(fd); + if (len < BUFSIZ) desc_str[len] = 0; + } + if (desc_str[0]) + msgDebug("Loading module %s (%s)\n", dp->d_name, desc_str); + else + msgDebug("Loading module %s\n", dp->d_name); + if (kldload(module) < 0 && errno != EEXIST) { + if (desc_str[0]) + msgConfirm("Loading module %s failed\n%s", dp->d_name, desc_str); + else + msgConfirm("Loading module %s failed", dp->d_name); + } + } + if (strcmp(dp->d_name + dp->d_namlen - (sizeof(".ko.gz") - 1), ".ko.gz") == 0) { + snprintf(module, sizeof(module), "/tmp/%s", dp->d_name); + module[strlen(module) - sizeof(".gz")] = '\0'; + snprintf(desc, sizeof(desc), "zcat < %s/%s > %s", MODULESDIR, + dp->d_name, module); + system(desc); + if (kldload(module) < 0 && errno != EEXIST) { + if (desc_str[0]) + msgConfirm("Loading module %s failed\n%s", dp->d_name, desc_str); + else + msgConfirm("Loading module %s failed", dp->d_name); + } + unlink(module); + } + } + closedir(dirp); + } +} + +void +driverFloppyCheck(void) +{ + /* Prompt for the driver floppy if requested. */ + if (kenv(KENV_GET, "driver_floppy", NULL, 0) >= 0 && + !msgYesNo("Would you like to load kernel modules from the driver floppy?")) + (void)kldBrowser(NULL); +} + +int +kldBrowser(dialogMenuItem *self) +{ + DMenu *menu; + int i, what = DITEM_SUCCESS, msize, count; + DIR *dir; + struct dirent *de; + char *err; + + err = NULL; + + if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { + msgConfirm("Unable to set media device to floppy."); + what |= DITEM_FAILURE; + mediaClose(); + return what; + } + + if (!DEVICE_INIT(mediaDevice)) { + msgConfirm("Unable to mount floppy filesystem."); + what |= DITEM_FAILURE; + mediaClose(); + return what; + } + + msize = sizeof(DMenu) + (sizeof(dialogMenuItem) * 2); + count = 0; + if ((menu = malloc(msize)) == NULL) { + err = "Failed to allocate memory for menu"; + goto errout; + } + + bcopy(&MenuKLD, menu, sizeof(DMenu)); + + bzero(&menu->items[count], sizeof(menu->items[0])); + menu->items[count].prompt = strdup("X Exit"); + menu->items[count].title = strdup("Exit this menu (returning to previous)"); + menu->items[count].fire = dmenuExit; + count++; + + if ((dir = opendir(DISTMOUNT)) == NULL) { + err = "Couldn't open directory"; + goto errout; + } + + while ((de = readdir(dir)) != NULL) { + if (fnmatch("*.ko", de->d_name, FNM_CASEFOLD)) + continue; + + msize += sizeof(dialogMenuItem); + if ((menu = realloc(menu, msize)) == NULL) { + err = "Failed to allocate memory for menu item"; + goto errout; + } + + bzero(&menu->items[count], sizeof(menu->items[0])); + menu->items[count].fire = kldModuleFire; + + menu->items[count].prompt = strdup(de->d_name); + menu->items[count].title = menu->items[count].prompt; + + count++; + } + + closedir(dir); + + menu->items[count].prompt = NULL; + menu->items[count].title = NULL; + + dmenuOpenSimple(menu, FALSE); + + mediaClose(); + + deviceRescan(); + + errout: + for (i = 0; i < count; i++) + free(menu->items[i].prompt); + + free(menu); + + if (err != NULL) { + what |= DITEM_FAILURE; + if (!variable_get(VAR_NO_ERROR)) + msgConfirm(err); + } + + return (what); +} + +static int +kldModuleFire(dialogMenuItem *self) { + char fname[256]; + + bzero(fname, sizeof(fname)); + snprintf(fname, sizeof(fname), "%s/%s", DISTMOUNT, self->prompt); + + if (kldload(fname) < 0 && errno != EEXIST) { + if (!variable_get(VAR_NO_ERROR)) + msgConfirm("Loading module %s failed\n", fname); + } else { + if (!variable_get(VAR_NO_ERROR)) + msgConfirm("Loaded module %s OK", fname); + } + + return(0); + } diff --git a/usr.sbin/sysinstall/mouse.c b/usr.sbin/sysinstall/mouse.c new file mode 100644 index 0000000000000..574fd72359742 --- /dev/null +++ b/usr.sbin/sysinstall/mouse.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 1998 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) + * 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. + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHRO AND CONTRIBUTORS ``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 AUTHRO OR CONTRIBUTORS 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, 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. + * + * $FreeBSD$ + */ + +#include "sysinstall.h" +#include <string.h> + +int +mousedTest(dialogMenuItem *self) +{ + char *type; + char *port; + char *flags; + int ret; + + type = variable_get(VAR_MOUSED_TYPE); + port = variable_get(VAR_MOUSED_PORT); + flags = variable_get(VAR_MOUSED_FLAGS); + if ((type == NULL) || (port == NULL) + || (strlen(type) <= 0) || (strlen(port) <= 0) + || (strcmp(type, "NO") == 0)) { + msgConfirm("Please select a mouse protocol and a port first."); + return DITEM_FAILURE; + } + + msgNotify("Trying to start the mouse daemon..."); + if (file_readable("/var/run/moused.pid")) + vsystem("kill `cat /var/run/moused.pid`"); + systemExecute("vidcontrol -m on"); + if (flags != NULL) + vsystem("moused -t %s -p %s %s", type, port, flags); + else + vsystem("moused -t %s -p %s", type, port); + + ret = msgYesNo("Now move the mouse and see if it works.\n" + "(Note that buttons don't have any effect for now.)\n\n" + " Is the mouse cursor moving?\n"); + systemExecute("vidcontrol -m off"); + if (ret) { + if (file_readable("/var/run/moused.pid")) + vsystem("kill `cat /var/run/moused.pid`"); + variable_set2(VAR_MOUSED, "NO", 1); + } else { + variable_set2(VAR_MOUSED, "YES", 1); + vsystem("ln -fs /dev/sysmouse /dev/mouse"); /* backwards compat */ + } + + return DITEM_SUCCESS | DITEM_RESTORE; +} + +int +mousedDisable(dialogMenuItem *self) +{ + if (file_readable("/var/run/moused.pid")) + vsystem("kill `cat /var/run/moused.pid`"); + variable_set2(VAR_MOUSED, "NO", 1); + variable_set2(VAR_MOUSED_TYPE, "NO", 1); + variable_unset(VAR_MOUSED_PORT); + variable_unset(VAR_MOUSED_FLAGS); + msgConfirm("The mouse daemon is disabled."); + return DITEM_SUCCESS; +} + +int +setMouseFlags(dialogMenuItem *self) +{ + int ret; + ret = variable_get_value(VAR_MOUSED_FLAGS, + "Please Specify the mouse daemon flags. If you would like to\n" + "emulate 3 buttons, use -3 here.\n", 1) + ? DITEM_SUCCESS : DITEM_FAILURE; + if (ret != DITEM_SUCCESS) + variable_unset(VAR_MOUSED_FLAGS); + return ret; +} + diff --git a/usr.sbin/sysinstall/msg.c b/usr.sbin/sysinstall/msg.c new file mode 100644 index 0000000000000..4625ce2f77528 --- /dev/null +++ b/usr.sbin/sysinstall/msg.c @@ -0,0 +1,356 @@ +/* + * 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 <stdarg.h> +#include <sys/ioctl.h> +#include <sys/consio.h> + +Boolean +isDebug(void) +{ + char *cp; + + return (cp = variable_get(VAR_DEBUG)) && strcmp(cp, "no"); +} + +/* Whack up an informational message on the status line, in stand-out */ +void +msgYap(char *fmt, ...) +{ + va_list args; + char *errstr; + int attrs; + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + attrs = getattrs(stdscr); + attrset(A_REVERSE); + mvaddstr(StatusLine, 0, errstr); + attrset(attrs); + refresh(); +} + +/* Whack up an informational message on the status line */ +void +msgInfo(char *fmt, ...) +{ + va_list args; + char *errstr; + int i, attrs; + char line[81]; + + attrs = getattrs(stdscr); + /* NULL is a special convention meaning "erase the old stuff" */ + if (!fmt) { + move(StatusLine, 0); + clrtoeol(); + return; + } + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + memset(line, ' ', 80); + for (i = 0; i < 80; i++) { + if (errstr[i]) + line[i] = errstr[i]; + else + break; + } + line[80] = '\0'; + attrset(ATTR_TITLE); + mvaddstr(StatusLine, 0, line); + attrset(attrs); + move(StatusLine, 79); + refresh(); +} + +/* Whack up a warning on the status line */ +void +msgWarn(char *fmt, ...) +{ + va_list args; + char *errstr; + int attrs; + + errstr = (char *)alloca(FILENAME_MAX); + strcpy(errstr, "Warning: "); + va_start(args, fmt); + vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); + va_end(args); + attrs = getattrs(stdscr); + beep(); + attrset(ATTR_TITLE); + mvaddstr(StatusLine, 0, errstr); + attrset(attrs); + refresh(); + if (OnVTY && isDebug()) + msgDebug("Warning message `%s'\n", errstr); +} + +/* Whack up an error on the status line */ +void +msgError(char *fmt, ...) +{ + va_list args; + char *errstr; + int attrs; + + errstr = (char *)alloca(FILENAME_MAX); + strcpy(errstr, "Error: "); + va_start(args, fmt); + vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); + va_end(args); + beep(); + attrs = getattrs(stdscr); + attrset(ATTR_TITLE); + mvaddstr(StatusLine, 0, errstr); + attrset(attrs); + refresh(); + if (OnVTY && isDebug()) + msgDebug("Error message `%s'\n", errstr); +} + +/* Whack up a fatal error on the status line */ +void +msgFatal(char *fmt, ...) +{ + va_list args; + char *errstr; + int attrs; + + errstr = (char *)alloca(FILENAME_MAX); + strcpy(errstr, "Fatal Error: "); + va_start(args, fmt); + vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); + va_end(args); + beep(); + attrs = getattrs(stdscr); + attrset(ATTR_TITLE); + mvaddstr(StatusLine, 0, errstr); + addstr(" - "); + addstr("PRESS ANY KEY TO "); + if (getpid() == 1) + addstr("REBOOT"); + else + addstr("QUIT"); + attrset(attrs); + refresh(); + if (OnVTY) + msgDebug("Fatal error `%s'!\n", errstr); + getch(); + systemShutdown(1); +} + +/* Put up a message in a popup confirmation box */ +void +msgConfirm(char *fmt, ...) +{ + va_list args; + char *errstr; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (OnVTY) { + ioctl(0, VT_ACTIVATE, 1); + msgInfo(NULL); + } + dialog_notify(errstr); + restorescr(w); +} + +/* Put up a message in a popup information box */ +void +msgNotify(char *fmt, ...) +{ + va_list args; + char *errstr; + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (isDebug()) + msgDebug("Notify: %s\n", errstr); + dialog_msgbox(NULL, errstr, -1, -1, 0); +} + +/* Put up a message in a popup yes/no box and return 0 for YES, 1 for NO */ +int +msgYesNo(char *fmt, ...) +{ + va_list args; + char *errstr; + int ret; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (OnVTY) { + ioctl(0, VT_ACTIVATE, 1); /* Switch back */ + msgInfo(NULL); + } + if (variable_get(VAR_NONINTERACTIVE)) + return 0; /* If non-interactive, return YES all the time */ + ret = dialog_yesno("User Confirmation Requested", errstr, -1, -1); + restorescr(w); + return ret; +} + +/* Put up a message in a popup no/yes box and return 0 for YES, 1 for NO */ +int +msgNoYes(char *fmt, ...) +{ + va_list args; + char *errstr; + int ret; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (OnVTY) { + ioctl(0, VT_ACTIVATE, 1); /* Switch back */ + msgInfo(NULL); + } + if (variable_get(VAR_NONINTERACTIVE)) + return 1; /* If non-interactive, return NO all the time */ + ret = dialog_noyes("User Confirmation Requested", errstr, -1, -1); + restorescr(w); + return ret; +} + +/* Put up a message in an input box and return the value */ +char * +msgGetInput(char *buf, char *fmt, ...) +{ + va_list args; + char *errstr; + static char input_buffer[256]; + int rval; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (buf) + SAFE_STRCPY(input_buffer, buf); + else + input_buffer[0] = '\0'; + if (OnVTY) { + ioctl(0, VT_ACTIVATE, 1); /* Switch back */ + msgInfo(NULL); + } + rval = dialog_inputbox("Value Required", errstr, -1, -1, input_buffer); + restorescr(w); + if (!rval) + return input_buffer; + else + return NULL; +} + +/* Write something to the debugging port */ +void +msgDebug(char *fmt, ...) +{ + va_list args; + char *dbg; + + if (DebugFD == -1) + return; + dbg = (char *)alloca(FILENAME_MAX); + strcpy(dbg, "DEBUG: "); + va_start(args, fmt); + vsnprintf((char *)(dbg + strlen(dbg)), FILENAME_MAX, fmt, args); + va_end(args); + write(DebugFD, dbg, strlen(dbg)); +} + +/* Tell the user there's some output to go look at */ +void +msgWeHaveOutput(char *fmt, ...) +{ + va_list args; + char *errstr; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + msgDebug("Notify: %s\n", errstr); + dialog_clear_norefresh(); + sleep(2); + dialog_msgbox(NULL, errstr, -1, -1, 0); + restorescr(w); +} + +/* Simple versions of msgConfirm() and msgNotify() for calling from scripts */ +int +msgSimpleConfirm(char *str) +{ + msgConfirm("%s", str); + return DITEM_SUCCESS; +} + +int +msgSimpleNotify(char *str) +{ + msgNotify("%s", str); + return DITEM_SUCCESS; +} diff --git a/usr.sbin/sysinstall/network.c b/usr.sbin/sysinstall/network.c new file mode 100644 index 0000000000000..c57ad3de90a6b --- /dev/null +++ b/usr.sbin/sysinstall/network.c @@ -0,0 +1,355 @@ +/* + * 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. + * + */ + +/* These routines deal with getting things off of network media */ + +#include "sysinstall.h" +#include <signal.h> +#include <termios.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +static Boolean networkInitialized; +static pid_t startPPP(Device *devp); + +static pid_t pppPID; + +Boolean +mediaInitNetwork(Device *dev) +{ + int i; + char *rp; + char *cp, ifconfig[255]; + WINDOW *w; + + if (!RunningAsInit || networkInitialized) + return TRUE; + + if (isDebug()) + msgDebug("Init routine called for network device %s.\n", dev->name); + + if (!file_readable("/etc/resolv.conf")) { + if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) { + msgConfirm("Can't seem to write out /etc/resolv.conf. Net cannot be used."); + return FALSE; + } + } + + w = savescr(); + dialog_clear_norefresh(); + + /* Old PPP process lying around? */ + if (pppPID) { + msgConfirm("Killing previous PPP process %d.", pppPID); + kill(pppPID, SIGTERM); + pppPID = 0; + } + if (!strncmp("ppp", dev->name, 3)) { /* PPP? */ + if (!(pppPID = startPPP(dev))) { + msgConfirm("Unable to start PPP! This installation method cannot be used."); + return FALSE; + } + networkInitialized = TRUE; + return TRUE; + } + else if (!strncmp("sl", dev->name, 2)) { /* SLIP? */ + char *val; + char attach[256]; + + /* Cheesy slip attach */ + snprintf(attach, 256, "slattach -a -h -l -s 9600 %s", dev->devname); + val = msgGetInput(attach, + "Warning: SLIP is rather poorly supported in this revision\n" + "of the installation due to the lack of a dialing utility.\n" + "If you can use PPP for this instead then you're much better\n" + "off doing so, otherwise SLIP works fairly well for *hardwired*\n" + "links. Please edit the following slattach command for\n" + "correctness (default here is: VJ compression, Hardware flow-\n" + "control, ignore carrier and 9600 baud data rate). When you're\n" + "ready, press [ENTER] to execute it."); + if (!val) { + msgConfirm("slattach command was empty. Try again!"); + restorescr(w); + return FALSE; + } + else + SAFE_STRCPY(attach, val); + /* + * Doing this with vsystem() is actually bogus since we should be storing the pid of slattach + * for later killing. It's just too convenient to call vsystem(), however, rather than + * constructing a proper argument for exec() so we punt on doing slip right for now. + */ + if (vsystem("%s", attach)) { + msgConfirm("slattach returned a bad status! Please verify that\n" + "the command is correct and try this operation again."); + restorescr(w); + return FALSE; + } + restorescr(w); + } + + snprintf(ifconfig, 255, "%s%s", VAR_IFCONFIG, dev->name); + cp = variable_get(ifconfig); + if (cp) { + if (strcmp(cp, "DHCP")) { + msgDebug("ifconfig %s %s\n", dev->name, cp); + i = vsystem("ifconfig %s %s", dev->name, cp); + if (i) { + msgConfirm("Unable to configure the %s interface!\n" + "This installation method cannot be used.", + dev->name); + return FALSE; + } + rp = variable_get(VAR_GATEWAY); + if (!rp || *rp == '0') { + msgConfirm("No gateway has been set. You may be unable to access hosts\n" + "not on your local network"); + } + else { + msgDebug("Adding default route to %s.\n", rp); + vsystem("route -n add default %s", rp); + } + } + } else if ((cp = variable_get(VAR_IPV6ADDR)) == NULL || *cp == '\0') { + msgConfirm("The %s device is not configured. You will need to do so\n" + "in the Networking configuration menu before proceeding.", dev->name); + return FALSE; + } + + if (isDebug()) + msgDebug("Network initialized successfully.\n"); + networkInitialized = TRUE; + return TRUE; +} + +void +mediaShutdownNetwork(Device *dev) +{ + char *cp; + + if (!RunningAsInit || !networkInitialized) + return; + + msgDebug("Shutdown called for network device %s\n", dev->name); + /* Not a serial device? */ + if (strncmp("sl", dev->name, 2) && strncmp("ppp", dev->name, 3)) { + int i; + char ifconfig[255]; + + snprintf(ifconfig, 255, "%s%s", VAR_IFCONFIG, dev->name); + cp = variable_get(ifconfig); + if (!cp) + return; + msgDebug("ifconfig %s down\n", dev->name); + i = vsystem("ifconfig %s down", dev->name); + if (i) + msgConfirm("Warning: Unable to down the %s interface properly", dev->name); + cp = variable_get(VAR_GATEWAY); + if (cp) { + msgDebug("Deleting default route.\n"); + vsystem("route -n delete default"); + } + } + else if (pppPID) { + msgConfirm("Killing previous PPP process %d.", pppPID); + kill(pppPID, SIGTERM); + pppPID = 0; + } + networkInitialized = FALSE; +} + +/* Start PPP on the 3rd screen */ +static pid_t +startPPP(Device *devp) +{ + int fd2, pulse; + FILE *fp; + char *val; + pid_t pid = 0; + char myaddr[16], provider[16], speed[16], authname[32], authkey[16]; + char phone[16]; + WINDOW *w = savescr(); + + /* These are needed to make ppp work */ + Mkdir("/var/log"); + Mkdir("/var/run"); + Mkdir("/var/spool/lock"); + Mkdir("/etc/ppp"); + + dialog_clear_norefresh(); + if (!variable_get(VAR_SERIAL_SPEED)) + variable_set2(VAR_SERIAL_SPEED, "115200", 0); + /* Get any important user values */ + val = variable_get_value(VAR_SERIAL_SPEED, + "Enter the baud rate for your modem - this can be higher than the actual\n" + "maximum data rate since most modems can talk at one speed to the\n" + "computer and at another speed to the remote end.\n\n" + "If you're not sure what to put here, just select the default.", 0); + SAFE_STRCPY(speed, (val && *val) ? val : "115200"); + + val = variable_get(VAR_GATEWAY); + SAFE_STRCPY(provider, (val && *val) ? val : "0"); + + dialog_clear_norefresh(); + val = msgGetInput(provider, "Enter the IP address of your service provider or 0 if you\n" + "don't know it and would prefer to negotiate it dynamically."); + SAFE_STRCPY(provider, (val && *val) ? val : "0"); + + if (devp->private && ((DevInfo *)devp->private)->ipaddr[0]) + SAFE_STRCPY(myaddr, ((DevInfo *)devp->private)->ipaddr); + else + strcpy(myaddr, "0"); + + if (!Fake) + fp = fopen("/etc/ppp/ppp.linkup", "w"); + else + fp = fopen("/dev/stderr", "w"); + if (fp != NULL) { + fprintf(fp, "MYADDR:\n"); + fprintf(fp, " delete ALL\n"); + fprintf(fp, " add 0 0 HISADDR\n"); + fchmod(fileno(fp), 0755); + fclose(fp); + } + if (!Fake) + fd2 = open("/etc/ppp/ppp.secret", O_CREAT); + else + fd2 = -1; + if (fd2 != -1) { + fchmod(fd2, 0700); + close(fd2); + } + if (!Fake) + fp = fopen("/etc/ppp/ppp.conf", "a"); + else + fp = fopen("/dev/stderr", "w"); + if (!fp) { + msgConfirm("Couldn't open /etc/ppp/ppp.conf file! This isn't going to work"); + restorescr(w); + return 0; + } + authname[0] = '\0'; + pulse = 0; + dialog_clear_norefresh(); + if (!dialog_yesno("", "Does your ISP support PAP or CHAP ppp logins?", -1, -1)) { + val = msgGetInput(NULL, "Enter the name you use to login to your provider."); + SAFE_STRCPY(authname, val); + dialog_clear_norefresh(); + val = msgGetInput(NULL, "Enter the password you use to login to your provider."); + SAFE_STRCPY(authkey, val); + dialog_clear_norefresh(); + val = msgGetInput(NULL, "Enter the your provider's login phone number."); + SAFE_STRCPY(phone, val); + dialog_clear_norefresh(); + pulse = dialog_yesno("", "Does your telephone line support tone dialing?", -1, -1); + } + fprintf(fp, "\ninstall:\n"); + fprintf(fp, " set speed %s\n", speed); + fprintf(fp, " set device %s\n", devp->devname); + fprintf(fp, " set ifaddr %s %s 255.255.255.0 0.0.0.0\n", myaddr, provider); + fprintf(fp, " add! default HISADDR\n"); + fprintf(fp, " set timeout 0\n"); + fprintf(fp, " enable dns\n"); + fprintf(fp, " set log local phase\n"); + if(authname[0] != '\0'){ + fprintf(fp, " set dial \"ABORT BUSY ABORT NO\\\\sCARRIER TIMEOUT 5 \\\"\\\" AT OK-AT-OK ATE1Q0 OK \\\\dATD%c\\\\T TIMEOUT 40 CONNECT\"\n", pulse ? 'P' : 'T'); + fprintf(fp, " set login\n"); + fprintf(fp, " set authname %s\n", authname); + fprintf(fp, " set authkey %s\n", authkey); + fprintf(fp, " set phone %s\n", phone); + } + if (fchmod(fileno(fp), 0600) != 0) + msgConfirm("Warning: Failed to fix permissions on /etc/ppp/ppp.conf !"); + fclose(fp); + + /* Make the ppp config persistent */ + variable_set2(VAR_PPP_ENABLE, "YES", 0); + variable_set2(VAR_PPP_PROFILE, "install", 0); + + if (!Fake && !file_readable("/dev/tun0") && mknod("/dev/tun0", 0600 | S_IFCHR, makedev(52, 0))) { + msgConfirm("Warning: No /dev/tun0 device. PPP will not work!"); + restorescr(w); + return 0; + } + + if (isDebug()) + msgDebug("About to start PPP on device %s @ %s baud. Provider = %s\n", devp->devname, speed, provider); + + if (!Fake && !(pid = fork())) { + int i, fd; + struct termios foo; + extern int login_tty(int); + + for (i = getdtablesize(); i >= 0; i--) + close(i); + + /* We're going over to VTY2 */ + fd = open("/dev/ttyv2", O_RDWR); + ioctl(0, TIOCSCTTY, &fd); + dup2(0, 1); + dup2(0, 2); + DebugFD = 2; + if (login_tty(fd) == -1) + msgDebug("ppp: 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("ppp: Unable to set the erase character.\n"); + } + else + msgDebug("ppp: Unable to get the terminal attributes!\n"); + execlp("ppp", "ppp", "install", (char *)NULL); + msgDebug("PPP process failed to exec!\n"); + exit(1); + } + else { + dialog_clear_norefresh(); + msgConfirm("NOTICE: The PPP command is now started on VTY3 (type ALT-F3 to\n" + "interact with it, ALT-F1 to switch back here). If you are using\n" + "a PAP or CHAP login simply enter \"dial\", otherwise you'll need\n" + "to use the \"term\" command which starts a terminal emulator\n" + "which you can use to talk to your modem and dial the service\n" + "provider. Once you're connected, come back to this screen and\n" + "press return.\n\n" + "DO NOT PRESS [ENTER] HERE UNTIL THE CONNECTION IS FULLY\n" + "ESTABLISHED!"); + } + restorescr(w); + return pid; +} diff --git a/usr.sbin/sysinstall/nfs.c b/usr.sbin/sysinstall/nfs.c new file mode 100644 index 0000000000000..87788eaced6f2 --- /dev/null +++ b/usr.sbin/sysinstall/nfs.c @@ -0,0 +1,101 @@ +/* + * 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 <sys/errno.h> +#include <sys/fcntl.h> +#include <sys/param.h> +#include <sys/mount.h> + +#include <limits.h> + +Boolean NFSMounted; +static char mountpoint[] = "/dist"; + +Boolean +mediaInitNFS(Device *dev) +{ + Device *netDevice = (Device *)dev->private; + WINDOW *w = savescr(); + + if (NFSMounted) + return TRUE; + + if (!DEVICE_INIT(netDevice)) + return FALSE; + + if (Mkdir(mountpoint)) + return FALSE; + + msgNotify("Mounting %s over NFS on %s", dev->name, mountpoint); + if (vsystem("mount_nfs %s %s %s %s %s %s", + !variable_cmp(VAR_NFS_TCP, "YES") ? "-T" : "", + !variable_cmp(VAR_NFS_V3, "YES") ? "-3" : "", + !variable_cmp(VAR_SLOW_ETHER, "YES") ? + "-r 1024 -w 1024" : "-r 4096 -w 4096", + !variable_cmp(VAR_NFS_SECURE, "YES") ? "-P" : "", + dev->name, mountpoint)) { + msgConfirm("Error mounting %s on %s: %s.", dev->name, mountpoint, strerror(errno)); + if (netDevice) + DEVICE_SHUTDOWN(netDevice); + restorescr(w); + return FALSE; + } + NFSMounted = TRUE; + if (isDebug()) + msgDebug("Mounted NFS device %s onto %s\n", dev->name, mountpoint); + restorescr(w); + return TRUE; +} + +FILE * +mediaGetNFS(Device *dev, char *file, Boolean probe) +{ + return mediaGenericGet(mountpoint, file); +} + +void +mediaShutdownNFS(Device *dev) +{ + if (!NFSMounted) + return; + + msgDebug("Unmounting NFS partition on %s\n", mountpoint); + if (unmount(mountpoint, MNT_FORCE) != 0) + msgConfirm("Could not unmount the NFS partition: %s", strerror(errno)); + NFSMounted = FALSE; + return; +} diff --git a/usr.sbin/sysinstall/options.c b/usr.sbin/sysinstall/options.c new file mode 100644 index 0000000000000..8e3a7d96ac849 --- /dev/null +++ b/usr.sbin/sysinstall/options.c @@ -0,0 +1,341 @@ +/* + * The new sysinstall program. + * + * This is probably the last attempt in the `sysinstall' line, the next + * generation being slated for what's 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 <ctype.h> +#include <curses.h> +#include <term.h> + +int fixitTtyWhich(dialogMenuItem *); + +static char * +varCheck(Option opt) +{ + char *cp = NULL; + + if (opt.aux) + cp = variable_get((char *)opt.aux); + if (!cp) + return "NO"; + return cp; +} + +/* Show our little logo */ +static char * +resetLogo(char *str) +{ + return "[RESET!]"; +} + +static char * +mediaCheck(Option opt) +{ + if (mediaDevice) { + switch(mediaDevice->type) { + case DEVICE_TYPE_UFS: + case DEVICE_TYPE_DISK: + return "File system"; + + case DEVICE_TYPE_FLOPPY: + return "Floppy"; + + case DEVICE_TYPE_FTP: + return "FTP"; + + case DEVICE_TYPE_CDROM: + return "CDROM"; + + case DEVICE_TYPE_TAPE: + return "Tape"; + + case DEVICE_TYPE_DOS: + return "DOS"; + + case DEVICE_TYPE_NFS: + return "NFS"; + + case DEVICE_TYPE_NONE: + case DEVICE_TYPE_NETWORK: + case DEVICE_TYPE_ANY: + default: + return "<unknown>"; + } + } + return "<not yet set>"; +} + +#define TAPE_PROMPT "Please enter the tape block size in 512 byte blocks:" +#define NEWFS_PROMPT "Please enter newfs(8) parameters:" +#define RELNAME_PROMPT "Please specify the release you wish to load or\n\"any\" for a generic release install:" +#define BPKG_PROMPT "Please specify the name of the HTML browser package:" +#define BBIN_PROMPT "Please specify a full pathname to the HTML browser binary:" +#define EDITOR_PROMPT "Please specify the name of the text editor you wish to use:" +#define PKG_PROMPT "Please specify a temporary directory with lots of free space:" +#define INSTROOT_PROMPT "Please specify a root directory if installing somewhere other than /" +#define TIMEOUT_PROMPT "Please specify the number of seconds to wait for slow media:" + +static Option Options[] = { +{ "NFS Secure", "NFS server talks only on a secure port", + OPT_IS_VAR, NULL, VAR_NFS_SECURE, varCheck }, +{ "NFS Slow", "User is using a slow PC or ethernet card", + OPT_IS_VAR, NULL, VAR_SLOW_ETHER, varCheck }, +{ "NFS TCP", "Use TCP protocol for NFS", + OPT_IS_VAR, NULL, VAR_NFS_TCP, varCheck }, +{ "NFS version 3", "Use NFS version 3", + OPT_IS_VAR, NULL, VAR_NFS_V3, varCheck }, +{ "Debugging", "Emit extra debugging output on VTY2 (ALT-F2)", + OPT_IS_VAR, NULL, VAR_DEBUG, varCheck }, +{ "No Warnings", "Don't Warn the user when a setting seems incorrect", + OPT_IS_VAR, NULL, VAR_NO_WARN, varCheck }, +{ "Yes to All", "Assume \"Yes\" answers to all non-critical dialogs", + OPT_IS_VAR, NULL, VAR_NO_CONFIRM, varCheck }, +{ "DHCP", "Attempt automatic DHCP configuration of interfaces", + OPT_IS_VAR, NULL, VAR_TRY_DHCP, varCheck }, +{ "IPv6", "Attempt IPv6 configuration of interfaces", + OPT_IS_VAR, NULL, VAR_TRY_RTSOL, varCheck }, +{ "Skip PCCARD", "Skip PC Card probing, do not use PC Card devices for installation", + OPT_IS_VAR, NULL, VAR_SKIP_PCCARD, varCheck }, +{ "FTP username", "Username and password to use instead of anonymous", + OPT_IS_FUNC, mediaSetFTPUserPass, VAR_FTP_USER, varCheck }, +{ "Editor", "Which text editor to use during installation", + OPT_IS_VAR, EDITOR_PROMPT, VAR_EDITOR, varCheck }, +{ "Tape Blocksize", "Tape media block size in 512 byte blocks", + OPT_IS_VAR, TAPE_PROMPT, VAR_TAPE_BLOCKSIZE, varCheck }, +{ "Extract Detail", "How verbosely to display file name information during extractions", + OPT_IS_FUNC, mediaSetCPIOVerbosity, VAR_CPIO_VERBOSITY, varCheck }, +{ "Release Name", "Which release to attempt to load from installation media", + OPT_IS_VAR, RELNAME_PROMPT, VAR_RELNAME, varCheck }, +{ "Install Root", "Which directory to unpack distributions or packages relative to", + OPT_IS_VAR, INSTROOT_PROMPT, VAR_INSTALL_ROOT, varCheck }, +{ "Browser package", "This is the browser package that will be used for viewing HTML docs", + OPT_IS_VAR, BPKG_PROMPT, VAR_BROWSER_PACKAGE, varCheck }, +{ "Browser Exec", "This is the path to the main binary of the browser package", + OPT_IS_VAR, BBIN_PROMPT, VAR_BROWSER_BINARY, varCheck }, +{ "Media Type", "The current installation media type.", + OPT_IS_FUNC, mediaGetType, VAR_MEDIA_TYPE, mediaCheck }, +{ "Media Timeout", "Timeout value in seconds for slow media.", + OPT_IS_VAR, TIMEOUT_PROMPT, VAR_MEDIA_TIMEOUT, varCheck }, +{ "Package Temp", "The directory where package temporary files should go", + OPT_IS_VAR, PKG_PROMPT, VAR_PKG_TMPDIR, varCheck }, +{ "Newfs Args", "Default parameters for newfs(8)", + OPT_IS_VAR, NEWFS_PROMPT, VAR_NEWFS_ARGS, varCheck }, +{ "Fixit Console", "Which tty to use for the Fixit action.", + OPT_IS_FUNC, fixitTtyWhich, VAR_FIXIT_TTY, varCheck }, +{ "Re-scan Devices", "Re-run sysinstall's initial device probe", + OPT_IS_FUNC, deviceRescan }, +{ "Use Defaults", "Reset all values to startup defaults", + OPT_IS_FUNC, installVarDefaults, 0, resetLogo }, +{ NULL }, +}; + +#define OPT_START_ROW 4 +#define OPT_END_ROW 19 +#define OPT_NAME_COL 0 +#define OPT_VALUE_COL 16 +#define GROUP_OFFSET 40 + +static char * +value_of(Option opt) +{ + static char ival[40]; + + switch (opt.type) { + case OPT_IS_STRING: + return (char *)opt.data; + + case OPT_IS_INT: + sprintf(ival, "%lu", (long)opt.data); + return ival; + + case OPT_IS_FUNC: + case OPT_IS_VAR: + if (opt.check) + return opt.check(opt); + else + return "<*>"; + } + return "<unknown>"; +} + +static int +fire(Option opt) +{ + int status = 0; + + if (opt.type == OPT_IS_FUNC) { + int (*cp)(char *) = opt.data, rcode; + + rcode = cp(NULL); + status = 1; + } + else if (opt.type == OPT_IS_VAR) { + if (opt.data) { + (void)variable_get_value(opt.aux, opt.data, -1); + status = 1; + } + else if (variable_get(opt.aux)) { + if (!variable_cmp(opt.aux, "YES")) + variable_set2(opt.aux, "NO", -1); + else + variable_set2(opt.aux, "YES", -1); + } + else + variable_set2(opt.aux, "YES", 0); + } + if (opt.check) + opt.check(opt); + refresh(); + return status; +} + +int +optionsEditor(dialogMenuItem *self) +{ + int i, optcol, optrow, key; + static int currOpt = 0; + WINDOW *w = savescr(); + + dialog_clear(); + clear(); + + while (1) { + /* Whap up the header */ + attrset(A_REVERSE); mvaddstr(0, 0, "Options Editor"); attrset(A_NORMAL); + for (i = 0; i < 2; i++) { + mvaddstr(OPT_START_ROW - 2, OPT_NAME_COL + (i * GROUP_OFFSET), "Name"); + mvaddstr(OPT_START_ROW - 1, OPT_NAME_COL + (i * GROUP_OFFSET), "----"); + + mvaddstr(OPT_START_ROW - 2, OPT_VALUE_COL + (i * GROUP_OFFSET), "Value"); + mvaddstr(OPT_START_ROW - 1, OPT_VALUE_COL + (i * GROUP_OFFSET), "-----"); + } + /* And the footer */ + mvprintw(OPT_END_ROW + 1, 0, "Use SPACE to select/toggle an option, arrow keys to move,"); + mvprintw(OPT_END_ROW + 2, 0, "? or F1 for more help. When you're done, type Q to Quit."); + + optrow = OPT_START_ROW; + optcol = OPT_NAME_COL; + for (i = 0; Options[i].name; i++) { + /* Names are painted somewhat gratuitously each time, but it's easier this way */ + mvprintw(optrow, OPT_NAME_COL + optcol, Options[i].name); + if (currOpt == i) + attrset(ATTR_SELECTED); + mvprintw(optrow++, OPT_VALUE_COL + optcol, value_of(Options[i])); + if (currOpt == i) + attrset(A_NORMAL); + if (optrow == OPT_END_ROW) { + optrow = OPT_START_ROW; + optcol += GROUP_OFFSET; + } + clrtoeol(); + } + attrset(ATTR_TITLE); + mvaddstr(OPT_END_ROW + 4, 0, Options[currOpt].desc); + attrset(A_NORMAL); + clrtoeol(); + move(0, 14); + refresh(); + + /* Start the edit loop */ + key = toupper(getch()); + switch (key) { + case KEY_F(1): + case '?': + systemDisplayHelp("options"); + clear(); + break; + + case '\020': /* ^P */ + case KEY_UP: + if (currOpt) + --currOpt; + else + for (currOpt = 0; Options[currOpt + 1].name; currOpt++); + continue; + + case '\016': /* ^N */ + case KEY_DOWN: + if (Options[currOpt + 1].name) + ++currOpt; + else + currOpt = 0; + continue; + + case KEY_HOME: + currOpt = 0; + continue; + + case KEY_END: + while (Options[currOpt + 1].name) + ++currOpt; + continue; + + case ' ': + if (fire(Options[currOpt])) + clear(); + continue; + + case '\033': /* ESC */ + case 'Q': + clear(); + dialog_clear(); + restorescr(w); + return DITEM_SUCCESS | DITEM_CONTINUE; + + default: + beep(); + } + } + /* NOTREACHED */ + return DITEM_SUCCESS; +} + +int +fixitTtyWhich(dialogMenuItem *self) +{ + char *cp = variable_get(VAR_FIXIT_TTY); + + if (!cp) { + msgConfirm("The Fix-it TTY setting is not set to anything!"); + return DITEM_FAILURE; + } + else { + if (!strcmp(cp, "standard")) + variable_set2(VAR_FIXIT_TTY, "serial", 0); + else /* must be "serial" - wrap around */ + variable_set2(VAR_FIXIT_TTY, "standard", 0); + } + return DITEM_SUCCESS; +} diff --git a/usr.sbin/sysinstall/package.c b/usr.sbin/sysinstall/package.c new file mode 100644 index 0000000000000..7f23fc3cfdb76 --- /dev/null +++ b/usr.sbin/sysinstall/package.c @@ -0,0 +1,263 @@ +/* + * The new sysinstall program. + * + * This is probably the last program in the `sysinstall' line - the next + * generation being essentially a complete rewrite. + * + * 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. + * + * $FreeBSD$ + */ + +#include "sysinstall.h" +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/stat.h> + +static Boolean sigpipe_caught; + +static void +catch_pipe(int sig) +{ + sigpipe_caught = TRUE; +} + +extern PkgNode Top; + +/* Like package_extract, but assumes current media device and chases deps */ +int +package_add(char *name) +{ + PkgNodePtr tmp; + int i; + + if (!mediaVerify()) + return DITEM_FAILURE; + + if (!DEVICE_INIT(mediaDevice)) + return DITEM_FAILURE; + + i = index_initialize("packages/INDEX"); + if (DITEM_STATUS(i) != DITEM_SUCCESS) + return i; + + tmp = index_search(&Top, name, &tmp); + if (tmp) + return index_extract(mediaDevice, &Top, tmp, FALSE); + else { + msgConfirm("Sorry, package %s was not found in the INDEX.", name); + return DITEM_FAILURE; + } +} + +/* For use by dispatch */ +int +packageAdd(dialogMenuItem *self) +{ + char *cp; + + cp = variable_get(VAR_PACKAGE); + if (!cp) { + msgDebug("packageAdd: No package name passed in package variable\n"); + return DITEM_FAILURE; + } + else + return package_add(cp); +} + +Boolean +package_installed(char *name) +{ + char fname[FILENAME_MAX]; + int status /* = vsystem("pkg_info -e %s", name) */; + + /* XXX KLUDGE ALERT! This makes evil assumptions about how XXX + * packages register themselves and should *really be done with + * `pkg_info -e <name>' except that this it's too slow for an + * item check routine.. :-( + */ + snprintf(fname, FILENAME_MAX, "/var/db/pkg/%s", name); + status = access(fname, R_OK); + if (isDebug()) + msgDebug("package check for %s returns %s.\n", name, status ? "failure" : "success"); + return !status; +} + +/* Extract a package based on a namespec and a media device */ +int +package_extract(Device *dev, char *name, Boolean depended) +{ + char path[MAXPATHLEN]; + const char *PkgExts[] = { "", ".tbz", ".tbz2", ".tgz" }; + int ext, last_msg, pathend, ret; + FILE *fp; + + last_msg = 0; + + /* Check to make sure it's not already there */ + if (package_installed(name)) + return DITEM_SUCCESS; + + if (!DEVICE_INIT(dev)) { + msgConfirm("Unable to initialize media type for package extract."); + return DITEM_FAILURE; + } + + /* If necessary, initialize the ldconfig hints */ + if (!file_readable("/var/run/ld-elf.so.hints")) + vsystem("ldconfig /usr/lib /usr/lib/compat /usr/local/lib /usr/X11R6/lib"); + + /* Be initially optimistic */ + ret = DITEM_SUCCESS; + /* Make a couple of paranoid locations for temp files to live if user specified none */ + if (!variable_get(VAR_PKG_TMPDIR)) { + /* Set it to a location with as much space as possible */ + variable_set2(VAR_PKG_TMPDIR, "/var/tmp", 0); + } + Mkdir(variable_get(VAR_PKG_TMPDIR)); + vsystem("chmod 1777 %s", variable_get(VAR_PKG_TMPDIR)); + + if (!index(name, '/')) { + if (!strpbrk(name, "-_")) + pathend = snprintf(path, sizeof path, "packages/Latest/%s", name); + else + pathend = snprintf(path, sizeof path, "packages/All/%s", name); + } + else + pathend = snprintf(path, sizeof path, "%s", name); + + /* We have a path, call the device strategy routine to get the file */ + for (ext = 0 ; ext < sizeof PkgExts / sizeof PkgExts[0]; ++ext) { + strlcpy(path + pathend, PkgExts[ext], sizeof path - pathend); + if ((fp = DEVICE_GET(dev, path, TRUE))) + break; + } + + if (fp) { + int i = 0, tot, pfd[2]; + pid_t pid; + WINDOW *w = savescr(); + + sigpipe_caught = FALSE; + signal(SIGPIPE, catch_pipe); + + dialog_clear_norefresh(); + msgNotify("Adding %s%s\nfrom %s", path, depended ? " (as a dependency)" : "", dev->name); + pipe(pfd); + pid = fork(); + if (!pid) { + dup2(pfd[0], 0); close(pfd[0]); + dup2(DebugFD, 1); dup2(1, 2); + close(pfd[1]); + + /* Prevent pkg_add from wanting to interact in bad ways */ + setenv("PACKAGE_BUILDING", "t", 1); + setenv("BATCH", "t", 1); + + if (isDebug()) + i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-v", "-", + (char *)0); + else + i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-", + (char *)0); + } + else { + char buf[BUFSIZ]; + struct timeval start, stop; + + close(pfd[0]); + tot = 0; + (void)gettimeofday(&start, (struct timezone *)0); + + while (!sigpipe_caught && (i = fread(buf, 1, BUFSIZ, fp)) > 0) { + int seconds; + + tot += i; + /* Print statistics about how we're doing */ + (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; + if (seconds != last_msg) { + last_msg = seconds; + msgInfo("%10d bytes read from package %s @ %4.1f KBytes/second", tot, name, (tot / seconds) / 1000.0); + } + /* Write it out */ + if (sigpipe_caught || write(pfd[1], buf, i) != i) { + msgInfo("Write failure to pkg_add! Package may be corrupt."); + break; + } + } + close(pfd[1]); + fclose(fp); + if (sigpipe_caught) + msgInfo("pkg_add(1) apparently did not like the %s package.", name); + else if (i == -1) + msgInfo("I/O error while reading in the %s package.", name); + else + msgInfo("Package %s read successfully - waiting for pkg_add(1)", name); + refresh(); + i = waitpid(pid, &tot, 0); + dialog_clear_norefresh(); + if (sigpipe_caught || i < 0 || WEXITSTATUS(tot)) { + ret = DITEM_FAILURE; + if (variable_get(VAR_NO_CONFIRM)) + msgNotify("Add of package %s aborted, error code %d -\n" + "Please check the debug screen for more info.", name, WEXITSTATUS(tot)); + else + msgConfirm("Add of package %s aborted, error code %d -\n" + "Please check the debug screen for more info.", name, WEXITSTATUS(tot)); + } + else + msgNotify("Package %s was added successfully", name); + + /* Now catch any stragglers */ + while (wait3(&tot, WNOHANG, NULL) > 0); + + sleep(1); + restorescr(w); + } + } + else { + dialog_clear_norefresh(); + if (variable_get(VAR_NO_CONFIRM)) + msgNotify("Unable to fetch package %s from selected media.\n" + "No package add will be done.", name); + else + msgConfirm("Unable to fetch package %s from selected media.\n" + "No package add will be done.", name); + ret = DITEM_FAILURE; + } + signal(SIGPIPE, SIG_IGN); + return ret; +} diff --git a/usr.sbin/sysinstall/pccard.c b/usr.sbin/sysinstall/pccard.c new file mode 100644 index 0000000000000..0ddfad8b3d07a --- /dev/null +++ b/usr.sbin/sysinstall/pccard.c @@ -0,0 +1,290 @@ +/* + * PC Card support for sysinstall + * + * $FreeBSD$ + * + * Copyright (c) 1997-1999 + * Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org>. All rights reserved. + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + */ + +#include "sysinstall.h" +#include <sys/fcntl.h> +#include <sys/time.h> +#include <pccard/cardinfo.h> + +int pccard_mode = 0; + +/* + * Set up defines for pccardd interrupt selection. + */ +#ifdef PC98 +#define IRQ_COUNT 11 +#else +#define IRQ_COUNT 9 +#endif /* PC98 */ +#define IRQ_10 0x00001 +#define IRQ_11 0x00002 +#define IRQ_03 0x00004 +#define IRQ_09 0x00008 +#define IRQ_04 0x00010 +#define IRQ_07 0x00020 +#define IRQ_05 0x00040 +#define IRQ_06 0x00080 +#define IRQ_15 0x00100 +#ifdef PC98 +#define IRQ_12 0x00200 +#define IRQ_13 0x00400 +#endif /* PC98 */ + +unsigned int CardIrq; + +typedef struct _irq { + char *my_name; + char *my_flag; + unsigned int my_mask; + unsigned int my_bit; +} Irq; + +/* Fill in with potential free IRQs for pccardd */ +static Irq IrqTable[] = { + { "irq_03", "-i 3", ~IRQ_03, IRQ_03 }, + { "irq_04", "-i 4", ~IRQ_04, IRQ_04 }, + { "irq_05", "-i 5", ~IRQ_05, IRQ_05 }, + { "irq_06", "-i 6", ~IRQ_06, IRQ_06 }, + { "irq_07", "-i 7", ~IRQ_07, IRQ_07 }, + { "irq_09", "-i 9", ~IRQ_09, IRQ_09 }, + { "irq_10", "-i 10", ~IRQ_10, IRQ_10 }, + { "irq_11", "-i 11", ~IRQ_11, IRQ_11 }, + { "irq_15", "-i 15", ~IRQ_15, IRQ_15 }, +#ifdef PC98 + { "irq_12", "-i 12", ~IRQ_12, IRQ_12 }, + { "irq_13", "-i 13", ~IRQ_13, IRQ_13 }, +#endif /* PC98 */ + {NULL}, +}; + +int +pccardIrqReset(dialogMenuItem *self) +{ + CardIrq = 0; + return DITEM_SUCCESS | DITEM_REDRAW; +} + +static int +checkTrue(dialogMenuItem *item) +{ + return TRUE; +} + +DMenu MenuPCICMem = { + DMENU_NORMAL_TYPE | DMENU_SELECTION_RETURNS, + "Please select free address area used by PC Card controller", + "PC Card controller uses memory area to get card information.\n" + "Please specify an address that is not used by other devices.\n" + "If you're uncertain of detailed specification of your hardware,\n" +#ifdef PC98 + "leave it untouched (default == 0xd0000).\n" + "If you use PC-9801 P, NS/A, NX/C, NL/R or PC-9821 Ne please \n" + "select [DA] here.", +#else + "leave it untouched (default == 0xd0000).", +#endif /* PC98 */ + "Press F1 for more HELP", + "pccard", + { { "Default", "I/O address 0xd0000 - 0xd3fff", + NULL, dmenuSetVariable, NULL, "_pcicmem=0"}, + { "D4", "I/O address 0xd4000 - 0xd7fff", + NULL, dmenuSetVariable, NULL, "_pcicmem=1"}, + { "D8", "I/O address 0xd8000 - 0xdbfff", + NULL, dmenuSetVariable, NULL, "_pcicmem=2"}, + { "DC", "I/O address 0xdc000 - 0xdffff", + NULL, dmenuSetVariable, NULL, "_pcicmem=3"}, +#ifdef PC98 + { "DA", "I/O address 0xda000 - 0xdbfff", + NULL, dmenuSetVariable, NULL, "_pcicmem=4"}, +#endif /* PC98 */ + { NULL } }, +}; + +DMenu MenuCardIRQ = { + DMENU_CHECKLIST_TYPE | DMENU_SELECTION_RETURNS, + "Please specify the IRQs that may be used by PC Cards", + "(NOTE: remove any cards that will NOT be used for installation).\n" + "The IRQs that you choose must be free (unshared), or you risk \n" + "subpar performance and/or a complete system lockup (choose wisely).\n" + "One way to determine which IRQs are available is to \"cheat\" and\n" + "use the Windows 9x/2000 Device Manager as a reference prior to the\n" + "installation.\n", + "Select Free IRQ for pccardd", + NULL, + { { "X Exit", "Exit this menu", + checkTrue, dmenuExit, NULL, NULL, '<', '<', '<' }, + { "Reset", "Reset selected IRQ list", + NULL, pccardIrqReset, NULL, NULL, ' ', ' ', ' ' }, +#ifdef PC98 + { "3 IRQ 3", "(INT 0) is 2nd serial port, internal modem", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_03 }, + { "4 IRQ 5", "(INT 1) is Infrared communication, SCSI I/F, (2nd serial)", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_05 }, + { "5 IRQ 6", "(INT 2) is PC Card Controller", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_06 }, + { "6 IRQ 9", "(INT 3) is IDE disk Controller", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_09 }, + { "7 IRQ 10", "(INT 41) is often free", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_10 }, + { "8 IRQ 12", "(INT 5) is Internal sound", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_12 }, + { "9 IRQ 13", "(INT 6) is Bus Mouse", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_13 }, +#else + { "3 IRQ 10", "IRQ 10 is often free (verify in BIOS)", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_10 }, + { "4 IRQ 11", "Verify IRQ 11 is not being used as PCI shared interrupt", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_11 }, + { "5 IRQ 3", "IRQ 3 is often free in most laptops", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_03 }, + { "6 IRQ 9", "IRQ 9 may be used by video or sound or USB", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_09 }, + { "7 IRQ 4", "IRQ 4, usually COM1 (disable in BIOS to make free)", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_04 }, + { "8 IRQ 7", "IRQ 7, usually LPT1 (disable in BIOS to make free)", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_07 }, + { "9 IRQ 5", "IRQ 5, usually ISA Audio (disable in BIOS to make free)", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_05 }, + { "10 IRQ 15", "IRQ 15, usually Secondary IDE channel", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_15 }, + { "11 IRQ 6", "IRQ 6 will be free if laptop only has USB floppy drive", + dmenuFlagCheck, dmenuSetFlag, NULL, &CardIrq, '[', 'X', ']', IRQ_06 }, +#endif /* PC98 */ + { NULL } }, +}; + +void +pccardInitialize(void) +{ + int fd; + int t; + int i; + int pcic_mem = 0xd0000; + int beep_newstat; + char card_device[16]; + char card_irq[256] = ""; + char temp[256]; + char *spcic_mem; + char pccardd_cmd[256]; + WINDOW *w; + + pccard_mode = 1; + + if (!RunningAsInit && !Fake) { + /* It's not my job... */ + return; + } + + sprintf(card_device, CARD_DEVICE, 0); + + if ((fd = open(card_device, O_RDWR)) < 0) { + msgDebug("Can't open PC Card controller %s.\n", card_device); + return; + } + else if (msgYesNo("Found PC Card slot(s).\n" + "Use PC Card device as installation media?\n")) { + return; + } + close(fd); + + variable_set2("_pccard_install", "YES", 0); + + dmenuOpenSimple(&MenuPCICMem, FALSE); + spcic_mem = variable_get("_pcicmem"); + dmenuOpenSimple(&MenuCardIRQ, FALSE); + + sscanf(spcic_mem, "%d", &t); + switch (t) { + case 0: + pcic_mem = 0xd0000; + variable_set2("pccard_mem", "DEFAULT", 1); + break; + case 1: + pcic_mem = 0xd4000; + variable_set2("pccard_mem", "0xd4000", 1); + break; + case 2: + pcic_mem = 0xd8000; + variable_set2("pccard_mem", "0xd8000", 1); + break; + case 3: + pcic_mem = 0xdc000; + variable_set2("pccard_mem", "0xdc000", 1); + break; +#ifdef PC98 + case 4: + pcic_mem = 0xda000; + variable_set2("pccard_mem", "0xda000", 1); + break; +#endif /* PC98 */ + } + + /* get card_irq out of CardIrq somehow */ + if (CardIrq) { + for (i = 0; i < IRQ_COUNT; i++) { + if ((CardIrq & IrqTable[i].my_bit) != 0) { + sprintf(temp, "%s %s", card_irq, IrqTable[i].my_flag); + strcpy(card_irq, temp); + } + } + } + + w = savescr(); + dialog_clear_norefresh(); + msgConfirm("Now we start initializing PC Card controller and cards.\n" + "If you've executed this installer from a PC Card floppy\n" + "drive, this is the last chance to replace it with\n" + "installation media (PC Card Ethernet, CD, DVD, etc.).\n" + "Please insert installation media and press [Enter].\n" + "If you've not plugged the PC Card installation media\n" + "in yet, please plug it in now and press [Enter].\n" + "Otherwise, just press [Enter] to proceed."); + + dialog_clear(); + msgNotify("Initializing PC Card controller...."); + + if (!Fake) { + if ((fd = open(card_device, O_RDWR)) < 1) { + msgNotify("Can't open PC Card controller %s.\n", card_device); + restorescr(w); + return; + } + + if (ioctl(fd, PIOCRWMEM, &pcic_mem) < 0) { + msgNotify("ioctl %s failed.\n", card_device); + restorescr(w); + return; + } + beep_newstat = 2; + if (ioctl(fd, PIOCSBEEP, &beep_newstat) < 0) { + msgNotify("Warning: unable to set pccard insertion beep type for %s", + card_device); + restorescr(w); + return; + } + + } + + strcpy(pccardd_cmd, "/stand/pccardd "); + strcat(pccardd_cmd, card_irq); + strcat(pccardd_cmd, " -z"); + + variable_set2("pccardd_flags", card_irq, 1); + variable_set2("pccard_enable", "YES", 1); + + vsystem("%s", pccardd_cmd); + restorescr(w); +} diff --git a/usr.sbin/sysinstall/rtermcap.c b/usr.sbin/sysinstall/rtermcap.c new file mode 100644 index 0000000000000..84b3feb49ead2 --- /dev/null +++ b/usr.sbin/sysinstall/rtermcap.c @@ -0,0 +1,15 @@ +#include <stdio.h> +#include <termcap.h> + +int +main(int argc, char **argv) +{ + char buf[4096]; + int i; + + if (argc < 2) + return 1; + i = tgetent(buf, argv[1]); + printf("%s",buf); + return 0; +} diff --git a/usr.sbin/sysinstall/sysinstall.8 b/usr.sbin/sysinstall/sysinstall.8 new file mode 100644 index 0000000000000..d21657915ff63 --- /dev/null +++ b/usr.sbin/sysinstall/sysinstall.8 @@ -0,0 +1,946 @@ +.\" Copyright (c) 1997 +.\" Jordan Hubbard <jkh@FreeBSD.org>. 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. +.\" 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 AND CONTRIBUTORS ``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 CONTRIBUTORS 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, 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 9, 1997 +.Dt SYSINSTALL 8 +.Os +.Sh NAME +.Nm sysinstall +.Nd system installation and configuration tool +.Sh SYNOPSIS +.Nm +.Op Ar var=value +.Op Ar function +.Op Ar ... +.Sh DESCRIPTION +The +.Nm +utility is used for installing and configuring +.Fx +systems. +It is the first utility invoked by the +.Fx +installation boot +floppy and is also available as +.Pa /usr/sbin/sysinstall +on newly installed +.Fx +systems for use in later configuring the system. +.Pp +The +.Nm +utility is generally invoked without arguments for the default +behavior, where the main installation/configuration menu is presented. +.Pp +On those occasions where it is deemed necessary to invoke a subsystem +of sysinstall directly, however, it is also possible to do so by +naming the appropriate function entry points on the command line. +Since this action is essentially identical to running an installation +script, each command-line argument corresponding to a line of script, +the reader is encouraged to read the section on scripting for more +information on this feature. +.Sh NOTES +The +.Nm +utility is essentially nothing more than a monolithic C program with +the ability to write MBRs and disk labels (through the services +of the +.Xr libdisk 3 +library) and install distributions or packages onto new and +existing +.Fx +systems. +It also contains some extra intelligence +for running as a replacement for +.Xr init 8 +when it is invoked by the +.Fx +installation boot procedure. +It +assumes very little in the way of additional utility support and +performs most file system operations by calling the relevant syscalls +(such as +.Xr mount 2 ) +directly. +.Pp +The +.Nm +utility currently uses the +.Xr dialog 3 +library to do user interaction with simple ANSI line graphics, color +support for which is enabled by either running on a syscons VTY or some +other color-capable terminal emulator (newer versions of xterm will support +color when using the +.Dq xterm-color +termcap entry). +.Pp +This product is currently at the end of its life cycle and will +eventually be replaced. +.Sh RUNNING SCRIPTS +The +.Nm +utility may be either driven interactively through its various internal menus +or run in batch mode, driven by an external script. +Such a script may +be loaded and executed in one of 3 ways: +.Bl -tag -width Ds +.It Sy "LOAD_CONFIG_FILE" +If +.Nm +is compiled with LOAD_CONFIG_FILE set in the environment +(or in the Makefile) to some value, then that value will +be used as the filename to automatically look for and load +when +.Nm +starts up and with no user interaction required. +This option is aimed primarily at large sites who wish to create a +single prototype install for multiple machines with largely identical +configurations and/or installation options. +.It Sy "MAIN MENU" +If +.Nm +is run interactively, that is to say in the default manner, it will +bring up a main menu which contains a "load config file" option. +Selecting this option will prompt for the name of a script file which +it then will attempt to load from a DOS or UFS formatted floppy. +.It Sy "COMMAND LINE" +Each command line argument is treated as a script directive +when +.Nm +is run in multi-user mode. +Execution ends either by explicit request +(e.g.\& calling the +.Ar shutdown +directive), upon reaching the end of the argument list or on error. +.Pp +For example: +.Bd -literal +/usr/sbin/sysinstall _ftpPath=ftp://ziggy/pub/ mediaSetFTP configPackages +.Ed +.Pp +Would initialize +.Nm +for FTP installation media (using the server `ziggy') and then +bring up the package installation editor, exiting when finished. +.El +.Sh SCRIPT SYNTAX +A script is a list of one or more directives, each directive taking +the form of: +.Pp +.Ar var=value +.Pp +.Ar function +.Pp +or +.Ar #somecomment +.Pp +Where +.Ar var=value +is the assignment of some internal +.Nm +variable, e.g.\& "ftpPass=FuNkYChiKn", and +.Ar function +is the name of an internal +.Nm +function, e.g.\& "mediaSetFTP", and +.Ar #comment +is a single-line comment for documentation purposes (ignored by +sysinstall). +Each directive must be by itself on a single line, +functions taking their arguments by examining known variable names. +This requires that you be sure to assign the relevant variables before +calling a function which requires them. +.Pp +The +.Ar noError +variable can be assigned before each directive: this will cause any error +detected while processing the directive itself to be ignored. +The value of +.Ar noError +will automatically reset to the default "unassigned" every time a directive is +processed. +.Pp +When and where a function depends on the settings of one or more variables +will be noted in the following table: +.Pp +.Sy "Function Glossary" : +.Pp +.Bl -tag -width indent +.It configAnonFTP +Invoke the Anonymous FTP configuration menu. +.Pp +.Sy Variables : +None +.It configRouter +Select which routing daemon you wish to use, potentially +loading any required 3rd-party routing daemons as necessary. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It router +can be set to the name of the desired routing daemon, +e.g.\& +.Dq routed +or +.Dq gated , +otherwise it is prompted for. +.El +.It configNFSServer +Configure host as an NFS server. +.Pp +.Sy Variables : +None +.It configNTP +Configure host as a user of the Network Time Protocol. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It ntpdate_flags +The flags to +.Xr ntpdate 8 , +that is to say the name of the server to sync from. +.El +.It configPCNFSD +Configure host to support PC NFS. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It pcnfsd_pkg +The name of the PCNFSD package to load if necessary (defaults to hard coded +version). +.El +.It configPackages +Bring up the interactive package management menu. +.Pp +.Sy Variables : +None +.It configUsers +Add users and/or groups to the system. +.Pp +.Sy Variables : +None +.It diskPartitionEditor +Invokes the disk partition (MBR) editor. +.Pp +.Sy Variables : +.Bl -tag -width findx +.It geometry +The disk geometry, as a cyls/heads/sectors formatted string. +Default: no +change to geometry. +.It partition +Set to disk partitioning type or size, its value being +.Ar free +in order to use only remaining free space for +.Fx , +.Ar all +to use the entire disk for +.Fx +but maintain a proper partition +table, +.Ar existing +to use an existing +.Fx +partition (first found), +.Ar exclusive +to use the disk in +.Dq dangerously dedicated +mode or, finally, +.Ar somenumber +to allocate +.Ar somenumber +blocks of available free space to a new +.Fx +partition. +Default: Interactive mode. +.It bootManager +is set to one of +.Ar boot +to signify the installation of a boot manager, +.Ar standard +to signify installation of a "standard" non-boot MGR DOS +MBR or +.Ar none +to indicate that no change to the boot manager is desired. +Default: none. +.It diskInteractive +If set, bring up the interactive disk partition editor. +.El +.Pp +Note: Nothing is actually written to disk by this function, an explicit call to +.Ar diskPartitionWrite +being required for that to happen. +.It diskPartitionWrite +Causes any pending MBR changes (typically from the +.Ar diskPartitionEditor +function) to be written out. +.Pp +.Sy Variables : +None +.It diskLabelEditor +Invokes the disk label editor. +This is a bit trickier from a script +since you need to essentially label everything inside each +.Fx +(type 0xA5) partition created by the +.Ar diskPartitionEditor +function, and that requires knowing a few rules about how things are +laid out. +When creating a script to automatically allocate disk space +and partition it up, it is suggested that you first perform the +installation interactively at least once and take careful notes as to +what the slice names will be, then and only then hardwiring them into +the script. +.Pp +For example, let's say you have a SCSI disk on which you have created a new +.Fx +partition in slice 2 (your DOS partition residing in slice 1). +The slice name would be +.Ar da0s2 +for the whole +.Fx +partition +.Ar ( da0s1 +being your DOS primary +partition). +Now let's further assume that you have 500MB in this +partition and you want to sub-partition that space into root, swap, +var and usr file systems for +.Fx . +Your invocation of the +.Ar diskLabelEditor +function might involve setting the following variables: +.Bl -tag -width findx +.It Li "da0s2-1=ufs 40960 /" +A 20MB root file system (all sizes are in 512 byte blocks). +.It Li "da0s2-2=swap 131072 /" +A 64MB swap partition. +.It Li "da0s2-3=ufs 204800 /var" +A 100MB /var file system. +.It Li "da0s2-4=ufs 0 /usr 1" +With the balance of free space (around 316MB) going to the /usr +file system and with soft-updates enabled (the argument following +the mount point, if non-zero, means to set the soft updates flag). +.El +.Pp +One can also use the +.Ar diskLabelEditor +for mounting or erasing existing partitions as well as creating new +ones. +Using the previous example again, let's say that we also wanted +to mount our DOS partition and make sure that an +.Pa /etc/fstab +entry is created for it in the new installation. +Before calling the +.Ar diskLabelEditor +function, we simply add an additional line: +.Pp +.Dl "da0s1=/dos_c N" +.Pp +before the call. +This tells the label editor that you want to mount +the first slice on +.Pa /dos_c +and not to attempt to newfs it (not that +.Nm +would attempt this for a DOS partition in any case, but it could just +as easily be an existing UFS partition being named here and the 2nd +field is non-optional). +.Pp +You can also set the +.Ar diskInteractive +variable to request that the disk label editor use an interactive dialog +to partition the disk instead of using variables to explicitly layout the +disk as described above. +.Pp +Note: No file system data is actually written to disk until an +explicit call to +.Ar diskLabelCommit +is made. +.It diskLabelCommit +Writes out all pending disklabel information and creates and/or mounts any +file systems which have requests pending from the +.Ar diskLabelEditor +function. +.Pp +.Sy Variables : +None +.It distReset +Resets all selected distributions to the empty set (no distributions selected). +.Pp +.Sy Variables : +None +.It distSetCustom +Allows the selection of a custom distribution set (e.g.\& not just one of the +existing "canned" sets) with no user interaction. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It dists +List of distributions to load. +Possible distribution values are: +.Bl -tag -width indentxx +.It Li base +The base binary distribution. +.It Li doc +Miscellaneous documentation +.It Li games +Games +.It Li manpages +Manual pages (unformatted) +.It Li catpages +Pre-formatted manual pages +.It Li proflibs +Profiled libraries for developers. +.It Li dict +Dictionary information (for tools like spell). +.It Li info +GNU info files and other extra docs. +.It Li compat1x +Compatibility with +.Fx +1.x +.It Li compat20 +Compatibility with +.Fx 2.0 +.It Li compat21 +Compatibility with +.Fx 2.1 +.It Li compat22 +.Fx 2.2 +and +.Fx 3.0 +a.out binary compatibility +.It Li compat3x +Compatibility with +.Fx +3.x +(available for +.Fx 4.0 +systems only) +.It Li compat4x +Compatibility with +.Fx +4.x +(available for +.Fx 5.0 +systems only) +.It Li ports +The ports collection. +.It Li ssecure +/usr/src/secure +.It Li sbase +/usr/src/[top level files] +.It Li scontrib +/usr/src/contrib +.It Li sgnu +/usr/src/gnu +.It Li setc +/usr/src/etc +.It Li sgames +/usr/src/games +.It Li sinclude +/usr/src/include +.It Li skrb5 +/usr/src/kerberos5 +.It Li slib +/usr/src/lib +.It Li slibexec +/usr/src/libexec +.It Li srelease +/usr/src/release +.It Li srescue +/usr/src/rescue +.It Li sbin +/usr/src/bin +.It Li ssbin +/usr/src/sbin +.It Li sshare +/usr/src/share +.It Li ssys +/usr/src/sys +.It Li subin +/usr/src/usr.bin +.It Li susbin +/usr/src/usr.sbin +.It Li ssmailcf +/usr/src/usr.sbin/sendmail/cf +.It Li Xbin +X.Org client applications. +.It Li Xlib +X.Org libraries. +.It Li Xman +X.Org manual pages. +.It Li Xdoc +X.Org protocol and library documentation. +.It Li Xprog +X.Org imake distribution. +.It Li Xsrv +X.Org X server. +.It Li Xnest +X.Org nested X server. +.It Li Xprt +X.Org print server. +.It Li Xvfb +X.Org virtual frame-buffer X server. +.It Li Xfmsc +X.Org miscellaneous font set. +.It Li Xf75 +X.Org 75DPI font set. +.It Li Xf100 +X.Org 100DPI font set. +.It Li Xfcyr +X.Org Cyrillic font set. +.It Li Xft1 +X.Org Type 1 font set. +.It Li Xftt +X.Org TrueType font set. +.It Li Xfs +X.Org font server. +.El +.El +.It distSetDeveloper +Selects the standard Developer's distribution set. +.Pp +.Sy Variables : +None +.It distSetXDeveloper +Selects the standard X Developer's distribution set. +.Pp +.Sy Variables : +None +.It distSetKernDeveloper +Selects the standard kernel Developer's distribution set. +.Pp +.Sy Variables : +None +.It distSetUser +Selects the standard user distribution set. +.Pp +.Sy Variables : +None +.It distSetXUser +Selects the standard X user's distribution set. +.Pp +.Sy Variables : +None +.It distSetMinimum +Selects the very minimum distribution set. +.Pp +.Sy Variables : +None +.It distSetEverything +Selects the full whack - all available distributions. +.Pp +.Sy Variables : +None +.It distSetSrc +Interactively select source subcomponents. +.Pp +.Sy Variables : +None +.It distSetXOrg +Interactively select X.Org subcomponents. +.Pp +.Sy Variables : +None +.It distExtractAll +Install all currently selected distributions (requires that +media device also be selected). +.Pp +.Sy Variables : +None +.It docBrowser +Install (if necessary) an HTML documentation browser and go to the +HTML documentation submenu. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It browserPackage +The name of the browser package to try and install as necessary. +Defaults to latest links package. +.It browserBinary +The name of the browser binary itself (if overriding the +.Ar browserPackage +variable). +Defaults to links. +.El +.It installCommit +Commit any and all pending changes to disk. +This function +is essentially shorthand for a number of more granular "commit" +functions. +.Pp +.Sy Variables : +None +.It installExpress +Start an "express" installation, asking few questions of +the user. +.Pp +.Sy Variables : +None +.It installStandard +Start a "standard" installation, the most user-friendly +installation type available. +.Pp +.Sy Variables : +None +.It installUpgrade +Start an upgrade installation. +.Pp +.Sy Variables : +None +.It installFixitHoloShell +Start up the "emergency holographic shell" over on VTY4 +if running as init. +This will also happen automatically +as part of the installation process unless +.Ar noHoloShell +is set. +.Pp +.Sy Variables : +None +.It installFixitCDROM +Go into "fixit" mode, assuming a live file system CDROM +currently in the drive. +.Pp +.Sy Variables : +None +.It installFixitFloppy +Go into "fixit" mode, assuming an available fixit floppy +disk (user will be prompted for it). +.Pp +.Sy Variables : +None +.It installFilesystems +Do just the file system initialization part of an install. +.Pp +.Sy Variables : +None +.It installVarDefaults +Initialize all variables to their defaults, overriding any +previous settings. +.Pp +.Sy Variables : +None +.It loadConfig +Sort of like an #include statement, it allows you to load one +configuration file from another. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It configFile +The fully qualified pathname of the file to load. +.El +.It mediaClose +If a media device is open, close it. +.Pp +.Sy Variables : +None +.It mediaSetCDROM +Select a +.Fx +CDROM as the installation media. +.Pp +.Sy Variables : +None +.It mediaSetFloppy +Select a pre-made floppy installation set as the installation media. +.Pp +.Sy Variables : +None +.It mediaSetDOS +Select an existing DOS primary partition as the installation media. +The first primary partition found is used (e.g.\& C:). +.Pp +.Sy Variables : +None +.It mediaSetTape +Select a tape device as the installation media. +.Pp +.Sy Variables : +None +.It mediaSetFTP +Select an FTP site as the installation media. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It hostname +The name of the host being installed (non-optional). +.It domainname +The domain name of the host being installed (optional). +.It defaultrouter +The default router for this host (non-optional). +.It netDev +Which host interface to use +.Ar ( ed0 +or +.Ar ep0 , +for example. +Non-optional). +.It netInteractive +If set, bring up the interactive network setup form even +if all relevant configuration variables are already set (optional). +.It ipaddr +The IP address for the selected host interface (non-optional). +.It netmask +The netmask for the selected host interface (non-optional). +.It _ftpPath +The fully qualified URL of the FTP site containing the +.Fx +distribution you are interested in, e.g.\& +.Ar ftp://ftp.FreeBSD.org/pub/FreeBSD/ . +.El +.It mediaSetFTPActive +Alias for +.Ar mediaSetFTP +using "active" FTP transfer mode. +.Pp +.Sy Variables : +Same as for +.Ar mediaSetFTP . +.It mediaSetFTPPassive +Alias for +.Ar mediaSetFTP +using "passive" FTP transfer mode. +.Pp +.Sy Variables : +Same as for +.Ar mediaSetFTP . +.It mediaSetHTTP +Alias for +.Ar mediaSetFTP +using an HTTP proxy. +.Pp +.Sy Variables : +See +.Ar mediaSetFTP , +plus +.Bl -tag -width indent +.It _httpPath +The proxy to use (host:port) (non-optional). +.El +.It mediaSetUFS +Select an existing UFS partition (mounted with the label editor) as +the installation media. +.Pp +.Sy Variables : +.Bl -tag -width indent +.It ufs +full /path to directory containing the +.Fx +distribution you are +interested in. +.El +.It mediaSetNFS +.Pp +.Sy Variables : +.Bl -tag -width indent +.It hostname +The name of the host being installed (non-optional). +.It domainname +The domain name of the host being installed (optional). +.It defaultrouter +The default router for this host (non-optional). +.It netDev +Which host interface to use +.Ar ( ed0 +or +.Ar ep0 , +for example. +Non-optional). +.It netInteractive +If set, bring up the interactive network setup form even +if all relevant configuration variables are already set (optional). +.It ipaddr +The IP address for the selected host interface (non-optional). +.It netmask +The netmask for the selected host interface (non-optional). +.It nfs +full hostname:/path specification for directory containing +the +.Fx +distribution you are interested in. +.El +.It mediaSetFTPUserPass +.Pp +.Sy Variables : +.Bl -tag -width indent +.It ftpUser +The username to log in as on the ftp server site. +Default: ftp +.It ftpPass +The password to use for this username on the ftp +server site. +Default: user@host +.El +.It mediaSetCPIOVerbosity +.Pp +.Sy Variables : +.Bl -tag -width indent +.It cpioVerbose +Can be used to set the verbosity of cpio extractions to low, medium or +high. +.El +.It mediaGetType +Interactively get the user to specify some type of media. +.Pp +.Sy Variables : +None +.It optionsEditor +Invoke the interactive options editor. +.Pp +.Sy Variables : +None +.It packageAdd +Try to fetch and add a package to the system (requires +that a media type be set), +.Pp +.Sy Variables : +.Bl -tag -width indent +.It package +The name of the package to add, e.g.\& bash-1.14.7 or ncftp-2.4.2. +.El +.It addGroup +Invoke the interactive group editor. +.Pp +.Sy Variables : +None +.It addUser +Invoke the interactive user editor. +.Pp +.Sy Variables : +None +.It shutdown +Stop the script and terminate sysinstall. +.Pp +.Sy Variables : +None +.It system +Execute an arbitrary command with +.Xr system 3 +.Pp +.Sy Variables : +.Bl -tag -width indent +.It command +The name of the command to execute. +When running +from a boot floppy, very minimal expectations should +be made as to what is available until/unless a relatively +full system installation has just been done. +.El +.It tcpMenuSelect +Configure a network device. +.Pp +.Sy Variables : +Same as for +.Ar mediaSetFTP +except that +.Ar _ftpPath +is not used. +.El +.Sh DISTRIBUTION MEDIA +The following files can be used to affect the operation of +.Nm +when used during initial system installation. +.Bl -tag -width ".Pa packages/INDEX" +.It Pa cdrom.inf +A text file of properties, listed one per line, that describe the +contents of the media in use. +The syntax for each line is simply +.Dq Ar property No = Ar value . +Currently, only the following properties are recognized. +.Bl -tag -width ".Va CD_MACHINE_ARCH" +.It Va CD_VERSION +This property should be set to the +.Fx +version on the current +media volume. +For example, +.Dq Li "CD_VERSION = 5.3" . +.It Va CD_MACHINE_ARCH +This property should be set to the architecture of the contents on +this volume. +This property is normally only used with +.Fx +products that contain +CDs for different architectures, to provide better error messages if +users try to install Alpha packages on an i386 machine. +For example, +.Dq Li "CD_MACHINE_ARCH = alpha" . +.It Va CD_VOLUME +In a multi-volume collection (such as the +.Fx +4-CD set), the +.Pa ports/INDEX +file on each disc should contain the full package index for the set. +The last field of the +.Pa INDEX +file denotes which volume the package +appears on, and the +.Va CD_VOLUME +property here defines the volume ID of the current disc. +.El +.It Pa packages/INDEX +The package index file. +Each package is listed on a separate line with additional meta-data +such as the required dependencies. +This index is generated by +.Dq Li "make index" +from the +.Xr ports 7 +collection. +When multi-volume support is enabled, an additional field should be +added to each line indicating which media volume contains the given +package. +.El +.Pp +For information about building a full release of +.Fx , +please see +.Xr release 7 . +.Sh FILES +This utility may edit the contents of +.Pa /etc/rc.conf , +.Pa /etc/hosts , +and +.Pa /etc/resolv.conf +as necessary to reflect changes in the network configuration. +.Sh SEE ALSO +If you have a reasonably complete source tree online, take +a look at +.Pa /usr/src/usr.sbin/sysinstall/install.cfg +for a sample installation script. +.Sh HISTORY +This version of +.Nm +first appeared in +.Fx 2.0 . +.Sh AUTHORS +.An Jordan K. Hubbard Aq jkh@FreeBSD.org +.Sh BUGS +This utility is a prototype which lasted several years past +its expiration date and is greatly in need of death. diff --git a/usr.sbin/sysinstall/sysinstall.h b/usr.sbin/sysinstall/sysinstall.h new file mode 100644 index 0000000000000..657b35f486029 --- /dev/null +++ b/usr.sbin/sysinstall/sysinstall.h @@ -0,0 +1,888 @@ +/* + * The new sysinstall program. + * + * This is probably the last attempt in the `sysinstall' line, the next + * generation being slated to essentially a complete rewrite. + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SYSINSTALL_H_INCLUDE +#define _SYSINSTALL_H_INCLUDE + +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <setjmp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <dialog.h> +#include "ui_objects.h" +#include "dir.h" +#include "colors.h" +#include "dist.h" + +/*** Defines ***/ + +#if defined(__i386__) || defined(__alpha__) || defined(__amd64__) +#define WITH_SYSCONS +#define WITH_MICE +#endif + +#if defined(__i386__) || defined(__amd64__) +#define WITH_SLICES +#endif + +#if defined(__i386__) || defined(__alpha__) +#define WITH_LINUX +#endif + +#if defined(PC98) +#define PCCARD_ARCH 1 /* Support PCCARD installations */ +#endif + +/* device limits */ +#define DEV_NAME_MAX 128 /* The maximum length of a device name */ +#define DEV_MAX 100 /* The maximum number of devices we'll deal with */ +#define INTERFACE_MAX 50 /* Maximum number of network interfaces we'll deal with */ +#define IO_ERROR -2 /* Status code for I/O error rather than normal EOF */ + +/* Number of seconds to wait for data to come off even the slowest media */ +#define MEDIA_TIMEOUT 300 + +/* + * I make some pretty gross assumptions about having a max of 50 chunks + * total - 8 slices and 42 partitions. I can't easily display many more + * than that on the screen at once! + * + * For 2.1 I'll revisit this and try to make it more dynamic, but since + * this will catch 99.99% of all possible cases, I'm not too worried. + */ +#define MAX_CHUNKS 40 + +/* Internal environment variable names */ +#define DISK_PARTITIONED "_diskPartitioned" +#define DISK_LABELLED "_diskLabelled" +#define DISK_SELECTED "_diskSelected" +#define SYSTEM_STATE "_systemState" +#define RUNNING_ON_ROOT "_runningOnRoot" +#define TCP_CONFIGURED "_tcpConfigured" + +/* Ones that can be tweaked from config files */ +#define VAR_BLANKTIME "blanktime" +#define VAR_BOOTMGR "bootManager" +#define VAR_BROWSER_BINARY "browserBinary" +#define VAR_BROWSER_PACKAGE "browserPackage" +#define VAR_CPIO_VERBOSITY "cpioVerbose" +#define VAR_DEBUG "debug" +#define VAR_DESKSTYLE "_deskStyle" +#define VAR_DISK "disk" +#define VAR_DISKINTERACTIVE "diskInteractive" +#define VAR_DISTS "dists" +#define VAR_DIST_MAIN "distMain" +#define VAR_DIST_SRC "distSRC" +#define VAR_DIST_X11 "distX11" +#define VAR_DEDICATE_DISK "dedicateDisk" +#define VAR_DOMAINNAME "domainname" +#define VAR_EDITOR "editor" +#define VAR_EXTRAS "ifconfig_" +#define VAR_COMMAND "command" +#define VAR_CONFIG_FILE "configFile" +#define VAR_FIXIT_TTY "fixitTty" +#define VAR_FTP_DIR "ftpDirectory" +#define VAR_FTP_PASS "ftpPass" +#define VAR_FTP_PATH "_ftpPath" +#define VAR_FTP_PORT "ftpPort" +#define VAR_FTP_STATE "ftpState" +#define VAR_FTP_USER "ftpUser" +#define VAR_FTP_HOST "ftpHost" +#define VAR_HTTP_PATH "_httpPath" +#define VAR_HTTP_PROXY "httpProxy" +#define VAR_HTTP_PORT "httpPort" +#define VAR_HTTP_HOST "httpHost" +#define VAR_HTTP_FTP_MODE "httpFtpMode" +#define VAR_GATEWAY "defaultrouter" +#define VAR_GEOMETRY "geometry" +#define VAR_HOSTNAME "hostname" +#define VAR_IFCONFIG "ifconfig_" +#define VAR_INSTALL_CFG "installConfig" +#define VAR_INSTALL_ROOT "installRoot" +#define VAR_IPADDR "ipaddr" +#define VAR_IPV6_ENABLE "ipv6_enable" +#define VAR_IPV6ADDR "ipv6addr" +#define VAR_KERN_SECURELEVEL "kern_securelevel" +#define VAR_KEYMAP "keymap" +#define VAR_LABEL "label" +#define VAR_LABEL_COUNT "labelCount" +#define VAR_LINUX_ENABLE "linux_enable" +#define VAR_MEDIA_TYPE "mediaType" +#define VAR_MEDIA_TIMEOUT "MEDIA_TIMEOUT" +#define VAR_MOUSED "moused_enable" +#define VAR_MOUSED_FLAGS "moused_flags" +#define VAR_MOUSED_PORT "moused_port" +#define VAR_MOUSED_TYPE "moused_type" +#define VAR_NAMESERVER "nameserver" +#define VAR_NETINTERACTIVE "netInteractive" +#define VAR_NETMASK "netmask" +#define VAR_NETWORK_DEVICE "netDev" +#define VAR_NEWFS_ARGS "newfsArgs" +#define VAR_NFS_PATH "nfs" +#define VAR_NFS_HOST "nfsHost" +#define VAR_NFS_V3 "nfs_use_v3" +#define VAR_NFS_TCP "nfs_use_tcp" +#define VAR_NFS_SECURE "nfs_reserved_port_only" +#define VAR_NFS_SERVER "nfs_server_enable" +#define VAR_NO_CONFIRM "noConfirm" +#define VAR_NO_ERROR "noError" +#define VAR_NO_HOLOSHELL "noHoloShell" +#define VAR_NO_INET6 "noInet6" +#define VAR_NO_WARN "noWarn" +#define VAR_NO_USR "noUsr" +#define VAR_NO_TMP "noTmp" +#define VAR_NO_HOME "noHome" +#define VAR_NONINTERACTIVE "nonInteractive" +#define VAR_NOVELL "novell" +#define VAR_OSF1_ENABLE "osf1_enable" +#define VAR_RPCBIND_ENABLE "rpcbind_enable" +#define VAR_NTPDATE_FLAGS "ntpdate_flags" +#define VAR_PACKAGE "package" +#define VAR_PARTITION "partition" +#define VAR_PCNFSD "pcnfsd" +#define VAR_PKG_TMPDIR "PKG_TMPDIR" +#define VAR_PORTS_PATH "ports" +#define VAR_PPP_ENABLE "ppp_enable" +#define VAR_PPP_PROFILE "ppp_profile" +#define VAR_RELNAME "releaseName" +#define VAR_ROOT_SIZE "rootSize" +#define VAR_ROUTER "router" +#define VAR_ROUTER_ENABLE "router_enable" +#define VAR_ROUTERFLAGS "router_flags" +#define VAR_SENDMAIL_ENABLE "sendmail_enable" +#define VAR_SERIAL_SPEED "serialSpeed" +#define VAR_SLOW_ETHER "slowEthernetCard" +#define VAR_SWAP_SIZE "swapSize" +#define VAR_TAPE_BLOCKSIZE "tapeBlocksize" +#define VAR_TRY_DHCP "tryDHCP" +#define VAR_TRY_RTSOL "tryRTSOL" +#define VAR_SKIP_PCCARD "skipPCCARD" +#define VAR_UFS_PATH "ufs" +#define VAR_USR_SIZE "usrSize" +#define VAR_VAR_SIZE "varSize" +#define VAR_TMP_SIZE "tmpSize" +#define VAR_HOME_SIZE "homeSize" +#define VAR_XORG_CONFIG "_xorgconfig" +#define VAR_TERM "TERM" +#define VAR_CONSTERM "_consterm" + +#define DEFAULT_TAPE_BLOCKSIZE "20" + +/* One MB worth of blocks */ +#define ONE_MEG 2048 +#define ONE_GIG (ONE_MEG * 1024) + +/* Which selection attributes to use */ +#define ATTR_SELECTED (ColorDisplay ? item_selected_attr : item_attr) +#define ATTR_TITLE button_active_attr + +/* Handy strncpy() macro */ +#define SAFE_STRCPY(to, from) sstrncpy((to), (from), sizeof (to) - 1) + +/*** Types ***/ +typedef int Boolean; +typedef struct disk Disk; +typedef struct chunk Chunk; + +/* Bitfields for menu options */ +#define DMENU_NORMAL_TYPE 0x1 /* Normal dialog menu */ +#define DMENU_RADIO_TYPE 0x2 /* Radio dialog menu */ +#define DMENU_CHECKLIST_TYPE 0x4 /* Multiple choice menu */ +#define DMENU_SELECTION_RETURNS 0x8 /* Immediate return on item selection */ + +typedef struct _dmenu { + int type; /* What sort of menu we are */ + char *title; /* Our title */ + char *prompt; /* Our prompt */ + char *helpline; /* Line of help at bottom */ + char *helpfile; /* Help file for "F1" */ +#if (__STDC_VERSION__ >= 199901L) || (__GNUC__ >= 3) + dialogMenuItem items[]; /* Array of menu items */ +#elif __GNUC__ + dialogMenuItem items[0]; /* Array of menu items */ +#else +#error "Create hack for C89 and K&R compilers." +#endif +} DMenu; + +/* An rc.conf variable */ +typedef struct _variable { + struct _variable *next; + char *name; + char *value; + int dirty; +} Variable; + +#define NO_ECHO_OBJ(type) ((type) | (DITEM_NO_ECHO << 16)) +#define TYPE_OF_OBJ(type) ((type) & 0xff) +#define ATTR_OF_OBJ(type) ((type) >> 16) + +/* A screen layout structure */ +typedef struct _layout { + int y; /* x & Y co-ordinates */ + int x; + int len; /* The size of the dialog on the screen */ + int maxlen; /* How much the user can type in ... */ + char *prompt; /* The string for the prompt */ + char *help; /* The display for the help line */ + void *var; /* The var to set when this changes */ + int type; /* The type of the dialog to create */ + void *obj; /* The obj pointer returned by libdialog */ +} Layout; + +typedef enum { + DEVICE_TYPE_NONE, + DEVICE_TYPE_DISK, + DEVICE_TYPE_FLOPPY, + DEVICE_TYPE_FTP, + DEVICE_TYPE_NETWORK, + DEVICE_TYPE_CDROM, + DEVICE_TYPE_TAPE, + DEVICE_TYPE_DOS, + DEVICE_TYPE_UFS, + DEVICE_TYPE_NFS, + DEVICE_TYPE_ANY, + DEVICE_TYPE_HTTP, +} DeviceType; + +/* CDROM mount codes */ +#define CD_UNMOUNTED 0 +#define CD_ALREADY_MOUNTED 1 +#define CD_WE_MOUNTED_IT 2 + +/* A "device" from sysinstall's point of view */ +typedef struct _device { + char name[DEV_NAME_MAX]; + char *description; + char *devname; + DeviceType type; + Boolean enabled; + Boolean (*init)(struct _device *dev); + FILE * (*get)(struct _device *dev, char *file, Boolean probe); + void (*shutdown)(struct _device *dev); + void *private; + unsigned int flags; + unsigned int volume; +} Device; + +/* Some internal representations of partitions */ +typedef enum { + PART_NONE, + PART_SLICE, + PART_SWAP, + PART_FILESYSTEM, + PART_FAT, + PART_EFI +} PartType; + +#define NEWFS_UFS_CMD "newfs" +#define NEWFS_MSDOS_CMD "newfs_msdos" + +enum newfs_type { NEWFS_UFS, NEWFS_MSDOS, NEWFS_CUSTOM }; +#define NEWFS_UFS_STRING "UFS" +#define NEWFS_MSDOS_STRING "FAT" +#define NEWFS_CUSTOM_STRING "CST" + +/* The longest set of custom command line arguments we'll pass. */ +#define NEWFS_CMD_ARGS_MAX 256 + +typedef struct _part_info { + char mountpoint[FILENAME_MAX]; + + /* Is invocation of newfs desired? */ + Boolean do_newfs; + + enum newfs_type newfs_type; + union { + struct { + char user_options[NEWFS_CMD_ARGS_MAX]; + Boolean acls; /* unused */ + Boolean multilabel; /* unused */ + Boolean softupdates; + Boolean ufs1; + } newfs_ufs; + struct { + /* unused */ + } newfs_msdos; + struct { + char command[NEWFS_CMD_ARGS_MAX]; + } newfs_custom; + } newfs_data; +} PartInfo; + +/* An option */ +typedef struct _opt { + char *name; + char *desc; + enum { OPT_IS_STRING, OPT_IS_INT, OPT_IS_FUNC, OPT_IS_VAR } type; + void *data; + void *aux; + char *(*check)(); +} Option; + +/* Weird index nodey things we use for keeping track of package information */ +typedef enum { PACKAGE, PLACE } node_type; /* Types of nodes */ + +typedef struct _pkgnode { /* A node in the reconstructed hierarchy */ + struct _pkgnode *next; /* My next sibling */ + node_type type; /* What am I? */ + char *name; /* My name */ + char *desc; /* My description (Hook) */ + struct _pkgnode *kids; /* My little children */ + void *data; /* A place to hang my data */ +} PkgNode; +typedef PkgNode *PkgNodePtr; + +/* A single package */ +typedef struct _indexEntry { /* A single entry in an INDEX file */ + char *name; /* name */ + char *path; /* full path to port */ + char *prefix; /* port prefix */ + char *comment; /* one line description */ + char *descrfile; /* path to description file */ + char *deps; /* packages this depends on */ + int depc; /* how many depend on me */ + int installed; /* indicates if it is installed */ + char *maintainer; /* maintainer */ + unsigned int volume; /* Volume of package */ +} IndexEntry; +typedef IndexEntry *IndexEntryPtr; + +typedef int (*commandFunc)(char *key, void *data); + +#define HOSTNAME_FIELD_LEN 128 +#define IPADDR_FIELD_LEN 16 +#define EXTRAS_FIELD_LEN 128 + +/* This is the structure that Network devices carry around in their private, erm, structures */ +typedef struct _devPriv { + int use_rtsol; + int use_dhcp; + char ipaddr[IPADDR_FIELD_LEN]; + char netmask[IPADDR_FIELD_LEN]; + char extras[EXTRAS_FIELD_LEN]; +} DevInfo; + + +/*** Externs ***/ +extern jmp_buf BailOut; /* Used to get the heck out */ +extern int CDROMInitQuiet; /* Don't whine if mount(2) fails */ +extern int DebugFD; /* Where diagnostic output goes */ +extern Boolean Fake; /* Don't actually modify anything - testing */ +extern Boolean Restarting; /* Are we restarting sysinstall? */ +extern Boolean SystemWasInstalled; /* Did we install it? */ +extern Boolean RunningAsInit; /* Are we running stand-alone? */ +extern Boolean DialogActive; /* Is the dialog() stuff up? */ +extern Boolean ColorDisplay; /* Are we on a color display? */ +extern Boolean OnVTY; /* On a syscons VTY? */ +extern Variable *VarHead; /* The head of the variable chain */ +extern Device *mediaDevice; /* Where we're getting our distribution from */ +extern unsigned int Dists; /* Which distributions we want */ +extern unsigned int SrcDists; /* Which src distributions we want */ +extern unsigned int XOrgDists; /* Which X.Org dists we want */ +extern int BootMgr; /* Which boot manager to use */ +extern int StatusLine; /* Where to print our status messages */ +extern DMenu MenuInitial; /* Initial installation menu */ +extern DMenu MenuFixit; /* Fixit repair menu */ +#if defined(__i386__) || defined(__amd64__) +#ifdef PC98 +extern DMenu MenuIPLType; /* Type of IPL to write on the disk */ +#else +extern DMenu MenuMBRType; /* Type of MBR to write on the disk */ +#endif +#endif +extern DMenu MenuConfigure; /* Final configuration menu */ +extern DMenu MenuDocumentation; /* Documentation menu */ +extern DMenu MenuFTPOptions; /* FTP Installation options */ +extern DMenu MenuIndex; /* Index menu */ +extern DMenu MenuOptions; /* Installation options */ +extern DMenu MenuOptionsLanguage; /* Language options menu */ +extern DMenu MenuKLD; /* Prototype KLD menu */ +extern DMenu MenuMedia; /* Media type menu */ +#ifdef WITH_MICE +extern DMenu MenuMouse; /* Mouse type menu */ +#endif +extern DMenu MenuMediaCDROM; /* CDROM media menu */ +extern DMenu MenuMediaDOS; /* DOS media menu */ +extern DMenu MenuMediaFloppy; /* Floppy media menu */ +extern DMenu MenuMediaFTP; /* FTP media menu */ +extern DMenu MenuMediaTape; /* Tape media menu */ +extern DMenu MenuNetworkDevice; /* Network device menu */ +extern DMenu MenuNTP; /* NTP time server menu */ +extern DMenu MenuSecurity; /* System security options menu */ +extern DMenu MenuSecurelevel; /* Securelevel menu */ +extern DMenu MenuStartup; /* Startup services menu */ +#ifdef WITH_SYSCONS +extern DMenu MenuSyscons; /* System console configuration menu */ +extern DMenu MenuSysconsFont; /* System console font configuration menu */ +extern DMenu MenuSysconsKeymap; /* System console keymap configuration menu */ +extern DMenu MenuSysconsKeyrate; /* System console keyrate configuration menu */ +extern DMenu MenuSysconsSaver; /* System console saver configuration menu */ +extern DMenu MenuSysconsScrnmap; /* System console screenmap configuration menu */ +extern DMenu MenuSysconsTtys; /* System console terminal type menu */ +#endif +extern DMenu MenuNetworking; /* Network configuration menu */ +extern DMenu MenuMTA; /* MTA selection menu */ +extern DMenu MenuInstallCustom; /* Custom Installation menu */ +extern DMenu MenuDistributions; /* Distribution menu */ +extern DMenu MenuDiskDevices; /* Disk type devices */ +extern DMenu MenuSubDistributions; /* Custom distribution menu */ +extern DMenu MenuSrcDistributions; /* Source distribution menu */ +extern DMenu MenuXOrg; /* X.Org main menu */ +extern DMenu MenuXOrgSelect; /* X.Org distribution selection menu */ +extern DMenu MenuXOrgSelectCore; /* X.Org core distribution menu */ +extern DMenu MenuXOrgSelectServer; /* X.Org server distribution menu */ +extern DMenu MenuXOrgSelectFonts; /* X.Org font selection menu */ +extern DMenu MenuXDesktops; /* X Desktops menu */ +extern DMenu MenuHTMLDoc; /* HTML Documentation menu */ +extern DMenu MenuUsermgmt; /* User management menu */ +extern DMenu MenuFixit; /* Fixit floppy/CDROM/shell menu */ +extern DMenu MenuXOrgConfig; /* Select X.Org configuration tool */ +extern int FixItMode; /* FixItMode starts shell onc urrent device (ie Serial port) */ +extern const char * StartName; /* Which name we were started as */ + +/* Important chunks. */ +extern Chunk *HomeChunk; +extern Chunk *RootChunk; +extern Chunk *SwapChunk; +extern Chunk *TmpChunk; +extern Chunk *UsrChunk; +extern Chunk *VarChunk; +#ifdef __ia64__ +extern Chunk *EfiChunk; +#endif + +/* Stuff from libdialog which isn't properly declared outside */ +extern void display_helpfile(void); +extern void display_helpline(WINDOW *w, int y, int width); + +/*** Prototypes ***/ + +/* anonFTP.c */ +extern int configAnonFTP(dialogMenuItem *self); + +/* cdrom.c */ +extern Boolean mediaInitCDROM(Device *dev); +extern FILE *mediaGetCDROM(Device *dev, char *file, Boolean probe); +extern void mediaShutdownCDROM(Device *dev); + +/* command.c */ +extern void command_clear(void); +extern void command_sort(void); +extern void command_execute(void); +extern void command_shell_add(char *key, char *fmt, ...) __printflike(2, 3); +extern void command_func_add(char *key, commandFunc func, void *data); + +/* config.c */ +extern void configEnvironmentRC_conf(void); +extern void configEnvironmentResolv(char *config); +extern void configRC_conf(void); +extern int configFstab(dialogMenuItem *self); +extern int configRC(dialogMenuItem *self); +extern int configResolv(dialogMenuItem *self); +extern int configPackages(dialogMenuItem *self); +extern int configSaver(dialogMenuItem *self); +extern int configSaverTimeout(dialogMenuItem *self); +#ifdef WITH_LINUX +extern int configLinux(dialogMenuItem *self); +#endif +extern int configNTP(dialogMenuItem *self); +#ifdef __alpha__ +extern int configOSF1(dialogMenuItem *self); +#endif +extern int configUsers(dialogMenuItem *self); +extern int configRouter(dialogMenuItem *self); +extern int configPCNFSD(dialogMenuItem *self); +extern int configInetd(dialogMenuItem *self); +extern int configNFSServer(dialogMenuItem *self); +extern int configMTAPostfix(dialogMenuItem *self); +extern int configMTAExim(dialogMenuItem *self); +extern int configRpcBind(dialogMenuItem *self); +extern int configWriteRC_conf(dialogMenuItem *self); +extern int configSecurelevel(dialogMenuItem *self); +extern int configSecurelevelDisabled(dialogMenuItem *self); +extern int configSecurelevelSecure(dialogMenuItem *self); +extern int configSecurelevelHighlySecure(dialogMenuItem *self); +extern int configSecurelevelNetworkSecure(dialogMenuItem *self); +extern int configEtcTtys(dialogMenuItem *self); +#ifdef __i386__ +extern int checkLoaderACPI(void); +extern int configLoaderACPI(int); +#endif + +/* devices.c */ +extern DMenu *deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), + int (*check)(dialogMenuItem *d)); +extern void deviceGetAll(void); +extern void deviceReset(void); +extern void deviceRescan(void); +extern Device **deviceFind(char *name, DeviceType type); +extern Device **deviceFindDescr(char *name, char *desc, DeviceType class); +extern int deviceCount(Device **devs); +extern Device *new_device(char *name); +extern Device *deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled, + Boolean (*init)(Device *mediadev), + FILE * (*get)(Device *dev, char *file, Boolean probe), + void (*shutDown)(Device *mediadev), + void *private); +extern Boolean dummyInit(Device *dev); +extern FILE *dummyGet(Device *dev, char *dist, Boolean probe); +extern void dummyShutdown(Device *dev); + +/* dhcp.c */ +extern int dhcpParseLeases(char *file, char *hostname, char *domain, char *nameserver, + char *ipaddr, char *gateway, char *netmask); + +/* disks.c */ +#ifdef WITH_SLICES +extern void diskPartition(Device *dev); +extern int diskPartitionEditor(dialogMenuItem *self); +#endif +extern int diskPartitionWrite(dialogMenuItem *self); +extern int diskGetSelectCount(Device ***devs); + +/* dispatch.c */ +extern int dispatchCommand(char *command); +extern int dispatch_load_floppy(dialogMenuItem *self); +extern int dispatch_load_file_int(int); +extern int dispatch_load_file(dialogMenuItem *self); + + +/* dist.c */ +extern int distReset(dialogMenuItem *self); +extern int distConfig(dialogMenuItem *self); +extern int distSetCustom(dialogMenuItem *self); +extern int distUnsetCustom(dialogMenuItem *self); +extern int distSetDeveloper(dialogMenuItem *self); +extern int distSetXDeveloper(dialogMenuItem *self); +extern int distSetKernDeveloper(dialogMenuItem *self); +extern int distSetXKernDeveloper(dialogMenuItem *self); +extern int distSetUser(dialogMenuItem *self); +extern int distSetXUser(dialogMenuItem *self); +extern int distSetMinimum(dialogMenuItem *self); +extern int distSetEverything(dialogMenuItem *self); +extern int distSetSrc(dialogMenuItem *self); +extern int distSetXOrg(dialogMenuItem *self); +extern int distExtractAll(dialogMenuItem *self); + +/* dmenu.c */ +extern int dmenuDisplayFile(dialogMenuItem *tmp); +extern int dmenuSubmenu(dialogMenuItem *tmp); +extern int dmenuSystemCommand(dialogMenuItem *tmp); +extern int dmenuSystemCommandBox(dialogMenuItem *tmp); +extern int dmenuExit(dialogMenuItem *tmp); +extern int dmenuISetVariable(dialogMenuItem *tmp); +extern int dmenuSetVariable(dialogMenuItem *tmp); +extern int dmenuSetKmapVariable(dialogMenuItem *tmp); +extern int dmenuSetVariables(dialogMenuItem *tmp); +extern int dmenuToggleVariable(dialogMenuItem *tmp); +extern int dmenuSetFlag(dialogMenuItem *tmp); +extern int dmenuSetValue(dialogMenuItem *tmp); +extern Boolean dmenuOpen(DMenu *menu, int *choice, int *scroll, int *curr, int *max, Boolean buttons); +extern Boolean dmenuOpenSimple(DMenu *menu, Boolean buttons); +extern int dmenuVarCheck(dialogMenuItem *item); +extern int dmenuVarsCheck(dialogMenuItem *item); +extern int dmenuFlagCheck(dialogMenuItem *item); +extern int dmenuRadioCheck(dialogMenuItem *item); + +/* doc.c */ +extern int docBrowser(dialogMenuItem *self); +extern int docShowDocument(dialogMenuItem *self); + +/* dos.c */ +extern Boolean mediaCloseDOS(Device *dev, FILE *fp); +extern Boolean mediaInitDOS(Device *dev); +extern FILE *mediaGetDOS(Device *dev, char *file, Boolean probe); +extern void mediaShutdownDOS(Device *dev); + +/* floppy.c */ +extern int getRootFloppy(void); +extern Boolean mediaInitFloppy(Device *dev); +extern FILE *mediaGetFloppy(Device *dev, char *file, Boolean probe); +extern void mediaShutdownFloppy(Device *dev); + +/* ftp_strat.c */ +extern Boolean mediaCloseFTP(Device *dev, FILE *fp); +extern Boolean mediaInitFTP(Device *dev); +extern FILE *mediaGetFTP(Device *dev, char *file, Boolean probe); +extern void mediaShutdownFTP(Device *dev); + +/* http.c */ +extern Boolean mediaInitHTTP(Device *dev); +extern FILE *mediaGetHTTP(Device *dev, char *file, Boolean probe); + +/* globals.c */ +extern void globalsInit(void); + +/* index.c */ +int index_read(FILE *fp, PkgNodePtr papa); +int index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll); +void index_init(PkgNodePtr top, PkgNodePtr plist); +void index_node_free(PkgNodePtr top, PkgNodePtr plist); +void index_sort(PkgNodePtr top); +void index_print(PkgNodePtr top, int level); +int index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended); +int index_initialize(char *path); +PkgNodePtr index_search(PkgNodePtr top, char *str, PkgNodePtr *tp); + +/* install.c */ +extern Boolean checkLabels(Boolean whinge); +extern int installCommit(dialogMenuItem *self); +extern int installCustomCommit(dialogMenuItem *self); +extern int installExpress(dialogMenuItem *self); +extern int installStandard(dialogMenuItem *self); +extern int installFixitHoloShell(dialogMenuItem *self); +extern int installFixitCDROM(dialogMenuItem *self); +extern int installFixitFloppy(dialogMenuItem *self); +extern int installFixupBase(dialogMenuItem *self); +extern int installUpgrade(dialogMenuItem *self); +extern int installFilesystems(dialogMenuItem *self); +extern int installVarDefaults(dialogMenuItem *self); +extern void installEnvironment(void); +extern Boolean copySelf(void); + +/* kget.c */ +extern int kget(char *out); + +/* keymap.c */ +extern int loadKeymap(const char *lang); + +/* label.c */ +extern int diskLabelEditor(dialogMenuItem *self); +extern int diskLabelCommit(dialogMenuItem *self); + +/* makedevs.c (auto-generated) */ +extern const char termcap_ansi[]; +extern const char termcap_vt100[]; +extern const char termcap_cons25w[]; +extern const char termcap_cons25[]; +extern const char termcap_cons25_m[]; +extern const char termcap_cons25r[]; +extern const char termcap_cons25r_m[]; +extern const char termcap_cons25l1[]; +extern const char termcap_cons25l1_m[]; +extern const char termcap_xterm[]; +extern const u_char font_iso_8x16[]; +extern const u_char font_cp850_8x16[]; +extern const u_char font_cp866_8x16[]; +extern const u_char koi8_r2cp866[]; +extern u_char default_scrnmap[]; + +/* media.c */ +extern char *cpioVerbosity(void); +extern void mediaClose(void); +extern int mediaTimeout(void); +extern int mediaSetCDROM(dialogMenuItem *self); +extern int mediaSetFloppy(dialogMenuItem *self); +extern int mediaSetDOS(dialogMenuItem *self); +extern int mediaSetTape(dialogMenuItem *self); +extern int mediaSetFTP(dialogMenuItem *self); +extern int mediaSetFTPActive(dialogMenuItem *self); +extern int mediaSetFTPPassive(dialogMenuItem *self); +extern int mediaSetHTTP(dialogMenuItem *self); +extern int mediaSetUFS(dialogMenuItem *self); +extern int mediaSetNFS(dialogMenuItem *self); +extern int mediaSetFTPUserPass(dialogMenuItem *self); +extern int mediaSetCPIOVerbosity(dialogMenuItem *self); +extern int mediaGetType(dialogMenuItem *self); +extern Boolean mediaExtractDist(char *dir, char *dist, FILE *fp); +extern Boolean mediaExtractDistBegin(char *dir, int *fd, int *zpid, int *cpic); +extern Boolean mediaExtractDistEnd(int zpid, int cpid); +extern Boolean mediaVerify(void); +extern FILE *mediaGenericGet(char *base, const char *file); + +/* misc.c */ +extern Boolean file_readable(char *fname); +extern Boolean file_executable(char *fname); +extern Boolean directory_exists(const char *dirname); +extern char *root_bias(char *path); +extern char *itoa(int value); +extern char *string_concat(char *p1, char *p2); +extern char *string_concat3(char *p1, char *p2, char *p3); +extern char *string_prune(char *str); +extern char *string_skipwhite(char *str); +extern char *string_copy(char *s1, char *s2); +extern char *pathBaseName(const char *path); +extern void safe_free(void *ptr); +extern void *safe_malloc(size_t size); +extern void *safe_realloc(void *orig, size_t size); +extern dialogMenuItem *item_add(dialogMenuItem *list, char *prompt, char *title, + int (*checked)(dialogMenuItem *self), + int (*fire)(dialogMenuItem *self), + void (*selected)(dialogMenuItem *self, int is_selected), + void *data, int *aux, int *curr, int *max); +extern void items_free(dialogMenuItem *list, int *curr, int *max); +extern int Mkdir(char *); +extern int Mkdir_command(char *key, void *data); +extern int Mount(char *, void *data); +extern int Mount_msdosfs(char *mountp, void *devname); +extern WINDOW *openLayoutDialog(char *helpfile, char *title, int x, int y, int width, int height); +extern ComposeObj *initLayoutDialog(WINDOW *win, Layout *layout, int x, int y, int *max); +extern int layoutDialogLoop(WINDOW *win, Layout *layout, ComposeObj **obj, + int *n, int max, int *cbutton, int *cancel); + +extern WINDOW *savescr(void); +extern void restorescr(WINDOW *w); +extern char *sstrncpy(char *dst, const char *src, int size); + +/* modules.c */ +extern void driverFloppyCheck(void); +extern void moduleInitialize(void); +extern int kldBrowser(dialogMenuItem *self); + +/* mouse.c */ +extern int mousedTest(dialogMenuItem *self); +extern int mousedDisable(dialogMenuItem *self); +extern int setMouseFlags(dialogMenuItem *self); + +/* msg.c */ +extern Boolean isDebug(void); +extern void msgInfo(char *fmt, ...) __printf0like(1, 2); +extern void msgYap(char *fmt, ...) __printflike(1, 2); +extern void msgWarn(char *fmt, ...) __printflike(1, 2); +extern void msgDebug(char *fmt, ...) __printflike(1, 2); +extern void msgError(char *fmt, ...) __printflike(1, 2); +extern void msgFatal(char *fmt, ...) __printflike(1, 2); +extern void msgConfirm(char *fmt, ...) __printflike(1, 2); +extern void msgNotify(char *fmt, ...) __printflike(1, 2); +extern void msgWeHaveOutput(char *fmt, ...) __printflike(1, 2); +extern int msgYesNo(char *fmt, ...) __printflike(1, 2); +extern int msgNoYes(char *fmt, ...) __printflike(1, 2); +extern char *msgGetInput(char *buf, char *fmt, ...) __printflike(2, 3); +extern int msgSimpleConfirm(char *); +extern int msgSimpleNotify(char *); + +/* network.c */ +extern Boolean mediaInitNetwork(Device *dev); +extern void mediaShutdownNetwork(Device *dev); + +/* nfs.c */ +extern Boolean mediaInitNFS(Device *dev); +extern FILE *mediaGetNFS(Device *dev, char *file, Boolean probe); +extern void mediaShutdownNFS(Device *dev); + +/* options.c */ +extern int optionsEditor(dialogMenuItem *self); + +/* package.c */ +extern int packageAdd(dialogMenuItem *self); +extern int package_add(char *name); +extern int package_extract(Device *dev, char *name, Boolean depended); +extern Boolean package_installed(char *name); + +/* pccard.c */ +extern void pccardInitialize(void); + +/* system.c */ +extern void systemInitialize(int argc, char **argv); +extern void systemShutdown(int status); +extern int execExecute(char *cmd, char *name); +extern int systemExecute(char *cmd); +extern void systemSuspendDialog(void); +extern void systemResumeDialog(void); +extern int systemDisplayHelp(char *file); +extern char *systemHelpFile(char *file, char *buf); +extern void systemChangeFont(const u_char font[]); +extern void systemChangeLang(char *lang); +extern void systemChangeTerminal(char *color, const u_char c_termcap[], char *mono, const u_char m_termcap[]); +extern void systemChangeScreenmap(const u_char newmap[]); +extern void systemCreateHoloshell(void); +extern int vsystem(char *fmt, ...) __printflike(1, 2); + +/* tape.c */ +extern char *mediaTapeBlocksize(void); +extern Boolean mediaInitTape(Device *dev); +extern FILE *mediaGetTape(Device *dev, char *file, Boolean probe); +extern void mediaShutdownTape(Device *dev); + +/* tcpip.c */ +extern int tcpOpenDialog(Device *dev); +extern int tcpMenuSelect(dialogMenuItem *self); +extern Device *tcpDeviceSelect(void); + +/* termcap.c */ +extern int set_termcap(void); + +/* ttys.c */ +extern void configTtys(void); + +/* ufs.c */ +extern void mediaShutdownUFS(Device *dev); +extern Boolean mediaInitUFS(Device *dev); +extern FILE *mediaGetUFS(Device *dev, char *file, Boolean probe); + +/* usb.c */ +extern void usbInitialize(void); + +/* user.c */ +extern int userAddGroup(dialogMenuItem *self); +extern int userAddUser(dialogMenuItem *self); + +/* variable.c */ +extern void variable_set(char *var, int dirty); +extern void variable_set2(char *name, char *value, int dirty); +extern char *variable_get(char *var); +extern int variable_cmp(char *var, char *value); +extern void variable_unset(char *var); +extern char *variable_get_value(char *var, char *prompt, int dirty); +extern int variable_check(char *data); +extern int variable_check2(char *data); +extern int dump_variables(dialogMenuItem *self); +extern void free_variables(void); +extern void pvariable_set(char *var); +extern char *pvariable_get(char *var); + +/* wizard.c */ +extern void slice_wizard(Disk *d); + +/* + * Macros. Please find a better place for us! + */ +#define DEVICE_INIT(d) ((d) != NULL ? (d)->init((d)) : (Boolean)0) +#define DEVICE_GET(d, b, f) ((d) != NULL ? (d)->get((d), (b), (f)) : NULL) +#define DEVICE_SHUTDOWN(d) ((d) != NULL ? (d)->shutdown((d)) : (void)0) + +#ifdef USE_GZIP +#define UNZIPPER "gunzip" +#else +#define UNZIPPER "bunzip2" +#endif + +#endif +/* _SYSINSTALL_H_INCLUDE */ diff --git a/usr.sbin/sysinstall/system.c b/usr.sbin/sysinstall/system.c new file mode 100644 index 0000000000000..65c353a41c9e5 --- /dev/null +++ b/usr.sbin/sysinstall/system.c @@ -0,0 +1,542 @@ +/* + * 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 blatently 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 <signal.h> +#include <termios.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/consio.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <ufs/ufs/ufsmount.h> + + +/* 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); +} + +/* + * Harvest children if we are init. + */ +static void +reap_children(int sig) +{ + int errbak = errno; + + while (waitpid(-1, NULL, WNOHANG) > 0) + ; + errno = errbak; +} + +/* Expand a file into a convenient location, nuking it each time */ +static char * +expand(char *fname) +{ + char *gunzip = RunningAsInit ? "/stand/gunzip" : "/usr/bin/gunzip"; + + 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", gunzip, 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:/usr/X11R6/bin", 1); + setbuf(stdin, 0); + setbuf(stderr, 0); +#ifdef __alpha__ + i = 0; + sysctlbyname("machdep.unaligned_print", NULL, 0, &i, sizeof(i)); +#endif +#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) + 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(__alpha__) || defined(__sparc64__) + reboot(RB_HALT); +#else + reboot(0); +#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/sysinstall/help/%s.hlp", file); + if (file_readable(buf)) + return buf; + snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/sysinstall/help/%s.TXT", 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; + + 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 (!RunningAsInit) + execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); + else + execl("/stand/sh", "/stand/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); + 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 + it serial mode + since there is no + virtual console */ + systemResumeDialog(); + } + } + } +} diff --git a/usr.sbin/sysinstall/tape.c b/usr.sbin/sysinstall/tape.c new file mode 100644 index 0000000000000..fd73da568e852 --- /dev/null +++ b/usr.sbin/sysinstall/tape.c @@ -0,0 +1,127 @@ +/* + * 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. + * + */ + +/* These routines deal with getting things off of tape media */ + +#include "sysinstall.h" +#include <sys/fcntl.h> +#include <sys/param.h> + +static Boolean tapeInitted; + +char * +mediaTapeBlocksize(void) +{ + char *cp = variable_get(VAR_TAPE_BLOCKSIZE); + + return cp ? cp : DEFAULT_TAPE_BLOCKSIZE; +} + +Boolean +mediaInitTape(Device *dev) +{ + /* This is REALLY gross, but we need to do the init later in get due to the fact + * that media is initialized BEFORE a filesystem is mounted now. + */ + return TRUE; +} + +FILE * +mediaGetTape(Device *dev, char *file, Boolean probe) +{ + char buf[PATH_MAX]; + FILE *fp; + + int i; + + if (!tapeInitted) { + WINDOW *w = savescr(); + + msgDebug("Tape init routine called for %s (private dir is %s)\n", + dev->name, (char *)dev->private); + Mkdir(dev->private); + if (chdir(dev->private)) { + msgConfirm("Unable to CD to %s before extracting tape!\n" + "Tape media is not selected and thus cannot be installed from.", + (char *)dev->private); + return (FILE *)IO_ERROR; + } + /* We know the tape is already in the drive, so go for it */ + msgNotify("First extracting distributions from %s...", dev->description); + if (!strcmp(dev->name, "rft0")) + i = vsystem("ft | cpio -idum %s --block-size %s", cpioVerbosity(), mediaTapeBlocksize()); + else + i = vsystem("cpio -idum %s --block-size %s -I %s", cpioVerbosity(), mediaTapeBlocksize(), dev->devname); + if (!i) { + tapeInitted = TRUE; + msgDebug("Tape initialized successfully.\n"); + } + else { + msgConfirm("Tape extract command failed with status %d!\n" + "Unable to use tape media.", i); + restorescr(w); + return (FILE *)IO_ERROR; + } + restorescr(w); + } + + sprintf(buf, "%s/%s", (char *)dev->private, file); + if (isDebug()) + msgDebug("Request for %s from tape (looking in %s)\n", file, buf); + if (file_readable(buf)) + fp = fopen(buf, "r"); + else { + sprintf(buf, "%s/releases/%s", (char *)dev->private, file); + fp = fopen(buf, "r"); + } + /* Nuke the files behind us to save space */ + if (fp) + unlink(buf); + return fp; +} + +void +mediaShutdownTape(Device *dev) +{ + if (!tapeInitted) + return; + if (file_readable((char *)dev->private)) { + msgDebug("Cleaning up results of tape extract in %s..\n", + (char *)dev->private); + (void)vsystem("rm -rf %s", (char *)dev->private); + } + tapeInitted = FALSE; +} diff --git a/usr.sbin/sysinstall/tcpip.c b/usr.sbin/sysinstall/tcpip.c new file mode 100644 index 0000000000000..1d2534fe1c193 --- /dev/null +++ b/usr.sbin/sysinstall/tcpip.c @@ -0,0 +1,697 @@ +/* + * $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 <sys/param.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +/* 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 }, + { 0 }, +}; + +#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; + + 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++ != '.') + return 0; + b = strtol(endptr, &endptr, 10); + if (*endptr++ != '.') + return 0; + c = strtol(endptr, &endptr, 10); + if (*endptr++ != '.') + return 0; + d = strtol(endptr, &endptr, 10); + if (*endptr != '\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; + unsigned 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 */ + mask = strtoul(netmask, &endptr, 10); + if (!_validByte(mask) || *endptr++ != '.') + return 0; + 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) +{ + /* If it fails, do it the old-fashioned way */ + if (dhcpParseLeases("/var/db/dhclient.leases", 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..."); + vsystem("dhclient -r %s", devp->name); + if (0 == vsystem("dhclient -1 %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, "lp", 2)) + 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]; +#ifdef PCCARD_ARCH + char *pccard; +#endif + 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) + sprintf(temp, "DHCP"); + else + sprintf(temp, "inet %s %s netmask %s", + ipaddr, extras, netmask); + variable_set2(ifn, temp, 1); + } +#ifdef PCCARD_ARCH + pccard = variable_get("_pccard_install"); + if (pccard && strcmp(pccard, "YES") == 0 && ipv4_enable) { + variable_set2("pccard_ifconfig", temp, 1); + } +#endif + 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; +} + +/* Get a network device */ +Device * +tcpDeviceSelect(void) +{ + DMenu *menu; + Device **devs, *rval; + int cnt; + + devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); + cnt = deviceCount(devs); + rval = NULL; + + if (!cnt) { + msgConfirm("No network devices available!"); + return NULL; + } + else 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 if (variable_get(VAR_NONINTERACTIVE) && variable_get(VAR_NETWORK_DEVICE)) { + devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); + cnt = deviceCount(devs); + if (cnt) { + 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; +} diff --git a/usr.sbin/sysinstall/termcap.c b/usr.sbin/sysinstall/termcap.c new file mode 100644 index 0000000000000..1d8e047bc12a2 --- /dev/null +++ b/usr.sbin/sysinstall/termcap.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1994, Paul Richards. + * + * All rights reserved. + * + * This software may be used, modified, copied, distributed, and sold, in both + * source and binary form provided that the above copyright and these terms + * are retained, verbatim, as the first lines of this file. Under no + * circumstances is the author responsible for the proper functioning of this + * software, nor does the author assume any responsibility for damages + * incurred with its use. + * + * $FreeBSD$ + */ + +#include "sysinstall.h" +#include <stdarg.h> +#include <fcntl.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/consio.h> + +#define VTY_STATUS_LINE 24 +#define TTY_STATUS_LINE 23 + +static void +prompt_term(char **termp, char **termcapp) +{ + char str[80]; + static struct { + const char *term, *termcap; + } lookup[] = { { "ansi", termcap_ansi }, + { "vt100", termcap_vt100 }, + { "cons25", termcap_cons25 }, + { "cons25-m", termcap_cons25_m }, + { "xterm", termcap_xterm }, + { "cons25w", termcap_cons25w } }; /* must be last */ + + if (RunningAsInit) { + while (1) { + int i; + + printf("\nThese are the predefined terminal types available to\n"); + printf("sysinstall when running stand-alone. Please choose the\n"); + printf("closest match for your particular terminal.\n\n"); + printf("1 ...................... Standard ANSI terminal.\n"); + printf("2 ...................... VT100 or compatible terminal.\n"); + printf("3 ...................... FreeBSD system console (color).\n"); + printf("4 ...................... FreeBSD system console (monochrome).\n\n"); + printf("5 ...................... xterm terminal emulator.\n\n"); + printf("Your choice: (1-5) "); + fflush(stdout); + fgets(str, 80, stdin); + i = str[0] - '0'; + if (i > 0 && i < 6) { + *termp = (char *)lookup[i - 1].term; + *termcapp = (char *)lookup[i - 1].termcap; + break; + } + else + printf("\007Invalid choice, please try again.\n\n"); + } + } + else { + printf("\nPlease set your TERM variable before running this program.\n"); + printf("Defaulting to an ANSI compatible terminal - please press RETURN\n"); + fgets(str, 80, stdin); /* Just to make it interactive */ + *termp = (char *)"ansi"; + *termcapp = (char *)termcap_ansi; + } +} + +int +set_termcap(void) +{ + char *term; + int stat; + struct ttysize ts; + + term = getenv("TERM"); + stat = ioctl(STDERR_FILENO, GIO_COLOR, &ColorDisplay); + + if (!RunningAsInit) { + if (isDebug()) + DebugFD = open("sysinstall.debug", O_WRONLY|O_CREAT|O_TRUNC, 0644); + else + DebugFD = -1; + if (DebugFD < 0) + DebugFD = open("/dev/null", O_RDWR, 0); + } + + if (!OnVTY || (stat < 0)) { + if (!term) { + char *term, *termcap; + + prompt_term(&term, &termcap); + if (setenv("TERM", term, 1) < 0) + return -1; + if (setenv("TERMCAP", termcap, 1) < 0) + return -1; + } + if (DebugFD < 0) + DebugFD = open("/dev/null", O_RDWR, 0); + } + else { + int i, on; + + if (getpid() == 1) { + DebugFD = open("/dev/ttyv1", O_WRONLY); + if (DebugFD != -1) { + on = 1; + i = ioctl(DebugFD, TIOCCONS, (char *)&on); + msgDebug("ioctl(%d, TIOCCONS, NULL) = %d (%s)\n", + DebugFD, i, !i ? "success" : strerror(errno)); + } + } + +#ifdef PC98 + if (!term) { + if (setenv("TERM", "cons25w", 1) < 0) + return -1; + if (setenv("TERMCAP", termcap_cons25w, 1) < 0) + return -1; + } +#else + if (ColorDisplay) { + if (!term) { + if (setenv("TERM", "cons25", 1) < 0) + return -1; + if (setenv("TERMCAP", termcap_cons25, 1) < 0) + return -1; + } + } + else { + if (!term) { + if (setenv("TERM", "cons25-m", 1) < 0) + return -1; + if (setenv("TERMCAP", termcap_cons25_m, 1) < 0) + return -1; + } + } +#endif + } + if (ioctl(0, TIOCGSIZE, &ts) == -1) { + msgDebug("Unable to get terminal size - errno %d\n", errno); + ts.ts_lines = 0; + } + StatusLine = ts.ts_lines ? ts.ts_lines - 1: (OnVTY ? VTY_STATUS_LINE : TTY_STATUS_LINE); + return 0; +} diff --git a/usr.sbin/sysinstall/ttys.c b/usr.sbin/sysinstall/ttys.c new file mode 100644 index 0000000000000..0de954cceb39c --- /dev/null +++ b/usr.sbin/sysinstall/ttys.c @@ -0,0 +1,162 @@ +/* + * 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) 2001 + * Andrey A. Chernov. 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 ANDREY A. CHERNOV ``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 ANDREY A. CHERNOV 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 <sys/stat.h> +#include <ctype.h> +#include <ttyent.h> + +#define _X_EXTENSION ".XXXXXX" + +void +configTtys(void) +{ + size_t len; + int t, tlen, changed; + FILE *fp, *np; + char sq, *line, *p, *q, *cp, *tptr; + char templ[sizeof(_PATH_TTYS) + sizeof(_X_EXTENSION) - 1]; + struct ttyent *tnam; + + if ((cp = variable_get(VAR_CONSTERM)) == NULL || + strcmp(cp, "NO") == 0) + return; + if (!file_readable(_PATH_TTYS)) { + msgConfirm("%s not exist or not readable", _PATH_TTYS); + return; + } + if ((fp = fopen(_PATH_TTYS, "r")) == NULL) { + msgConfirm("Can't open %s for read: %s", _PATH_TTYS, + strerror(errno)); + return; + } + strcpy(templ, _PATH_TTYS _X_EXTENSION); + if ((t = mkstemp(templ)) < 0) { + msgConfirm("Can't create %s: %s", templ, strerror(errno)); + (void)fclose(fp); + return; + } + if (fchmod(t, 0644)) { + msgConfirm("Can't fchmod %s: %s", templ, strerror(errno)); + (void)fclose(fp); + return; + } + if ((np = fdopen(t, "w")) == NULL) { + msgConfirm("Can't fdopen %s: %s", templ, strerror(errno)); + (void)close(t); + (void)fclose(fp); + (void)unlink(templ); + return; + } + changed = 0; + while ((line = fgetln(fp, &len)) != NULL) { + p = line; + while (p < (line + len) && isspace((unsigned char)*p)) + ++p; + if (strncmp(p, "ttyv", 4) != 0) { + dump: + if (fwrite(line, len, 1, np) != 1) { + wrerr: + msgConfirm("%s: write error: %s", templ, strerror(errno)); + (void)fclose(fp); + (void)fclose(np); + (void)unlink(templ); + return; + } + } else { + q = p; + while(q < (line + len) && !isspace((unsigned char)*q)) + ++q; + if (!isspace((unsigned char)*q)) + goto dump; + sq = *q; + *q = '\0'; + tnam = getttynam(p); + *q = sq; + if (tnam == NULL || tnam->ty_type == NULL || + strcmp(tnam->ty_type, cp) == 0 || + strncmp(tnam->ty_type, "cons", 4) != 0 || + !isdigit((unsigned char)tnam->ty_type[4]) + ) + goto dump; + tlen = strlen(tnam->ty_type); + tptr = NULL; + p = ++q; + while(p < (line + len)) { + if (strncmp(p, tnam->ty_type, tlen) == 0) { + tptr = p; + break; + } + ++p; + } + if (tptr == NULL) + goto dump; + changed = 1; + if (fwrite(line, tptr - line, 1, np) != 1 || + fputs(cp, np) || + fwrite(tptr + tlen, + len - (tptr + tlen - line), 1, np) != 1) + goto wrerr; + } + } + if (!feof(fp)) { + msgConfirm("%s: read error: %s", _PATH_TTYS, strerror(errno)); + (void)fclose(fp); + (void)fclose(np); + (void)unlink(templ); + return; + } + (void)fclose(fp); + if (fclose(np)) { + if (changed) + msgConfirm("%s: close error: %s", templ, strerror(errno)); + else + variable_set2(VAR_CONSTERM, "NO", 0); + (void)unlink(templ); + return; + } + if (!changed) { + (void)unlink(templ); + variable_set2(VAR_CONSTERM, "NO", 0); + return; + } + if (rename(templ, _PATH_TTYS)) { + msgConfirm("Can't rename %s to %s: %s", templ, _PATH_TTYS, + strerror(errno)); + return; + } + variable_set2(VAR_CONSTERM, "NO", 0); +} diff --git a/usr.sbin/sysinstall/ufs.c b/usr.sbin/sysinstall/ufs.c new file mode 100644 index 0000000000000..c9515ae82b28c --- /dev/null +++ b/usr.sbin/sysinstall/ufs.c @@ -0,0 +1,49 @@ +/* + * 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. + * Copyright (c) 1995 + * Gary J Palmer. 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 <sys/fcntl.h> +#include <sys/param.h> + +/* No init or shutdown routines necessary - all done in mediaSetUFS() */ + +FILE * +mediaGetUFS(Device *dev, char *file, Boolean probe) +{ + return mediaGenericGet((char *)dev->private, file); +} diff --git a/usr.sbin/sysinstall/usb.c b/usr.sbin/sysinstall/usb.c new file mode 100644 index 0000000000000..4eedbd555f89e --- /dev/null +++ b/usr.sbin/sysinstall/usb.c @@ -0,0 +1,44 @@ +/* + * USB support for sysinstall + * + * $FreeBSD$ + * + * Copyright (c) 2000 John Baldwin <jhb@FreeBSD.org>. All rights reserved. + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + */ + +#include "sysinstall.h" +#include <sys/fcntl.h> +#include <sys/time.h> + +void +usbInitialize(void) +{ + int fd; + WINDOW *w; + + if (!RunningAsInit && !Fake) { + /* It's not my job... */ + return; + } + + if ((fd = open("/dev/usb", O_RDONLY)) < 0) { + msgDebug("Can't open USB controller.\n"); + return; + } + close(fd); + + w = savescr(); + msgNotify("Initializing USB controller...."); + + variable_set2("usbd_enable", "YES", 1); + + vsystem("/stand/usbd"); + restorescr(w); +} diff --git a/usr.sbin/sysinstall/user.c b/usr.sbin/sysinstall/user.c new file mode 100644 index 0000000000000..ecee440fe7884 --- /dev/null +++ b/usr.sbin/sysinstall/user.c @@ -0,0 +1,742 @@ +/* + * $FreeBSD$ + * + * Copyright (c) 1996 + * Jörg Wunsch. All rights reserved. + * + * The basic structure has been taken from tcpip.c, which is: + * + * Copyright (c) 1995 + * Gary J Palmer. All rights reserved. + * 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. + * + */ + +#include "sysinstall.h" +#include <utmp.h> +#include <ctype.h> +#include <sys/param.h> +#include <sysexits.h> + +/* The help file for the user mgmt screen */ +#define USER_HELPFILE "usermgmt" + +/* XXX should they be moved out to sysinstall.h? */ +#define GNAME_FIELD_LEN 32 +#define GID_FIELD_LEN 10 +#define GMEMB_FIELD_LEN 64 + +#define UID_FIELD_LEN 10 +#define UGROUP_FIELD_LEN GNAME_FIELD_LEN +#define GECOS_FIELD_LEN 64 +#define UMEMB_FIELD_LEN GMEMB_FIELD_LEN +#define HOMEDIR_FIELD_LEN 48 +#define SHELL_FIELD_LEN 48 +#define PASSWD_FIELD_LEN 32 + +/* These are nasty, but they make the layout structure a lot easier ... */ + +static char gname[GNAME_FIELD_LEN], + gid[GID_FIELD_LEN], + gmemb[GMEMB_FIELD_LEN], + uname[UT_NAMESIZE + 1], + passwd[PASSWD_FIELD_LEN], + uid[UID_FIELD_LEN], + ugroup[UGROUP_FIELD_LEN], + gecos[GECOS_FIELD_LEN], + umemb[UMEMB_FIELD_LEN], + homedir[HOMEDIR_FIELD_LEN], + shell[SHELL_FIELD_LEN]; +#define CLEAR(v) memset(v, 0, sizeof v) + +static int okbutton, cancelbutton; + + +/* What the screen size is meant to be */ +#define USER_DIALOG_Y 0 +#define USER_DIALOG_X 8 +#define USER_DIALOG_WIDTH COLS - 16 +#define USER_DIALOG_HEIGHT LINES - 2 + +/* The group configuration menu. */ +static Layout groupLayout[] = { +#define LAYOUT_GNAME 0 + { 4, 10, 20, GNAME_FIELD_LEN - 1, + "Group name:", "The alphanumeric name of the new group (mandatory)", + gname, STRINGOBJ, NULL }, +#define LAYOUT_GID 1 + { 4, 38, 10, GID_FIELD_LEN - 1, + "GID:", "The numerical ID for this group (leave blank for automatic choice)", + gid, STRINGOBJ, NULL }, +#define LAYOUT_GMEMB 2 + { 11, 10, 40, GMEMB_FIELD_LEN - 1, + "Group members:", "Who belongs to this group (i.e., gets access rights for it)", + gmemb, STRINGOBJ, NULL }, +#define LAYOUT_OKBUTTON 3 + { 18, 15, 0, 0, + "OK", "Select this if you are happy with these settings", + &okbutton, BUTTONOBJ, NULL }, +#define LAYOUT_CANCELBUTTON 4 + { 18, 35, 0, 0, + "CANCEL", "Select this if you wish to cancel this screen", + &cancelbutton, BUTTONOBJ, NULL }, + { 0 }, +}; + +/* The user configuration menu. */ +static Layout userLayout[] = { +#define LAYOUT_UNAME 0 + { 3, 6, UT_NAMESIZE, UT_NAMESIZE + 1, + "Login ID:", "The login name of the new user (mandatory)", + uname, STRINGOBJ, NULL }, +#define LAYOUT_UID 1 + { 3, 23, 8, UID_FIELD_LEN - 1, + "UID:", "The numerical ID for this user (leave blank for automatic choice)", + uid, STRINGOBJ, NULL }, +#define LAYOUT_UGROUP 2 + { 3, 33, 8, UGROUP_FIELD_LEN - 1, + "Group:", "The login group name for this user (leave blank for automatic choice)", + ugroup, STRINGOBJ, NULL }, +#define LAYOUT_PASSWD 3 + { 3, 43, 15, PASSWD_FIELD_LEN - 1, + "Password:", "The password for this user (enter this field with care!)", + passwd, NO_ECHO_OBJ(STRINGOBJ), NULL }, +#define LAYOUT_GECOS 4 + { 8, 6, 33, GECOS_FIELD_LEN - 1, + "Full name:", "The user's full name (comment)", + gecos, STRINGOBJ, NULL }, +#define LAYOUT_UMEMB 5 + { 8, 43, 15, UMEMB_FIELD_LEN - 1, + "Member groups:", "The groups this user belongs to (i.e. gets access rights for)", + umemb, STRINGOBJ, NULL }, +#define LAYOUT_HOMEDIR 6 + { 13, 6, 20, HOMEDIR_FIELD_LEN - 1, + "Home directory:", "The user's home directory (leave blank for default)", + homedir, STRINGOBJ, NULL }, +#define LAYOUT_SHELL 7 + { 13, 29, 29, SHELL_FIELD_LEN - 1, + "Login shell:", "The user's login shell (leave blank for default)", + shell, STRINGOBJ, NULL }, +#define LAYOUT_U_OKBUTTON 8 + { 18, 15, 0, 0, + "OK", "Select this if you are happy with these settings", + &okbutton, BUTTONOBJ, NULL }, +#define LAYOUT_U_CANCELBUTTON 9 + { 18, 35, 0, 0, + "CANCEL", "Select this if you wish to cancel this screen", + &cancelbutton, BUTTONOBJ, NULL }, + { 0 }, +}; + +/* whine */ +static void +feepout(char *msg) +{ + beep(); + dialog_notify(msg); +} + +/* Check for the settings on the screen. */ + +static int +verifyGroupSettings(void) +{ + char tmp[256], *cp; + long lgid; + + if (strlen(gname) == 0) { + feepout("The group name field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw group show -q -n %s > /dev/null", gname); + if (vsystem("%s", tmp) == 0) { + feepout("This group name is already in use."); + return 0; + } + if (strlen(gid) > 0) { + lgid = strtol(gid, &cp, 10); + if (lgid < 0 || lgid >= 65536 || (*cp != '\0' && !isspace(*cp))) { + feepout("The GID must be a number between 1 and 65535."); + return 0; + } + } + if (strlen(gmemb) > 0) { + if (strpbrk(gmemb, " \t") != NULL) { + feepout("The group member list must not contain any whitespace;\n" + "use commas to separate the names."); + return 0; + } +#ifndef notyet /* XXX */ + feepout("Sorry, the group member list feature\n" + "is currently not yet implemented."); + return 0; +#endif + } + + return 1; +} + +/* + * Ask pw(8) to fill in the blanks for us. + * Works solely on the global variables. + */ + +static void +completeGroup(void) +{ + int pfd[2], i; + char tmp[256], *cp; + ssize_t l; + size_t amnt; + pid_t pid; + char *vec[4] = + { + "pw", "group", "next", 0 + }; + + pipe (pfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i) || WEXITSTATUS(i) != 0) + /* ignore by now */ + return; + if ((cp = strchr(tmp, '\n')) != NULL) + *cp = '\0'; + strncpy(gid, tmp, sizeof gid); + } +} + +static void +addGroup(WINDOW *ds_win) +{ + char tmp[256]; + int pfd[2], i; + ssize_t l; + size_t amnt; + pid_t pid; + char *vec[8] = + { + "pw", "group", "add", "-n", 0, "-g", 0, 0 + }; +#define VEC_GNAME 4 +#define VEC_GID 6 + + msgNotify("Adding group \"%s\"...", gname); + + pipe (pfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + vec[VEC_GNAME] = gname; + + if (strlen(gid) > 0) + vec[VEC_GID] = gid; + else + vec[VEC_GID - 1] = 0; + + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i)) + msgDebug("pw(8) exited with signal %d.\n", WTERMSIG(i)); + else if(WEXITSTATUS(i)) + { + i = 0; + if(strncmp(tmp, "pw: ", 4) == 0) + i = 4; + tmp[sizeof tmp - 1] = '\0'; /* sanity */ + msgConfirm("The `pw' command exited with an error status.\n" + "Its error message was:\n\n%s", + &tmp[i]); + } + } +#undef VEC_GNAME +#undef VEC_GID +} + +int +userAddGroup(dialogMenuItem *self) +{ + WINDOW *ds_win, *save; + ComposeObj *obj = NULL; + int n = 0, cancel = FALSE, ret; + int max, firsttime = TRUE; + + if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) { + msgConfirm("This option may only be used after the system is installed, sorry!"); + return DITEM_FAILURE; + } + + save = savescr(); + dialog_clear_norefresh(); + /* We need a curses window */ + if (!(ds_win = openLayoutDialog(USER_HELPFILE, " User and Group Management ", + USER_DIALOG_X, USER_DIALOG_Y, USER_DIALOG_WIDTH, USER_DIALOG_HEIGHT))) { + beep(); + msgConfirm("Cannot open addgroup dialog window!!"); + return(DITEM_FAILURE); + } + + /* Draw a group entry box */ + draw_box(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 8, USER_DIALOG_HEIGHT - 8, + USER_DIALOG_WIDTH - 17, dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 22, " Add a new group "); + + CLEAR(gname); + CLEAR(gid); + CLEAR(gmemb); + + /* Some more initialisation before we go into the main input loop */ + obj = initLayoutDialog(ds_win, groupLayout, USER_DIALOG_X, USER_DIALOG_Y, &max); + +reenter: + cancelbutton = okbutton = 0; + if (firsttime) { + /* fill in the blanks, well, just the GID */ + completeGroup(); + RefreshStringObj(groupLayout[LAYOUT_GID].obj); + firsttime = FALSE; + } + + while (layoutDialogLoop(ds_win, groupLayout, &obj, &n, max, &cancelbutton, &cancel)); + + if (!cancel && !verifyGroupSettings()) + goto reenter; + + /* Clear this crap off the screen */ + delwin(ds_win); + dialog_clear_norefresh(); + use_helpfile(NULL); + + if (!cancel) { + addGroup(ds_win); + ret = DITEM_SUCCESS; + } + else + ret = DITEM_FAILURE; + restorescr(save); + return ret; +} + +/* Check for the settings on the screen. */ + +static int +verifyUserSettings(WINDOW *ds_win) +{ + char tmp[256], *cp; + long luid; + WINDOW *save; + int rv; + + if (strlen(uname) == 0) { + feepout("The user name field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw user show -q -n %s > /dev/null", uname); + if (vsystem("%s", tmp) == 0) { + feepout("This user name is already in use."); + return 0; + } + if (strlen(uid) > 0) { + luid = strtol(uid, &cp, 10); + if (luid < 0 || luid >= 65536 || (*cp != '\0' && !isspace(*cp))) { + feepout("The UID must be a number between 1 and 65535."); + return 0; + } + } + if ((homedir[0]!=0) && (homedir[0]!='/')) { + feepout("The pathname for home directories must begin with a '/'."); + return 0; + } + if (strlen(shell) > 0) { + setusershell(); + while((cp = getusershell()) != NULL) + if (strcmp(cp, shell) == 0) + break; + endusershell(); + if (cp == NULL) { + save = savescr(); + rv = msgYesNo("Warning:\n\n" + "The requested shell \"%s\" is not\n" + "a valid user shell.\n\n" + "Use it anyway?\n", shell); + restorescr(save); + wrefresh(ds_win); + if (rv != DITEM_SUCCESS) + return 0; + } + + } + + if (strlen(umemb) > 0) { + if (strpbrk(umemb, " \t") != NULL) { + feepout("The member groups list must not contain any whitespace;\n" + "use commas to separate the names."); + return 0; + } + } + + return 1; +} + +/* + * Ask pw(8) to fill in the blanks for us. + * Works solely on the global variables. + */ + +static void +completeUser(void) +{ + int pfd[2], i; + char tmp[256], *cp, *cp2; + ssize_t l; + size_t amnt; + pid_t pid; + char *vec[7] = + { + "pw", "user", "add", "-N", "-n", 0, 0 + }; +#define VEC_UNAME 5 + + pipe (pfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + vec[VEC_UNAME] = uname; + + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i) || WEXITSTATUS(i) != 0) + /* ignore by now */ + return; + if ((cp = strchr(tmp, '\n')) != NULL) + *cp = '\0'; + if ((cp = strchr(tmp, ':')) == NULL || (cp = strchr(++cp, ':')) == NULL) + return; + cp++; + if ((cp2 = strchr(cp, ':')) == NULL) + return; + *cp2++ = '\0'; + strncpy(uid, cp, sizeof uid); + cp = cp2; + if ((cp2 = strchr(cp, ':')) == NULL) + return; + *cp2++ = '\0'; +#ifdef notyet /* XXX pw user add -g doesn't accept a numerical GID */ + strncpy(ugroup, cp, sizeof ugroup); +#endif + cp = cp2; + if ((cp2 = strchr(cp, ':')) == NULL || (cp2 = strchr(++cp2, ':')) == NULL || + (cp = cp2 = strchr(++cp2, ':')) == NULL || (cp2 = strchr(++cp2, ':')) == NULL) + return; + *cp2++ = '\0'; + cp++; + strncpy(gecos, cp, sizeof gecos); + cp = cp2; + if ((cp2 = strchr(cp, ':')) == NULL) + return; + *cp2++ = '\0'; + if (*cp2) + strncpy(shell, cp2, sizeof shell); + } +#undef VEC_UNAME +} + +static void +addUser(WINDOW *ds_win) +{ + char tmp[256], *msg; + int pfd[2], ipfd[2], i, j; + ssize_t l; + size_t amnt; + pid_t pid; + /* + * Maximal list: + * pw user add -m -n uname -g grp -u uid -c comment -d homedir -s shell -G grplist -h 0 + */ + char *vec[21] = + { + "pw", "user", "add", "-m", "-n", /* ... */ + }; +#define VEC_UNAME 5 + + msgNotify("Adding user \"%s\"...", uname); + + pipe (pfd); + pipe (ipfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(ipfd[0], 0); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + vec[i = VEC_UNAME] = uname; + i++; +#define ADDVEC(var, option) do { if (strlen(var) > 0) { vec[i++] = option; vec[i++] = var; } } while (0) + ADDVEC(ugroup, "-g"); + ADDVEC(uid, "-u"); + ADDVEC(gecos, "-c"); + ADDVEC(homedir, "-d"); + ADDVEC(shell, "-s"); + ADDVEC(umemb, "-G"); + if (passwd[0]) { + vec[i++] = "-h"; + vec[i++] = "0"; + } + vec[i] = 0; + + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + close(ipfd[0]); + + if (passwd[0]) + write(ipfd[1], passwd, strlen(passwd)); + close(ipfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i)) + { + j = WTERMSIG(i); + msg = "The `pw' command exited with signal %d.\n"; + goto sysfail; + } + else if((j = WEXITSTATUS(i))) + { + i = 0; + if(strncmp(tmp, "pw: ", 4) == 0) + i = 4; + tmp[sizeof tmp - 1] = '\0'; /* sanity */ + if (j == EX_DATAERR || j == EX_NOUSER || j == EX_SOFTWARE) + msgConfirm("The `pw' command exited with an error status.\n" + "Its error message was:\n\n%s", + &tmp[i]); + else + { + msg = "The `pw' command exited with unexpected status %d.\n"; + sysfail: + msgDebug(msg, j); + msgDebug("Command stdout and stderr was:\n\n%s", tmp); + msgConfirm(msg, j); + } + } + else if (!passwd[0]) + msgConfirm("You will need to enter a password for this user\n" + "later, using the passwd(1) command from the shell.\n\n" + "The account for `%s' is currently still disabled.", + uname); + } +#undef VEC_UNAME +#undef ADDVEC +} + +int +userAddUser(dialogMenuItem *self) +{ + WINDOW *ds_win, *save; + ComposeObj *obj = NULL; + int n = 0, cancel = FALSE, ret; + int max, firsttime = TRUE, filled=0; + + if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) { + msgConfirm("This option may only be used after the system is installed, sorry!"); + return DITEM_FAILURE; + } + + save = savescr(); + dialog_clear_norefresh(); + + /* We need a curses window */ + if (!(ds_win = openLayoutDialog(USER_HELPFILE, " User and Group Management ", + USER_DIALOG_X, USER_DIALOG_Y, USER_DIALOG_WIDTH, USER_DIALOG_HEIGHT))) { + beep(); + msgConfirm("Cannot open adduser dialog window!!"); + return(DITEM_FAILURE); + } + + /* Draw a user entry box */ + draw_box(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 3, USER_DIALOG_HEIGHT - 6, + USER_DIALOG_WIDTH - 6, dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 22, " Add a new user "); + + CLEAR(uname); + CLEAR(uid); + CLEAR(ugroup); + CLEAR(gecos); + CLEAR(passwd); + CLEAR(umemb); + CLEAR(homedir); + CLEAR(shell); + + /* Some more initialisation before we go into the main input loop */ + obj = initLayoutDialog(ds_win, userLayout, USER_DIALOG_X, USER_DIALOG_Y, &max); + +reenter: + cancelbutton = okbutton = 0; + if (firsttime) { + /* fill in the blanks, well, just the GID */ + completeUser(); + RefreshStringObj(userLayout[LAYOUT_UID].obj); + RefreshStringObj(userLayout[LAYOUT_UGROUP].obj); + RefreshStringObj(userLayout[LAYOUT_GECOS].obj); + RefreshStringObj(userLayout[LAYOUT_UMEMB].obj); + RefreshStringObj(userLayout[LAYOUT_HOMEDIR].obj); + RefreshStringObj(userLayout[LAYOUT_SHELL].obj); + firsttime = FALSE; + } + + while (layoutDialogLoop(ds_win, userLayout, &obj, &n, max, &cancelbutton, &cancel)) { + /* Prevent this from being irritating if user really means NO */ + if (filled < 3) { + if ((uname[0]) && !homedir[0]) { + SAFE_STRCPY(homedir,"/home/"); + strcat(homedir,uname); + RefreshStringObj(userLayout[LAYOUT_HOMEDIR].obj); + ++filled; + } + } + }; + + if (!cancel && !verifyUserSettings(ds_win)) + goto reenter; + + /* Clear this crap off the screen */ + delwin(ds_win); + dialog_clear_norefresh(); + use_helpfile(NULL); + + if (!cancel) { + addUser(ds_win); + ret = DITEM_SUCCESS; + } + else + ret = DITEM_FAILURE; + restorescr(save); + return ret; +} + diff --git a/usr.sbin/sysinstall/variable.c b/usr.sbin/sysinstall/variable.c new file mode 100644 index 0000000000000..e86104fd100a0 --- /dev/null +++ b/usr.sbin/sysinstall/variable.c @@ -0,0 +1,326 @@ +/* + * 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. + * Copyright (c) 2001 + * Murray Stokely. 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" + +/* Routines for dealing with variable lists */ + +static void +make_variable(char *var, char *value, int dirty) +{ + Variable *vp; + + /* Trim leading and trailing whitespace */ + var = string_skipwhite(string_prune(var)); + + if (!var || !*var) + return; + + + /* Now search to see if it's already in the list */ + for (vp = VarHead; vp; vp = vp->next) { + if (!strcmp(vp->name, var)) { + if (vp->dirty && !dirty) + return; + setenv(var, value, 1); + free(vp->value); + vp->value = strdup(value); + if (dirty != -1) + vp->dirty = dirty; + return; + } + } + + setenv(var, value, 1); + /* No? Create a new one */ + vp = (Variable *)safe_malloc(sizeof(Variable)); + vp->name = strdup(var); + vp->value = strdup(value); + if (dirty == -1) + dirty = 0; + vp->dirty = dirty; + vp->next = VarHead; + VarHead = vp; +} + +void +variable_set(char *var, int dirty) +{ + char tmp[1024], *cp; + + if (!var) + msgFatal("NULL variable name & value passed."); + else if (!*var) + msgDebug("Warning: Zero length name & value passed to variable_set()\n"); + SAFE_STRCPY(tmp, var); + if ((cp = index(tmp, '=')) == NULL) + msgFatal("Invalid variable format: %s", var); + *(cp++) = '\0'; + make_variable(tmp, string_skipwhite(cp), dirty); +} + +void +variable_set2(char *var, char *value, int dirty) +{ + if (!var || !value) + msgFatal("Null name or value passed to set_variable2(%s) = %s!", + var ? var : "", value ? value : ""); + else if (!*var || !*value) + msgDebug("Warning: Zero length name or value passed to variable_set2(%s) = %s\n", + var, value); + make_variable(var, value, dirty); +} + +char * +variable_get(char *var) +{ + return getenv(var); +} + +int +variable_cmp(char *var, char *value) +{ + char *val; + + if ((val = variable_get(var))) + return strcmp(val, value); + return -1; +} + +void +variable_unset(char *var) +{ + Variable *vp; + char name[512], *cp; + + if ((cp = index(var, '=')) != NULL) + sstrncpy(name, var, cp - var); + else + SAFE_STRCPY(name, var); + unsetenv(name); + /* Now search to see if it's in our list, if we have one.. */ + if (!VarHead) + return; + else if (!VarHead->next && !strcmp(VarHead->name, name)) { + safe_free(VarHead->name); + safe_free(VarHead->value); + free(VarHead); + VarHead = NULL; + } + else { + for (vp = VarHead; vp; vp = vp->next) { + if (!strcmp(vp->name, name)) { + Variable *save = vp->next; + + safe_free(vp->name); + safe_free(vp->value); + *vp = *save; + safe_free(save); + break; + } + } + } +} + +/* Prompt user for the name of a variable */ +char * +variable_get_value(char *var, char *prompt, int dirty) +{ + char *cp; + + cp = variable_get(var); + if (cp && variable_get(VAR_NONINTERACTIVE)) + return cp; + else if ((cp = msgGetInput(cp, "%s", prompt)) != NULL) + variable_set2(var, cp, dirty); + else + cp = NULL; + return cp; +} + +/* Check if value passed in data (in the form "variable=value") is + * valid, and it's status compared to the value of variable stored in + * env + * + * Possible return values : + * -3: Invalid line, the data string is NOT set as an env variable + * -2: Invalid line, the data string is set as an env variable + * -1: Invalid line + * 0: Valid line, is NOT equal to env version + * 1: Valid line, is equal to env version + * 2: Valid line, value empty - e.g. foo="" + * 3: Valid line, does not exist in env +*/ +int +variable_check2(char *data) +{ + char *cp, *cp2, *cp3, tmp[256]; + + if (data == NULL) + return -1; + SAFE_STRCPY(tmp, data); + if ((cp = index(tmp, '=')) != NULL) { + *(cp++) = '\0'; + if (*cp == '"') { /* smash quotes if present */ + ++cp; + if ((cp3 = index(cp, '"')) != NULL) + *cp3 = '\0'; + } + else if ((cp3 = index(cp, ',')) != NULL) + *cp3 = '\0'; + cp2 = variable_get(tmp); + if (cp2 != NULL) { + if (*cp == '\0') + return 2; + else + return strcmp(cp, cp2) == 0 ? 1 : 0; + } + else + return 3; + } + else + return variable_get(tmp) != NULL ? -2 : -3; +} + +/* Check if the value passed in data (in the form "variable=value") is + equal to the value of variable stored in env */ +int +variable_check(char *data) +{ + int ret; + ret = variable_check2(data); + + switch(ret) { + case -2: + case 1: + case 2: + return TRUE; + /* NOT REACHED */ + default: + return FALSE; + } +} + +int +dump_variables(dialogMenuItem *unused) +{ + FILE *fp; + Variable *vp; + + if (isDebug()) + msgDebug("Writing sysinstall variables to file..\n"); + + fp = fopen("/etc/sysinstall.vars", "w"); + if (!fp) { + msgConfirm("Unable to write to /etc/sysinstall.vars: %s", + strerror(errno)); + return DITEM_FAILURE; + } + + for (vp = VarHead; vp; vp = vp->next) + fprintf(fp, "%s=\"%s\" (%d)\n", vp->name, vp->value, vp->dirty); + + fclose(fp); + + return DITEM_SUCCESS; +} + +/* Free all of the variables, useful to really start over as when the + user selects "restart" from the interrupt menu. */ +void +free_variables(void) +{ + Variable *vp; + + /* Free the variables from our list, if we have one.. */ + if (!VarHead) + return; + else if (!VarHead->next) { + unsetenv(VarHead->name); + safe_free(VarHead->name); + safe_free(VarHead->value); + free(VarHead); + VarHead = NULL; + } + else { + for (vp = VarHead; vp; ) { + Variable *save = vp; + unsetenv(vp->name); + safe_free(vp->name); + safe_free(vp->value); + vp = vp->next; + safe_free(save); + } + VarHead = NULL; + } +} + +/* + * Persistent variables. The variables modified by these functions + * are not cleared between invocations of sysinstall. This is useful + * to allow the user to completely restart sysinstall, without having + * it load all of the modules again from the installation media which + * are still in memory. + */ + +void +pvariable_set(char *var) +{ + char tmp[1024]; + + if (!var) + msgFatal("NULL variable name & value passed."); + else if (!*var) + msgDebug("Warning: Zero length name & value passed to variable_set()\n"); + /* Add a trivial namespace to whatever name the caller chooses. */ + SAFE_STRCPY(tmp, "SYSINSTALL_PVAR"); + if (index(var, '=') == NULL) + msgFatal("Invalid variable format: %s", var); + strlcat(tmp, var, 1024); + putenv(tmp); +} + +char * +pvariable_get(char *var) +{ + char tmp[1024]; + + SAFE_STRCPY(tmp, "SYSINSTALL_PVAR"); + strlcat(tmp, var, 1024); + return getenv(tmp); +} diff --git a/usr.sbin/sysinstall/wizard.c b/usr.sbin/sysinstall/wizard.c new file mode 100644 index 0000000000000..98e0a5caf997e --- /dev/null +++ b/usr.sbin/sysinstall/wizard.c @@ -0,0 +1,201 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * $FreeBSD$ + * + */ + +#include "sysinstall.h" +#include <fcntl.h> +#include <err.h> +#include <libdisk.h> + +int +scan_block(int fd, daddr_t block) +{ + u_char foo[512]; + + if (-1 == lseek(fd,block * 512,SEEK_SET)) + err(1,"lseek"); + if (512 != read(fd,foo, 512)) + return 1; + return 0; +} + +void +Scan_Disk(Disk *d) +{ + char device[64]; + u_long l; + int i,j,fd; + + strcpy(device,"/dev/"); + strcat(device,d->name); + + fd = open(device,O_RDWR); + if (fd < 0) { + msgWarn("open(%s) failed", device); + return; + } + for(i=-1,l=0;;l++) { + j = scan_block(fd,l); + if (j != i) { + if (i == -1) { + printf("%c: %lu.",j ? 'B' : 'G', l); + fflush(stdout); + } else if (i == 0) { + printf(".%lu\nB: %lu.",l-1,l); + fflush(stdout); + } else { + printf(".%lu\nG: %lu.",l-1,l); + fflush(stdout); + } + i = j; + } + } + close(fd); +} + +void +slice_wizard(Disk *d) +{ + Disk *db; + char myprompt[BUFSIZ]; + char input[BUFSIZ]; + char *p,*q=0; + char **cp,*cmds[200]; + int ncmd,i; + + systemSuspendDialog(); + sprintf(myprompt,"%s> ", d->name); + while(1) { + printf("--==##==--\n"); + Debug_Disk(d); + p = CheckRules(d); + if (p) { + printf("%s",p); + free(p); + } + printf("%s", myprompt); + fflush(stdout); + q = p = fgets(input,sizeof(input),stdin); + if(!p) + break; + for(cp = cmds; (*cp = strsep(&p, " \t\n")) != NULL;) + if (**cp != '\0') + cp++; + ncmd = cp - cmds; + if(!ncmd) + continue; + if (!strcasecmp(*cmds,"quit")) { break; } + if (!strcasecmp(*cmds,"exit")) { break; } + if (!strcasecmp(*cmds,"q")) { break; } + if (!strcasecmp(*cmds,"x")) { break; } + if (!strcasecmp(*cmds,"delete") && ncmd == 2) { + printf("delete = %d\n", + Delete_Chunk(d, + (struct chunk *)strtol(cmds[1],0,0))); + continue; + } + if (!strcasecmp(*cmds,"allfreebsd")) { + All_FreeBSD(d, 0); + continue; + } + if (!strcasecmp(*cmds,"dedicate")) { + All_FreeBSD(d, 1); + continue; + } + if (!strcasecmp(*cmds,"bios") && ncmd == 4) { + Set_Bios_Geom(d, + strtol(cmds[1],0,0), + strtol(cmds[2],0,0), + strtol(cmds[3],0,0)); + continue; + } + if (!strcasecmp(*cmds,"list")) { + cp = Disk_Names(); + printf("Disks:"); + for(i=0;cp[i];i++) { + printf(" %s",cp[i]); + free(cp[i]); + } + free(cp); + continue; + } +#ifdef PC98 + if (!strcasecmp(*cmds,"create") && ncmd == 7) { + printf("Create=%d\n", + Create_Chunk(d, + strtol(cmds[1],0,0), + strtol(cmds[2],0,0), + strtol(cmds[3],0,0), + strtol(cmds[4],0,0), + strtol(cmds[5],0,0), + cmds[6])); + continue; + } +#else + if (!strcasecmp(*cmds,"create") && ncmd == 6) { + printf("Create=%d\n", + Create_Chunk(d, + strtol(cmds[1],0,0), + strtol(cmds[2],0,0), + strtol(cmds[3],0,0), + strtol(cmds[4],0,0), + strtol(cmds[5],0,0), "")); + continue; + } +#endif + if (!strcasecmp(*cmds,"read")) { + db = d; + if (ncmd > 1) + d = Open_Disk(cmds[1]); + else + d = Open_Disk(d->name); + if (d) + Free_Disk(db); + else + d = db; + continue; + } + if (!strcasecmp(*cmds,"scan")) { + Scan_Disk(d); + continue; + } + if (!strcasecmp(*cmds,"write")) { + printf("Write=%d\n", + Fake ? 0 : Write_Disk(d)); + q = strdup(d->name); + Free_Disk(d); + d = Open_Disk(q); + continue; + } + if (strcasecmp(*cmds,"help")) + printf("\007ERROR\n"); + printf("CMDS:\n"); + printf("allfreebsd\t\t"); + printf("dedicate\t\t"); + printf("bios cyl hd sect\n"); + printf("collapse [pointer]\t\t"); +#ifdef PC98 + printf("create offset size enum subtype flags name\n"); +#else + printf("create offset size enum subtype flags\n"); +#endif + printf("subtype(part): swap=1, ffs=7\t\t"); + printf("delete pointer\n"); + printf("list\t\t"); + printf("quit\n"); + printf("read [disk]\t\t"); + printf("scan\n"); + printf("write\t\t"); + printf("\n"); + + } + systemResumeDialog(); +} |
