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