Skip to content

Commit bd6acf9

Browse files
Yury-MonZonalchark
authored andcommitted
90-loaderentry.install: kernel-install BLS plugin (runtime)
Sources flipper-bls.sh and handles the booted root only. add: stage the kernel into /boot/<entry-token>/ and write that root's single entry (title/overlays from the matching flipper-profiles line, else the root name). remove: content-based cleanup plus reap of the now-empty token dir. The menu band number is part of the pre-baked entry-token, so the plugin reads it rather than computing one.
1 parent 972e5e2 commit bd6acf9

1 file changed

Lines changed: 46 additions & 210 deletions

File tree

overlays/configs/kernel/install.d/90-loaderentry.install

Lines changed: 46 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@
99
# Keys written: standard BLS (title, version, machine-id, sort-key, options, linux,
1010
# devicetree, devicetree-overlay, initrd) plus 'devicetreedir' - a U-Boot extension
1111
# (DTB directory for cross-board fdtdir auto-selection; a U-Boot alias of 'fdtdir').
12+
#
13+
# The shared entry-writing helpers live in /usr/lib/flipper-bls.sh (also sourced by the
14+
# btrfs snapshot tooling: create_profile / rename_profile).
1215

1316
set -e
17+
. /usr/lib/flipper-bls.sh
1418

19+
# ===========================================================================
20+
# kernel-install plugin body.
21+
# ===========================================================================
1522
COMMAND="${1:?}"
1623
KERNEL_VERSION="${2:?}"
1724
ENTRY_DIR_ABS="${3:?}"
@@ -25,113 +32,40 @@ ENTRY_TOKEN="${KERNEL_INSTALL_ENTRY_TOKEN:?}"
2532
MACHINE_ID="${KERNEL_INSTALL_MACHINE_ID:-}"
2633
CONF_ROOT="${KERNEL_INSTALL_CONF_ROOT:-/etc/kernel}"
2734
ENTRIES="$BOOT_ROOT/loader/entries"
28-
ENTRY_STEM="$ENTRIES/$ENTRY_TOKEN-$KERNEL_VERSION"
2935
PROFILES="${FLIPPER_PROFILES:-/etc/kernel/flipper-profiles}"
3036
KCONFIG="$BOOT_ROOT/config-$KERNEL_VERSION"
31-
VENDOR=rockchip
32-
TITLE_MAX="${FLIPPER_TITLE_MAX:-26}"
33-
34-
# Where the kernel package installs DTBs/overlays: primary dir + the modules fallback.
35-
DTB_DIR="/usr/lib/linux-image-$KERNEL_VERSION"
36-
DTB_DIRS="$DTB_DIR /usr/lib/modules/$KERNEL_VERSION/dtb"
37-
38-
# U-Boot reads the btrfs TOP LEVEL (subvolid 5), so in-entry devicetreedir/overlay paths must
39-
# be prefixed with the root subvolume the entry boots -- /@<subvol>/usr/lib/... -- where that
40-
# root's DTBs live (the kernel package installs them in every root's /usr/lib). The prefix is
41-
# derived per entry from its own rootflags=subvol= (each profile boots a different root). The
42-
# staged kernel/initrd live under /boot (the boot subvolume) and are never prefixed.
43-
# Set FDT_SUBVOL_PREFIX to override the derivation (e.g. "" if the root is not a subvolume).
44-
fdt_prefix() { # $1 = options string -> "/<rootflags-subvol>" (or $FDT_SUBVOL_PREFIX if set)
45-
if [ "${FDT_SUBVOL_PREFIX+x}" = x ]; then printf '%s' "$FDT_SUBVOL_PREFIX"; return 0; fi
46-
_sv=$(printf '%s' "$1" | tr ' ' '\n' | sed -n 's/^rootflags=subvol=//p' | tail -n1)
47-
[ -n "$_sv" ] && printf '/%s' "$_sv"
48-
return 0
49-
}
50-
51-
log() { [ "${KERNEL_INSTALL_VERBOSE:-0}" -gt 0 ] && echo "flipper-bls: $*" >&2; return 0; }
52-
die() { echo "flipper-bls: $*" >&2; exit 1; }
53-
trim() { printf '%s' "$1" | sed 's/^ *//; s/ *$//'; }
54-
# copy a file into the entry dir as root:root 0644
55-
stage_file() { install -m 0644 -o root -g root "$1" "$2" || die "could not copy '$1'"; }
37+
set_dtb_dirs
38+
[ -n "${BOOT_MNT:-}" ] || BOOT_MNT="/"
5639

