Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162728690
D58184.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D58184.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58184: bsdinstall: give pkgbase/distextract a progress bar
Attached
Detach File
Event Timeline
Log In to Comment