Page MenuHomeFreeBSD

bsdpv: revive dpv with optional bsddialog(3)
Needs RevisionPublic

Authored by dteske on Jul 10 2026, 1:10 AM.
Tags
None
Referenced Files
F171208020: D58133.id185678.diff
Wed, Sep 9, 1:02 PM
Unknown Object (File)
Tue, Sep 8, 5:23 PM
Unknown Object (File)
Tue, Sep 8, 4:49 PM
Unknown Object (File)
Tue, Sep 8, 4:09 PM
Unknown Object (File)
Tue, Sep 8, 1:12 PM
Unknown Object (File)
Tue, Sep 8, 12:44 PM
Unknown Object (File)
Tue, Sep 8, 7:07 AM
Unknown Object (File)
Tue, Sep 8, 1:41 AM

Details

Summary

Resurrect dialog progress view -- disconnected from the build since
LGPL dialog(3) removal -- as libbsdpv/bsdpv, with the public API
renamed dpv_* to bsdpv_* to mark a clean break from the code that
required GNU dialog.

libdpv depended on dlg_gauge_reallocate(), which bsddialog(3) does not
provide. The dialog renderer is instead written to a persistent gauge
API -- bsddialog_gauge_open(), _update(), _flush(), _close() -- that
gives the caller ownership of the widget lifecycle rather than
respawning the gauge on every update. That API is proposed upstream
(bsddialog merge request 12) but has not yet landed, so contrib/bsddialog
1.1 cannot satisfy it; bsddialog(3) support is therefore a compile-time
option, BSDPV_BSDDIALOG, defaulting to off. The default build compiles
the dialog renderer out under HAVE_BSDDIALOG guards and links against
libutil alone -- no bsddialog, no ncurses. Flip the default when contrib
grows the API. Terminal styling that previously reached into dialog's
color table now derives from bsddialog_get_theme() and
bsddialog_color_attrs(). The DPV_DISPLAY_DIALOG and DPV_DISPLAY_XDIALOG
spawn modes are removed: the former exec'd the GPL utility this change
exists to shed, and the latter served a long-dead X11 port. libfigpar
stays disconnected because its only consumer here was .dialogrc parsing
and bsddialog has no .dialogrc support; the one general-purpose routine
libdpv used from it, strexpandnl(), is absorbed as a private utility.
Both new components are PRIVATELIB, matching libbsddialog, so no
external ABI is promised.

The utility defaults to a command-line progress view on standard error;
-D selects the bsddialog(3) gauge when built with that support and is
refused otherwise. A new CLI renderer in libbsdpv paints per-file bars,
an optional Overall row (-m), -a text, and the status line with CSI
updates, decoupled from the gauge refresh rate (-U). Library callers
that leave display_type zero still get BSDPV_DISPLAY_BSDDIALOG for ABI
stability; a build without bsddialog support treats that request as
BSDPV_DISPLAY_CLI. bsdpv_announce(3) exposes transient Opening/Waiting
status while blocked outside the main progress loop (FIFO peers, -m
paths); honor -U 0 by not remapping zero to the default rate and by
clearing leftover announce text when progress resumes. Multi-path (-m)
mode opens paths serially, treats '-' as /dev/stdin, and uses
non-blocking FIFO I/O so the UI stays responsive.

Three latent bugs inherited from dpv are fixed in the port: the
status-line formats given with -i/-I were unconditionally clobbered
after option parsing (and the many-files default was assigned the
solo-file format); the /dev/stdin descriptor heuristic was applied even
when stdin was a pipe, driving the input descriptor negative when -o or
-x was in use; and a transfer that ended between display updates could
exit without rendering its final Done/Fail state.

Add a pkgbase package for bsdpv. While here, fix creation of
$INCDIR/private/bsdpv/ by modifying share/mk/bsd.incs.mk.

Test Plan

Build/install, then ...

CLI tests (no bsddialog required):

  1. yes | bsdpv -l - followed by Ctrl-c to abort when done
  2. yes | bsdpv -lN 1000000000:-

Tests requiring bsddialog 1.2+ with persistent-gauge API and BSDPV_BSDDIALOG = yes:

  1. yes | bsdpv -Dl - followed by Ctrl-c to abort when done
  2. yes | bsdpv -DlN 1000000000:-

