summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsdinstall
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2011-02-18 14:54:34 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2011-02-18 14:54:34 +0000
commitb35b3cdb7175a6a6ac7a09b47e1d1cfc53c27816 (patch)
treeae8a7479d39ff2e070411cc1748b53d6224feed4 /usr.sbin/bsdinstall
parent1856110dc5d29373ef581edaf6d2f92392a12cd0 (diff)
downloadFreeBSD-src-b35b3cdb7175a6a6ac7a09b47e1d1cfc53c27816.zip
FreeBSD-src-b35b3cdb7175a6a6ac7a09b47e1d1cfc53c27816.tar.gz
Import bsdinstall. This is meant to be (eventually in conjunction with
pc-sysinstall) a replacement for sysinstall in the 9.0 release and beyond. Currently supported platforms are sparc64, pc98, i386, amd64, powerpc, and powerpc64. Integration into the build system will occur in the coming weeks. Merging with pc-sysinstall will use this code as a frontend, while temporarily retaining the interactive partition editor here. This work will be done in parallel with improvements on this code and release integration. Thanks to all who have provided testing and comments!
Diffstat (limited to 'usr.sbin/bsdinstall')
-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
32 files changed, 3971 insertions, 0 deletions
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