bsdinstall: add pkgbase target

Reviewed by:	ziaee (manpages), kevans (lua), emaste
Relnotes:	Yes
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D49822
This commit is contained in:
Isaac Freund 2025-04-01 23:25:49 +00:00 committed by Ed Maste
parent 77be1f2fa6
commit ee9cfd7275
5 changed files with 224 additions and 0 deletions

View file

@ -0,0 +1,7 @@
FreeBSD-base: {
url: "pkg+https://pkg.FreeBSD.org/${ABI}/%%SUBURL%%",
mirror_type: "srv",
signature_type: "fingerprints",
fingerprints: "/usr/share/keys/pkg",
enabled: yes
}

View file

@ -12,4 +12,21 @@ SCRIPTSDIR_startbsdinstall= ${LIBEXECDIR}/bsdinstall
UPDATE_DEPENDFILE= no
FILESDIR= ${SHAREDIR}/bsdinstall
FILES= FreeBSD-base.conf
_BRANCH!= ${MAKE} -C ${SRCTOP}/release -V BRANCH
BRANCH?= ${_BRANCH}
_REVISION!= ${MAKE} -C ${SRCTOP}/release -V REVISION
REVISION?= ${_REVISION}
.if ${BRANCH} == CURRENT || ${BRANCH} == STABLE
SUBURL= base_latest
.else
SUBURL= base_release_${REVISION:C/[0-9]+\.//}
.endif
FreeBSD-base.conf: FreeBSD-base.conf.in
sed "s|%%SUBURL%%|${SUBURL}|" < ${.ALLSRC} > ${.TARGET}
.include <bsd.prog.mk>

View file

@ -244,6 +244,17 @@ Extracts the distributions listed in
.Ev DISTRIBUTIONS
into
.Ev BSDINSTALL_CHROOT .
.It Cm pkgbase Op Fl --no-kernel
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.
If the
.Fl --no-kernel
option is passed, no kernel is installed.
.It Cm firmware
executes
.Xr fwget 8
@ -324,6 +335,17 @@ Example:
.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
.Xr pkg 8
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.

View file

@ -1,3 +1,5 @@
.include <bsd.compat.pre.mk>
SCRIPTS=auto \
adduser \
bootconfig \
@ -17,6 +19,7 @@ SCRIPTS=auto \
netconfig \
netconfig_ipv4 \
netconfig_ipv6 \
pkgbase \
rootpass \
script \
services \
@ -29,4 +32,7 @@ BINDIR= ${LIBEXECDIR}/bsdinstall
MAN=
pkgbase: pkgbase.in
sed "s|%%_ALL_libcompats%%|${_ALL_libcompats}|" < ${.ALLSRC} > ${.TARGET}
.include <bsd.prog.mk>

View file

@ -0,0 +1,172 @@
#!/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.
local all_libcompats <const> = "%%_ALL_libcompats%%"
-- 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
local 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
local 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
local function append_list(list, other)
for _, item in ipairs(other) do
table.insert(list, item)
end
end
-- Returns a list of pkgbase packages equivalent to the default base.txz and kernel.txz
local function select_packages(pkg, options)
local components = {
["kernel"] = {},
["kernel-dbg"] = {},
["base"] = {},
["base-dbg"] = {},
["src"] = {},
["tests"] = {},
}
for compat in all_libcompats:gmatch("%S+") do
components["lib" .. compat] = {}
components["lib" .. compat .. "-dbg"] = {}
end
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(components["src"], package)
elseif package == "FreeBSD-tests" or package:match("^FreeBSD%-tests%-.*") then
table.insert(components["tests"], package)
elseif package:match("^FreeBSD%-kernel%-.*") then
-- Kernels other than FreeBSD-kernel-generic are ignored
if package == "FreeBSD-kernel-generic" then
table.insert(components["kernel"], package)
elseif package == "FreeBSD-kernel-generic-dbg" then
table.insert(components["kernel-dbg"], package)
end
elseif package:match(".*%-dbg$") then
table.insert(components["base-dbg"], package)
else
local found = false
for compat in all_libcompats:gmatch("%S+") do
if package:match(".*%-dbg%-lib" .. compat .. "$") then
table.insert(components["lib" .. compat .. "-dbg"], package)
found = true
break
elseif package:match(".*%-lib" .. compat .. "$") then
table.insert(components["lib" .. compat], package)
found = true
break
end
end
if not found then
table.insert(components["base"], package)
end
end
end
-- Don't assert the existence of dbg, tests, and src packages here. If using
-- a custom local repository with BSDINSTALL_PKG_REPOS_DIR we shouldn't
-- require it to have all packages.
assert(#components["kernel"] == 1)
assert(#components["base"] > 0)
local selected = {}
append_list(selected, components["base"])
if not options.no_kernel then
append_list(selected, components["kernel"])
end
return selected
end
local function parse_options()
local options = {}
for _, a in ipairs(arg) do
if a == "--no-kernel" then
options.no_kernel = true
else
io.stderr:write("Error: unknown option " .. a .. "\n")
os.exit(1)
end
end
return options
end
-- Fetch and install pkgbase packages to BSDINSTALL_CHROOT.
-- Respect BSDINSTALL_PKG_REPOS_DIR if set, otherwise use pkg.freebsd.org.
local function pkgbase()
local options = parse_options()
-- 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/"
assert(os.execute("mkdir -p " .. repos_dir))
assert(os.execute("cp /usr/share/bsdinstall/FreeBSD-base.conf " .. repos_dir))
-- Since pkg always interprets fingerprints paths as relative to
-- the --rootdir we must copy the key from the host.
assert(os.execute("mkdir -p " .. chroot .. "/usr/share/keys"))
assert(os.execute("cp -R /usr/share/keys/pkg " .. chroot .. "/usr/share/keys/"))
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, options), " ")
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 not os.execute(pkg .. "install -U -y -r FreeBSD-base " .. packages) then
os.exit(1)
end
end
pkgbase()