aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/sysinstall
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2005-04-20 19:11:07 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2005-04-20 19:11:07 +0000
commit79c906b55063e4f0f0d3281363970da4e619cf56 (patch)
tree09cc3ca07e7d7250dd9d9d550c76eacaf462ca91 /usr.sbin/sysinstall
parent7b100a2efc2b0855b788d000f7b2215fb73a5221 (diff)
parent1e4e7f70c04a80eee7cfe0ecc6787272a43ba8bc (diff)
Notes
Diffstat (limited to 'usr.sbin/sysinstall')
-rw-r--r--usr.sbin/sysinstall/Makefile99
-rw-r--r--usr.sbin/sysinstall/anonFTP.c327
-rw-r--r--usr.sbin/sysinstall/cdrom.c218
-rw-r--r--usr.sbin/sysinstall/command.c184
-rw-r--r--usr.sbin/sysinstall/devices.c597
-rw-r--r--usr.sbin/sysinstall/dhcp.c158
-rw-r--r--usr.sbin/sysinstall/disks.c1001
-rw-r--r--usr.sbin/sysinstall/dispatch.c440
-rw-r--r--usr.sbin/sysinstall/dist.c825
-rw-r--r--usr.sbin/sysinstall/dist.h93
-rw-r--r--usr.sbin/sysinstall/dmenu.c319
-rw-r--r--usr.sbin/sysinstall/doc.c123
-rw-r--r--usr.sbin/sysinstall/dos.c94
-rw-r--r--usr.sbin/sysinstall/floppy.c158
-rw-r--r--usr.sbin/sysinstall/ftp.c288
-rw-r--r--usr.sbin/sysinstall/globals.c93
-rw-r--r--usr.sbin/sysinstall/help/anonftp.hlp19
-rw-r--r--usr.sbin/sysinstall/help/configure.hlp10
-rw-r--r--usr.sbin/sysinstall/help/distributions.hlp35
-rw-r--r--usr.sbin/sysinstall/help/drives.hlp92
-rw-r--r--usr.sbin/sysinstall/help/fixit.hlp7
-rw-r--r--usr.sbin/sysinstall/help/html.hlp20
-rw-r--r--usr.sbin/sysinstall/help/media.hlp54
-rw-r--r--usr.sbin/sysinstall/help/network_device.hlp58
-rw-r--r--usr.sbin/sysinstall/help/options.hlp124
-rw-r--r--usr.sbin/sysinstall/help/partition.hlp169
-rw-r--r--usr.sbin/sysinstall/help/register.hlp76
-rw-r--r--usr.sbin/sysinstall/help/securelevel.hlp38
-rw-r--r--usr.sbin/sysinstall/help/shortcuts.hlp114
-rw-r--r--usr.sbin/sysinstall/help/slice.hlp65
-rw-r--r--usr.sbin/sysinstall/help/tcp.hlp34
-rw-r--r--usr.sbin/sysinstall/help/usage.hlp65
-rw-r--r--usr.sbin/sysinstall/help/usermgmt.hlp89
-rw-r--r--usr.sbin/sysinstall/http.c279
-rw-r--r--usr.sbin/sysinstall/index.c835
-rw-r--r--usr.sbin/sysinstall/install.c1267
-rw-r--r--usr.sbin/sysinstall/install.cfg99
-rw-r--r--usr.sbin/sysinstall/installUpgrade.c498
-rw-r--r--usr.sbin/sysinstall/keymap.c95
-rw-r--r--usr.sbin/sysinstall/label.c1692
-rw-r--r--usr.sbin/sysinstall/list.h60
-rw-r--r--usr.sbin/sysinstall/main.c187
-rw-r--r--usr.sbin/sysinstall/media.c882
-rw-r--r--usr.sbin/sysinstall/menus.c2300
-rw-r--r--usr.sbin/sysinstall/misc.c529
-rw-r--r--usr.sbin/sysinstall/modules.c229
-rw-r--r--usr.sbin/sysinstall/mouse.c103
-rw-r--r--usr.sbin/sysinstall/msg.c356
-rw-r--r--usr.sbin/sysinstall/network.c355
-rw-r--r--usr.sbin/sysinstall/nfs.c101
-rw-r--r--usr.sbin/sysinstall/options.c341
-rw-r--r--usr.sbin/sysinstall/package.c263
-rw-r--r--usr.sbin/sysinstall/pccard.c290
-rw-r--r--usr.sbin/sysinstall/rtermcap.c15
-rw-r--r--usr.sbin/sysinstall/sysinstall.8946
-rw-r--r--usr.sbin/sysinstall/sysinstall.h888
-rw-r--r--usr.sbin/sysinstall/system.c542
-rw-r--r--usr.sbin/sysinstall/tape.c127
-rw-r--r--usr.sbin/sysinstall/tcpip.c697
-rw-r--r--usr.sbin/sysinstall/termcap.c150
-rw-r--r--usr.sbin/sysinstall/ttys.c162
-rw-r--r--usr.sbin/sysinstall/ufs.c49
-rw-r--r--usr.sbin/sysinstall/usb.c44
-rw-r--r--usr.sbin/sysinstall/user.c742
-rw-r--r--usr.sbin/sysinstall/variable.c326
-rw-r--r--usr.sbin/sysinstall/wizard.c201
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();
+}