svn commit: r216834 - in user/nwhitehorn/bsdinstall: . distextract distfetch libexec partedit scripts

Nathan Whitehorn nwhitehorn at FreeBSD.org
Fri Dec 31 02:19:39 UTC 2010


Author: nwhitehorn
Date: Fri Dec 31 02:19:38 2010
New Revision: 216834
URL: http://svn.freebsd.org/changeset/base/216834

Log:
  Add a simple installer I wrote in a few days last week. It is capable of
  installing a booting system on 3 of the 6 platforms currently using
  sysinstall (amd64, i386, and powerpc). This is intended to replace
  sysinstall, but not to take the place of more full-featured installers
  like pc-sysinstall.
  
  The installer is shell- and dialog-based, but requires the new, vastly
  improved version of libdialog available from Thomas Dickey. Hopefully this
  can be imported into base once we no longer need the existing libdialog's
  consumers (sysinstall, sade, and tzsetup).
  
  Many features still needed. Slippery when wet. Etc.

Added:
  user/nwhitehorn/bsdinstall/
  user/nwhitehorn/bsdinstall/NOTES
  user/nwhitehorn/bsdinstall/README
  user/nwhitehorn/bsdinstall/bsdinstall   (contents, props changed)
  user/nwhitehorn/bsdinstall/distextract/
  user/nwhitehorn/bsdinstall/distextract/Makefile
  user/nwhitehorn/bsdinstall/distextract/distextract.c
  user/nwhitehorn/bsdinstall/distfetch/
  user/nwhitehorn/bsdinstall/distfetch/Makefile
  user/nwhitehorn/bsdinstall/distfetch/distfetch.c
  user/nwhitehorn/bsdinstall/libexec/
  user/nwhitehorn/bsdinstall/libexec/auto   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/config   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/distextract   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/distfetch   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/hostname   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/mediaselect   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/mount   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/netconfig   (contents, props changed)
  user/nwhitehorn/bsdinstall/libexec/partedit   (contents, props changed)
  user/nwhitehorn/bsdinstall/partedit/
  user/nwhitehorn/bsdinstall/partedit/Makefile
  user/nwhitehorn/bsdinstall/partedit/diskeditor.c
  user/nwhitehorn/bsdinstall/partedit/diskeditor.h
  user/nwhitehorn/bsdinstall/partedit/gpart_ops.c
  user/nwhitehorn/bsdinstall/partedit/partedit.c
  user/nwhitehorn/bsdinstall/partedit/partedit.h
  user/nwhitehorn/bsdinstall/partedit/partedit_powerpc.c
  user/nwhitehorn/bsdinstall/partedit/partedit_x86.c
  user/nwhitehorn/bsdinstall/scripts/
  user/nwhitehorn/bsdinstall/scripts/auto   (contents, props changed)
  user/nwhitehorn/bsdinstall/scripts/config   (contents, props changed)
  user/nwhitehorn/bsdinstall/scripts/hostname   (contents, props changed)
  user/nwhitehorn/bsdinstall/scripts/mediaselect   (contents, props changed)
  user/nwhitehorn/bsdinstall/scripts/mount   (contents, props changed)
  user/nwhitehorn/bsdinstall/scripts/netconfig   (contents, props changed)

Added: user/nwhitehorn/bsdinstall/NOTES
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/NOTES	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,3 @@
+Targets for tarballs: installkernel installworld (distrib-dirs distribution)
+
+Tools used in scripts: dialog sh awk sort cp dd ifconfig sysctl xargs mkdir mount cat uname netstat newfs

Added: user/nwhitehorn/bsdinstall/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/README	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,28 @@
+FreeBSD Stopgap Installer
+=========================
+Nathan Whitehorn
+December 30, 2010
+
+This is designed to be a lightweight replacement for sysinstall until future
+installers show up, but more modular and easily extended. It is scriptable
+from shell scripts. The full installer can be run by executing bsdinstall auto,
+and is intended to be run from a live environment (e.g. a live CD or PXE boot).
+bsdinstall must be in PATH. In addition to base tools, Thomas Dickey's new
+dialog must be installed (devel/cdialog).
+
+Status:
+- Installs working, bootable systems on powerpc, amd64, and i386
+
+Missing features:
+- Distfile fetching not entirely hooked up
+- Root password configuration and user adding not yet added
+- Network configuration sets up networking for the new system, but not (yet)
+  the current one
+
+Goals:
+- Reinvent as few wheels as possible
+- Extensability
+- Scriptability without a scripting language -- the installer itself should
+  be a script a user can modify
+- Minimal grubbing around in outputs of shell commands with awk, sed, etc.
+