bsddialog support requires upstream to land https://gitlab.com/alfix/bsddialog/-/merge_requests/12

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 76418
Build 73301: arc lint + arc unit

Event Timeline

dteske retitled this revision from commit 1214275b63fee367987c62bda49bf8519353d2ef Author: Devin Teske <dteske@FreeBSD.org> Date: Fri Jul 3 09:48:34 2026 -0700 to bsdpv: revive dpv atop bsddialog.Jul 10 2026, 1:10 AM
dteske edited the summary of this revision. (Show Details)
dteske added reviewers: adrian, asiciliano, emaste, des.
dteske added reviewers: manpages, Installer.

Worth repeating:

Requires new bsddialog 1.2 here https://reviews.freebsd.org/D58118

bcr added a subscriber: bcr.

Nice man pages you have there. Shame if no-one would approve them. ;-)

This revision is now accepted and ready to land.Jul 11 2026, 1:45 PM
usr.bin/bsdpv/Makefile
2

to add a new package, you also have to add the package definition in packages/bsdpv/ and update packages/Makefile.

please run make buildkernel buildworld update-packages to check the new package(s) are built correctly.

Add CLI interface, new default (require -D to enable bsddialog).
Add package files (thanks ivy)

This revision now requires review to proceed.Jul 27 2026, 6:30 AM

What's the point of having it in base ?

What's the point of having it in base ?

Fair question. Short answer: base already had this job, and base still needs it.

dpv lived in base as the progress view for installer/config-style work. Upstream dialog grew dlg_reallocate_gauge for that path (2013/09/21); when FreeBSD moved off LGPL dialog(3) to bsddialog(3), that persistent-gauge lifecycle did not come along, so dpv was disconnected from the build rather than ported. This finishes that migration: same job, on bsddialog(3), with a CLI default for non-dialog contexts. The missing gauge open/update/flush/close path is proposed upstream in bsddialog MR !12 (FreeBSD discussion in D58118).

The immediate consumers are also in base: bsdconfig’s parallel package install progress (D58183) and bsdinstall/distextract progress (D58184), including the pkgbase install path. Those run before (or without) ports, so a ports-only helper does not cover installer/config/pkgbase.

Happy to expand on any of that if useful.

this breaks buildworld for me, i believe due to the changes in bsd.incs.mk:

===> lib/atf/libatf-c/tests/detail (includes)
--- _INCSINS ---
install -U  -C -o root -g wheel -m 444  /src/bsd/main/contrib/atf/atf-c/build.h /src/bsd/main/contrib/atf/atf-c/check.h /src/bsd/main/contrib/atf/atf-c/defs.h /src/bsd/main/contrib/atf/atf-c/error.h /src/bsd/main/contrib/atf/atf-c/error_fwd.h /src/bsd/main/contrib/atf/atf-c/macros.h /src/bsd/main/contrib/atf/atf-c/tc.h /src/bsd/main/contrib/atf/atf-c/tp.h /src/bsd/main/contrib/atf/atf-c/utils.h /build/obj/bsd/src/bsd/main/amd64.amd64/tmp/usr/include/atf-c/
make[5]: warning: Invalid character " " in variable name "INCSOWN_atf-c.h install-INCSdir"
        in command "${INSTALL} ${TAG_ARGS:D${TAG_ARGS},dev} -C -o ${${:UINCS}OWN_${.ALLSRC:T}}  -g ${${:UINCS}GRP_${.ALLSRC:T}} -m ${${:UINCS}MODE_${.ALLSRC:T}}  ${.ALLSRC:Ninstall-${:UINCS}dir}  ${DESTDIR}${${:UINCS}DIR_${.ALLSRC:T}}/${${:UINCS}NAME_${.ALLSRC:T}}"
--- includes_subdir_lib/atf/libatf-c++ ---
--- includes_subdir_lib/atf/libatf-c++/tests ---
===> lib/atf/libatf-c++/tests (includes)
--- includes_subdir_lib/atf/libatf-c ---
        in target "_INCSINS_atf-c.h" from /src/bsd/main/share/mk/bsd.incs.mk:70
        in make[5] in directory "/src/bsd/main/lib/atf/libatf-c"
