Page MenuHomeFreeBSD

D58184.diff
No OneTemporary

D58184.diff

diff --git a/usr.sbin/bsdinstall/distextract/Makefile b/usr.sbin/bsdinstall/distextract/Makefile
--- a/usr.sbin/bsdinstall/distextract/Makefile
+++ b/usr.sbin/bsdinstall/distextract/Makefile
@@ -1,6 +1,6 @@
BINDIR= ${LIBEXECDIR}/bsdinstall
PROG= distextract
-LIBADD= archive bsddialog m
+LIBADD= archive bsdpv bsddialog m
SRCS= distextract.c
MAN=
diff --git a/usr.sbin/bsdinstall/distextract/Makefile.depend b/usr.sbin/bsdinstall/distextract/Makefile.depend
--- a/usr.sbin/bsdinstall/distextract/Makefile.depend
+++ b/usr.sbin/bsdinstall/distextract/Makefile.depend
@@ -6,6 +6,7 @@
lib/${CSU_DIR} \
lib/libarchive \
lib/libbsddialog \
+ lib/libbsdpv \
lib/libc \
lib/libcompiler_rt \
lib/msun \
diff --git a/usr.sbin/bsdinstall/distextract/distextract.c b/usr.sbin/bsdinstall/distextract/distextract.c
--- a/usr.sbin/bsdinstall/distextract/distextract.c
+++ b/usr.sbin/bsdinstall/distextract/distextract.c
@@ -30,13 +30,14 @@
#include <sys/param.h>
#include <archive.h>
-#include <ctype.h>
#include <bsddialog.h>
-#include <bsddialog_progressview.h>
+#include <bsdpv.h>
+#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -47,25 +48,32 @@
/* Data to process */
static const char *distdir = NULL;
static struct archive *archive = NULL;
+static struct bsdpv_file_node *dists = NULL;
/* Function prototypes */
static void sig_int(int sig);
static int count_files(const char *file);
-static int extract_files(struct bsddialog_fileminibar *file);
+static int extract_files(struct bsdpv_file_node *file, int out);
+static void errmsgbox(const char *title, const char *fmt, ...)
+ __printflike(2, 3);
-#define _errx(...) (bsddialog_end(), errx(__VA_ARGS__))
+#define _errx(...) (bsdpv_end(), errx(__VA_ARGS__))
int
main(void)
{
char *chrootdir;
char *distributions;
- char *distribs, *distrib;
int retval;
- size_t minibar_size = sizeof(struct bsddialog_fileminibar);
- unsigned int nminibars;
- struct bsddialog_fileminibar *dists;
- struct bsddialog_progviewconf pvconf;
+ size_t config_size = sizeof(struct bsdpv_config);
+ size_t file_node_size = sizeof(struct bsdpv_file_node);
+ size_t span;
+ struct bsdpv_config *config;
+ struct bsdpv_file_node *dist = dists;
+ static char backtitle[] = OSNAME " Installer";
+ static char title[] = "Archive Extraction";
+ static char aprompt[] = "\n Overall Progress:";
+ static char pprompt[] = "Extracting distribution files...\n";
struct bsddialog_conf conf;
struct sigaction act;
char error[PATH_MAX + 512];
@@ -74,51 +82,57 @@
errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set");
if ((distdir = getenv("BSDINSTALL_DISTDIR")) == NULL)
distdir = "";
- if ((distribs = strdup(distributions)) == NULL)
- errx(EXIT_FAILURE, "memory error");
+ /* Initialize bsddialog(3) for the pre-scan info/error dialogs */
if (bsddialog_init() == BSDDIALOG_ERROR)
- errx(EXIT_FAILURE, "Error libbsdialog: %s",
+ errx(EXIT_FAILURE, "Error libbsddialog: %s",
bsddialog_geterror());
bsddialog_initconf(&conf);
- bsddialog_backtitle(&conf, OSNAME " Installer");
+ bsddialog_backtitle(&conf, backtitle);
bsddialog_infobox(&conf,
"Checking distribution archives.\nPlease wait...", 4, 35);
- /* Parse $DISTRIBUTIONS */
- nminibars = 0;
- dists = NULL;
- while ((distrib = strsep(&distribs, "\t\n\v\f\r ")) != NULL) {
- if (strlen(distrib) == 0)
+ /*
+ * Parse $DISTRIBUTIONS into bsdpv(3) linked-list
+ */
+ while (*distributions != '\0') {
+ span = strcspn(distributions, "\t\n\v\f\r ");
+ if (span < 1) { /* currently on whitespace */
+ distributions++;
continue;
+ }
/* Allocate a new struct for the distribution */
- dists = realloc(dists, (nminibars + 1) * minibar_size);
- if (dists == NULL)
- _errx(EXIT_FAILURE, "Out of memory!");
+ if (dist == NULL) {
+ if ((dist = calloc(1, file_node_size)) == NULL)
+ _errx(EXIT_FAILURE, "Out of memory!");
+ dists = dist;
+ } else {
+ dist->next = calloc(1, file_node_size);
+ if (dist->next == NULL)
+ _errx(EXIT_FAILURE, "Out of memory!");
+ dist = dist->next;
+ }
- /* Set file path */
- dists[nminibars].path = distrib;
+ /* Set path */
+ if ((dist->path = malloc(span + 1)) == NULL)
+ _errx(EXIT_FAILURE, "Out of memory!");
+ snprintf(dist->path, span + 1, "%s", distributions);
+ dist->path[span] = '\0';
- /* Set mini bar label */
- dists[nminibars].label = strrchr(dists[nminibars].path, '/');
- if (dists[nminibars].label == NULL)
- dists[nminibars].label = dists[nminibars].path;
+ /* Set display name */
+ dist->name = strrchr(dist->path, '/');
+ if (dist->name == NULL)
+ dist->name = dist->path;
/* Set initial length in files (-1 == error) */
- dists[nminibars].size = count_files(dists[nminibars].path);
- if (dists[nminibars].size < 0) {
- bsddialog_end();
+ dist->length = count_files(dist->path);
+ if (dist->length < 0) {
+ bsdpv_end();
return (EXIT_FAILURE);
}
- /* Set initial status and implicitly miniperc to pending */
- dists[nminibars].status = BSDDIALOG_MG_PENDING;
-
- /* Set initial read */
- dists[nminibars].read = 0;
-
- nminibars += 1;
+ distributions += span;
}
/* Optionally chdir(2) into $BSDINSTALL_CHROOT */
@@ -127,9 +141,8 @@
snprintf(error, sizeof(error),
"Could not change to directory %s: %s\n",
chrootdir, strerror(errno));
- conf.title = "Error";
- bsddialog_msgbox(&conf, error, 0, 0);
- bsddialog_end();
+ errmsgbox("Error", "%s", error);
+ bsdpv_end();
return (EXIT_FAILURE);
}
@@ -137,26 +150,38 @@
act.sa_handler = sig_int;
sigaction(SIGINT, &act, 0);
- conf.title = "Archive Extraction";
- conf.auto_minwidth = 40;
- pvconf.callback = extract_files;
- pvconf.refresh = 1;
- pvconf.fmtbottomstr = "%10lli files read @ %'9.1f files/sec.";
- bsddialog_total_progview = 0;
- bsddialog_interruptprogview = bsddialog_abortprogview = false;
- retval = bsddialog_progressview(&conf,
- "\nExtracting distribution files...\n", 0, 0,
- &pvconf, nminibars, dists);
-
- if (retval == BSDDIALOG_ERROR) {
- fprintf(stderr, "progressview error: %s\n",
- bsddialog_geterror());
- }
-
- bsddialog_end();
+ /*
+ * End bsddialog(3) mode; bsdpv(3) manages its own init/teardown so
+ * that the terminal is in a known state before the progress view.
+ */
+ bsdpv_end();
- free(distribs);
- free(dists);
+ /*
+ * Hand off to bsdpv(3)
+ */
+ if ((config = calloc(1, config_size)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory!");
+ config->backtitle = backtitle;
+ config->title = title;
+ config->pprompt = pprompt;
+ config->aprompt = aprompt;
+ config->options |= BSDPV_WIDE_MODE;
+ config->label_size = -1;
+ config->action = extract_files;
+ config->status_solo =
+ "%10lli files read @ %'9.1f files/sec.";
+ config->status_many =
+ "%10lli files read @ %'9.1f files/sec. [%i/%i busy/wait]";
+ retval = bsdpv(config, dists);
+
+ bsdpv_free();
+ free(config);
+ while ((dist = dists) != NULL) {
+ dists = dist->next;
+ if (dist->path != NULL)
+ free(dist->path);
+ free(dist);
+ }
return (retval);
}
@@ -164,7 +189,36 @@
static void
sig_int(int sig __unused)
{
- bsddialog_interruptprogview = true;
+ bsdpv_interrupt = TRUE;
+}
+
+/*
+ * Display an error in a bsddialog(3) msgbox. Initializes bsddialog(3) mode if
+ * it is not already active (e.g., when called from within the bsdpv(3) action
+ * callback, where bsddialog(3) is already initialized).
+ */
+static void
+errmsgbox(const char *title, const char *fmt, ...)
+{
+ va_list ap;
+ int inmode;
+ struct bsddialog_conf conf;
+ char errormsg[PATH_MAX + 512];
+
+ va_start(ap, fmt);
+ vsnprintf(errormsg, sizeof(errormsg), fmt, ap);
+ va_end(ap);
+
+ inmode = bsddialog_inmode();
+ if (!inmode && bsddialog_init() == BSDDIALOG_ERROR) {
+ warnx("%s: %s", title, errormsg);
+ return;
+ }
+ bsddialog_initconf(&conf);
+ conf.title = title;
+ bsddialog_msgbox(&conf, errormsg, 0, 0);
+ if (!inmode)
+ bsddialog_end();
}
/*
@@ -182,8 +236,6 @@
struct archive_entry *entry;
char line[512];
char path[PATH_MAX];
- char errormsg[PATH_MAX + 512];
- struct bsddialog_conf conf;
if (manifest == NULL) {
snprintf(path, sizeof(path), "%s/MANIFEST", distdir);
@@ -217,12 +269,9 @@
* Either no manifest, or manifest didn't mention this archive.
* Use archive(3) to read the archive, counting files within.
*/
- bsddialog_initconf(&conf);
if ((archive = archive_read_new()) == NULL) {
- snprintf(errormsg, sizeof(errormsg),
- "Error: %s\n", archive_error_string(NULL));
- conf.title = "Extract Error";
- bsddialog_msgbox(&conf, errormsg, 0, 0);
+ errmsgbox("Extract Error", "Error: %s\n",
+ archive_error_string(NULL));
return (-1);
}
archive_read_support_format_all(archive);
@@ -230,11 +279,8 @@
snprintf(path, sizeof(path), "%s/%s", distdir, file);
retval = archive_read_open_filename(archive, path, 4096);
if (retval != ARCHIVE_OK) {
- snprintf(errormsg, sizeof(errormsg),
- "Error while extracting %s: %s\n", file,
- archive_error_string(archive));
- conf.title = "Extract Error";
- bsddialog_msgbox(&conf, errormsg, 0, 0);
+ errmsgbox("Extract Error", "Error while extracting %s: %s\n",
+ file, archive_error_string(archive));
archive = NULL;
return (-1);
}
@@ -249,24 +295,18 @@
}
static int
-extract_files(struct bsddialog_fileminibar *file)
+extract_files(struct bsdpv_file_node *file, int out __unused)
{
int retval;
struct archive_entry *entry;
char path[PATH_MAX];
- char errormsg[PATH_MAX + 512];
- struct bsddialog_conf conf;
-
- bsddialog_initconf(&conf);
/* Open the archive if necessary */
if (archive == NULL) {
if ((archive = archive_read_new()) == NULL) {
- snprintf(errormsg, sizeof(errormsg),
- "Error: %s\n", archive_error_string(NULL));
- conf.title = "Extract Error";
- bsddialog_msgbox(&conf, errormsg, 0, 0);
- bsddialog_abortprogview = true;
+ errmsgbox("Extract Error", "Error: %s\n",
+ archive_error_string(NULL));
+ bsdpv_abort = TRUE;
return (-1);
}
archive_read_support_format_all(archive);
@@ -274,13 +314,10 @@
snprintf(path, sizeof(path), "%s/%s", distdir, file->path);
retval = archive_read_open_filename(archive, path, 4096);
if (retval != 0) {
- snprintf(errormsg, sizeof(errormsg),
- "Error opening %s: %s\n", file->label,
- archive_error_string(archive));
- conf.title = "Extract Error";
- bsddialog_msgbox(&conf, errormsg, 0, 0);
- file->status = BSDDIALOG_MG_FAILED;
- bsddialog_abortprogview = true;
+ errmsgbox("Extract Error", "Error opening %s: %s\n",
+ file->name, archive_error_string(archive));
+ file->status = BSDPV_STATUS_FAILED;
+ bsdpv_abort = TRUE;
return (-1);
}
}
@@ -301,7 +338,7 @@
if (retval == ARCHIVE_EOF) {
archive_read_free(archive);
archive = NULL;
- file->status = BSDDIALOG_MG_DONE; /*Done*/;
+ file->status = BSDPV_STATUS_DONE;
return (100);
} else if (retval != ARCHIVE_OK &&
!(retval == ARCHIVE_WARN &&
@@ -312,22 +349,19 @@
* for our purposes. Would be nice if this were a libarchive
* option.
*/
- snprintf(errormsg, sizeof(errormsg),
- "Error while extracting %s: %s\n", file->label,
- archive_error_string(archive));
- conf.title = "Extract Error";
- bsddialog_msgbox(&conf, errormsg, 0, 0);
- file->status = BSDDIALOG_MG_FAILED; /* Failed */
- bsddialog_abortprogview = true;
+ errmsgbox("Extract Error", "Error while extracting %s: %s\n",
+ file->name, archive_error_string(archive));
+ file->status = BSDPV_STATUS_FAILED;
+ bsdpv_abort = TRUE;
return (-1);
}
- bsddialog_total_progview++;
+ bsdpv_overall_read++;
file->read++;
/* Calculate [overall] percentage of completion (if possible) */
- if (file->size >= 0)
- return (file->read * 100 / file->size);
+ if (file->length >= 0)
+ return (file->read * 100 / file->length);
else
return (-1);
}
diff --git a/usr.sbin/bsdinstall/scripts/pkgbase.in b/usr.sbin/bsdinstall/scripts/pkgbase.in
--- a/usr.sbin/bsdinstall/scripts/pkgbase.in
+++ b/usr.sbin/bsdinstall/scripts/pkgbase.in
@@ -29,6 +29,14 @@
end
end
+-- Returns true if the named program is found in $PATH.
+local function have(program)
+ local p = io.popen("command -v " .. program .. " 2>/dev/null")
+ local output = p:read("*a")
+ p:close()
+ return output ~= nil and output ~= ""
+end
+
-- Read from the given fd until EOF
-- Returns all the data read as a single string
local function read_all(fd)
@@ -306,6 +314,79 @@
return packages
end
+-- Returns the number of packages a `pkg install' of $packages would install
+-- (dependencies included), by parsing a dry-run. Returns 0 if it cannot be
+-- determined, which callers treat as "progress total unknown".
+local function count_to_install(pkg, packages)
+ local out = capture(pkg .. "install -U -n -y -r FreeBSD-base " ..
+ packages .. " 2>&1")
+ local n = out:match("Number of packages to be installed: (%d+)")
+ return tonumber(n) or 0
+end
+
+-- Install $packages while displaying a bsdpv(1) progress view driven by
+-- pkg(8)'s event pipe. $total is the number of INFO_INSTALL_FINISHED events
+-- expected (see count_to_install()). Returns pkg(8)'s success (Boolean).
+--
+-- Three processes cooperate: pkg(8) (this parent) writes JSON events to a
+-- FIFO; a translator child converts each INFO_INSTALL_FINISHED into one line;
+-- and a bsdpv(1) child renders those lines as overall progress. bsdpv(1) reads
+-- its lines from a pipe (rather than the FIFO) so that pkg(8)'s own event
+-- stream cannot be misread as progress input.
+local function install_with_progress(pkg, packages, total)
+ local tmp = capture("mktemp -d -t bsdinstall-pkgbase")
+ local evpath = tmp .. "/event.pipe"
+ assert(os.execute("mkfifo " .. evpath))
+
+ -- Pipe carrying one line per completed package into bsdpv(1)
+ local pv_r, pv_w = assert(unistd.pipe())
+
+ -- Child 1: the progress view
+ local pv_pid = assert(unistd.fork())
+ if pv_pid == 0 then
+ assert(unistd.close(pv_w))
+ if pv_r ~= 0 then
+ assert(unistd.dup2(pv_r, 0))
+ assert(unistd.close(pv_r))
+ end
+ assert(unistd.execp("bsdpv", {
+ "-klN",
+ "-t", "Fetching and Installing Packages",
+ "-b", "FreeBSD Installer",
+ "-p", "Installing base system packages...",
+ tostring(total) .. ":packages",
+ }))
+ unistd._exit(127)
+ end
+ assert(unistd.close(pv_r))
+
+ -- Child 2: translate pkg(8) events into progress lines. Opening the
+ -- FIFO read-only blocks until pkg(8) opens it for writing, so the
+ -- reader is present before any event is emitted.
+ local tr_pid = assert(unistd.fork())
+ if tr_pid == 0 then
+ local ev = assert(io.open(evpath, "r"))
+ for line in ev:lines() do
+ if line:find("INFO_INSTALL_FINISHED", 1, true) then
+ unistd.write(pv_w, "x\n")
+ end
+ end
+ ev:close()
+ unistd.close(pv_w)
+ unistd._exit(0)
+ end
+ assert(unistd.close(pv_w))
+
+ -- Parent: perform the installation, funneling events to the translator
+ local ok = os.execute("env EVENT_PIPE=" .. evpath .. " " .. pkg ..
+ "install -U -y -r FreeBSD-base " .. packages)
+
+ sys_wait.wait(tr_pid)
+ sys_wait.wait(pv_pid)
+ os.execute("rm -rf " .. tmp)
+ return ok
+end
+
local function parse_options()
local options = {}
for _, a in ipairs(arg) do
@@ -365,7 +446,22 @@
end
end
- if not os.execute(pkg .. "install -U -y -r FreeBSD-base " .. packages) then
+ -- Packages are already fetched above, so the install below is
+ -- database-bound and quick to stream. When bsdpv(1) is available
+ -- (it is not during early bootstrap) show a progress view driven by
+ -- pkg(8)'s event pipe; otherwise fall back to plain pkg(8) output.
+ local installed
+ if have("bsdpv") then
+ local total = count_to_install(pkg, packages)
+ if total > 0 then
+ installed = install_with_progress(pkg, packages, total)
+ end
+ end
+ if installed == nil then
+ installed = os.execute(pkg ..
+ "install -U -y -r FreeBSD-base " .. packages)
+ end
+ if not installed then
os.exit(1)
end

File Metadata

Mime Type
text/plain
Expires
Fri, Jul 17, 5:28 AM (8 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35143779
Default Alt Text
D58184.diff (15 KB)

Event Timeline