Added: user/nwhitehorn/bsdinstall/bsdinstall
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/bsdinstall	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+DISTRIBUTIONS="kernel world distribution"; export DISTRIBUTIONS
+BSDINSTALL_LOG="/tmp/bsdinstall_log"; export BSDINSTALL_LOG
+PATH_FSTAB="/tmp/fstab"; export PATH_FSTAB
+BSDINSTALL_DISTDIR="/var/dist"; export BSDINSTALL_DISTDIR
+BSDINSTALL_CHROOT="/mnt"; export BSDINSTALL_CHROOT
+
+VERB=$1
+
+$(dirname $0)/libexec/$VERB
+

Added: user/nwhitehorn/bsdinstall/distextract/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/distextract/Makefile	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,10 @@
+# $FreeBSD $
+
+PROG=	distextract
+LDADD=	-larchive -lncursesw -L/usr/local/lib -lcdialog
+CFLAGS= -I/usr/local/include
+
+WARNS?=	6
+NO_MAN=	true
+
+.include <bsd.prog.mk>

Added: user/nwhitehorn/bsdinstall/distextract/distextract.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/distextract/distextract.c	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,174 @@
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <archive.h>
+#include <cdialog/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, *disk;
+	struct archive_entry *entry;
+	char errormsg[512];
+	char status[8];
+	const void *block;
+	size_t bsize;
+	off_t offset;
+	int i, err, progress, last_progress;
+
+	err = 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.tgz", 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;
+	disk = archive_write_disk_new();
+	archive_write_disk_set_options(disk, ARCHIVE_EXTRACT_TIME |
+	    ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL |
+	    ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_OWNER |
+	    ARCHIVE_EXTRACT_XATTR);
+	archive_write_disk_set_standard_lookup(disk);
+
+	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.tgz", 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_write_header(disk, entry);
+			if (err != ARCHIVE_OK)
+				break;
+
+			while (1) {
+				err = archive_read_data_block(archive,
+				    &block, &bsize, &offset);
+				if (err != ARCHIVE_OK)
+					break;
+				err = archive_write_data_block(disk,
+				    block, bsize, offset);
+				if (err != ARCHIVE_OK)
+					break;
+			}
+
+			if (err != ARCHIVE_EOF)
+				break;
+			archive_write_finish_entry(disk);
+
+			archive_file++;
+			current_files++;
+		}
+
+		items[i*2 + 1] = "Done";
+
+		if (err != ARCHIVE_EOF) {
+			const char *errstring;
+			if (archive_errno(archive) != 0)
+				errstring = archive_error_string(archive);
+			else
+				errstring = archive_error_string(disk);
+
+			snprintf(errormsg, sizeof(errormsg),
+			    "Error while extracting %s: %s\n", items[i*2],
+			    errstring);
+			items[i*2 + 1] = "Failed";
+			dialog_msgbox("Extract Error", errormsg, 0, 0,
+			    TRUE);
+			goto exit;
+		}
+
+		archive_read_free(archive);
+	}
+
+exit:
+	end_dialog();
+
+	return (err);
+}

Added: user/nwhitehorn/bsdinstall/distfetch/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/distfetch/Makefile	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,10 @@
+# $FreeBSD $
+
+PROG=	distfetch
+LDADD=	-lfetch -lncursesw -L/usr/local/lib -lcdialog
+CFLAGS= -I/usr/local/include
+
+WARNS?=	6
+NO_MAN=	true
+
+.include <bsd.prog.mk>