make[5]: warning: Invalid character " " in variable name "INCSGRP_atf-c.h install-INCSdir"
        in command "${INSTALL} ${TAG_ARGS:D${TAG_ARGS},dev} -C -o ${${:UINCS}OWN_${.ALLSRC:T}}  -g ${${:UINCS}GRP_${.ALLSRC:T}} -m ${${:UINCS}MODE_${.ALLSRC:T}}  ${.ALLSRC:Ninstall-${:UINCS}dir}  ${DESTDIR}${${:UINCS}DIR_${.ALLSRC:T}}/${${:UINCS}NAME_${.ALLSRC:T}}"
        in target "_INCSINS_atf-c.h" from /src/bsd/main/share/mk/bsd.incs.mk:70
        in make[5] in directory "/src/bsd/main/lib/atf/libatf-c"
make[5]: warning: Invalid character " " in variable name "INCSMODE_atf-c.h install-INCSdir"
        in command "${INSTALL} ${TAG_ARGS:D${TAG_ARGS},dev} -C -o ${${:UINCS}OWN_${.ALLSRC:T}}  -g ${${:UINCS}GRP_${.ALLSRC:T}} -m ${${:UINCS}MODE_${.ALLSRC:T}}  ${.ALLSRC:Ninstall-${:UINCS}dir}  ${DESTDIR}${${:UINCS}DIR_${.ALLSRC:T}}/${${:UINCS}NAME_${.ALLSRC:T}}"
        in target "_INCSINS_atf-c.h" from /src/bsd/main/share/mk/bsd.incs.mk:70
        in make[5] in directory "/src/bsd/main/lib/atf/libatf-c"
make[5]: warning: Invalid character " " in variable name "INCSDIR_atf-c.h install-INCSdir"
        in command "${INSTALL} ${TAG_ARGS:D${TAG_ARGS},dev} -C -o ${${:UINCS}OWN_${.ALLSRC:T}}  -g ${${:UINCS}GRP_${.ALLSRC:T}} -m ${${:UINCS}MODE_${.ALLSRC:T}}  ${.ALLSRC:Ninstall-${:UINCS}dir}  ${DESTDIR}${${:UINCS}DIR_${.ALLSRC:T}}/${${:UINCS}NAME_${.ALLSRC:T}}"
        in target "_INCSINS_atf-c.h" from /src/bsd/main/share/mk/bsd.incs.mk:70
        in make[5] in directory "/src/bsd/main/lib/atf/libatf-c"
make[5]: warning: Invalid character " " in variable name "INCSNAME_atf-c.h install-INCSdir"
        in command "${INSTALL} ${TAG_ARGS:D${TAG_ARGS},dev} -C -o ${${:UINCS}OWN_${.ALLSRC:T}}  -g ${${:UINCS}GRP_${.ALLSRC:T}} -m ${${:UINCS}MODE_${.ALLSRC:T}}  ${.ALLSRC:Ninstall-${:UINCS}dir}  ${DESTDIR}${${:UINCS}DIR_${.ALLSRC:T}}/${${:UINCS}NAME_${.ALLSRC:T}}"
        in target "_INCSINS_atf-c.h" from /src/bsd/main/share/mk/bsd.incs.mk:70
        in make[5] in directory "/src/bsd/main/lib/atf/libatf-c"

[...]

--- includes_subdir_lib/atf/libatf-c++ ---
--- install-INCSdir ---
install -U -d  -o root -g wheel -m 755  /build/obj/bsd/src/bsd/main/amd64.amd64/tmp/usr/include/atf-c++
--- includes_subdir_lib/atf/libatf-c ---
install: invalid file mode: /src/bsd/main/contrib/atf/atf-c.h
*** [_INCSINS_atf-c.h] Error code 64

make[5]: stopped making "includes" in /src/bsd/main/lib/atf/libatf-c
make[5]: 1 error
In D58133#1341701, @ivy wrote:

this breaks buildworld for me, i believe due to the changes in bsd.incs.mk:

