summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/mtree/BSD.usr.dist2
-rw-r--r--usr.sbin/Makefile1
-rw-r--r--usr.sbin/bsdinstall/Makefile6
-rwxr-xr-xusr.sbin/bsdinstall/bsdinstall43
-rw-r--r--usr.sbin/bsdinstall/distextract/Makefile10
-rw-r--r--usr.sbin/bsdinstall/distextract/distextract.c176
-rw-r--r--usr.sbin/bsdinstall/distfetch/Makefile10
-rw-r--r--usr.sbin/bsdinstall/distfetch/distfetch.c187
-rw-r--r--usr.sbin/bsdinstall/partedit/Makefile25
-rw-r--r--usr.sbin/bsdinstall/partedit/diskeditor.c261
-rw-r--r--usr.sbin/bsdinstall/partedit/diskeditor.h47
-rw-r--r--usr.sbin/bsdinstall/partedit/gpart_ops.c1092
-rw-r--r--usr.sbin/bsdinstall/partedit/part_wizard.c344
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit.c445
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit.h80
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_generic.c69
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_pc98.c69
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_powerpc.c63
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_sparc64.c63
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_x86.c79
-rw-r--r--usr.sbin/bsdinstall/scripts/Makefile9
-rwxr-xr-xusr.sbin/bsdinstall/scripts/adduser34
-rwxr-xr-xusr.sbin/bsdinstall/scripts/auto192
-rwxr-xr-xusr.sbin/bsdinstall/scripts/config32
-rwxr-xr-xusr.sbin/bsdinstall/scripts/hostname48
-rwxr-xr-xusr.sbin/bsdinstall/scripts/jail81
-rwxr-xr-xusr.sbin/bsdinstall/scripts/keymap32
-rwxr-xr-xusr.sbin/bsdinstall/scripts/mount55
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig121
-rwxr-xr-xusr.sbin/bsdinstall/scripts/rootpass37
-rwxr-xr-xusr.sbin/bsdinstall/scripts/services53
-rwxr-xr-xusr.sbin/bsdinstall/scripts/time29
-rwxr-xr-xusr.sbin/bsdinstall/scripts/umount42
-rwxr-xr-xusr.sbin/bsdinstall/scripts/wlanconfig137
34 files changed, 3974 insertions, 0 deletions
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index 845b675..6e77bbf 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -32,6 +32,8 @@
..
..
libexec
+ bsdinstall
+ ..
lpr
ru
..
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index f3e853e..6209cb5 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -7,6 +7,7 @@ SUBDIR= adduser \
arp \
bootparamd \
burncd \
+ bsdinstall \
cdcontrol \
chkgrp \
chown \
diff --git a/usr.sbin/bsdinstall/Makefile b/usr.sbin/bsdinstall/Makefile
new file mode 100644
index 0000000..5e39b0b
--- /dev/null
+++ b/usr.sbin/bsdinstall/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+SUBDIR= distextract distfetch partedit scripts
+SCRIPTS= bsdinstall
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdinstall/bsdinstall b/usr.sbin/bsdinstall/bsdinstall
new file mode 100755
index 0000000..04162c8
--- /dev/null
+++ b/usr.sbin/bsdinstall/bsdinstall
@@ -0,0 +1,43 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+: ${DISTRIBUTIONS="kernel.tgz world.tgz"}; export DISTRIBUTIONS
+: ${BSDINSTALL_LOG="/tmp/bsdinstall_log"}; export BSDINSTALL_LOG
+: ${BSDINSTALL_TMPETC="/tmp/bsdinstall_etc"}; export BSDINSTALL_TMPETC
+: ${PATH_FSTAB="$BSDINSTALL_TMPETC/fstab"}; export PATH_FSTAB
+: ${BSDINSTALL_DISTDIR="/usr/freebsd-dist"}; export BSDINSTALL_DISTDIR
+: ${BSDINSTALL_CHROOT="/mnt"}; export BSDINSTALL_CHROOT
+
+VERB=$1; shift
+
+if [ -z $VERB ]; then
+ VERB=auto
+fi
+
+exec /usr/libexec/bsdinstall/$VERB $@
+
diff --git a/usr.sbin/bsdinstall/distextract/Makefile b/usr.sbin/bsdinstall/distextract/Makefile
new file mode 100644
index 0000000..3ad1f98
--- /dev/null
+++ b/usr.sbin/bsdinstall/distextract/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+BINDIR= /usr/libexec/bsdinstall
+PROG= distextract
+LDADD= -larchive -lncursesw -ldialog -lm
+
+WARNS?= 6
+NO_MAN= true
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdinstall/distextract/distextract.c b/usr.sbin/bsdinstall/distextract/distextract.c
new file mode 100644
index 0000000..efd9a1b
--- /dev/null
+++ b/usr.sbin/bsdinstall/distextract/distextract.c
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <archive.h>
+#include <dialog.h>
+
+static int extract_files(int nfiles, const char **files);
+
+int
+main(void)
+{
+ char *diststring = strdup(getenv("DISTRIBUTIONS"));
+ const char **dists;
+ int i, retval, ndists = 0;
+ for (i = 0; diststring[i] != 0; i++)
+ if (isspace(diststring[i]) && !isspace(diststring[i+1]))
+ ndists++;
+ ndists++; /* Last one */
+
+ dists = calloc(ndists, sizeof(const char *));
+ for (i = 0; i < ndists; i++)
+ dists[i] = strsep(&diststring, " \t");
+
+ chdir(getenv("BSDINSTALL_CHROOT"));
+ retval = extract_files(ndists, dists);
+
+ free(diststring);
+ free(dists);
+
+ return (retval);
+}
+
+static int
+extract_files(int nfiles, const char **files)
+{
+ const char *items[nfiles*2];
+ char path[PATH_MAX];
+ int archive_files[nfiles];
+ int total_files, current_files, archive_file;
+ struct archive *archive;
+ struct archive_entry *entry;
+ char errormsg[512];
+ char status[8];
+ int i, err, progress, last_progress;
+
+ err = 0;
+ progress = 0;
+
+ /* Make the transfer list for dialog */
+ for (i = 0; i < nfiles; i++) {
+ items[i*2] = strrchr(files[i], '/');
+ if (items[i*2] != NULL)
+ items[i*2]++;
+ else
+ items[i*2] = files[i];
+ items[i*2 + 1] = "Pending";
+ }
+
+ init_dialog(stdin, stdout);
+ dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
+ dlg_put_backtitle();
+ dialog_msgbox("",
+ "Checking distribution archives.\nPlease wait...", 0, 0, FALSE);
+
+ /* Open all the archives */
+ total_files = 0;
+ for (i = 0; i < nfiles; i++) {
+ archive = archive_read_new();
+ archive_read_support_format_all(archive);
+ archive_read_support_compression_all(archive);
+ sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
+ err = archive_read_open_filename(archive, path, 4096);
+ if (err != ARCHIVE_OK) {
+ snprintf(errormsg, sizeof(errormsg),
+ "Error while extracting %s: %s\n", items[i*2],
+ archive_error_string(archive));
+ items[i*2 + 1] = "Failed";
+ dialog_msgbox("Extract Error", errormsg, 0, 0,
+ TRUE);
+ goto exit;
+ }
+ archive_files[i] = 0;
+ while (archive_read_next_header(archive, &entry) == ARCHIVE_OK)
+ archive_files[i]++;
+ total_files += archive_files[i];
+ archive_read_free(archive);
+ }
+
+ current_files = 0;
+
+ for (i = 0; i < nfiles; i++) {
+ archive = archive_read_new();
+ archive_read_support_format_all(archive);
+ archive_read_support_compression_all(archive);
+ sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
+ err = archive_read_open_filename(archive, path, 4096);
+
+ items[i*2 + 1] = "In Progress";
+ archive_file = 0;
+
+ while ((err = archive_read_next_header(archive, &entry)) ==
+ ARCHIVE_OK) {
+ last_progress = progress;
+ progress = (current_files*100)/total_files;
+
+ sprintf(status, "-%d",
+ (archive_file*100)/archive_files[i]);
+ items[i*2 + 1] = status;
+
+ if (progress > last_progress)
+ dialog_mixedgauge("Archive Extraction",
+ "Extracting distribution files...", 0, 0,
+ progress, nfiles,
+ __DECONST(char **, items));
+
+ err = archive_read_extract(archive, entry,
+ ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER |
+ ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL |
+ ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS);
+
+ if (err != ARCHIVE_OK)
+ break;
+
+ archive_file++;
+ current_files++;
+ }
+
+ items[i*2 + 1] = "Done";
+
+ if (err != ARCHIVE_EOF) {
+ snprintf(errormsg, sizeof(errormsg),
+ "Error while extracting %s: %s\n", items[i*2],
+ archive_error_string(archive));
+ items[i*2 + 1] = "Failed";
+ dialog_msgbox("Extract Error", errormsg, 0, 0,
+ TRUE);
+ goto exit;
+ }
+
+ archive_read_free(archive);
+ }
+
+ err = 0;
+exit:
+ end_dialog();
+
+ return (err);
+}
diff --git a/usr.sbin/bsdinstall/distfetch/Makefile b/usr.sbin/bsdinstall/distfetch/Makefile
new file mode 100644
index 0000000..5a449ac1
--- /dev/null
+++ b/usr.sbin/bsdinstall/distfetch/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+BINDIR= /usr/libexec/bsdinstall
+PROG= distfetch
+LDADD= -lfetch -lncursesw -ldialog -lm
+
+WARNS?= 6
+NO_MAN= true
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdinstall/distfetch/distfetch.c b/usr.sbin/bsdinstall/distfetch/distfetch.c
new file mode 100644
index 0000000..2e1d1b3
--- /dev/null
+++ b/usr.sbin/bsdinstall/distfetch/distfetch.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <sys/param.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fetch.h>
+#include <dialog.h>
+
+static int fetch_files(int nfiles, char **urls);
+
+int
+main(void)
+{
+ char *diststring = strdup(getenv("DISTRIBUTIONS"));
+ char **urls;
+ int i, nfetched, ndists = 0;
+ for (i = 0; diststring[i] != 0; i++)
+ if (isspace(diststring[i]) && !isspace(diststring[i+1]))
+ ndists++;
+ ndists++; /* Last one */
+
+ urls = calloc(ndists, sizeof(const char *));
+ for (i = 0; i < ndists; i++) {
+ urls[i] = malloc(PATH_MAX);
+ sprintf(urls[i], "%s/%s", getenv("BSDINSTALL_DISTSITE"),
+ strsep(&diststring, " \t"));
+ }
+
+ chdir(getenv("BSDINSTALL_DISTDIR"));
+ nfetched = fetch_files(ndists, urls);
+
+ free(diststring);
+ for (i = 0; i < ndists; i++)
+ free(urls[i]);
+ free(urls);
+
+ return ((nfetched == ndists) ? 0 : 1);
+}
+
+static int
+fetch_files(int nfiles, char **urls)
+{
+ const char **items;
+ FILE *fetch_out, *file_out;
+ struct url_stat ustat;
+ off_t total_bytes, current_bytes, fsize;
+ char status[8];
+ char errormsg[512];
+ uint8_t block[4096];
+ size_t chunk;
+ int i, progress, last_progress;
+ int nsuccess = 0; /* Number of files successfully downloaded */
+
+ progress = 0;
+
+ /* Make the transfer list for dialog */
+ items = calloc(sizeof(char *), nfiles * 2);
+ for (i = 0; i < nfiles; i++) {
+ items[i*2] = strrchr(urls[i], '/');
+ if (items[i*2] != NULL)
+ items[i*2]++;
+ else
+ items[i*2] = urls[i];
+ items[i*2 + 1] = "Pending";
+ }
+
+ init_dialog(stdin, stdout);
+ dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
+ dlg_put_backtitle();
+
+ dialog_msgbox("", "Connecting to server.\nPlease wait...", 0, 0, FALSE);
+
+ /* Try to stat all the files */
+ total_bytes = 0;
+ for (i = 0; i < nfiles; i++) {
+ if (fetchStatURL(urls[i], &ustat, "") == 0 && ustat.size > 0)
+ total_bytes += ustat.size;
+ }
+
+ current_bytes = 0;
+ for (i = 0; i < nfiles; i++) {
+ last_progress = progress;
+ if (total_bytes == 0)
+ progress = (i*100)/nfiles;
+
+ fetchLastErrCode = 0;
+ fetch_out = fetchXGetURL(urls[i], &ustat, "");
+ if (fetch_out == NULL) {
+ snprintf(errormsg, sizeof(errormsg),
+ "Error while fetching %s: %s\n", urls[i],
+ fetchLastErrString);
+ items[i*2 + 1] = "Failed";
+ dialog_msgbox("Fetch Error", errormsg, 0, 0,
+ TRUE);
+ continue;
+ }
+
+ items[i*2 + 1] = "In Progress";
+ fsize = 0;
+ file_out = fopen(items[i*2], "w+");
+ if (file_out == NULL) {
+ snprintf(errormsg, sizeof(errormsg),
+ "Error while fetching %s: %s\n",
+ urls[i], strerror(errno));
+ items[i*2 + 1] = "Failed";
+ dialog_msgbox("Fetch Error", errormsg, 0, 0,
+ TRUE);
+ fclose(fetch_out);
+ continue;
+ }
+
+ while ((chunk = fread(block, 1, sizeof(block), fetch_out))
+ > 0) {
+ if (fwrite(block, 1, chunk, file_out) < chunk)
+ break;
+
+ current_bytes += chunk;
+ fsize += chunk;
+
+ if (total_bytes > 0) {
+ last_progress = progress;
+ progress = (current_bytes*100)/total_bytes;
+ }
+
+ if (ustat.size > 0) {
+ sprintf(status, "-%jd", (fsize*100)/ustat.size);
+ items[i*2 + 1] = status;
+ }
+
+ if (progress > last_progress)
+ dialog_mixedgauge("Fetching Distribution",
+ "Fetching distribution files...", 0, 0,
+ progress, nfiles,
+ __DECONST(char **, items));
+ }
+
+ if (ustat.size > 0 && fsize < ustat.size) {
+ if (fetchLastErrCode == 0)
+ snprintf(errormsg, sizeof(errormsg),
+ "Error while fetching %s: %s\n",
+ urls[i], strerror(errno));
+ else
+ snprintf(errormsg, sizeof(errormsg),
+ "Error while fetching %s: %s\n",
+ urls[i], fetchLastErrString);
+ items[i*2 + 1] = "Failed";
+ dialog_msgbox("Fetch Error", errormsg, 0, 0,
+ TRUE);
+ } else {
+ items[i*2 + 1] = "Done";
+ nsuccess++;
+ }
+
+ fclose(fetch_out);
+ fclose(file_out);
+ }
+ end_dialog();
+
+ free(items);
+ return (nsuccess);
+}
diff --git a/usr.sbin/bsdinstall/partedit/Makefile b/usr.sbin/bsdinstall/partedit/Makefile
new file mode 100644
index 0000000..80d89cc
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/Makefile
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+BINDIR= /usr/libexec/bsdinstall
+PROG= partedit
+LINKS= ${BINDIR}/partedit ${BINDIR}/autopart
+LDADD= -lgeom -lncursesw -lutil -ldialog -lm
+
+PARTEDIT_ARCH= ${MACHINE}
+.if ${MACHINE} == "i386" || ${MACHINE} == "amd64"
+PARTEDIT_ARCH= x86
+.endif
+.if ${MACHINE} == "sun4v"
+PARTEDIT_ARCH= sparc64
+.endif
+.if !exists(partedit_${PARTEDIT_ARCH}.c)
+PARTEDIT_ARCH= generic
+.endif
+
+SRCS= diskeditor.c partedit.c gpart_ops.c partedit_${PARTEDIT_ARCH}.c \
+ part_wizard.c
+
+WARNS?= 3
+NO_MAN= true
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdinstall/partedit/diskeditor.c b/usr.sbin/bsdinstall/partedit/diskeditor.c
new file mode 100644
index 0000000..c97b003
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/diskeditor.c
@@ -0,0 +1,261 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <libutil.h>
+#include <dialog.h>
+#include <dlg_keys.h>
+
+#include "diskeditor.h"
+
+static void
+print_partedit_item(WINDOW *partitions, struct partedit_item *items,
+ int item, int nscroll, int selected)
+{
+ chtype attr = A_NORMAL;
+ char sizetext[16];
+ int y = item - nscroll + 1;
+
+ wattrset(partitions, selected ? item_selected_attr : item_attr);
+ wmove(partitions, y, MARGIN + items[item].indentation*2);
+ dlg_print_text(partitions, items[item].name, 8, &attr);
+ wmove(partitions, y, 15);
+ wattrset(partitions, item_attr);
+
+ humanize_number(sizetext, 7, items[item].size, "B", HN_AUTOSCALE,
+ HN_DECIMAL);
+ dlg_print_text(partitions, sizetext, 8, &attr);
+ wmove(partitions, y, 25);
+ dlg_print_text(partitions, items[item].type, 15, &attr);
+ wmove(partitions, y, 40);
+ if (items[item].mountpoint != NULL)
+ dlg_print_text(partitions, items[item].mountpoint, 8, &attr);
+}
+
+int
+diskeditor_show(const char *title, const char *cprompt,
+ struct partedit_item *items, int nitems, int *selected, int *nscroll)
+{
+ WINDOW *dialog, *partitions;
+ char *prompt;
+ const char *buttons[] =
+ { "Create", "Delete", "Modify", "Revert", "Auto", "Exit", NULL };
+ int x, y;
+ int i;
+ int height, width, min_width;
+ int partlist_height, partlist_width, min_partlist_width;
+ int cur_scroll = 0;
+ int key, fkey;
+ int cur_button = 0, cur_part = 0;
+ int result = DLG_EXIT_UNKNOWN;
+
+ static DLG_KEYS_BINDING binding[] = {
+ ENTERKEY_BINDINGS,
+ DLG_KEYS_DATA( DLGK_ENTER, ' ' ),
+ DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ),
+ DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ),
+ DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ),
+ DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
+ DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
+ DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ),
+
+ SCROLLKEY_BINDINGS,
+ END_KEYS_BINDING
+ };
+
+ /*
+ * Set up editor window.
+ */
+ prompt = dlg_strclone(cprompt);
+
+ min_width = 50;
+ height = width = 0;
+ partlist_height = 10;
+ min_partlist_width = 0;
+ dlg_tab_correct_str(prompt);
+ dlg_button_layout(buttons, &min_width);
+ dlg_auto_size(title, prompt, &height, &width, 2, min_width);
+ height += partlist_height;
+ partlist_width = width - 2*MARGIN;
+ dlg_print_size(height, width);
+ dlg_ctl_size(height, width);
+
+ x = dlg_box_x_ordinate(width);
+ y = dlg_box_y_ordinate(height);
+
+ dialog = dlg_new_window(height, width, y, x);
+ dlg_register_window(dialog, "diskeditorbox", binding);
+ dlg_register_buttons(dialog, "diskeditorbox", buttons);
+
+ dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ dlg_draw_bottom_box(dialog);
+ dlg_draw_title(dialog, title);
+ wattrset(dialog, dialog_attr);
+
+ /* Partition list sub-window */
+ partitions = dlg_sub_window(dialog, partlist_height, partlist_width,
+ y + 3, x + 1);
+ dlg_register_window(partitions, "partlist", binding);
+ dlg_register_buttons(partitions, "partlist", buttons);
+ wattrset(partitions, menubox_attr);
+
+ dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
+ cur_button, FALSE, width);
+ dlg_print_autowrap(dialog, prompt, height, width);
+
+ if (selected != NULL)
+ cur_part = *selected;
+ if (nscroll != NULL)
+ cur_scroll = *nscroll;
+ if (cur_part - cur_scroll >= partlist_height - 2 ||
+ cur_part - cur_scroll < 0)
+ cur_scroll = cur_part;
+
+repaint:
+ dlg_draw_box(dialog, 3, 1, partlist_height, partlist_width,
+ menubox_border_attr, menubox_attr);
+ for (i = cur_scroll; i < MIN(cur_scroll + partlist_height - 2, nitems);
+ i++)
+ print_partedit_item(partitions, items, i, cur_scroll,
+ i == cur_part);
+ if (nitems > partlist_height - 2)
+ dlg_draw_arrows(partitions, cur_scroll > 0,
+ nitems > cur_scroll + partlist_height - 2,
+ partlist_width - 5, 0, partlist_height - 1);
+ wrefresh(partitions);
+
+ while (result == DLG_EXIT_UNKNOWN) {
+ key = dlg_mouse_wgetch(dialog, &fkey);
+ if ((i = dlg_char_to_button(key, buttons)) >= 0) {
+ cur_button = i;
+ dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
+ cur_button, FALSE, width);
+ break;
+ }
+
+ if (!fkey)
+ continue;
+
+ switch (key) {
+ case DLGK_FIELD_NEXT:
+ cur_button = dlg_next_button(buttons, cur_button);
+ if (cur_button < 0)
+ cur_button = 0;
+ dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
+ cur_button, FALSE, width);
+ break;
+ case DLGK_FIELD_PREV:
+ cur_button = dlg_prev_button(buttons, cur_button);
+ if (cur_button < 0)
+ cur_button = 0;
+ dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
+ cur_button, FALSE, width);
+ break;
+ case DLGK_ITEM_NEXT:
+ if (cur_part == nitems - 1)
+ break; /* End of list */
+
+ /* Deselect old item */
+ print_partedit_item(partitions, items, cur_part,
+ cur_scroll, 0);
+ /* Select new item */
+ cur_part++;
+ if (cur_part - cur_scroll >= partlist_height - 2) {
+ cur_scroll = cur_part;
+ goto repaint;
+ }
+ print_partedit_item(partitions, items, cur_part,
+ cur_scroll, 1);
+ wrefresh(partitions);
+ break;
+ case DLGK_ITEM_PREV:
+ if (cur_part == 0)
+ break; /* Start of list */
+
+ /* Deselect old item */
+ print_partedit_item(partitions, items, cur_part,
+ cur_scroll, 0);
+ /* Select new item */
+ cur_part--;
+ if (cur_part - cur_scroll < 0) {
+ cur_scroll = cur_part;
+ goto repaint;
+ }
+ print_partedit_item(partitions, items, cur_part,
+ cur_scroll, 1);
+ wrefresh(partitions);
+ break;
+ case DLGK_PAGE_NEXT:
+ cur_scroll += (partlist_height - 2);
+ if (cur_scroll + partlist_height - 2 >= nitems)
+ cur_scroll = nitems - (partlist_height - 2);
+ if (cur_part < cur_scroll)
+ cur_part = cur_scroll;
+ goto repaint;
+ case DLGK_PAGE_PREV:
+ cur_scroll -= (partlist_height - 2);
+ if (cur_scroll < 0)
+ cur_scroll = 0;
+ if (cur_part >= cur_scroll + partlist_height - 2)
+ cur_part = cur_scroll;
+ goto repaint;
+ case DLGK_PAGE_FIRST:
+ cur_scroll = 0;
+ cur_part = cur_scroll;
+ goto repaint;
+ case DLGK_PAGE_LAST:
+ cur_scroll = nitems - (partlist_height - 2);
+ cur_part = cur_scroll;
+ goto repaint;
+ case DLGK_ENTER:
+ goto done;
+ default:
+ if (is_DLGK_MOUSE(key)) {
+ cur_button = key - M_EVENT;
+ dlg_draw_buttons(dialog, height - 2*MARGIN, 0,
+ buttons, cur_button, FALSE, width);
+ goto done;
+ }
+ break;
+ }
+ }
+
+done:
+ if (selected != NULL)
+ *selected = cur_part;
+ if (nscroll != NULL)
+ *nscroll = cur_scroll;
+
+ dlg_del_window(partitions);
+ dlg_del_window(dialog);
+ dlg_mouse_free_regions();
+
+ return (cur_button);
+}
+
diff --git a/usr.sbin/bsdinstall/partedit/diskeditor.h b/usr.sbin/bsdinstall/partedit/diskeditor.h
new file mode 100644
index 0000000..f122267
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/diskeditor.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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$
+ */
+
+#ifndef _PARTEDIT_DISKEDITOR_H
+#define _PARTEDIT_DISKEDITOR_H
+
+#include <inttypes.h>
+
+struct partedit_item {
+ int indentation;
+ const char *name;
+ intmax_t size;
+ const char *type;
+ char *mountpoint;
+
+ void *cookie;
+};
+
+int diskeditor_show(const char *title, const char *prompt,
+ struct partedit_item *items, int nitems, int *selected, int *scroll);
+
+#endif
diff --git a/usr.sbin/bsdinstall/partedit/gpart_ops.c b/usr.sbin/bsdinstall/partedit/gpart_ops.c
new file mode 100644
index 0000000..f6fcc08
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/gpart_ops.c
@@ -0,0 +1,1092 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <sys/param.h>
+#include <errno.h>
+#include <libutil.h>
+#include <inttypes.h>
+
+#include <libgeom.h>
+#include <dialog.h>
+#include <dlg_keys.h>
+
+#include "partedit.h"
+
+#define GPART_FLAGS "x" /* Do not commit changes by default */
+
+static void
+gpart_show_error(const char *title, const char *explanation, const char *errstr)
+{
+ char *errmsg;
+ char message[512];
+ int error;
+
+ if (explanation == NULL)
+ explanation = "";
+
+ error = strtol(errstr, &errmsg, 0);
+ if (errmsg != errstr) {
+ while (errmsg[0] == ' ')
+ errmsg++;
+ if (errmsg[0] != '\0')
+ sprintf(message, "%s%s. %s", explanation,
+ strerror(error), errmsg);
+ else
+ sprintf(message, "%s%s", explanation, strerror(error));
+ } else {
+ sprintf(message, "%s%s", explanation, errmsg);
+ }
+
+ dialog_msgbox(title, message, 0, 0, TRUE);
+}
+
+int
+gpart_partition(const char *lg_name, const char *scheme)
+{
+ int cancel, choice;
+ struct gctl_req *r;
+ const char *errstr;
+
+ DIALOG_LISTITEM items[] = {
+ {"APM", "Apple Partition Map",
+ "Bootable on PowerPC Apple Hardware", 0 },
+ {"BSD", "BSD Labels",
+ "Bootable on most x86 systems", 0 },
+ {"GPT", "GUID Partition Table",
+ "Bootable on most x86 systems", 0 },
+ {"MBR", "DOS Partitions",
+ "Bootable on most x86 systems", 0 },
+ {"PC98", "NEC PC9801 Partition Table",
+ "Bootable on NEC PC9801 systems", 0 },
+ {"VTOC8", "Sun VTOC8 Partition Table",
+ "Bootable on Sun SPARC systems", 0 },
+ };
+
+schememenu:
+ if (scheme == NULL) {
+ dialog_vars.default_item = __DECONST(char *, default_scheme());
+ cancel = dlg_menu("Partition Scheme",
+ "Select a partition scheme for this volume:", 0, 0, 0,
+ sizeof(items) / sizeof(items[0]), items, &choice, NULL);
+ dialog_vars.default_item = NULL;
+
+ if (cancel)
+ return (-1);
+
+ if (!is_scheme_bootable(items[choice].name)) {
+ char message[512];
+ sprintf(message, "This partition scheme (%s) is not "
+ "bootable on this platform. Are you sure you want "
+ "to proceed?", items[choice].name);
+ dialog_vars.defaultno = TRUE;
+ cancel = dialog_yesno("Warning", message, 0, 0);
+ dialog_vars.defaultno = FALSE;
+ if (cancel) /* cancel */
+ goto schememenu;
+ }
+
+ scheme = items[choice].name;
+ }
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, lg_name);
+ gctl_ro_param(r, "flags", -1, GPART_FLAGS);
+ gctl_ro_param(r, "scheme", -1, scheme);
+ gctl_ro_param(r, "verb", -1, "create");
+
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+ scheme = NULL;
+ goto schememenu;
+ }
+ gctl_free(r);
+
+ if (bootcode_path(scheme) != NULL)
+ get_part_metadata(lg_name, 1)->bootcode = 1;
+ return (0);
+}
+
+static void
+gpart_activate(struct gprovider *pp)
+{
+ struct gconfig *gc;
+ struct gctl_req *r;
+ const char *errstr, *scheme;
+ const char *attribute = NULL;
+ intmax_t idx;
+
+ /*
+ * Some partition schemes need this partition to be marked 'active'
+ * for it to be bootable.
+ */
+ LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "scheme") == 0) {
+ scheme = gc->lg_val;
+ break;
+ }
+ }
+
+ if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "EBR") == 0 ||
+ strcmp(scheme, "PC98") == 0)
+ attribute = "active";
+ else
+ return;
+
+ LIST_FOREACH(gc, &pp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "index") == 0) {
+ idx = atoi(gc->lg_val);
+ break;
+ }
+ }
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
+ gctl_ro_param(r, "verb", -1, "set");
+ gctl_ro_param(r, "attrib", -1, attribute);
+ gctl_ro_param(r, "index", sizeof(idx), &idx);
+
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0')
+ gpart_show_error("Error", "Error marking partition active:",
+ errstr);
+ gctl_free(r);
+}
+
+static void
+gpart_bootcode(struct ggeom *gp)
+{
+ const char *bootcode;
+ struct gconfig *gc;
+ struct gctl_req *r;
+ const char *errstr, *scheme;
+ uint8_t *boot;
+ size_t bootsize, bytes;
+ int bootfd;
+
+ /*
+ * Write default bootcode to the newly partitioned disk, if that
+ * applies on this platform.
+ */
+ LIST_FOREACH(gc, &gp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "scheme") == 0) {
+ scheme = gc->lg_val;
+ break;
+ }
+ }
+
+ bootcode = bootcode_path(scheme);
+ if (bootcode == NULL)
+ return;
+
+ bootfd = open(bootcode, O_RDONLY);
+ if (bootfd <= 0) {
+ dialog_msgbox("Bootcode Error", strerror(errno), 0, 0,
+ TRUE);
+ return;
+ }
+
+ bootsize = lseek(bootfd, 0, SEEK_END);
+ boot = malloc(bootsize);
+ lseek(bootfd, 0, SEEK_SET);
+ bytes = 0;
+ while (bytes < bootsize)
+ bytes += read(bootfd, boot + bytes, bootsize - bytes);
+ close(bootfd);
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, gp->lg_name);
+ gctl_ro_param(r, "verb", -1, "bootcode");
+ gctl_ro_param(r, "bootcode", bootsize, boot);
+
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0')
+ gpart_show_error("Bootcode Error", NULL, errstr);
+ gctl_free(r);
+ free(boot);
+}
+
+static void
+gpart_partcode(struct gprovider *pp)
+{
+ struct gconfig *gc;
+ const char *scheme;
+ const char *indexstr;
+ char message[255], command[255];
+
+ LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "scheme") == 0) {
+ scheme = gc->lg_val;
+ break;
+ }
+ }
+
+ /* Make sure this partition scheme needs partcode on this platform */
+ if (partcode_path(scheme) == NULL)
+ return;
+
+ LIST_FOREACH(gc, &pp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "index") == 0) {
+ indexstr = gc->lg_val;
+ break;
+ }
+ }
+
+ /* Shell out to gpart for partcode for now */
+ sprintf(command, "gpart bootcode -p %s -i %s %s",
+ partcode_path(scheme), indexstr, pp->lg_geom->lg_name);
+ if (system(command) != 0) {
+ sprintf(message, "Error installing partcode on partition %s",
+ pp->lg_name);
+ dialog_msgbox("Error", message, 0, 0, TRUE);
+ }
+}
+
+void
+gpart_destroy(struct ggeom *lg_geom, int force)
+{
+ struct gprovider *pp;
+ struct gctl_req *r;
+ const char *errstr;
+
+ /* Begin with the hosing: delete all partitions */
+ LIST_FOREACH(pp, &lg_geom->lg_provider, lg_provider)
+ gpart_delete(pp);
+
+ /* Now destroy the geom itself */
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
+ gctl_ro_param(r, "flags", -1, GPART_FLAGS);
+ gctl_ro_param(r, "verb", -1, "destroy");
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0')
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+
+ /* If asked, commit the change */
+ if (force) {
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
+ gctl_ro_param(r, "verb", -1, "commit");
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0')
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+ }
+
+ /* And any metadata associated with the partition scheme itself */
+ delete_part_metadata(lg_geom->lg_name);
+}
+
+void
+gpart_edit(struct gprovider *pp)
+{
+ struct gctl_req *r;
+ struct gconfig *gc;
+ struct gconsumer *cp;
+ struct ggeom *geom;
+ const char *errstr, *oldtype, *scheme;
+ struct partition_metadata *md;
+ char sizestr[32];
+ intmax_t idx;
+ int hadlabel, choice, junk, nitems;
+ unsigned i;
+
+ DIALOG_FORMITEM items[] = {
+ {0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0,
+ FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)",
+ FALSE},
+ {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0,
+ FALSE, "Partition size. Append K, M, G for kilobytes, "
+ "megabytes or gigabytes.", FALSE},
+ {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
+ FALSE, "Path at which to mount this partition (leave blank "
+ "for swap, set to / for root filesystem)", FALSE},
+ {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
+ "Partition name. Not all partition schemes support this.",
+ FALSE},
+ };
+
+ /*
+ * Find the PART geom we are manipulating. This may be a consumer of
+ * this provider, or its parent. Check the consumer case first.
+ */
+ geom = NULL;
+ LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
+ if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
+ char message[512];
+ /*
+ * The PART object is a consumer, so the user wants to
+ * edit the partition table. gpart doesn't really
+ * support this, so we have to hose the whole table
+ * first.
+ */
+
+ sprintf(message, "Changing the partition scheme on "
+ "this disk (%s) requires deleting all existing "
+ "partitions on this drive. This will PERMANENTLY "
+ "ERASE any data stored here. Are you sure you want "
+ "to proceed?", cp->lg_geom->lg_name);
+ dialog_vars.defaultno = TRUE;
+ choice = dialog_yesno("Warning", message, 0, 0);
+ dialog_vars.defaultno = FALSE;
+
+ if (choice == 1) /* cancel */
+ return;
+
+ /* Destroy the geom and all sub-partitions */
+ gpart_destroy(cp->lg_geom, 0);
+
+ /* Now re-partition and return */
+ gpart_partition(cp->lg_geom->lg_name, NULL);
+ return;
+ }
+
+ if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
+ geom = pp->lg_geom;
+
+ if (geom == NULL) {
+ /* Disk not partitioned, so partition it */
+ gpart_partition(pp->lg_geom->lg_name, NULL);
+ return;
+ }
+
+ LIST_FOREACH(gc, &geom->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "scheme") == 0) {
+ scheme = gc->lg_val;
+ break;
+ }
+ }
+
+ /* Labels only supported on GPT and APM */
+ if (strcmp(scheme, "GPT") == 0 || strcmp(scheme, "APM") == 0)
+ nitems = 4;
+ else
+ nitems = 3;
+
+ /* Edit editable parameters of a partition */
+ hadlabel = 0;
+ LIST_FOREACH(gc, &pp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "type") == 0) {
+ oldtype = gc->lg_val;
+ items[0].text = gc->lg_val;
+ }
+ if (strcmp(gc->lg_name, "label") == 0 && gc->lg_val != NULL) {
+ hadlabel = 1;
+ items[3].text = gc->lg_val;
+ }
+ if (strcmp(gc->lg_name, "index") == 0)
+ idx = atoi(gc->lg_val);
+ }
+
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->name != NULL && strcmp(md->name, pp->lg_name) == 0) {
+ if (md->fstab != NULL)
+ items[2].text = md->fstab->fs_file;
+ break;
+ }
+ }
+
+ humanize_number(sizestr, 7, pp->lg_mediasize, "B", HN_AUTOSCALE,
+ HN_NOSPACE | HN_DECIMAL);
+ items[1].text = sizestr;
+
+editpart:
+ choice = dlg_form("Edit Partition", "", 0, 0, 0, nitems, items, &junk);
+
+ if (choice) /* Cancel pressed */
+ return;
+
+ /* Check if the label has a / in it */
+ if (strchr(items[3].text, '/') != NULL) {
+ dialog_msgbox("Error", "Label contains a /, which is not an "
+ "allowed character.", 0, 0, TRUE);
+ goto editpart;
+ }
+
+ if (strncmp(items[0].text, "freebsd-", 8) != 0 &&
+ items[0].text[0] != '\0') {
+ char message[512];
+
+ sprintf(message, "Cannot mount unknown file system %s!\n",
+ items[0].text);
+ dialog_msgbox("Error", message, 0, 0, TRUE);
+ goto editpart;
+ }
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, geom->lg_name);
+ gctl_ro_param(r, "flags", -1, GPART_FLAGS);
+ gctl_ro_param(r, "verb", -1, "modify");
+ gctl_ro_param(r, "index", sizeof(idx), &idx);
+ if (hadlabel || items[3].text[0] != '\0')
+ gctl_ro_param(r, "label", -1, items[3].text);
+ gctl_ro_param(r, "type", -1, items[0].text);
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+ goto editpart;
+ }
+ gctl_free(r);
+
+ set_default_part_metadata(pp->lg_name, scheme, items[0].text,
+ items[2].text, strcmp(oldtype, items[0].text) != 0);
+
+ for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++)
+ if (items[i].text_free)
+ free(items[i].text);
+}
+
+void
+set_default_part_metadata(const char *name, const char *scheme,
+ const char *type, const char *mountpoint, int newfs)
+{
+ struct partition_metadata *md;
+
+ /* Set part metadata */
+ md = get_part_metadata(name, 1);
+
+ if (newfs) {
+ if (md->newfs != NULL) {
+ free(md->newfs);
+ md->newfs = NULL;
+ }
+
+ if (strcmp(type, "freebsd-ufs") == 0) {
+ md->newfs = malloc(255);
+ sprintf(md->newfs, "newfs /dev/%s", name);
+ }
+ }
+
+ if (strcmp(type, "freebsd-swap") == 0)
+ mountpoint = "none";
+ if (strcmp(type, "freebsd-boot") == 0)
+ md->bootcode = 1;
+
+ /* VTOC8 needs partcode in UFS partitions */
+ if (strcmp(scheme, "VTOC8") == 0 && strcmp(type, "freebsd-ufs") == 0)
+ md->bootcode = 1;
+
+ if (mountpoint == NULL || mountpoint[0] == '\0') {
+ if (md->fstab != NULL) {
+ free(md->fstab->fs_spec);
+ free(md->fstab->fs_file);
+ free(md->fstab->fs_vfstype);
+ free(md->fstab->fs_mntops);
+ free(md->fstab->fs_type);
+ free(md->fstab);
+ md->fstab = NULL;
+ }
+ } else {
+ if (md->fstab == NULL) {
+ md->fstab = malloc(sizeof(struct fstab));
+ } else {
+ free(md->fstab->fs_spec);
+ free(md->fstab->fs_file);
+ free(md->fstab->fs_vfstype);
+ free(md->fstab->fs_mntops);
+ free(md->fstab->fs_type);
+ }
+ md->fstab->fs_spec = malloc(strlen(name) + 6);
+ sprintf(md->fstab->fs_spec, "/dev/%s", name);
+ md->fstab->fs_file = strdup(mountpoint);
+ /* Get VFS from text after freebsd-, if possible */
+ if (strncmp("freebsd-", type, 8))
+ md->fstab->fs_vfstype = strdup(&type[8]);
+ else
+ md->fstab->fs_vfstype = strdup(type); /* Guess */
+ md->fstab->fs_vfstype = strdup(&type[8]);
+ if (strcmp(type, "freebsd-swap") == 0) {
+ md->fstab->fs_type = strdup(FSTAB_SW);
+ md->fstab->fs_freq = 0;
+ md->fstab->fs_passno = 0;
+ } else {
+ md->fstab->fs_type = strdup(FSTAB_RW);
+ if (strcmp(mountpoint, "/") == 0) {
+ md->fstab->fs_freq = 1;
+ md->fstab->fs_passno = 1;
+ } else {
+ md->fstab->fs_freq = 2;
+ md->fstab->fs_passno = 2;
+ }
+ }
+ md->fstab->fs_mntops = strdup(md->fstab->fs_type);
+ }
+}
+
+static
+int part_compare(const void *xa, const void *xb)
+{
+ struct gprovider **a = (struct gprovider **)xa;
+ struct gprovider **b = (struct gprovider **)xb;
+ intmax_t astart, bstart;
+ struct gconfig *gc;
+
+ astart = bstart = 0;
+ LIST_FOREACH(gc, &(*a)->lg_config, lg_config)
+ if (strcmp(gc->lg_name, "start") == 0) {
+ astart = strtoimax(gc->lg_val, NULL, 0);
+ break;
+ }
+ LIST_FOREACH(gc, &(*b)->lg_config, lg_config)
+ if (strcmp(gc->lg_name, "start") == 0) {
+ bstart = strtoimax(gc->lg_val, NULL, 0);
+ break;
+ }
+
+ if (astart < bstart)
+ return -1;
+ else if (astart > bstart)
+ return 1;
+ else
+ return 0;
+}
+
+intmax_t
+gpart_max_free(struct ggeom *geom, intmax_t *npartstart)
+{
+ struct gconfig *gc;
+ struct gprovider *pp, **providers;
+ intmax_t lastend;
+ intmax_t start, end;
+ intmax_t maxsize, maxstart;
+ intmax_t partstart, partend;
+ int i, nparts;
+
+ /* Now get the maximum free size and free start */
+ start = end = 0;
+ LIST_FOREACH(gc, &geom->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "first") == 0)
+ start = strtoimax(gc->lg_val, NULL, 0);
+ if (strcmp(gc->lg_name, "last") == 0)
+ end = strtoimax(gc->lg_val, NULL, 0);
+ }
+
+ i = nparts = 0;
+ LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
+ nparts++;
+ providers = calloc(nparts, sizeof(providers[0]));
+ LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
+ providers[i++] = pp;
+ qsort(providers, nparts, sizeof(providers[0]), part_compare);
+
+ lastend = start - 1;
+ maxsize = 0;
+ for (i = 0; i < nparts; i++) {
+ pp = providers[i];
+
+ LIST_FOREACH(gc, &pp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "start") == 0)
+ partstart = strtoimax(gc->lg_val, NULL, 0);
+ if (strcmp(gc->lg_name, "end") == 0)
+ partend = strtoimax(gc->lg_val, NULL, 0);
+ }
+
+ if (partstart - lastend > maxsize) {
+ maxsize = partstart - lastend - 1;
+ maxstart = lastend + 1;
+ }
+
+ lastend = partend;
+ }
+
+ if (end - lastend > maxsize) {
+ maxsize = end - lastend - 1;
+ maxstart = lastend + 1;
+ }
+
+ pp = LIST_FIRST(&geom->lg_consumer)->lg_provider;
+
+ /* Compute beginning of new partition and maximum available space */
+ if (pp->lg_stripesize > 0 &&
+ (maxstart*pp->lg_sectorsize % pp->lg_stripesize) != 0) {
+ intmax_t offset = (pp->lg_stripesize -
+ ((maxstart*pp->lg_sectorsize) % pp->lg_stripesize)) /
+ pp->lg_sectorsize;
+ maxstart += offset;
+ maxsize -= offset;
+ }
+
+ if (npartstart != NULL)
+ *npartstart = maxstart;
+
+ return (maxsize);
+}
+
+void
+gpart_create(struct gprovider *pp, char *default_type, char *default_size,
+ char *default_mountpoint, char **partname, int interactive)
+{
+ struct gctl_req *r;
+ struct gconfig *gc;
+ struct gconsumer *cp;
+ struct ggeom *geom;
+ const char *errstr, *scheme;
+ char sizestr[32], startstr[32], output[64];
+ intmax_t maxsize, size, sector, firstfree, stripe;
+ uint64_t bytes;
+ int nitems, choice, junk;
+ unsigned i;
+
+ DIALOG_FORMITEM items[] = {
+ {0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0,
+ FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)",
+ FALSE},
+ {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0,
+ FALSE, "Partition size. Append K, M, G for kilobytes, "
+ "megabytes or gigabytes.", FALSE},
+ {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
+ FALSE, "Path at which to mount partition (blank for "
+ "swap, / for root filesystem)", FALSE},
+ {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
+ "Partition name. Not all partition schemes support this.",
+ FALSE},
+ };
+
+ if (partname != NULL)
+ *partname = NULL;
+
+ /* Record sector and stripe sizes */
+ sector = pp->lg_sectorsize;
+ stripe = pp->lg_stripesize;
+
+ /*
+ * Find the PART geom we are manipulating. This may be a consumer of
+ * this provider, or its parent. Check the consumer case first.
+ */
+ geom = NULL;
+ LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
+ if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
+ geom = cp->lg_geom;
+ break;
+ }
+
+ if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
+ geom = pp->lg_geom;
+
+ /* Now get the partition scheme */
+ scheme = NULL;
+ if (geom != NULL) {
+ LIST_FOREACH(gc, &geom->lg_config, lg_config)
+ if (strcmp(gc->lg_name, "scheme") == 0)
+ scheme = gc->lg_val;
+ }
+
+ if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) {
+ if (gpart_partition(pp->lg_geom->lg_name, NULL) == 0)
+ dialog_msgbox("",
+ "The partition table has been successfully created."
+ " Please press Create again to create partitions.",
+ 0, 0, TRUE);
+
+ return;
+ }
+
+ /*
+ * If we still don't have a geom, either the user has
+ * canceled partitioning or there has been an error which has already
+ * been displayed, so bail.
+ */
+ if (geom == NULL)
+ return;
+
+ maxsize = size = gpart_max_free(geom, &firstfree);
+ if (size <= 0) {
+ dialog_msgbox("Error", "No free space left on device.", 0, 0,
+ TRUE);
+ return;
+ }
+
+ humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE,
+ HN_NOSPACE | HN_DECIMAL);
+ items[1].text = sizestr;
+
+ /* Special-case the MBR default type for nested partitions */
+ if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "PC98") == 0)
+ items[0].text = "freebsd";
+
+ /* Labels only supported on GPT and APM */
+ if (strcmp(scheme, "GPT") == 0 || strcmp(scheme, "APM") == 0)
+ nitems = 4;
+ else
+ nitems = 3;
+
+ if (default_type != NULL)
+ items[0].text = default_type;
+ if (default_size != NULL)
+ items[1].text = default_size;
+ if (default_mountpoint != NULL)
+ items[2].text = default_mountpoint;
+
+addpartform:
+ if (interactive) {
+ choice = dlg_form("Add Partition", "", 0, 0, 0, nitems,
+ items, &junk);
+ if (choice) /* Cancel pressed */
+ return;
+ }
+
+ size = maxsize;
+ if (strlen(items[1].text) > 0) {
+ if (expand_number(items[1].text, &bytes) != 0) {
+ char error[512];
+
+ sprintf(error, "Invalid size: %s\n", strerror(errno));
+ dialog_msgbox("Error", error, 0, 0, TRUE);
+ goto addpartform;
+ }
+ size = MIN((intmax_t)(bytes/sector), maxsize);
+ }
+
+ /* Check if the label has a / in it */
+ if (strchr(items[3].text, '/') != NULL) {
+ dialog_msgbox("Error", "Label contains a /, which is not an "
+ "allowed character.", 0, 0, TRUE);
+ goto addpartform;
+ }
+
+ /* Warn if no mountpoint set */
+ if (strcmp(items[0].text, "freebsd-ufs") == 0 &&
+ items[2].text[0] != '/') {
+ dialog_vars.defaultno = TRUE;
+ choice = dialog_yesno("Warning",
+ "This partition does not have a valid mountpoint "
+ "(for the partition from which you intend to boot the "
+ "operating system, the mountpoint should be /). Are you "
+ "sure you want to continue?"
+ , 0, 0);
+ dialog_vars.defaultno = FALSE;
+ if (choice == 1) /* cancel */
+ goto addpartform;
+ }
+
+ /* If this is the root partition, check that this scheme is bootable */
+ if (strcmp(items[2].text, "/") == 0 && !is_scheme_bootable(scheme)) {
+ char message[512];
+ sprintf(message, "This partition scheme (%s) is not bootable "
+ "on this platform. Are you sure you want to proceed?",
+ scheme);
+ dialog_vars.defaultno = TRUE;
+ choice = dialog_yesno("Warning", message, 0, 0);
+ dialog_vars.defaultno = FALSE;
+ if (choice == 1) /* cancel */
+ goto addpartform;
+ }
+
+ /*
+ * If this is the root partition, and we need a boot partition, ask
+ * the user to add one.
+ */
+ if (strcmp(items[2].text, "/") == 0 && bootpart_size(scheme) > 0) {
+ if (interactive)
+ choice = dialog_yesno("Boot Partition",
+ "This partition scheme requires a boot partition "
+ "for the disk to be bootable. Would you like to "
+ "make one now?", 0, 0);
+ else
+ choice = 0;
+
+ if (choice == 0) { /* yes */
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, geom->lg_name);
+ gctl_ro_param(r, "flags", -1, GPART_FLAGS);
+ gctl_ro_param(r, "verb", -1, "add");
+ gctl_ro_param(r, "type", -1, "freebsd-boot");
+ snprintf(sizestr, sizeof(sizestr), "%jd",
+ bootpart_size(scheme) / sector);
+ gctl_ro_param(r, "size", -1, sizestr);
+ snprintf(startstr, sizeof(startstr), "%jd", firstfree);
+ gctl_ro_param(r, "start", -1, startstr);
+ gctl_rw_param(r, "output", sizeof(output), output);
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0')
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+
+ get_part_metadata(strtok(output, " "), 1)->bootcode = 1;
+
+ /* Now adjust the part we are really adding forward */
+ firstfree += bootpart_size(scheme) / sector;
+ size -= (bootpart_size(scheme) + stripe)/sector;
+ if (stripe > 0 && (firstfree*sector % stripe) != 0)
+ firstfree += (stripe - ((firstfree*sector) %
+ stripe)) / sector;
+ }
+ }
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, geom->lg_name);
+ gctl_ro_param(r, "flags", -1, GPART_FLAGS);
+ gctl_ro_param(r, "verb", -1, "add");
+
+ gctl_ro_param(r, "type", -1, items[0].text);
+ snprintf(sizestr, sizeof(sizestr), "%jd", size);
+ gctl_ro_param(r, "size", -1, sizestr);
+ snprintf(startstr, sizeof(startstr), "%jd", firstfree);
+ gctl_ro_param(r, "start", -1, startstr);
+ if (items[3].text[0] != '\0')
+ gctl_ro_param(r, "label", -1, items[3].text);
+ gctl_rw_param(r, "output", sizeof(output), output);
+
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+ goto addpartform;
+ }
+
+ if (strcmp(items[0].text, "freebsd-boot") == 0)
+ get_part_metadata(strtok(output, " "), 1)->bootcode = 1;
+ else if (strcmp(items[0].text, "freebsd") == 0)
+ gpart_partition(strtok(output, " "), "BSD");
+ else
+ set_default_part_metadata(strtok(output, " "), scheme,
+ items[0].text, items[2].text, 1);
+
+ for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++)
+ if (items[i].text_free)
+ free(items[i].text);
+ gctl_free(r);
+
+ if (partname != NULL)
+ *partname = strdup(strtok(output, " "));
+}
+
+void
+gpart_delete(struct gprovider *pp)
+{
+ struct gconfig *gc;
+ struct ggeom *geom;
+ struct gconsumer *cp;
+ struct gctl_req *r;
+ const char *errstr;
+ intmax_t idx;
+ int choice, is_partition;
+
+ /* Is it a partition? */
+ is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0);
+
+ /* Find out if this is the root of a gpart geom */
+ geom = NULL;
+ LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
+ if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
+ geom = cp->lg_geom;
+ break;
+ }
+
+ /* Destroy all consumers */
+ if (geom != NULL) {
+ if (is_partition) {
+ char message[512];
+ /*
+ * We have to actually really delete the sub-partition
+ * tree so that the consumers will go away and the
+ * partition can be deleted. Warn the user.
+ */
+
+ sprintf(message, "Deleting this partition (%s) "
+ "requires deleting all existing sub-partitions. "
+ "This will PERMANENTLY ERASE any data stored here "
+ "and CANNOT BE REVERTED. Are you sure you want to "
+ "proceed?", cp->lg_geom->lg_name);
+ dialog_vars.defaultno = TRUE;
+ choice = dialog_yesno("Warning", message, 0, 0);
+ dialog_vars.defaultno = FALSE;
+
+ if (choice == 1) /* cancel */
+ return;
+ }
+
+ gpart_destroy(geom, is_partition);
+ }
+
+ /*
+ * If this is not a partition, see if that is a problem, complain if
+ * necessary, and return always, since we need not do anything further,
+ * error or no.
+ */
+ if (!is_partition) {
+ if (geom == NULL)
+ dialog_msgbox("Error",
+ "Only partitions can be deleted.", 0, 0, TRUE);
+ return;
+ }
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name);
+ gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
+ gctl_ro_param(r, "flags", -1, GPART_FLAGS);
+ gctl_ro_param(r, "verb", -1, "delete");
+
+ LIST_FOREACH(gc, &pp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "index") == 0) {
+ idx = atoi(gc->lg_val);
+ gctl_ro_param(r, "index", sizeof(idx), &idx);
+ break;
+ }
+ }
+
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+ return;
+ }
+
+ gctl_free(r);
+
+ delete_part_metadata(pp->lg_name);
+}
+
+void
+gpart_revert_all(struct gmesh *mesh)
+{
+ struct gclass *classp;
+ struct gconfig *gc;
+ struct ggeom *gp;
+ struct gctl_req *r;
+ const char *errstr;
+ const char *modified;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+ if (strcmp(classp->lg_name, "PART") == 0)
+ break;
+ }
+
+ if (strcmp(classp->lg_name, "PART") != 0) {
+ dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
+ return;
+ }
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+ modified = "true"; /* XXX: If we don't know (kernel too old),
+ * assume there are modifications. */
+ LIST_FOREACH(gc, &gp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "modified") == 0) {
+ modified = gc->lg_val;
+ break;
+ }
+ }
+
+ if (strcmp(modified, "false") == 0)
+ continue;
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, gp->lg_name);
+ gctl_ro_param(r, "verb", -1, "undo");
+
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0')
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+ }
+}
+
+void
+gpart_commit(struct gmesh *mesh)
+{
+ struct partition_metadata *md;
+ struct gclass *classp;
+ struct ggeom *gp;
+ struct gconfig *gc;
+ struct gconsumer *cp;
+ struct gprovider *pp;
+ struct gctl_req *r;
+ const char *errstr;
+ const char *modified;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+ if (strcmp(classp->lg_name, "PART") == 0)
+ break;
+ }
+
+ if (strcmp(classp->lg_name, "PART") != 0) {
+ dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
+ return;
+ }
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+ modified = "true"; /* XXX: If we don't know (kernel too old),
+ * assume there are modifications. */
+ LIST_FOREACH(gc, &gp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "modified") == 0) {
+ modified = gc->lg_val;
+ break;
+ }
+ }
+
+ if (strcmp(modified, "false") == 0)
+ continue;
+
+ /* Add bootcode if necessary, before the commit */
+ md = get_part_metadata(gp->lg_name, 0);
+ if (md != NULL && md->bootcode)
+ gpart_bootcode(gp);
+
+ /* Now install partcode on its partitions, if necessary */
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ md = get_part_metadata(pp->lg_name, 0);
+ if (md == NULL || !md->bootcode)
+ continue;
+
+ /* Mark this partition active if that's required */
+ gpart_activate(pp);
+
+ /* Check if the partition has sub-partitions */
+ LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
+ if (strcmp(cp->lg_geom->lg_class->lg_name,
+ "PART") == 0)
+ break;
+
+ if (cp == NULL) /* No sub-partitions */
+ gpart_partcode(pp);
+ }
+
+ r = gctl_get_handle();
+ gctl_ro_param(r, "class", -1, "PART");
+ gctl_ro_param(r, "arg0", -1, gp->lg_name);
+ gctl_ro_param(r, "verb", -1, "commit");
+
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0')
+ gpart_show_error("Error", NULL, errstr);
+ gctl_free(r);
+ }
+}
+
diff --git a/usr.sbin/bsdinstall/partedit/part_wizard.c b/usr.sbin/bsdinstall/partedit/part_wizard.c
new file mode 100644
index 0000000..e18293a
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/part_wizard.c
@@ -0,0 +1,344 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <sys/param.h>
+#include <errno.h>
+#include <libutil.h>
+#include <inttypes.h>
+
+#include <libgeom.h>
+#include <dialog.h>
+#include <dlg_keys.h>
+
+#include "partedit.h"
+
+#define MIN_FREE_SPACE (1024*1024*1024) /* 1 GB */
+#define SWAP_SIZE(available) MIN(available/20, 4*1024*1024*1024LL)
+
+static char *boot_disk(struct gmesh *mesh);
+static char *wizard_partition(struct gmesh *mesh, const char *disk);
+static int wizard_makeparts(struct gmesh *mesh, const char *disk);
+
+int
+part_wizard(void) {
+ int error;
+ struct gmesh mesh;
+ char *disk, *schemeroot;
+
+startwizard:
+ error = geom_gettree(&mesh);
+
+ dlg_put_backtitle();
+ error = geom_gettree(&mesh);
+ disk = boot_disk(&mesh);
+ if (disk == NULL)
+ return (1);
+
+ dlg_clear();
+ dlg_put_backtitle();
+ schemeroot = wizard_partition(&mesh, disk);
+ free(disk);
+ if (schemeroot == NULL)
+ return (1);
+
+ geom_deletetree(&mesh);
+ dlg_clear();
+ dlg_put_backtitle();
+ error = geom_gettree(&mesh);
+
+ error = wizard_makeparts(&mesh, schemeroot);
+ if (error)
+ goto startwizard;
+ free(schemeroot);
+
+ geom_deletetree(&mesh);
+
+ return (0);
+}
+
+static char *
+boot_disk(struct gmesh *mesh)
+{
+ struct gclass *classp;
+ struct gconfig *gc;
+ struct ggeom *gp;
+ struct gprovider *pp;
+ DIALOG_LISTITEM *disks = NULL;
+ const char *type;
+ char diskdesc[512];
+ char *chosen;
+ int i, err, selected, n = 0;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+ if (strcmp(classp->lg_name, "DISK") != 0 &&
+ strcmp(classp->lg_name, "MD") != 0)
+ continue;
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+ if (LIST_EMPTY(&gp->lg_provider))
+ continue;
+
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ type = NULL;
+ LIST_FOREACH(gc, &pp->lg_config, lg_config)
+ if (strcmp(gc->lg_name, "type") == 0)
+ type = gc->lg_val;
+
+ /* Skip swap-backed md devices */
+ if (strcmp(classp->lg_name, "MD") == 0 &&
+ type != NULL && strcmp(type, "swap") == 0)
+ continue;
+
+ disks = realloc(disks, (++n)*sizeof(disks[0]));
+ disks[n-1].name = pp->lg_name;
+ humanize_number(diskdesc, 7, pp->lg_mediasize,
+ "B", HN_AUTOSCALE, HN_DECIMAL);
+ if (strncmp(pp->lg_name, "ad", 2) == 0)
+ strcat(diskdesc, " ATA Hard Disk");
+ else if (strncmp(pp->lg_name, "da", 2) == 0)
+ strcat(diskdesc, " SCSI Hard Disk");
+ else if (strncmp(pp->lg_name, "md", 2) == 0)
+ strcat(diskdesc, " Memory Disk");
+ else if (strncmp(pp->lg_name, "cd", 2) == 0) {
+ n--;
+ continue;
+ }
+ disks[n-1].text = strdup(diskdesc);
+ disks[n-1].help = NULL;
+ disks[n-1].state = 0;
+ }
+ }
+ }
+
+ if (n > 1) {
+ err = dlg_menu("Partitioning",
+ "Select the disk on which to install FreeBSD.", 0, 0, 0,
+ n, disks, &selected, NULL);
+
+ chosen = (err == 0) ? strdup(disks[selected].name) : NULL;
+ } else if (n == 1) {
+ chosen = strdup(disks[0].name);
+ } else {
+ chosen = NULL;
+ }
+
+ for (i = 0; i < n; i++)
+ free(disks[i].text);
+
+ return (chosen);
+}
+
+static struct gprovider *
+provider_for_name(struct gmesh *mesh, const char *name)
+{
+ struct gclass *classp;
+ struct gprovider *pp = NULL;
+ struct ggeom *gp;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+ if (strcmp(classp->lg_name, "DISK") != 0 &&
+ strcmp(classp->lg_name, "PART") != 0 &&
+ strcmp(classp->lg_name, "MD") != 0)
+ continue;
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+ if (LIST_EMPTY(&gp->lg_provider))
+ continue;
+
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider)
+ if (strcmp(pp->lg_name, name) == 0)
+ break;
+
+ if (pp != NULL) break;
+ }
+
+ if (pp != NULL) break;
+ }
+
+ return (pp);
+}
+
+static char *
+wizard_partition(struct gmesh *mesh, const char *disk)
+{
+ struct gclass *classp;
+ struct ggeom *gpart = NULL;
+ struct gconfig *gc;
+ char message[512];
+ const char *scheme = NULL;
+ char *retval = NULL;
+ int choice;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class)
+ if (strcmp(classp->lg_name, "PART") == 0)
+ break;
+
+ if (classp != NULL) {
+ LIST_FOREACH(gpart, &classp->lg_geom, lg_geom)
+ if (strcmp(gpart->lg_name, disk) == 0)
+ break;
+ }
+
+ if (gpart != NULL) {
+ LIST_FOREACH(gc, &gpart->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "scheme") == 0) {
+ scheme = gc->lg_val;
+ break;
+ }
+ }
+ }
+
+query:
+ dialog_vars.yes_label = "Entire Disk";
+ dialog_vars.no_label = "Partition";
+ if (gpart != NULL)
+ dialog_vars.defaultno = TRUE;
+
+ snprintf(message, sizeof(message), "Would you like to use this entire "
+ "disk (%s) for FreeBSD or partition it to share it with other "
+ "operating systems? Using the entire disk will erase any data "
+ "currently stored there.", disk);
+ choice = dialog_yesno("Partition", message, 0, 0);
+
+ dialog_vars.yes_label = NULL;
+ dialog_vars.no_label = NULL;
+ dialog_vars.defaultno = FALSE;
+
+ if (choice == 1 && scheme != NULL && !is_scheme_bootable(scheme)) {
+ char warning[512];
+ int subchoice;
+
+ sprintf(warning, "The existing partition scheme on this "
+ "disk (%s) is not bootable on this platform. To install "
+ "FreeBSD, it must be repartitioned. This will destroy all "
+ "data on the disk. Are you sure you want to proceed?",
+ scheme);
+ subchoice = dialog_yesno("Non-bootable Disk", warning, 0, 0);
+ if (subchoice != 0)
+ goto query;
+
+ gpart_destroy(gpart, 1);
+ gpart_partition(disk, default_scheme());
+ scheme = default_scheme();
+ }
+
+ if (scheme == NULL || strcmp(scheme, "(none)") == 0 || choice == 0) {
+ if (gpart != NULL) { /* Erase partitioned disk */
+ choice = dialog_yesno("Confirmation", "This will erase "
+ "the disk. Are you sure you want to proceed?", 0, 0);
+ if (choice != 0)
+ goto query;
+
+ gpart_destroy(gpart, 1);
+ }
+
+ gpart_partition(disk, default_scheme());
+ scheme = default_scheme();
+ }
+
+ if (strcmp(scheme, "PC98") == 0 || strcmp(scheme, "MBR") == 0) {
+ struct gmesh submesh;
+ geom_gettree(&submesh);
+ gpart_create(provider_for_name(&submesh, disk),
+ "freebsd", NULL, NULL, &retval,
+ choice /* Non-interactive for "Entire Disk" */);
+ geom_deletetree(&submesh);
+ } else {
+ retval = strdup(disk);
+ }
+
+ return (retval);
+}
+
+static int
+wizard_makeparts(struct gmesh *mesh, const char *disk)
+{
+ struct gmesh submesh;
+ struct gclass *classp;
+ struct ggeom *gp;
+ struct gconfig *gc;
+ const char *scheme;
+ struct gprovider *pp;
+ intmax_t swapsize, available;
+ char swapsizestr[10], rootsizestr[10];
+ int retval;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class)
+ if (strcmp(classp->lg_name, "PART") == 0)
+ break;
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
+ if (strcmp(gp->lg_name, disk) == 0)
+ break;
+
+ LIST_FOREACH(gc, &gp->lg_config, lg_config)
+ if (strcmp(gc->lg_name, "scheme") == 0)
+ scheme = gc->lg_val;
+
+ pp = provider_for_name(mesh, disk);
+
+ available = gpart_max_free(gp, NULL)*pp->lg_sectorsize;
+ if (available < MIN_FREE_SPACE) {
+ char availablestr[10], neededstr[10], message[512];
+ humanize_number(availablestr, 7, available, "B", HN_AUTOSCALE,
+ HN_DECIMAL);
+ humanize_number(neededstr, 7, MIN_FREE_SPACE, "B", HN_AUTOSCALE,
+ HN_DECIMAL);
+ sprintf(message, "There is not enough free space on %s to "
+ "install FreeBSD (%s free, %s required). Would you like "
+ "to choose another disk or to open the partition editor?",
+ disk, availablestr, neededstr);
+
+ dialog_vars.yes_label = "Another Disk";
+ dialog_vars.no_label = "Editor";
+ retval = dialog_yesno("Warning", message, 0, 0);
+ dialog_vars.yes_label = NULL;
+ dialog_vars.no_label = NULL;
+
+ return (!retval); /* Editor -> return 0 */
+ }
+
+ swapsize = SWAP_SIZE(available);
+ humanize_number(swapsizestr, 7, swapsize, "B", HN_AUTOSCALE,
+ HN_NOSPACE | HN_DECIMAL);
+ humanize_number(rootsizestr, 7, available - swapsize - 1024*1024,
+ "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL);
+
+ geom_gettree(&submesh);
+ pp = provider_for_name(&submesh, disk);
+ gpart_create(pp, "freebsd-ufs", rootsizestr, "/", NULL, 0);
+ geom_deletetree(&submesh);
+
+ geom_gettree(&submesh);
+ pp = provider_for_name(&submesh, disk);
+ gpart_create(pp, "freebsd-swap", swapsizestr, NULL, NULL, 0);
+ geom_deletetree(&submesh);
+
+ return (0);
+}
+
diff --git a/usr.sbin/bsdinstall/partedit/partedit.c b/usr.sbin/bsdinstall/partedit/partedit.c
new file mode 100644
index 0000000..cb3c018
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/partedit.c
@@ -0,0 +1,445 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <sys/param.h>
+#include <libgen.h>
+#include <libutil.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include <fstab.h>
+#include <libgeom.h>
+#include <dialog.h>
+#include <dlg_keys.h>
+
+#include "diskeditor.h"
+#include "partedit.h"
+
+struct pmetadata_head part_metadata;
+
+static int apply_changes(struct gmesh *mesh);
+static struct partedit_item *read_geom_mesh(struct gmesh *mesh, int *nitems);
+static void add_geom_children(struct ggeom *gp, int recurse,
+ struct partedit_item **items, int *nitems);
+static void init_fstab_metadata(void);
+static void get_mount_points(struct partedit_item *items, int nitems);
+static int validate_setup(void);
+
+int
+main(int argc, const char **argv) {
+ struct partition_metadata *md;
+ const char *prompt;
+ struct partedit_item *items;
+ struct gmesh mesh;
+ int i, op, nitems, nscroll;
+ int error;
+
+ TAILQ_INIT(&part_metadata);
+
+ init_fstab_metadata();
+
+ init_dialog(stdin, stdout);
+ if (strcmp(basename(argv[0]), "sade") != 0)
+ dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
+ dialog_vars.item_help = TRUE;
+ nscroll = i = 0;
+
+ if (strcmp(basename(argv[0]), "autopart") == 0) { /* Guided */
+ prompt = "Please review the disk setup. When complete, press "
+ "the Exit button.";
+ part_wizard();
+ } else {
+ prompt = "Create partitions for FreeBSD. No changes will be "
+ "made until you select Exit.";
+ }
+
+ /* Show the part editor either immediately, or to confirm wizard */
+ while (1) {
+ error = geom_gettree(&mesh);
+ items = read_geom_mesh(&mesh, &nitems);
+ get_mount_points(items, nitems);
+ dlg_clear();
+ dlg_put_backtitle();
+
+ if (i >= nitems)
+ i = nitems - 1;
+ op = diskeditor_show("Partition Editor", prompt,
+ items, nitems, &i, &nscroll);
+
+ switch (op) {
+ case 0: /* Create */
+ gpart_create((struct gprovider *)(items[i].cookie),
+ NULL, NULL, NULL, NULL, 1);
+ break;
+ case 1: /* Delete */
+ gpart_delete((struct gprovider *)(items[i].cookie));
+ break;
+ case 2: /* Modify */
+ gpart_edit((struct gprovider *)(items[i].cookie));
+ break;
+ case 3: /* Revert */
+ gpart_revert_all(&mesh);
+ while ((md = TAILQ_FIRST(&part_metadata)) != NULL) {
+ if (md->fstab != NULL) {
+ free(md->fstab->fs_spec);
+ free(md->fstab->fs_file);
+ free(md->fstab->fs_vfstype);
+ free(md->fstab->fs_mntops);
+ free(md->fstab->fs_type);
+ free(md->fstab);
+ }
+ if (md->newfs != NULL)
+ free(md->newfs);
+ free(md->name);
+
+ TAILQ_REMOVE(&part_metadata, md, metadata);
+ free(md);
+ }
+ init_fstab_metadata();
+ break;
+ case 4: /* Auto */
+ part_wizard();
+ break;
+ }
+
+ error = 0;
+ if (op == 5 && validate_setup()) { /* Finished */
+ dialog_vars.extra_button = TRUE;
+ dialog_vars.extra_label =
+ __DECONST(char *, "Abort");
+ dialog_vars.ok_label = __DECONST(char *, "Save");
+ op = dialog_yesno("Confirmation", "Your changes will "
+ "now be written to disk. If you have chosen to "
+ "overwrite existing data, it will be PERMANENTLY "
+ "ERASED. Are you sure you want to proceed?", 0, 0);
+ dialog_vars.extra_button = FALSE;
+ dialog_vars.ok_label = NULL;
+
+ if (op == 0) { /* Save */
+ error = apply_changes(&mesh);
+ break;
+ } else if (op == 3) { /* Don't save => Quit */
+ gpart_revert_all(&mesh);
+ error = -1;
+ break;
+ }
+ }
+
+ geom_deletetree(&mesh);
+ free(items);
+ }
+
+
+ geom_deletetree(&mesh);
+ free(items);
+ end_dialog();
+
+ return (error);
+}
+
+struct partition_metadata *
+get_part_metadata(const char *name, int create)
+{
+ struct partition_metadata *md;
+
+ TAILQ_FOREACH(md, &part_metadata, metadata)
+ if (md->name != NULL && strcmp(md->name, name) == 0)
+ break;
+
+ if (md == NULL && create) {
+ md = calloc(1, sizeof(*md));
+ md->name = strdup(name);
+ TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
+ }
+
+ return (md);
+}
+
+void
+delete_part_metadata(const char *name) {
+ struct partition_metadata *md;
+
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->name != NULL && strcmp(md->name, name) == 0) {
+ if (md->fstab != NULL) {
+ free(md->fstab->fs_spec);
+ free(md->fstab->fs_file);
+ free(md->fstab->fs_vfstype);
+ free(md->fstab->fs_mntops);
+ free(md->fstab->fs_type);
+ free(md->fstab);
+ }
+ if (md->newfs != NULL)
+ free(md->newfs);
+ free(md->name);
+
+ TAILQ_REMOVE(&part_metadata, md, metadata);
+ free(md);
+ break;
+ }
+ }
+}
+
+static int
+validate_setup(void)
+{
+ struct partition_metadata *md;
+ int root_found = FALSE;
+
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0)
+ root_found = TRUE;
+
+ /* XXX: Check for duplicate mountpoints */
+ }
+
+ if (!root_found) {
+ dialog_msgbox("Error", "No root partition was found. "
+ "The root FreeBSD partition must have a mountpoint of '/'.",
+ 0, 0, TRUE);
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+static int
+apply_changes(struct gmesh *mesh)
+{
+ struct partition_metadata *md;
+ char message[512];
+ int i, nitems, error;
+ const char **items;
+ const char *fstab_path;
+ FILE *fstab;
+
+ nitems = 1; /* Partition table changes */
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->newfs != NULL)
+ nitems++;
+ }
+ items = calloc(nitems * 2, sizeof(const char *));
+ items[0] = "Writing partition tables";
+ items[1] = "7"; /* In progress */
+ i = 1;
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->newfs != NULL) {
+ char *item;
+ item = malloc(255);
+ sprintf(item, "Initializing %s", md->name);
+ items[i*2] = item;
+ items[i*2 + 1] = "Pending";
+ i++;
+ }
+ }
+
+ i = 0;
+ dialog_mixedgauge("Initializing",
+ "Initializing file systems. Please wait.", 0, 0, i*100/nitems,
+ nitems, __DECONST(char **, items));
+ gpart_commit(mesh);
+ items[i*2 + 1] = "3";
+ i++;
+
+ if (getenv("BSDINSTALL_LOG") == NULL)
+ setenv("BSDINSTALL_LOG", "/dev/null", 1);
+
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->newfs != NULL) {
+ items[i*2 + 1] = "7"; /* In progress */
+ dialog_mixedgauge("Initializing",
+ "Initializing file systems. Please wait.", 0, 0,
+ i*100/nitems, nitems, __DECONST(char **, items));
+ sprintf(message, "(echo %s; %s) >>%s 2>>%s",
+ md->newfs, md->newfs, getenv("BSDINSTALL_LOG"),
+ getenv("BSDINSTALL_LOG"));
+ error = system(message);
+ items[i*2 + 1] = (error == 0) ? "3" : "1";
+ i++;
+ }
+ }
+ dialog_mixedgauge("Initializing",
+ "Initializing file systems. Please wait.", 0, 0,
+ i*100/nitems, nitems, __DECONST(char **, items));
+
+ for (i = 1; i < nitems; i++)
+ free(__DECONST(char *, items[i*2]));
+ free(items);
+
+ if (getenv("PATH_FSTAB") != NULL)
+ fstab_path = getenv("PATH_FSTAB");
+ else
+ fstab_path = "/etc/fstab";
+ fstab = fopen(fstab_path, "w+");
+ if (fstab == NULL) {
+ sprintf(message, "Cannot open fstab file %s for writing (%s)\n",
+ getenv("PATH_FSTAB"), strerror(errno));
+ dialog_msgbox("Error", message, 0, 0, TRUE);
+ return (-1);
+ }
+ fprintf(fstab, "# Device\tMountpoint\tFStype\tOptions\tDump\tPass#\n");
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->fstab != NULL)
+ fprintf(fstab, "%s\t%s\t%s\t%s\t%d\t%d\n",
+ md->fstab->fs_spec, md->fstab->fs_file,
+ md->fstab->fs_vfstype, md->fstab->fs_mntops,
+ md->fstab->fs_freq, md->fstab->fs_passno);
+ }
+ fclose(fstab);
+
+ return (0);
+}
+
+static struct partedit_item *
+read_geom_mesh(struct gmesh *mesh, int *nitems) {
+ struct gclass *classp;
+ struct ggeom *gp;
+ struct partedit_item *items;
+
+ *nitems = 0;
+ items = NULL;
+
+ /*
+ * Build the device table. First add all disks (and CDs).
+ */
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+ if (strcmp(classp->lg_name, "DISK") != 0 &&
+ strcmp(classp->lg_name, "MD") != 0)
+ continue;
+
+ /* Now recurse into all children */
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
+ add_geom_children(gp, 0, &items, nitems);
+ }
+
+ return (items);
+}
+
+static void
+add_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items,
+ int *nitems) {
+ struct gconsumer *cp;
+ struct gprovider *pp;
+ struct gconfig *gc;
+
+ if (strcmp(gp->lg_class->lg_name, "PART") == 0 &&
+ !LIST_EMPTY(&gp->lg_config)) {
+ LIST_FOREACH(gc, &gp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "scheme") == 0)
+ (*items)[*nitems-1].type = gc->lg_val;
+ }
+ }
+
+ if (LIST_EMPTY(&gp->lg_provider))
+ return;
+
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ if (strcmp(gp->lg_class->lg_name, "LABEL") == 0)
+ continue;
+
+ /* Skip WORM media */
+ if (strncmp(pp->lg_name, "cd", 2) == 0)
+ continue;
+
+ *items = realloc(*items,
+ (*nitems+1)*sizeof(struct partedit_item));
+ (*items)[*nitems].indentation = recurse;
+ (*items)[*nitems].name = pp->lg_name;
+ (*items)[*nitems].size = pp->lg_mediasize;
+ (*items)[*nitems].mountpoint = NULL;
+ (*items)[*nitems].type = "";
+ (*items)[*nitems].cookie = pp;
+
+ LIST_FOREACH(gc, &pp->lg_config, lg_config) {
+ if (strcmp(gc->lg_name, "type") == 0)
+ (*items)[*nitems].type = gc->lg_val;
+ }
+
+ /* Skip swap-backed MD devices */
+ if (strcmp(gp->lg_class->lg_name, "MD") == 0 &&
+ strcmp((*items)[*nitems].type, "swap") == 0)
+ continue;
+
+ (*nitems)++;
+
+ LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
+ add_geom_children(cp->lg_geom, recurse+1, items,
+ nitems);
+
+ /* Only use first provider for acd */
+ if (strcmp(gp->lg_class->lg_name, "ACD") == 0)
+ break;
+ }
+}
+
+static void
+init_fstab_metadata(void)
+{
+ struct fstab *fstab;
+ struct partition_metadata *md;
+
+ setfsent();
+ while ((fstab = getfsent()) != NULL) {
+ md = calloc(1, sizeof(struct partition_metadata));
+
+ md->name = NULL;
+ if (strncmp(fstab->fs_spec, "/dev/", 5) == 0)
+ md->name = strdup(&fstab->fs_spec[5]);
+
+ md->fstab = malloc(sizeof(struct fstab));
+ md->fstab->fs_spec = strdup(fstab->fs_spec);
+ md->fstab->fs_file = strdup(fstab->fs_file);
+ md->fstab->fs_vfstype = strdup(fstab->fs_vfstype);
+ md->fstab->fs_mntops = strdup(fstab->fs_mntops);
+ md->fstab->fs_type = strdup(fstab->fs_type);
+ md->fstab->fs_freq = fstab->fs_freq;
+ md->fstab->fs_passno = fstab->fs_passno;
+
+ md->newfs = NULL;
+
+ TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
+ }
+}
+
+static void
+get_mount_points(struct partedit_item *items, int nitems)
+{
+ struct partition_metadata *md;
+ int i;
+
+ for (i = 0; i < nitems; i++) {
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->name != NULL && md->fstab != NULL &&
+ strcmp(md->name, items[i].name) == 0) {
+ items[i].mountpoint = md->fstab->fs_file;
+ break;
+ }
+ }
+ }
+}
diff --git a/usr.sbin/bsdinstall/partedit/partedit.h b/usr.sbin/bsdinstall/partedit/partedit.h
new file mode 100644
index 0000000..6176d68
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/partedit.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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$
+ */
+
+#ifndef _PARTEDIT_PARTEDIT_H
+#define _PARTEDIT_PARTEDIT_H
+
+#include <sys/queue.h>
+#include <inttypes.h>
+#include <fstab.h>
+
+struct gprovider;
+struct gmesh;
+struct ggeom;
+
+TAILQ_HEAD(pmetadata_head, partition_metadata);
+extern struct pmetadata_head part_metadata;
+
+struct partition_metadata {
+ char *name; /* name of this partition, as in GEOM */
+
+ struct fstab *fstab; /* fstab data for this partition */
+ char *newfs; /* shell command to initialize partition */
+
+ int bootcode;
+
+ TAILQ_ENTRY(partition_metadata) metadata;
+};
+
+struct partition_metadata *get_part_metadata(const char *name, int create);
+void delete_part_metadata(const char *name);
+
+int part_wizard(void);
+
+/* gpart operations */
+void gpart_delete(struct gprovider *pp);
+void gpart_destroy(struct ggeom *lg_geom, int force);
+void gpart_edit(struct gprovider *pp);
+void gpart_create(struct gprovider *pp, char *default_type, char *default_size,
+ char *default_mountpoint, char **output, int interactive);
+intmax_t gpart_max_free(struct ggeom *gp, intmax_t *start);
+void gpart_revert(struct gprovider *pp);
+void gpart_revert_all(struct gmesh *mesh);
+void gpart_commit(struct gmesh *mesh);
+int gpart_partition(const char *lg_name, const char *scheme);
+void set_default_part_metadata(const char *name, const char *scheme,
+ const char *type, const char *mountpoint, int newfs);
+
+/* machine-dependent bootability checks */
+const char *default_scheme(void);
+int is_scheme_bootable(const char *part_type);
+size_t bootpart_size(const char *part_type);
+const char *bootcode_path(const char *part_type);
+const char *partcode_path(const char *part_type);
+
+#endif
diff --git a/usr.sbin/bsdinstall/partedit/partedit_generic.c b/usr.sbin/bsdinstall/partedit/partedit_generic.c
new file mode 100644
index 0000000..96faafa
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/partedit_generic.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <string.h>
+
+#include "partedit.h"
+
+const char *
+default_scheme(void) {
+ /*
+ * Our loader can parse GPT, so pick that as the default for lack of
+ * a better idea.
+ */
+
+ return ("GPT");
+}
+
+int
+is_scheme_bootable(const char *part_type) {
+ /*
+ * We don't know anything about this platform, so don't irritate the
+ * user by claiming the chosen partition scheme isn't bootable.
+ */
+
+ return (1);
+}
+
+/* No clue => no boot partition, bootcode, or partcode */
+
+size_t
+bootpart_size(const char *part_type) {
+ return (0);
+}
+
+const char *
+bootcode_path(const char *part_type) {
+ return (NULL);
+}
+
+const char *
+partcode_path(const char *part_type) {
+ return (NULL);
+}
+
diff --git a/usr.sbin/bsdinstall/partedit/partedit_pc98.c b/usr.sbin/bsdinstall/partedit/partedit_pc98.c
new file mode 100644
index 0000000..ec438f6
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/partedit_pc98.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <string.h>
+
+#include "partedit.h"
+
+const char *
+default_scheme(void) {
+ return ("PC98");
+}
+
+int
+is_scheme_bootable(const char *part_type) {
+ if (strcmp(part_type, "BSD") == 0)
+ return (1);
+ if (strcmp(part_type, "PC98") == 0)
+ return (1);
+
+ return (0);
+}
+
+size_t
+bootpart_size(const char *part_type) {
+ /* No boot partition */
+ return (0);
+}
+
+const char *
+bootcode_path(const char *part_type) {
+ if (strcmp(part_type, "PC98") == 0)
+ return ("/boot/pc98boot");
+ if (strcmp(part_type, "BSD") == 0)
+ return ("/boot/boot");
+
+ return (NULL);
+}
+
+const char *
+partcode_path(const char *part_type) {
+ /* No partcode */
+ return (NULL);
+}
+
diff --git a/usr.sbin/bsdinstall/partedit/partedit_powerpc.c b/usr.sbin/bsdinstall/partedit/partedit_powerpc.c
new file mode 100644
index 0000000..23bd8b6
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/partedit_powerpc.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <string.h>
+
+#include "partedit.h"
+
+const char *
+default_scheme(void) {
+ return ("APM");
+}
+
+int
+is_scheme_bootable(const char *part_type) {
+ if (strcmp(part_type, "APM") == 0)
+ return (1);
+ return (0);
+}
+
+size_t
+bootpart_size(const char *part_type) {
+ if (strcmp(part_type, "APM") == 0)
+ return (800*1024);
+ return (0);
+}
+
+const char *
+bootcode_path(const char *part_type) {
+ return (NULL);
+}
+
+const char *
+partcode_path(const char *part_type) {
+ if (strcmp(part_type, "APM") == 0)
+ return ("/boot/boot1.hfs");
+ return (NULL);
+}
+
diff --git a/usr.sbin/bsdinstall/partedit/partedit_sparc64.c b/usr.sbin/bsdinstall/partedit/partedit_sparc64.c
new file mode 100644
index 0000000..b8ee052
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/partedit_sparc64.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <string.h>
+
+#include "partedit.h"
+
+const char *
+default_scheme(void) {
+ return ("VTOC8");
+}
+
+int
+is_scheme_bootable(const char *part_type) {
+ if (strcmp(part_type, "VTOC8") == 0)
+ return (1);
+ return (0);
+}
+
+size_t
+bootpart_size(const char *part_type) {
+ /* No standalone boot partition */
+
+ return (0);
+}
+
+const char *
+bootcode_path(const char *part_type) {
+ return (NULL);
+}
+
+const char *
+partcode_path(const char *part_type) {
+ if (strcmp(part_type, "VTOC8") == 0)
+ return ("/boot/boot1");
+ return (NULL);
+}
+
diff --git a/usr.sbin/bsdinstall/partedit/partedit_x86.c b/usr.sbin/bsdinstall/partedit/partedit_x86.c
new file mode 100644
index 0000000..a03a7a7
--- /dev/null
+++ b/usr.sbin/bsdinstall/partedit/partedit_x86.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 <string.h>
+
+#include "partedit.h"
+
+const char *
+default_scheme(void) {
+ return ("GPT");
+}
+
+int
+is_scheme_bootable(const char *part_type) {
+ if (strcmp(part_type, "BSD") == 0)
+ return (1);
+ if (strcmp(part_type, "GPT") == 0)
+ return (1);
+ if (strcmp(part_type, "MBR") == 0)
+ return (1);
+
+ return (0);
+}
+
+size_t
+bootpart_size(const char *part_type) {
+ if (strcmp(part_type, "GPT") == 0)
+ return (64*1024);
+
+ /* No partcode except for GPT */
+ return (0);
+}
+
+const char *
+bootcode_path(const char *part_type) {
+ if (strcmp(part_type, "GPT") == 0)
+ return ("/boot/pmbr");
+ if (strcmp(part_type, "MBR") == 0)
+ return ("/boot/mbr");
+ if (strcmp(part_type, "BSD") == 0)
+ return ("/boot/boot");
+
+ return (NULL);
+}
+
+const char *
+partcode_path(const char *part_type) {
+ if (strcmp(part_type, "GPT") == 0)
+ return ("/boot/gptboot");
+
+ /* No partcode except for GPT */
+ return (NULL);
+}
+
diff --git a/usr.sbin/bsdinstall/scripts/Makefile b/usr.sbin/bsdinstall/scripts/Makefile
new file mode 100644
index 0000000..d68ea5a
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+SCRIPTS= auto adduser config hostname jail keymap mount netconfig rootpass \
+ services time umount wlanconfig
+BINDIR= /usr/libexec/bsdinstall
+
+NO_MAN= true
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdinstall/scripts/adduser b/usr.sbin/bsdinstall/scripts/adduser
new file mode 100755
index 0000000..35c50ed
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/adduser
@@ -0,0 +1,34 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+clear
+echo "FreeBSD Installer"
+echo "========================"
+echo "Add Users"
+echo
+chroot $BSDINSTALL_CHROOT adduser
diff --git a/usr.sbin/bsdinstall/scripts/auto b/usr.sbin/bsdinstall/scripts/auto
new file mode 100755
index 0000000..5fc8f0e
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/auto
@@ -0,0 +1,192 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+echo "Begun Installation at $(date)" > $BSDINSTALL_LOG
+
+error() {
+ dialog --backtitle "FreeBSD Installer" --title "Abort" \
+ --no-label "Exit" --yes-label "Restart" --yesno \
+ "An installation step has been aborted. Would you like to restart the installation or exit the installer?" 0 0
+ if [ $? -ne 0 ]; then
+ exit
+ else
+ test -f $PATH_FSTAB && bsdinstall umount
+ exec $0
+ fi
+}
+
+
+rm -rf $BSDINSTALL_TMPETC
+mkdir $BSDINSTALL_TMPETC
+
+trap true SIGINT # This section is optional
+bsdinstall keymap
+
+trap error SIGINT # Catch cntrl-C here
+bsdinstall hostname || error
+
+FETCH_DISTRIBUTIONS=""
+for dist in $DISTRIBUTIONS; do
+ if [ ! -f $BSDINSTALL_DISTDIR/$dist ]; then
+ FETCH_DISTRIBUTIONS="$FETCH_DISTRIBUTIONS $dist"
+ fi
+done
+
+if [ ! -z "$FETCH_DISTRIBUTIONS" -a ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ dialog --backtitle "FreeBSD Installer" --title "Network Installation" --msgbox "No installation files were found on the boot volume. The next few screens will allow you to configure networking so that they can be downloaded from the Internet." 0 0
+ bsdinstall netconfig || error
+ NETCONFIG_DONE=yes
+fi
+
+rm $PATH_FSTAB
+touch $PATH_FSTAB
+
+dialog --backtitle "FreeBSD Installer" --title "Partitioning" --extra-button \
+ --extra-label "Manual" --ok-label "Guided" --cancel-label "Shell" \
+ --yesno "Would you like to use the guided partitioning tool (recommended for beginners) or to set up partitions manually (experts)? You can also open a shell and set up partitions entirely by hand." 0 0
+
+case $? in
+0) # Guided
+ bsdinstall autopart || error
+ bsdinstall mount || error
+ ;;
+1) # Shell
+ clear
+ echo "Use this shell to set up partitions for the new system. When finished, mount the system at $BSDINSTALL_CHROOT and place an fstab file for the new system at $PATH_FSTAB. Then type 'exit'. You can also enter the partition editor at any time by entering 'bsdinstall partedit'."
+ sh
+ ;;
+3) # Manual
+ bsdinstall partedit || error
+ bsdinstall mount || error
+ ;;
+*)
+ error
+ ;;
+esac
+
+if [ ! -z "$FETCH_DISTRIBUTIONS" ]; then
+ ALL_DISTRIBUTIONS="$DISTRIBUTIONS"
+
+ # Download to a directory in the new system as scratch space
+ BSDINSTALL_FETCHDEST="$BSDINSTALL_CHROOT/usr/bsdinstall-dist"
+ mkdir -p "$BSDINSTALL_FETCHDEST" || error
+
+ export DISTRIBUTIONS="$FETCH_DISTRIBUTIONS"
+ # Try to use any existing distfiles
+ [ -d $BSDINSTALL_DISTDIR -a "$FETCH_DISTRIBUTIONS" != "$ALL_DISTRIBUTIONS" ] && mount_unionfs "$BSDINSTALL_FETCHDEST" "$BSDINSTALL_DISTDIR"
+
+ # Otherwise, fetch everything
+ if [ $? -ne 0 ]; then
+ export DISTRIBUTIONS="$ALL_DISTRIBUTIONS"
+ export BSDINSTALL_DISTDIR="$BSDINSTALL_FETCHDEST"
+ fi
+
+ bsdinstall distfetch || error
+ export DISTRIBUTIONS="$ALL_DISTRIBUTIONS"
+fi
+
+bsdinstall distextract || error
+bsdinstall rootpass || error
+
+trap true SIGINT # This section is optional
+if [ "$NETCONFIG_DONE" != yes ]; then
+ bsdinstall netconfig # Don't check for errors -- the user may cancel
+fi
+bsdinstall time
+bsdinstall services
+
+dialog --backtitle "FreeBSD Installer" --title "Add User Accounts" --yesno \
+ "Would you like to add users to the installed system now?" 0 0 && \
+ bsdinstall adduser
+
+finalconfig() {
+ exec 3>&1
+ REVISIT=$(dialog --backtitle "FreeBSD Installer" \
+ --title "Final Configuration" --no-cancel --menu \
+ "Setup of your FreeBSD system is nearly complete. You can now modify your configuration choices or apply more complex changes using a shell." 0 0 0 \
+ "Add User" "Add a user to the system" \
+ "Root Password" "Change root password" \
+ "Hostname" "Set system hostname" \
+ "Network" "Networking configuration" \
+ "Services" "Set daemons to run on startup" \
+ "Time Zone" "Set system timezone" \
+ "Shell" "Open a shell in the new system" \
+ "Reboot" "Apply configuration and reboot" 2>&1 1>&3)
+ exec 3>&-
+
+ case "$REVISIT" in
+ "Add User")
+ bsdinstall adduser
+ finalconfig
+ ;;
+ "Root Password")
+ bsdinstall rootpass
+ finalconfig
+ ;;
+ "Hostname")
+ bsdinstall hostname
+ finalconfig
+ ;;
+ "Network")
+ bsdinstall netconfig
+ finalconfig
+ ;;
+ "Services")
+ bsdinstall services
+ finalconfig
+ ;;
+ "Time Zone")
+ bsdinstall time
+ finalconfig
+ ;;
+ "Shell")
+ clear
+ echo This shell is operating in a chroot in the new system. \
+ When finished making configuration changes, type \"exit\".
+ chroot "$BSDINSTALL_CHROOT" /bin/sh
+ # Don't hose local rc.conf changes
+ cp $BSDINSTALL_CHROOT/etc/rc.conf $BSDINSTALL_TMPETC/rc.conf.manual
+ finalconfig
+ ;;
+ esac
+}
+
+# Allow user to change his mind
+finalconfig
+
+trap error SIGINT # SIGINT is bad again
+bsdinstall config || error
+
+if [ ! -z "$BSDINSTALL_FETCHDEST" ]; then
+ [ "$BSDINSTALL_FETCHDEST" != "$BSDINSTALL_DISTDIR" ] && \
+ umount "$BSDINSTALL_DISTDIR"
+ rm -rf "$BSDINSTALL_FETCHDEST"
+fi
+
+echo "Installation Completed at $(date)" >> $BSDINSTALL_LOG
+
diff --git a/usr.sbin/bsdinstall/scripts/config b/usr.sbin/bsdinstall/scripts/config
new file mode 100755
index 0000000..5d7c3ce
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/config
@@ -0,0 +1,32 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+cat $BSDINSTALL_TMPETC/rc.conf.* >> $BSDINSTALL_TMPETC/rc.conf
+rm $BSDINSTALL_TMPETC/rc.conf.*
+
+cp $BSDINSTALL_TMPETC/* $BSDINSTALL_CHROOT/etc
diff --git a/usr.sbin/bsdinstall/scripts/hostname b/usr.sbin/bsdinstall/scripts/hostname
new file mode 100755
index 0000000..a53fd80
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/hostname
@@ -0,0 +1,48 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+: ${DIALOG_OK=0}
+: ${DIALOG_CANCEL=1}
+: ${DIALOG_HELP=2}
+: ${DIALOG_EXTRA=3}
+: ${DIALOG_ITEM_HELP=4}
+: ${DIALOG_ESC=255}
+
+exec 3>&1
+HOSTNAME=`dialog --backtitle 'FreeBSD Installer' --title 'Set Hostname' --nocancel --inputbox \
+ 'Please choose a hostname for this machine.
+
+If you are running on a managed network, please ask your network administrator for an appropriate name.' \
+ 0 0 $(hostname) 2>&1 1>&3`
+if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
+exec 3>&-
+
+echo "hostname=\"$HOSTNAME\"" > $BSDINSTALL_TMPETC/rc.conf.hostname
+if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ hostname -s "$HOSTNAME"
+fi
diff --git a/usr.sbin/bsdinstall/scripts/jail b/usr.sbin/bsdinstall/scripts/jail
new file mode 100755
index 0000000..d1adebb
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/jail
@@ -0,0 +1,81 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+echo "Begun Installation at $(date)" > $BSDINSTALL_LOG
+
+export BSDINSTALL_CHROOT=$1
+export DISTRIBUTIONS="`echo $DISTRIBUTIONS | sed 's/kernel\.[^ ]* //g'`"
+
+error() {
+ dialog --backtitle "FreeBSD Installer" --title "Abort" \
+ --no-label "Exit" --yes-label "Restart" --yesno \
+ "You have canceled an installation step. Would you like to restart the installation or exit the installer?" 0 0
+ if [ $? -ne 0 ]; then
+ exit
+ else
+ test -f $PATH_FSTAB && bsdinstall umount
+ exec $0
+ fi
+}
+
+
+rm -rf $BSDINSTALL_TMPETC
+mkdir $BSDINSTALL_TMPETC
+
+trap error SIGINT # SIGINT is bad
+
+FETCH_DISTRIBUTIONS=""
+for dist in $DISTRIBUTIONS; do
+ if [ ! -f $BSDINSTALL_DISTDIR/$dist ]; then
+ FETCH_DISTRIBUTIONS="$FETCH_DISTRIBUTIONS $dist"
+ fi
+done
+
+if [ ! -z $FETCH_DISTRIBUTIONS ]; then
+ ALL_DISTRIBUTIONS=$DISTRIBUTIONS
+ DISTRIBUTIONS=$FETCH_DISTRIBUTIONS
+ bsdinstall distfetch || error
+ DISTRIBUTIONS=$ALL_DISTRIBUTIONS
+fi
+
+bsdinstall distextract || error
+bsdinstall rootpass || error
+
+trap true SIGINT # This section is optional
+bsdinstall time
+bsdinstall services
+
+dialog --backtitle "FreeBSD Installer" --title "Add User Accounts" --yesno \
+ "Would you like to add users to the installed system now?" 0 0 && \
+ bsdinstall adduser
+
+trap error SIGINT # SIGINT is bad again
+bsdinstall config || error
+
+echo "Installation Completed at $(date)" >> $BSDINSTALL_LOG
+
diff --git a/usr.sbin/bsdinstall/scripts/keymap b/usr.sbin/bsdinstall/scripts/keymap
new file mode 100755
index 0000000..501b1d1
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/keymap
@@ -0,0 +1,32 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+kbdcontrol -d >/dev/null 2>&1
+if [ $? -eq 0 ]; then
+ kbdmap 3>&2 2>&1 1>&3 | grep 'keymap=' > $BSDINSTALL_TMPETC/rc.conf.keymap
+fi
diff --git a/usr.sbin/bsdinstall/scripts/mount b/usr.sbin/bsdinstall/scripts/mount
new file mode 100755
index 0000000..fca8000
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/mount
@@ -0,0 +1,55 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+TMP_FSTAB=/tmp/bsdinstall-tmp-fstab
+
+cat $PATH_FSTAB | awk -v BSDINSTALL_CHROOT=$BSDINSTALL_CHROOT '{
+ if ($2 ~ "^/.*") {
+ fsname = $2;
+ if (fsname == "/")
+ fsname = ""
+ printf("%s\t%s%s\t%s\t%s\t%s\t%s\n", $1, BSDINSTALL_CHROOT,
+ fsname, $3, $4, $5, $6);
+ }
+}' > $TMP_FSTAB
+
+FILESYSTEMS=`cat $TMP_FSTAB | awk '/^[^#].*/ {if ($2 ~ "^/.*") printf("%s\n", $2);}' | sort -t /`
+
+for i in $FILESYSTEMS; do
+ mkdir -p $i 2>/dev/null
+ MNTERROR=`mount -F $TMP_FSTAB $i 2>&1`
+ if [ $? -ne 0 ]; then
+ dialog --backtitle "FreeBSD Installer" --title "Error" \
+ --msgbox "Error mounting partition $i:\n$MNTERROR" 0 0
+ exit 1
+ fi
+done
+
+# User might want a shell and require devfs, so mount it
+mkdir $BSDINSTALL_CHROOT/dev 2>/dev/null
+mount -t devfs devfs $BSDINSTALL_CHROOT/dev
diff --git a/usr.sbin/bsdinstall/scripts/netconfig b/usr.sbin/bsdinstall/scripts/netconfig
new file mode 100755
index 0000000..0374d12
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/netconfig
@@ -0,0 +1,121 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+INTERFACES=""
+DIALOG_TAGS=""
+
+: ${DIALOG_OK=0}
+: ${DIALOG_CANCEL=1}
+: ${DIALOG_HELP=2}
+: ${DIALOG_EXTRA=3}
+: ${DIALOG_ITEM_HELP=4}
+: ${DIALOG_ESC=255}
+
+echo -n > $BSDINSTALL_TMPETC/rc.conf.net
+
+for IF in `ifconfig -l`; do
+ test "$IF" = "lo0" && continue
+ (ifconfig -g wlan | egrep -wq $IF) && continue
+ INTERFACES="$INTERFACES $IF"
+ DESC=`sysctl -n dev.$(echo $IF | sed -E 's/([[:alpha:]]*)([[:digit:]]*)/\1.\2/g').%desc`
+ DIALOG_TAGS="$DIALOG_TAGS $IF \"$DESC\""
+done
+
+exec 3>&1
+INTERFACE=`echo $DIALOG_TAGS | xargs dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --menu 'Please select a network interface to configure:' 0 0 0 2>&1 1>&3`
+if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
+exec 3>&-
+
+# Do a dirty check to see if this a wireless interface -- there should be a
+# better way
+IFCONFIG_PREFIX=""
+if ifconfig $INTERFACE | grep -q 'media: IEEE 802.11 Wireless'; then
+ NEXT_WLAN_IFACE=wlan0 # XXX
+ echo wlans_$INTERFACE=\"$NEXT_WLAN_IFACE\" >> $BSDINSTALL_TMPETC/rc.conf.net
+ IFCONFIG_PREFIX="WPA "
+ if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ ifconfig $NEXT_WLAN_IFACE create wlandev $INTERFACE
+ ifconfig $NEXT_WLAN_IFACE up
+ fi
+ bsdinstall wlanconfig $NEXT_WLAN_IFACE || exec $0
+ INTERFACE="$NEXT_WLAN_IFACE"
+fi
+
+dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --yesno 'Would you like to use DHCP to configure this interface?' 0 0
+if [ $? -eq $DIALOG_OK ]; then
+ echo ifconfig_$INTERFACE=\"${IFCONFIG_PREFIX}DHCP\" >> $BSDINSTALL_TMPETC/rc.conf.net
+
+ if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ dialog --backtitle 'FreeBSD Installer' --infobox "Acquiring DHCP lease..." 0 0
+ dhclient $INTERFACE 2>> $BSDINSTALL_LOG
+ if [ $? -ne 0 ]; then
+ dialog --backtitle 'FreeBSD Installer' --msgbox "DHCP lease acquisition failed." 0 0
+ exec $0
+ fi
+ fi
+ exit 0
+fi
+
+IP_ADDRESS=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $2); }'`
+NETMASK=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $4); }'`
+ROUTER=`netstat -rn -f inet | awk '/default/ {printf("%s\n", $2);}'`
+
+exec 3>&1
+IF_CONFIG=$(dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --form 'Static Network Interface Configuration' 0 0 0 \
+ 'IP Address' 1 0 "$IP_ADDRESS" 1 20 16 0 \
+ 'Subnet Mask' 2 0 "$NETMASK" 2 20 16 0 \
+ 'Default Router' 3 0 "$ROUTER" 3 20 16 0 \
+ \
+ 'Nameserver' 5 0 "" 5 20 16 0 \
+ 'Search Domain' 6 0 "" 6 20 20 0 \
+2>&1 1>&3)
+if [ $? -eq $DIALOG_CANCEL ]; then exec $0; fi
+exec 3>&-
+
+echo $INTERFACE $IF_CONFIG |
+ awk -v prefix="$IFCONFIG_PREFIX" '{
+ printf("ifconfig_%s=\"%s%s netmask %s\"\n", $1, prefix, $2, $3);
+ printf("defaultrouter=\"%s\"\n", $4);
+ }' >> $BSDINSTALL_TMPETC/rc.conf.net
+
+if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ . $BSDINSTALL_TMPETC/rc.conf.net
+ ifconfig $INTERFACE `eval echo \\\$ifconfig_$INTERFACE`
+ route delete default
+ route add default $defaultrouter
+fi
+
+
+echo $IF_CONFIG |
+ awk '{
+ if ($4 != "")
+ printf("nameserver %s\n", $4);
+ if ($5 != "")
+ printf("search %s\n", $5);
+ }' > $BSDINSTALL_TMPETC/resolv.conf
+
diff --git a/usr.sbin/bsdinstall/scripts/rootpass b/usr.sbin/bsdinstall/scripts/rootpass
new file mode 100755
index 0000000..b7177fc
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/rootpass
@@ -0,0 +1,37 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+clear
+echo "FreeBSD Installer"
+echo "========================"
+echo
+
+echo "Please select a password for the system management account (root):"
+
+chroot $BSDINSTALL_CHROOT passwd root
+
diff --git a/usr.sbin/bsdinstall/scripts/services b/usr.sbin/bsdinstall/scripts/services
new file mode 100755
index 0000000..01c25fe
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/services
@@ -0,0 +1,53 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+if [ -f $BSDINSTALL_TMPETC/rc.conf.services ]; then
+ eval `sed -e s/YES/on/I -e s/NO/off/I $BSDINSTALL_TMPETC/rc.conf.services`
+else
+ # Default service states. Everything is off if not enabled.
+ sshd_enable="on"
+fi
+
+echo -n > $BSDINSTALL_TMPETC/rc.conf.services
+
+exec 3>&1
+DAEMONS=$(dialog --backtitle "FreeBSD Installer" \
+ --title "System Configuration" --nocancel --separate-output \
+ --checklist "Choose the services you would like to be started at boot:" \
+ 0 0 0 \
+ sshd "Secure shell daemon" ${sshd_enable:-off} \
+ moused "PS/2 mouse pointer on console" ${moused_enable:-off} \
+ ntpd "Synchronize system and network time" ${ntpd_enable:-off} \
+ powerd "Adjust CPU frequency dynamically" ${powerd_enable:-off} \
+2>&1 1>&3)
+exec 3>&-
+
+for daemon in $DAEMONS; do
+ echo ${daemon}_enable=\"YES\" >> $BSDINSTALL_TMPETC/rc.conf.services
+done
+
diff --git a/usr.sbin/bsdinstall/scripts/time b/usr.sbin/bsdinstall/scripts/time
new file mode 100755
index 0000000..74400b6
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/time
@@ -0,0 +1,29 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+chroot $BSDINSTALL_CHROOT tzsetup
diff --git a/usr.sbin/bsdinstall/scripts/umount b/usr.sbin/bsdinstall/scripts/umount
new file mode 100755
index 0000000..c19f6f3
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/umount
@@ -0,0 +1,42 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+TMP_FSTAB=/tmp/bsdinstall-tmp-fstab
+
+cat $PATH_FSTAB | awk -v BSDINSTALL_CHROOT=$BSDINSTALL_CHROOT '{
+ if ($2 ~ "^/.*") {
+ fsname = $2;
+ if (fsname == "/")
+ fsname = ""
+ printf("%s\t%s%s\t%s\t%s\t%s\t%s\n", $1, BSDINSTALL_CHROOT,
+ fsname, $3, $4, $5, $6);
+ }
+}' > $TMP_FSTAB
+
+umount $BSDINSTALL_CHROOT/dev 2>/dev/null
+umount -F $TMP_FSTAB -a 2>/dev/null
diff --git a/usr.sbin/bsdinstall/scripts/wlanconfig b/usr.sbin/bsdinstall/scripts/wlanconfig
new file mode 100755
index 0000000..d95ccff
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/wlanconfig
@@ -0,0 +1,137 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# 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$
+
+echo -n > $BSDINSTALL_TMPETC/wpa_supplicant.conf
+chmod 0600 $BSDINSTALL_TMPETC/wpa_supplicant.conf
+
+echo "ctrl_interface=/var/run/wpa_supplicant" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+echo "eapol_version=2" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+echo "ap_scan=1" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+echo "fast_reauth=1" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+echo >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+
+# Try to reach wpa_supplicant. If it isn't running and we can modify the
+# existing system, start it. Otherwise, fail.
+(wpa_cli ping >/dev/null 2>/dev/null || ([ ! -z $BSDINSTALL_CONFIGCURRENT ] && \
+ wpa_supplicant -B -i $1 -c $BSDINSTALL_TMPETC/wpa_supplicant.conf)) || \
+ (dialog --backtitle "FreeBSD Installer" --title "Error" --msgbox \
+ "Could not start wpa_supplicant!" 0 0; exit 1) || exit 1
+
+# See if we succeeded
+wpa_cli ping >/dev/null 2>/dev/null
+if [ $? -ne 0 -a -z $BSDINSTALL_CONFIGCURRENT ]; then
+ dialog --backtitle "FreeBSD Installer" --title "Error" --msgbox \
+ "Wireless cannot be configured without making changes to the local system!" \ 0 0
+ exit 1
+fi
+
+wpa_cli scan >>$BSDINSTALL_LOG
+dialog --backtitle "FreeBSD Installer" --title "Scanning" --ok-label "Skip" \
+ --pause "Waiting 5 seconds to scan for wireless networks..." \
+ 9 40 5 || exit 1
+
+SCAN_RESULTS=`wpa_cli scan_results`
+NETWORKS=`echo "$SCAN_RESULTS" | awk -F '\t' \
+ '/..:..:..:..:..:../ {if (length($5) > 0) printf("\"%s\"\t%s\n", $5, $4);}' |
+ sort | uniq`
+
+if [ -z $SCAN_RESULTS ]; then
+ dialog --backtitle "FreeBSD Installer" --title "Error" \
+ --yesno "No wireless networks were found. Rescan?" 0 0 && \
+ exec $0 $@
+ exit 1
+fi
+
+exec 3>&1
+NETWORK=`sh -c "dialog --extra-button --extra-label \"Rescan\" \
+ --backtitle \"FreeBSD Installer\" --title \"Network Selection\" --menu \
+ \"Select a wireless network to connect to.\" 0 0 0 \
+ $(echo $NETWORKS | tr '\n' ' ')" 2>&1 1>&3`
+case $? in
+0) # OK
+ ;;
+1) # Cancel
+ exit 1
+ ;;
+3) # Rescan
+ exec $0 $@
+ ;;
+esac
+exec 3>&-
+
+ENCRYPTION=`echo "$NETWORKS" | awk -F '\t' \
+ "/^\"$NETWORK\"\t/ {printf(\"%s\n\", \\\$2 );}"`
+
+if echo $ENCRYPTION | grep -q 'PSK'; then
+ exec 3>&1
+ PASS=`dialog --insecure --backtitle "FreeBSD Installer" \
+ --title "WPA Setup" --mixedform "" 0 0 0 \
+ "SSID" 1 0 "$NETWORK" 1 12 0 0 2 \
+ "Password" 2 0 "" 2 12 15 0 1 \
+ 2>&1 1>&3` \
+ || exec $0 $@
+ exec 3>&-
+echo "network={
+ ssid=\"$NETWORK\"
+ psk=\"$PASS\"
+ priority=5
+}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+elif echo $ENCRYPTION | grep -q WEP; then
+ echo FOO
+ exec 3>&1
+ WEPKEY=`dialog --insecure --backtitle "FreeBSD Installer" \
+ --title "WEP Setup" --mixedform "" 0 0 0 \
+ "SSID" 1 0 "$NETWORK" 1 12 0 0 2 \
+ "WEP Key 0" 2 0 "" 2 12 15 0 1 \
+ 2>&1 1>&3` \
+ || exec $0 $@
+echo "network={
+ ssid=\"$NETWORK\"
+ key_mgmt=NONE
+ wep_key0=\"$WEPKEY\"
+ wep_tx_keyidx=0
+ priority=5
+}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+else # Open
+echo "network={
+ ssid=\"$NETWORK\"
+ key_mgmt=NONE
+ priority=5
+}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+fi
+
+# Connect to any open networks policy
+echo "network={
+ priority=5
+ key_mgmt=NONE
+}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
+
+# Bring up new network
+test ! -z $BSDINSTALL_CONFIGCURRENT && wpa_cli reconfigure >>$BSDINSTALL_LOG
+
+exit 0
OpenPOWER on IntegriCloud