Page MenuHomeFreeBSD

D49822.id153638.diff
No OneTemporary

D49822.id153638.diff

diff --git a/usr.sbin/bsdinstall/bsdinstall.8 b/usr.sbin/bsdinstall/bsdinstall.8
--- a/usr.sbin/bsdinstall/bsdinstall.8
+++ b/usr.sbin/bsdinstall/bsdinstall.8
@@ -244,6 +244,14 @@
.Ev DISTRIBUTIONS
into
.Ev BSDINSTALL_CHROOT .
+.It Cm pkgbase
+Fetch and install base system packages to
+.Ev BSDINSTALL_CHROOT .
+Packages are fetched according to repository configuration in
+.Ev BSDINSTALL_PKG_REPOS_DIR
+if set, or
+.Lk pkg.freebsd.org
+otherwise.
.It Cm firmware
executes
.Xr fwget 8
@@ -324,6 +332,15 @@
.Pa https://download.freebsd.org/ftp/releases/powerpc/powerpc64/13.1-RELEASE/
or
.Pa http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/amd64/12.2-RELEASE/ .
+.It Ev BSDINSTALL_PKG_REPOS_DIR
+Directory containing pkg repository configuration files used by the
+.Cm pkgbase
+target.
+See
+.Sx REPOSITORY CONFIGURATION
+in
+.Xr pkg.conf 5 .
+Default: unset
.It Ev BSDINSTALL_CHROOT
The directory into which the distribution files should be unpacked and the
directory at which the root file system of the new system should be mounted.
diff --git a/usr.sbin/bsdinstall/scripts/Makefile b/usr.sbin/bsdinstall/scripts/Makefile
--- a/usr.sbin/bsdinstall/scripts/Makefile
+++ b/usr.sbin/bsdinstall/scripts/Makefile
@@ -17,6 +17,7 @@
netconfig \
netconfig_ipv4 \
netconfig_ipv6 \
+ pkgbase \
rootpass \
script \
services \
diff --git a/usr.sbin/bsdinstall/scripts/pkgbase b/usr.sbin/bsdinstall/scripts/pkgbase
new file mode 100755
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/pkgbase
@@ -0,0 +1,191 @@
+#!/usr/libexec/flua
+
+-- SPDX-License-Identifier: BSD-2-Clause
+--
+-- Copyright(c) 2025 The FreeBSD Foundation.
+--
+-- This software was developed by Isaac Freund <ifreund@freebsdfoundation.org>
+-- under sponsorship from the FreeBSD Foundation.
+
+-- Fetch and install pkgbase packages to BSDINSTALL_CHROOT.
+-- Respect BSDINSTALL_PKG_REPOS_DIR if set, otherwise use pkg.freebsd.org.
+function pkgbase()
+ -- TODO Support fully offline pkgbase installation by taking a new enough
+ -- version of pkg.pkg as input.
+ if not os.execute("pkg -N > /dev/null 2>&1") then
+ print("Bootstrapping pkg on the host system")
+ assert(os.execute("pkg bootstrap -y"))
+ end
+
+ local chroot = assert(os.getenv("BSDINSTALL_CHROOT"))
+ assert(os.execute("mkdir -p " .. chroot))
+
+ local repos_dir = os.getenv("BSDINSTALL_PKG_REPOS_DIR")
+ if not repos_dir then
+ repos_dir = chroot .. "/usr/local/etc/pkg/repos/"
+ create_base_repo_conf(repos_dir)
+ create_fingerprint(chroot)
+ end
+
+ -- We must use --repo-conf-dir rather than -o REPOS_DIR here as the latter
+ -- is interpreted relative to the --rootdir. BSDINSTALL_PKG_REPOS_DIR must
+ -- be allowed to point to a path outside the chroot.
+ local pkg = "pkg --rootdir " .. chroot ..
+ " --repo-conf-dir " .. repos_dir .. " -o IGNORE_OSVERSION=yes "
+
+ while not os.execute(pkg .. "update") do
+ if not prompt_yn("Updating repositories failed, try again?") then
+ print("Canceled")
+ os.exit(1)
+ end
+ end
+
+ local packages = table.concat(select_packages(pkg), " ")
+
+ while not os.execute(pkg .. "install -U -F -y -r FreeBSD-base " .. packages) do
+ if not prompt_yn("Fetching packages failed, try again?") then
+ print("Canceled")
+ os.exit(1)
+ end
+ end
+
+ if os.execute(pkg .. "install -U -y -r FreeBSD-base " .. packages) then
+ os.exit(0)
+ else
+ os.exit(1)
+ end
+end
+
+function create_fingerprint(chroot)
+ local dir = chroot .. "/usr/share/keys/pkg/trusted/"
+ assert(os.execute("mkdir -p " .. dir))
+ local f <close> = assert(io.open(dir .. "/pkg.freebsd.org.2013102301", "w"))
+ assert(f:write([[
+function: "sha256"
+fingerprint: "b0170035af3acc5f3f3ae1859dc717101b4e6c1d0a794ad554928ca0cbb2f438"
+]]))
+end
+
+function create_base_repo_conf(dir)
+ assert(os.execute("mkdir -p " .. dir))
+ local f <close> = assert(io.open(dir .. "/FreeBSD-base.conf", "w"))
+ assert(f:write(string.format([[
+FreeBSD-base: {
+ url: "%s",
+ mirror_type: "srv",
+ signature_type: "fingerprints",
+ fingerprints: "/usr/share/keys/pkg",
+ enabled: yes
+}
+]], base_repo_url())))
+end
+
+-- Returns the URL for the pkgbase repository that matches the version
+-- reported by freebsd-version(1)
+function base_repo_url()
+ -- e.g. 15.0-CURRENT, 14.2-STABLE, 14.1-RELEASE, 14.1-RELEASE-p6,
+ local raw = capture("freebsd-version")
+ local major, minor, branch = assert(raw:match("(%d+)%.(%d+)%-(%u+)"))
+
+ if math.tointeger(major) < 14 then
+ fatal("unsupported FreeBSD version: " .. raw)
+ end
+
+ if branch == "RELEASE" then
+ return "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_" .. minor
+ elseif branch == "CURRENT" or branch == "STABLE" then
+ return "pkg+https://pkg.FreeBSD.org/${ABI}/base_latest"
+ else
+ fatal("unsupported FreeBSD version: " .. raw)
+ end
+end
+
+-- Returns a list of pkgbase packages equivalent to the default base.txz and kernel.txz
+function select_packages(pkg)
+ local kernel = {}
+ local kernel_dbg = {}
+ local base = {}
+ local base_dbg = {}
+ local lib32 = {}
+ local lib32_dbg = {}
+ local src = {}
+ local tests = {}
+
+ local rquery = capture(pkg .. "rquery -U -r FreeBSD-base %n")
+ for package in rquery:gmatch("[^\n]+") do
+ if package == "FreeBSD-src" or package:match("FreeBSD%-src%-.*") then
+ table.insert(src, package)
+ elseif package == "FreeBSD-tests" or package:match("FreeBSD%-tests%-.*") then
+ table.insert(tests, package)
+ elseif package:match("FreeBSD%-kernel%-.*") then
+ -- Kernels other than FreeBSD-kernel-generic are ignored
+ if package == "FreeBSD-kernel-generic" then
+ table.insert(kernel, package)
+ elseif package == "FreeBSD-kernel-generic-dbg" then
+ table.insert(kernel_dbg, package)
+ end
+ elseif package:match(".*%-dbg%-lib32") then
+ table.insert(lib32_dbg, package)
+ elseif package:match(".*%-lib32") then
+ table.insert(lib32, package)
+ elseif package:match(".*%-dbg") then
+ table.insert(base_dbg, package)
+ else
+ table.insert(base, package)
+ end
+ end
+ assert(#kernel == 1)
+ assert(#kernel_dbg == 1)
+ assert(#base > 0)
+ assert(#base_dbg > 0)
+ assert(#lib32 > 0)
+ assert(#lib32_dbg > 0)
+ assert(#src > 0)
+ assert(#tests > 0)
+
+ local selected = {}
+ append_list(selected, kernel)
+ append_list(selected, base)
+
+ return selected
+end
+
+function append_list(list, other)
+ for _, item in ipairs(other) do
+ table.insert(list, item)
+ end
+end
+
+function prompt_yn(question)
+ while true do
+ io.write(question .. " (y/n) ")
+ local input = io.read()
+ if input == "y" or input == "Y" then
+ return true
+ elseif input == "n" or input == "N" then
+ return false
+ end
+ end
+end
+
+-- Run a command using the OS shell and capture the stdout
+-- Strips exactly one trailing newline if present, does not strip any other whitespace.
+-- Asserts that the command exits cleanly
+function capture(command)
+ local p = io.popen(command)
+ local output = p:read("*a")
+ assert(p:close())
+ -- Strip exactly one trailing newline from the output, if there is one
+ return output:match("(.-)\n$") or output
+end
+
+function fatal(msg)
+ err(msg)
+ os.exit(1)
+end
+
+function err(msg)
+ io.stderr:write("Error: " .. msg .. "\n")
+end
+
+pkgbase()

File Metadata

Mime Type
text/plain
Expires
Tue, May 26, 5:57 AM (18 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33525259
Default Alt Text
D49822.id153638.diff (7 KB)

Event Timeline