57-
# remove: drop the base entry and all profile variants for this kernel
40+
# remove: drop every entry for THIS version that boots the CURRENT root subvol, whatever its
41+
# entry-token (factory 'debian-*' and per-root 'flipperos-*' alike). Keyed on each entry's own
42+
# content (version + rootflags=subvol=), so it never touches another profile's entries and
43+
# survives any purge/cleanup path. kernel-install itself removes this root's staged dir.
5844
if [ "$COMMAND" = "remove" ]; then
59-
rm -f "$ENTRY_STEM.conf" "$ENTRY_STEM-"*.conf
60-
_id="" && [ -r /etc/os-release ] && _id="$(. /etc/os-release; printf '%s' "${IMAGE_ID:-$ID}")" || :
61-
if [ -n "$_id" ] && [ "$_id" != "$ENTRY_TOKEN" ]; then
62-
_alt="$ENTRIES/$_id-$KERNEL_VERSION"
63-
rm -f "$_alt.conf" "$_alt-"*.conf
64-
fi
45+
remove_entries "$(current_subvol)" "$KERNEL_VERSION"
46+
# kernel-install removed this version's staged dir; reap the now-empty per-token parent
47+
# ($BOOT_ROOT/$ENTRY_TOKEN) too. rmdir (not rm -rf) only succeeds if truly empty, so it
48+
# never touches a token dir that still has another version staged.
49+
rmdir "$BOOT_ROOT/$ENTRY_TOKEN" 2>/dev/null || :
6550
exit 0
6651
fi
6752
[ "$COMMAND" = "add" ] || exit 0
6853

69-
# In-entry paths are relative to the partition U-Boot actually reads. On Flipper One
70-
# that is always the root partition — /boot is a directory/subvolume on it, never a
71-
# separate boot partition U-Boot mounts — so paths must keep the /boot prefix, i.e.
72-
# BOOT_MNT=/. (Override BOOT_MNT in the environment if /boot ever becomes its own
73-
# partition, which would make boot_rel strip the mountpoint again.)
74-
[ -n "$BOOT_MNT" ] || BOOT_MNT="/"
75-
76-
# absolute path under BOOT_ROOT -> path as it must appear inside a BLS entry (relative
77-
# to the boot partition; identical to the absolute path when /boot is on the rootfs).
78-
boot_rel() { if [ "$BOOT_MNT" = "/" ]; then printf '%s\n' "$1"; else printf '%s\n' "${1#"$BOOT_MNT"}"; fi; }
79-
8054
ENTRY_DIR="$(boot_rel "$ENTRY_DIR_ABS")"
8155
[ -d "$ENTRY_DIR_ABS" ] || die "entry directory '$ENTRY_DIR_ABS' does not exist"
82-
83-
# The loader entries dir may not exist yet on a fresh boot partition.
8456
mkdir -p "$ENTRIES" || die "could not create '$ENTRIES'"
8557

86-
has_config() { [ -f "$KCONFIG" ] && grep -q "^CONFIG_$1=[ym]" "$KCONFIG"; }
58+
# Base cmdline shared by every entry (profiles append their rootflags=subvol=).
59+
compute_base_opts
8760