Thanks for testing. I didn't get a chance to test properly as I was exhausted from a long day and just wanted to get it upstreamed before it got any bigger. That's on me.

The install-${group}dir dependency ends up in .ALLSRC, so the per-header INCSOWN_* / -m lookups see atf-c.h install-INCSdir and blow up. I will rework that part so the directory is created without polluting .ALLSRC.

Separate note for a full build of this stack: D58133 also needs the bsddialog 1.2 APIs from parent D58118 (upstream MR !12). Without that, libbsdpv fails on the new gauge symbols; it is unrelated to the bsd.incs.mk breakage you hit.

Fix bsd.incs.mk include-dir install (do not put install-${group}dir in .ALLSRC; thanks ivy)

dteske retitled this revision from bsdpv: revive dpv atop bsddialog to bsdpv: revive dpv with optional bsddialog(3).Thu, Sep 3, 6:05 AM
dteske edited the test plan for this revision. (Show Details)

Make bsddialog(3) support optional

ziaee requested changes to this revision.Fri, Sep 4, 10:54 AM
ziaee added inline comments.
lib/libbsdpv/bsdpv.3
60–71

We usually put this in HISTORY

77

This is too wide to fit in a reference MANWIDTH. I think this type of structure is very clear and doesn't need to be indented. Alternatively, sometimes people will just use two spaces, but I personally think that looks bad.

429

Please don't use macros in width specifiers. They sometimes render as negative one space in some implementations and are totally cursed.

433

I'm not sure if these should have commas or maybe on their own lines?

450

Try the Defined Variable macros for defined variables! We also overload the everliving hell out of Dv such as for ioctls, but this is it's original purpose.

463

Names use Nm or Xr, but if it would have a manual on a different system it uses Sy for visual consistency with Nm.

467

Try the "mailto" macro to put the hyperlink in email addresses!

usr.bin/bsdpv/bsdpv.1
315

My gut reaction is that this information will not age well and is not so useful.

372
376
This revision now requires changes to proceed.Fri, Sep 4, 10:54 AM

Why does dpv absolutely have to be in base?

In D58133#1362427, @des wrote:

Why does dpv absolutely have to be in base?

Because its consumers are in base, and because a tool that tracks the release it lives in is a different program from one that must run on every release.

The first part is the familiar one. bsdinstall and bsdconfig are the consumers this library exists for, and they had this progress view from the 10.x days until dialog(3) left the tree. bsdinstall is baked into the release media, including memstick-mini, which carries no packages at all, so nothing it depends on can come from ports; that is settled by the media, not by preference. bsdconfig runs on a fresh install before pkg(8) is bootstrapped and often without network. Both are updated to use bsdpv in D58183 and D58184, and the pkgbase install path in particular is a long, silent step today.

The second part is the one I would ask you to weigh. We keep the compiler and bmake in base so the OS can build itself with nothing but the OS, and the same reasoning applies to what surrounds that build. A tool in base tracks one release: it can stay concise, and it can shrink when the branch it lives on gets simpler. The same tool in ports installs onto every supported release and has to behave correctly on each of them, so it accumulates conditionals on uname -r that never come off. srcpv(1) in D59425 is the newest consumer and the clearest illustration: it reads its schedule out of Makefile.inc1 and sys/modules of the tree in front of it, so it belongs beside those makefiles and moves with them. bsdconfig is the same argument at scale; at over 30k lines, carrying per-release compatibility for old branches is not a size it could survive.

manu asked the same question in July and the mechanism is in D58133#1341621. The library is PRIVATELIB, so no external ABI is promised, and pkgbase carries it as its own package. If the concern is a different one -- footprint, the -D dialog path, or whether the installer should have progress views at all -- I would like to hear it so I answer the right question.

In D58133#1362427, @des wrote:

Why does dpv absolutely have to be in base?

Because its consumers are in base, and because a tool that tracks the release it lives in is a different program from one that must run on every release.

Nothing in base depends on dpv.

In D58133#1364746, @des wrote:

Nothing in base depends on dpv.

Nothing in base depends on dpv. dpv was removed. This revision is
bsdpv.

D58183, D58184, and D59425 are the consumers, and they cannot land
until this does. The dependents cannot precede the dependency.