Added: user/nwhitehorn/bsdinstall/distfetch/distfetch.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/distfetch/distfetch.c	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,132 @@
+#include <sys/param.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fetch.h>
+#include <cdialog/dialog.h>
+
+static int fetch_files(int nfiles, const char **urls);
+
+int
+main(void)
+{
+	return (fetch_files(argc - 1, &argv[1]));
+}
+
+static int
+fetch_files(int nfiles, const char **urls)
+{
+	const char **items;
+	FILE *fetch_out, *file_out;
+	struct url_stat ustat;
+	off_t total_bytes, current_bytes;
+	char status[8];
+	char errormsg[512];
+	uint8_t block[4096];
+	size_t chunk, fsize;
+	int i, progress, last_progress;
+	
+	/* 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, "-%ld", (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));
+		}
+
+		items[i*2 + 1] = "Done";
+
+		if (ustat.size > 0 && fsize < (size_t)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);
+		}
+
+		fclose(fetch_out);
+		fclose(file_out);
+	}
+	end_dialog();
+
+	free(items);
+	return (0);
+}

Added: user/nwhitehorn/bsdinstall/libexec/auto
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/auto	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../scripts/auto
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/config
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/config	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../scripts/config
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/distextract
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/distextract	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../distextract/distextract
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/distfetch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/distfetch	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../distfetch/distfetch
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/hostname
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/hostname	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../scripts/hostname
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/mediaselect
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/mediaselect	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../scripts/mediaselect
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/mount
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/mount	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../scripts/mount
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/netconfig
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/netconfig	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../scripts/netconfig
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/libexec/partedit
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/libexec/partedit	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1 @@
+link ../partedit/partedit
\ No newline at end of file

Added: user/nwhitehorn/bsdinstall/partedit/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/partedit/Makefile	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,20 @@
+# $FreeBSD $
+
+PROG=	partedit
+LDADD=	-lgeom -lncursesw -lutil -L/usr/local/lib -lcdialog
+CFLAGS= -I/usr/local/include
+
+PARTEDIT_ARCH= ${MACHINE}
+.if ${MACHINE} == "i386" || ${MACHINE} == "amd64"
+PARTEDIT_ARCH= x86
+.endif
+.if !exists(partedit_${PARTEDIT_ARCH}.c)
+PARTEDIT_ARCH= generic
+.endif
+
+SRCS=	diskeditor.c partedit.c gpart_ops.c partedit_${PARTEDIT_ARCH}.c
+
+WARNS?=	3
+NO_MAN=	true
+
+.include <bsd.prog.mk>

Added: user/nwhitehorn/bsdinstall/partedit/diskeditor.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/partedit/diskeditor.c	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <libutil.h>
+#include <cdialog/dialog.h>
+#include <cdialog/dlg_keys.h>
+
+#include "diskeditor.h"
+
+static void
+print_partedit_item(WINDOW *partitions, struct partedit_item *items,
+    int item, int scroll, int selected)
+{
+	chtype attr = A_NORMAL;
+	char sizetext[16];
+	int y = item - scroll + 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 *scroll)
+{
+	WINDOW *dialog, *partitions;
+	char *prompt;
+	const char *buttons[] =
+	    { "Create", "Delete", "Edit", "Revert", "Finished", 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 (scroll != NULL)
+		cur_scroll = *scroll;
+	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 (scroll != NULL)
+		*scroll = cur_scroll;
+
+	dlg_del_window(partitions);
+	dlg_del_window(dialog);
+	dlg_mouse_free_regions();
+
+	return (cur_button);
+}
+

Added: user/nwhitehorn/bsdinstall/partedit/diskeditor.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/partedit/diskeditor.h	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,13 @@
+struct partedit_item {
+	int indentation;
+	const char *name;
+	size_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);
+

Added: user/nwhitehorn/bsdinstall/partedit/gpart_ops.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/partedit/gpart_ops.c	Fri Dec 31 02:19:38 2010	(r216834)
@@ -0,0 +1,775 @@
+#include <sys/param.h>
+#include <errno.h>
+#include <libutil.h>
+#include <inttypes.h>
+
+#include <libgeom.h>
+#include <cdialog/dialog.h>
+#include <cdialog/dlg_keys.h>
+
+#include "partedit.h"
+
+#define GPART_FLAGS "x" /* Do not commit changes by default */
+
+static void set_part_metadata(const char *name, const char *type,
+    const char *mountpoint, int newfs);
+
+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);
+}
+
+static int
+gpart_partition(struct gprovider *pp, 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) {
+		cancel = dlg_menu("Partition Scheme",
+		    "Select a partition scheme for this volume:", 0, 0, 0,
+		    sizeof(items) / sizeof(items[0]), items, &choice, 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, pp->lg_geom->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(pp->lg_geom->lg_name, 1)->bootcode = 1;
+	return (0);
+}
+
+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;
+		}
+	}
+
+	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_edit(struct gprovider *pp)
+{
+	struct gctl_req *r;
+	struct gconfig *gc;
+	struct gconsumer *cp;
+	struct gprovider *spp;
+	struct ggeom *geom;
+	const char *errstr, *oldtype;
+	struct partition_metadata *md;
+	char sizestr[32];
+	intmax_t index;
+	int hadlabel, choice, junk;
+	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, "Label:", 7, 2, 0, FALSE, "", 11, 2, 12, 15, 0, FALSE,
+		    "Partition name. Not all partition schemes support this.",
+		    FALSE},
+		{0, "Mountpoint:", 11, 3, 0, FALSE, "", 11, 3, 12, 15, 0,
+		    FALSE, "Path at which to mount this partition (leave blank "
+		    "for swap)", 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;
+
+			/* Begin with the hosing: delete all partitions */
+			LIST_FOREACH(spp, &cp->lg_geom->lg_provider,
+			    lg_provider)
+				gpart_delete(spp);
+
+			/* Now destroy the geom itself */
+			r = gctl_get_handle();
+			gctl_ro_param(r, "class", -1, "PART");
+			gctl_ro_param(r, "arg0", -1, cp->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);
+
+			/* And any metadata */
+			delete_part_metadata(cp->lg_geom->lg_name);
+
+			/* Now re-partition and return */
+			gpart_partition(pp, 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, NULL);
+		return;
+	}
+
+	/* Edit editable parameters of a partition */
+	hadlabel = 0;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list