88-
# ===========================================================================
89-
# Stage the artifacts shared by every entry (kernel, initrd(s), devicetree[dir]).
90-
# ===========================================================================
91-
92-
# Base kernel command line (profiles append to this).
93-
if [ -f "$CONF_ROOT/cmdline" ]; then
94-
BASE_OPTS="$(grep -Gv '^\s*#' "$CONF_ROOT/cmdline" | tr -s '[:space:]' ' ')"
95-
elif [ -f /usr/lib/kernel/cmdline ]; then
96-
BASE_OPTS="$(grep -Gv '^\s*#' /usr/lib/kernel/cmdline | tr -s '[:space:]' ' ')"
97-
else
98-
BASE_OPTS=""
99-
fi
100-
BASE_OPTS="$(trim "$BASE_OPTS")"
101-
102-
# If the boot entries are named after the machine ID, pin systemd.machine_id= on the
103-
# kernel command line so the machine ID stays stable inside the initrd (where it isn't
104-
# directly accessible yet) and across factory reset on a volatile root.
105-
# (No-op unless entry-token == machine-id, e.g. machine-id-based entry naming.)
106-
if [ -n "$MACHINE_ID" ] && [ "$ENTRY_TOKEN" = "$MACHINE_ID" ] && ! echo "$BASE_OPTS" | grep -q "systemd.machine_id="; then
107-
BASE_OPTS="$BASE_OPTS systemd.machine_id=$MACHINE_ID"
108-
fi
109-
110-
# Console selection replicating the old features.d/default logic:
111-
# FIQ kernel -> console=ttyFIQ0,1500000n8
112-
# mainline -> console=ttyS0,1500000n8 console=ttyS4,1500000n8 fbcon=map:1
113-
if has_config FIQ_DEBUGGER_CONSOLE; then
114-
BASE_OPTS="$(echo " $BASE_OPTS " | sed 's/ console=ttyS0,1500000n8 / /g')"
115-
BASE_OPTS="$(trim "$BASE_OPTS") console=ttyFIQ0,1500000n8"
116-
else
117-
BASE_OPTS="$(echo " $BASE_OPTS " | sed 's/ console=ttyS0,1500000n8 / /g')"
118-
BASE_OPTS="$(trim "$BASE_OPTS") console=ttyS0,1500000n8"
119-
BASE_OPTS="$(echo " $BASE_OPTS " | sed 's/ console=ttyS4,1500000n8 / /g')"
120-
BASE_OPTS="$(trim "$BASE_OPTS") console=ttyS4,1500000n8"
121-
BASE_OPTS="$(echo " $BASE_OPTS " | sed 's/ console=ttyFIQ0,1500000n8 / /g')"
122-
BASE_OPTS="$(trim "$BASE_OPTS") fbcon=map:1"
123-
fi
124-
125-
# Standard BLS sort-key (os-release IMAGE_ID, else ID): a spec-compliant reader uses
126-
# it to order entries
127-
SORT_KEY=""
128-
[ -r /etc/os-release ] && SORT_KEY="$(. /etc/os-release; printf '%s' "${IMAGE_ID:-$ID}")" || :
61+
# Standard BLS sort-key (os-release IMAGE_ID, else ID).
62+
SORT_KEY="$(os_sort_key)"
12963

13064
# Kernel image.
13165
stage_file "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux"
13266
KERNEL_ENTRY="$ENTRY_DIR/linux"
13367

134-
# devicetree (single, optional) copied into the entry dir.
68+
# devicetree (single, optional): copied into the entry dir.
13569
DEVICETREE=""; DEVICETREE_ENTRY=""
13670
[ -f "$CONF_ROOT/devicetree" ] && read -r DEVICETREE <"$CONF_ROOT/devicetree" || :
13771
if [ -n "$DEVICETREE" ]; then
@@ -144,33 +78,10 @@ if [ -n "$DEVICETREE" ]; then
14478
[ -n "$DEVICETREE_ENTRY" ] || die "device tree blob '$DEVICETREE' not found"
14579
fi
14680

147-
# devicetreedir (U-Boot fdtdir extension) — referenced in place, opt-in via a
148-
# /etc/kernel/devicetreedir file containing a true boolean. Only when no single
149-
# devicetree was configured.
150-
DEVICETREEDIR_SRC=""; DEVICETREEDIR_REL=""
151-
if [ -z "$DEVICETREE" ] && [ -f "$CONF_ROOT/devicetreedir" ]; then
152-
_v=""; read -r _v <"$CONF_ROOT/devicetreedir" || :
153-
case "$_v" in
154-
1|[Yy]|[Yy][Ee][Ss]|[Tt]|[Tt][Rr][Uu][Ee]|[Oo][Nn])
155-
for p in $DTB_DIRS; do
156-
[ -d "$p" ] || continue
157-
for d in "$p"/*.dtb "$p"/*/*.dtb "$p"/*/*/*.dtb; do
158-
[ -f "$d" ] && { DEVICETREEDIR_SRC="$p"; break; }
159-
done
160-
[ -n "$DEVICETREEDIR_SRC" ] && break
161-
done
162-
[ -n "$DEVICETREEDIR_SRC" ] || die "no device-tree directory for $KERNEL_VERSION"
163-
DEVICETREEDIR_REL="$(boot_rel "$DEVICETREEDIR_SRC")" # /usr/lib/...; prefixed per entry
164-
;;
165-
esac
166-
fi
167-
# Overlay directory: DT overlays sit flat next to the .dtb files (upstream layout),
168-
# i.e. in the same vendor dir the DTBs live in. Path == entry path while /boot is on
169-
# the rootfs.
170-
OVERLAY_DIR="${DEVICETREEDIR_SRC:-$DTB_DIR}/$VENDOR"
81+
# devicetreedir (U-Boot fdtdir extension) + overlay dir.
82+
discover_devicetreedir
17183

172-
# initrd(s): from the kernel-install staging area, positional args, or the
173-
# distro's well-known names. Collect the in-entry paths once for reuse.
84+
# initrd(s): from the kernel-install staging area, positional args, or well-known names.
17485
shift "$INITRD_SHIFT"
17586
INITRD_ENTRIES=""
17687
add_initrd() { INITRD_ENTRIES="$INITRD_ENTRIES${INITRD_ENTRIES:+ }$1"; }
@@ -185,104 +96,29 @@ for i in "$KERNEL_INSTALL_STAGING_AREA"/microcode* "$@" "$KERNEL_INSTALL_STAGING
18596
stage_file "$i" "$ENTRY_DIR_ABS/$_bn"
18697
add_initrd "$ENTRY_DIR/$_bn"
18798
done
188-
# Fallbacks when no initrd was staged into kernel-install (e.g. initramfs-tools).
18999
[ -z "$INITRD_ENTRIES" ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && add_initrd "$ENTRY_DIR/initrd"
190100
[ -z "$INITRD_ENTRIES" ] && [ -f "$BOOT_ROOT/initramfs-$KERNEL_VERSION.img" ] && add_initrd "$(boot_rel "$BOOT_ROOT/initramfs-$KERNEL_VERSION.img")"
191101
[ -z "$INITRD_ENTRIES" ] && [ -f "$BOOT_ROOT/initrd.img-$KERNEL_VERSION" ] && add_initrd "$(boot_rel "$BOOT_ROOT/initrd.img-$KERNEL_VERSION")"
192102

193-
# ===========================================================================
194-
# Entry writer + overlay discovery.
195-
# ===========================================================================
196-
197-
# write_entry FILE TITLE OPTIONS FDTOVERLAYS
198-
write_entry() {
199-
_f="$1"; _title="$2"; _opts="$3"; _fdtov="$4"
200-
# devicetreedir is prefixed with THIS entry's root subvol (U-Boot reads subvolid 5)
201-
_dtdir=""; [ -n "$DEVICETREEDIR_REL" ] && _dtdir="$(fdt_prefix "$_opts")$DEVICETREEDIR_REL"
202-
{
203-
echo "# Boot Loader Specification type#1 entry (Flipper One)"
204-
echo "title $_title"
205-
echo "version $KERNEL_VERSION"
206-
[ -n "$MACHINE_ID" ] && [ "$ENTRY_TOKEN" = "$MACHINE_ID" ] && echo "machine-id $MACHINE_ID"
207-
[ -n "$SORT_KEY" ] && echo "sort-key $SORT_KEY"
208-
[ -n "$_opts" ] && echo "options $_opts"
209-
echo "linux $KERNEL_ENTRY"
210-
[ -n "$DEVICETREE_ENTRY" ] && echo "devicetree $DEVICETREE_ENTRY"
211-
[ -n "$_dtdir" ] && echo "devicetreedir $_dtdir"
212-
[ -n "$_fdtov" ] && echo "devicetree-overlay $_fdtov"
213-
for _i in $INITRD_ENTRIES; do echo "initrd $_i"; done
214-
} >"$_f"
215-
return 0 # don't let a trailing empty conditional's status abort `set -e`
216-
}
217-
218-
# Echo the space-separated paths of the named DT overlays (flat, next to the DTBs).
219-
# Returns non-zero with no output if any one is missing.
220-
overlay_paths() { # $1 = subvol prefix (e.g. /@Desktop); remaining args = overlay names
221-
_pfx="$1"; shift
222-
_paths=""
223-
for _n in "$@"; do
224-
[ -f "$OVERLAY_DIR/$_n.dtbo" ] || return 1 # check the real on-disk path
225-
_paths="$_paths${_paths:+ }$_pfx$OVERLAY_DIR/$_n.dtbo"
226-
done
227-
printf '%s' "$_paths"
228-
}
229-
230-
# ===========================================================================
231-
# Write the entries.
232-
# ===========================================================================
233-
234-
# Menu titles must fit the device's small screen. A title is "<version> <profile>";
235-
# cap the TOTAL length at TITLE_MAX chars by trimming the (long) version while keeping
236-
# the profile suffix intact. Entry filenames and the 'version' field keep the full
237-
# kernel version, which kernel-install needs to stay consistent with /lib/modules.
238-
make_title() {
239-
_suf="$1"
240-
_avail=$(( TITLE_MAX - ${#_suf} - 1 ))
241-
if [ "$_avail" -ge 1 ]; then
242-
printf '%s %s' "$(printf '%s' "$KERNEL_VERSION" | cut -c"1-$_avail")" "$_suf"
243-
else
244-
printf '%s' "$_suf" | cut -c"1-$TITLE_MAX"
245-
fi
246-
}
247-
248-
# Base entry == the [DESKTOP] profile.
249-
write_entry "$ENTRY_STEM.conf" "$(make_title '[DESKTOP]')" "$BASE_OPTS" ""
250-
251-
[ -f "$PROFILES" ] || { log "$PROFILES not found, only the [DESKTOP] entry written"; exit 0; }
252-
253-
while IFS='|' read -r tok suf extra gate dtbos legend; do
254-
tok="$(echo "$tok" | tr -d '[:space:]')"
255-
case "$tok" in ''|\#*) continue ;; esac
256-
257-
suf="$(trim "$suf")"
258-
extra="$(trim "$extra")"
259-
gate="$(trim "$gate")"
260-
dtbos="$(trim "$dtbos")"
261-
262-
# gate may list several config symbols; all must be present.
263-
gated_out=0; _failed_g=""
264-
for g in $gate; do has_config "$g" || { gated_out=1; _failed_g="$g"; break; }; done
265-
if [ "$gated_out" = 1 ]; then log "skip $tok (CONFIG_$_failed_g not set for $KERNEL_VERSION)"; continue; fi
266-
267-
opts="$BASE_OPTS"
268-
[ -n "$extra" ] && opts="$opts $extra"
269-
270-
if [ -z "$dtbos" ]; then
271-
write_entry "$ENTRY_STEM-$tok.conf" "$(make_title "$suf")" "$opts" ""
272-
continue
273-
fi
274-
275-
# A leading '!' on the overlay list = required (skip if overlays absent, like the
276-
# old add_board_dtbo -z); otherwise optional (entry is still written, sans overlay).
277-
required=0
278-
case "$dtbos" in '!'*) required=1; dtbos="$(trim "${dtbos#\!}")" ;; esac
279-
280-
paths="$(overlay_paths "$(fdt_prefix "$opts")" $dtbos)" || paths=""
281-
if [ -z "$paths" ] && [ "$required" = 1 ]; then
282-
log "skip $tok (overlays not found for $KERNEL_VERSION)"
283-
continue
284-
fi
285-
write_entry "$ENTRY_STEM-$tok.conf" "$(make_title "$suf")" "$opts" "$paths"
286-
done <"$PROFILES"
103+
# Write this root's entry. apt/dpkg only ever touch the booted root, so emit ONLY its entry. The
104+
# entry-token (from kernel-install, baked per root as <NN>-flipperos-<subvol>) already carries the
105+
# menu band and IS the /boot/<token>/ staging dir, so there is no slot math here: match the booted
106+
# root to a profile line for its title/overlays, else treat it as a clone (title = name, own root).
107+
CUR_SUBVOL="$(current_subvol)"
108+
[ -n "$CUR_SUBVOL" ] || die "cannot determine current root subvol (findmnt)"
109+
110+
matched=0
111+
if [ -f "$PROFILES" ]; then
112+
while IFS='|' read -r tok suf extra gate dtbos legend; do
113+
tok="$(echo "$tok" | tr -d '[:space:]')"
114+
case "$tok" in ''|\#*) continue ;; esac
115+
extra="$(trim "$extra")"
116+
if [ "$(subvol_of "$extra")" = "$CUR_SUBVOL" ]; then
117+
emit_entry "$(trim "$suf")" "$extra" "$(trim "$gate")" "$(trim "$dtbos")"
118+
matched=1; break
119+
fi
120+
done <"$PROFILES"
121+
fi
122+
[ "$matched" = 1 ] || emit_entry "$(printf '%s' "$CUR_SUBVOL" | tr -d '@')" "rootflags=subvol=$CUR_SUBVOL" "" ""
287123

288124
exit 0

0 commit comments

Comments
 (0)