Splux Linux

source-based Linux using SPS

SPS · log · files · refs · tags · releases · people · languages · GitHub · commit

201b8d3


mkiso: usr-merge the live root and ship a working Plasma session.

Date
Commit201b8d39afa6aba859eab3f5f772c71c2afeb000
GitHubmirror

Parents

Stat

 bin/mkiso                     | 273 ++++++++++++++++++++++++++++++++++++------
 lib/mkiso/filesystem.recipe   |  58 +++++++++
 lib/mkiso/live-plasma         |   5 +
 lib/mkiso/live-plasma-session |  24 ++++
 lib/mkiso/live-rc             |   3 +
 lib/mkiso/plasma-bins         |  13 ++
 lib/mkiso/plasma-trees        |  22 ++++
 tests/test_mkiso.sh           |  24 +++-
 8 files changed, 385 insertions(+), 37 deletions(-)

Diff

diff --git a/bin/mkiso b/bin/mkiso
index 0bc2eb5..17c28ae 100755
--- a/bin/mkiso
+++ b/bin/mkiso
@@ -240,6 +240,11 @@ mkiso_copy_path()
 			cp -a "$mkiso_src"/. "$mkiso_dest"/ 2>/dev/null ||
 			cp -R "$mkiso_src"/. "$mkiso_dest"/ 2>/dev/null || :
 	else
+		# usr-merge puts busybox applets in usr/bin. cp onto a
+		# symlink follows it and overwrites busybox itself.
+		if [ -L "$mkiso_dest" ]; then
+			rm -f "$mkiso_dest"
+		fi
 		cp -a --reflink=auto "$mkiso_src" "$mkiso_dest" 2>/dev/null ||
 			cp -a "$mkiso_src" "$mkiso_dest" 2>/dev/null ||
 			cp "$mkiso_src" "$mkiso_dest" 2>/dev/null || :
@@ -380,6 +385,8 @@ mkiso_copy_plasma_runtime_deps()
 		/usr/lib64/libtaskmanager.so.6 \
 		/usr/lib64/libKirigami.so.6 \
 		/usr/lib64/libKirigamiPlatform.so.6 \
+		/usr/lib64/firefox/firefox-bin \
+		/usr/lib64/firefox/libxul.so \
 		/usr/lib/qt6/plugins/sqldrivers/libqsqlite.so \
 		/usr/lib/qt6/qml/org/kde/kirigami/libKirigamiplugin.so \
 		/usr/lib/qt6/plugins/kf6/kauth/backend/kauth_backend_plugin.so \
@@ -394,9 +401,11 @@ mkiso_copy_plasma_runtime_deps()
 		/usr/lib64/qt6/qml/org/kde \
 		/usr/lib64/qt6/plugins/plasma \
 		/usr/lib64/qt6/plugins/kwin \
+		/usr/lib64/qt6/plugins/kf6 \
 		/usr/lib/qt6/qml/org/kde \
 		/usr/lib/qt6/plugins/plasma \
-		/usr/lib/qt6/plugins/kwin
+		/usr/lib/qt6/plugins/kwin \
+		/usr/lib/qt6/plugins/kf6
 	do
 		[ -d "$mkiso_d" ] || continue
 		find "$mkiso_d" -type f -name '*.so' -print 2>/dev/null \
@@ -762,6 +771,9 @@ mkiso_verify_plasma()
 		usr/share/xkeyboard-config-2/rules/evdev \
 		usr/share/libinput/10-generic-keyboard.quirks \
 		usr/share/icons/breeze_cursors/index.theme \
+		usr/share/systemsettings/categories \
+		usr/share/glib-2.0/schemas/gschemas.compiled \
+		usr/lib/polkit-1/polkitd \
 		etc/xdg/kscreenlockerrc
 	do
 		if [ ! -e "$mkiso_live/$mkiso_need" ] &&
@@ -770,6 +782,18 @@ mkiso_verify_plasma()
 			mkiso_miss="$mkiso_miss $mkiso_need"
 		fi
 	done
+	if [ -e /usr/bin/firefox ]; then
+		if [ ! -e "$mkiso_live/usr/bin/firefox" ] &&
+			[ ! -L "$mkiso_live/usr/bin/firefox" ]
+		then
+			mkiso_miss="$mkiso_miss usr/bin/firefox"
+		fi
+		if [ ! -e "$mkiso_live/usr/lib64/firefox/firefox-bin" ] &&
+			[ ! -L "$mkiso_live/usr/lib64/firefox/firefox-bin" ]
+		then
+			mkiso_miss="$mkiso_miss usr/lib64/firefox/firefox-bin"
+		fi
+	fi
 	if ! ls "$mkiso_live"/usr/lib64/libgallium*.so* >/dev/null 2>&1
 	then
 		mkiso_miss="$mkiso_miss libgallium"
@@ -916,11 +940,202 @@ mkiso_busybox_links()
 	do
 		[ -n "$mkiso_ap" ] || continue
 		[ "$mkiso_ap" = busybox ] && continue
+		if [ -e "$mkiso_bbdir/$mkiso_ap" ] &&
+			[ ! -L "$mkiso_bbdir/$mkiso_ap" ]
+		then
+			continue
+		fi
 		ln -sf busybox "$mkiso_bbdir/$mkiso_ap"
 	done
 	ln -sf busybox "$mkiso_bbdir/sh"
 }
 
+# filesystem ships /bin -> usr/bin. A real /bin directory on the live
+# root makes pkin refuse the package, so sget install dies immediately.
+mkiso_ensure_usr_merge()
+{
+	mkdir -p "$mkiso_live/usr/bin" "$mkiso_live/usr/sbin" \
+		"$mkiso_live/usr/lib"
+	for mkiso_merge in bin:usr/bin sbin:usr/sbin lib:usr/lib
+	do
+		mkiso_merge_name=${mkiso_merge%%:*}
+		mkiso_merge_target=${mkiso_merge#*:}
+		mkiso_merge_path=$mkiso_live/$mkiso_merge_name
+		if [ -L "$mkiso_merge_path" ]; then
+			continue
+		fi
+		if [ -e "$mkiso_merge_path" ]; then
+			sps_die "$SPS_EX_BUILD" \
+				"live /$mkiso_merge_name exists and is not a usr-merge symlink"
+		fi
+		ln -s "$mkiso_merge_target" "$mkiso_merge_path"
+	done
+}
+
+# Own the usr-merge links and static files so later packages that depend
+# on filesystem can install on the live image itself.
+mkiso_install_base_filesystem()
+{
+	mkiso_fs_recipe=
+	if [ -n "${mkiso_core:-}" ] &&
+		[ -f "$mkiso_core/base/filesystem/recipe" ]
+	then
+		mkiso_fs_recipe=$mkiso_core/base/filesystem/recipe
+	elif [ -f "$mkiso_libdir/filesystem.recipe" ]; then
+		mkiso_fs_recipe=$mkiso_libdir/filesystem.recipe
+	fi
+	[ -n "$mkiso_fs_recipe" ] || return 0
+
+	printf '%s: installing filesystem into the live root\n' \
+		"$sps_prog" >&2
+	mkiso_fs_out=$(mktemp -d "${TMPDIR:-/tmp}/.sps-mkiso-fs.XXXXXX") ||
+		sps_die "$SPS_EX_BUILD" "cannot create filesystem package workspace"
+	mkiso_fs_st=0
+	if ! (
+		unset SPS_ROOT SPS_DB SPS_CACHE SPS_BUILD SPS_CONFIG \
+			SPS_REPOS_CONFIG SPS_COMPRESSION
+		SPS_ROOT=$mkiso_live
+		SPS_DB=$mkiso_live/var/lib/sps
+		SPS_CACHE=$mkiso_live/var/cache/sps
+		SPS_BUILD=$mkiso_live/var/tmp/sps
+		SPS_CONFIG=/dev/null
+		SPS_REPOS_CONFIG=/dev/null
+		SPS_COMPRESSION=none
+		PATH=$sps_bin_dir:$PATH
+		export SPS_ROOT SPS_DB SPS_CACHE SPS_BUILD SPS_CONFIG \
+			SPS_REPOS_CONFIG SPS_COMPRESSION SPS_LIBDIR PATH
+		mkdir -p "$SPS_DB" "$SPS_CACHE" "$SPS_BUILD"
+		mkpkg --output "$mkiso_fs_out" "$mkiso_fs_recipe" || exit 1
+		mkiso_fs_pkg=
+		for mkiso_fs_cand in "$mkiso_fs_out"/filesystem-*.pkg.tar \
+			"$mkiso_fs_out"/filesystem-*.pkg.tar.gz \
+			"$mkiso_fs_out"/filesystem-*.pkg.tar.xz \
+			"$mkiso_fs_out"/filesystem-*.pkg.tar.zst
+		do
+			[ -f "$mkiso_fs_cand" ] || continue
+			mkiso_fs_pkg=$mkiso_fs_cand
+			break
+		done
+		[ -n "$mkiso_fs_pkg" ] || exit 1
+		pkin --dependency "$mkiso_fs_pkg"
+	)
+	then
+		mkiso_fs_st=1
+	fi
+	rm -rf "$mkiso_fs_out"
+	[ "$mkiso_fs_st" -eq 0 ] ||
+		sps_die "$SPS_EX_BUILD" \
+			"failed to install filesystem into the live root"
+}
+
+mkiso_add_group()
+{
+	mkiso_gname=$1
+	mkiso_gid=$2
+	mkiso_gmembers=${3-}
+	mkiso_gfile=$mkiso_live/etc/group
+	[ -f "$mkiso_gfile" ] || printf '%s\n' 'root:x:0:' >"$mkiso_gfile"
+	grep -q "^${mkiso_gname}:" "$mkiso_gfile" && return 0
+	if [ -n "$mkiso_gmembers" ]; then
+		printf '%s:x:%s:%s\n' "$mkiso_gname" "$mkiso_gid" \
+			"$mkiso_gmembers" >>"$mkiso_gfile"
+	else
+		printf '%s:x:%s:\n' "$mkiso_gname" "$mkiso_gid" >>"$mkiso_gfile"
+	fi
+}
+
+mkiso_add_user()
+{
+	mkiso_uname=$1
+	mkiso_uid=$2
+	mkiso_ugid=$3
+	mkiso_ugeos=$4
+	mkiso_uhome=$5
+	mkiso_pfile=$mkiso_live/etc/passwd
+	mkiso_sfile=$mkiso_live/etc/shadow
+	[ -f "$mkiso_pfile" ] ||
+		printf '%s\n' 'root:x:0:0:root:/root:/bin/sh' >"$mkiso_pfile"
+	grep -q "^${mkiso_uname}:" "$mkiso_pfile" && return 0
+	printf '%s:x:%s:%s:%s:%s:/usr/bin/nologin\n' \
+		"$mkiso_uname" "$mkiso_uid" "$mkiso_ugid" "$mkiso_ugeos" \
+		"$mkiso_uhome" >>"$mkiso_pfile"
+	if [ -f "$mkiso_sfile" ] && ! grep -q "^${mkiso_uname}:" "$mkiso_sfile"
+	then
+		printf '%s:!:0:0:99999:7:::\n' "$mkiso_uname" >>"$mkiso_sfile"
+	fi
+}
+
+mkiso_write_live_accounts()
+{
+	mkdir -p "$mkiso_live/etc" "$mkiso_live/var/lib/polkit" \
+		"$mkiso_live/run/dbus"
+	if [ ! -s "$mkiso_live/etc/passwd" ]; then
+		printf '%s\n' 'root:x:0:0:root:/root:/bin/sh' \
+			>"$mkiso_live/etc/passwd"
+	fi
+	if [ ! -s "$mkiso_live/etc/group" ]; then
+		printf '%s\n' 'root:x:0:' >"$mkiso_live/etc/group"
+	fi
+	mkiso_add_group tty 5
+	mkiso_add_group disk 6
+	mkiso_add_group audio 17
+	mkiso_add_group video 18 root
+	mkiso_add_group input 71 root
+	mkiso_add_group render 107 root
+	mkiso_add_group messagebus 81
+	mkiso_add_group polkitd 87
+	mkiso_add_user messagebus 81 81 "User for D-BUS" /run/dbus
+	mkiso_add_user polkitd 87 87 "PolicyKit daemon owner" /var/lib/polkit
+	if [ ! -s "$mkiso_live/etc/hosts" ]; then
+		printf '%s\n' '127.0.0.1 localhost' '::1 localhost' \
+			>"$mkiso_live/etc/hosts"
+	fi
+	if ! grep -q splux-live "$mkiso_live/etc/hosts"; then
+		mkiso_hosts=$mkiso_live/etc/hosts
+		mkiso_hosts_tmp=$(mktemp "${TMPDIR:-/tmp}/.sps-hosts.XXXXXX") ||
+			sps_die "$SPS_EX_BUILD" "cannot stage live hosts"
+		awk '{
+			if ($1 == "127.0.0.1" && $0 !~ /splux-live/)
+				print $0 " splux-live"
+			else if ($1 == "::1" && $0 !~ /splux-live/)
+				print $0 " splux-live"
+			else
+				print
+		}' "$mkiso_hosts" >"$mkiso_hosts_tmp"
+		cat "$mkiso_hosts_tmp" >"$mkiso_hosts"
+		rm -f "$mkiso_hosts_tmp"
+	fi
+	if [ ! -s "$mkiso_live/etc/nsswitch.conf" ]; then
+		printf '%s\n' \
+			'passwd: files' \
+			'group: files' \
+			'shadow: files' \
+			'hosts: files dns' \
+			'networks: files' \
+			'protocols: files' \
+			'services: files' \
+			'ethers: files' \
+			'rpc: files' \
+			>"$mkiso_live/etc/nsswitch.conf"
+	fi
+	if [ ! -s "$mkiso_live/etc/shadow" ]; then
+		printf '%s\n' 'root::0:0:99999:7:::' \
+			>"$mkiso_live/etc/shadow"
+	else
+		mkiso_shadow_tmp=$(mktemp "${TMPDIR:-/tmp}/.sps-shadow.XXXXXX") ||
+			sps_die "$SPS_EX_BUILD" "cannot stage live shadow"
+		awk -F: 'BEGIN { OFS=":" }
+			$1 == "root" { $2 = ""; print; next }
+			{ print }' "$mkiso_live/etc/shadow" >"$mkiso_shadow_tmp"
+		cat "$mkiso_shadow_tmp" >"$mkiso_live/etc/shadow"
+		rm -f "$mkiso_shadow_tmp"
+	fi
+	chmod 600 "$mkiso_live/etc/shadow"
+	if [ -f "$mkiso_live/etc/gshadow" ]; then
+		chmod 600 "$mkiso_live/etc/gshadow"
+	fi
+}
+
 # Copy a host Plasma/Wayland stack. mkiso does not compile Qt.
 mkiso_copy_plasma()
 {
@@ -1138,12 +1353,14 @@ make -C "$sps_bin_dir/.." \
 	install install-config >/dev/null ||
 	sps_die "$SPS_EX_BUILD" "make install into the live root failed"
 
-mkdir -p "$mkiso_live/bin" "$mkiso_live/sbin" "$mkiso_live/usr/bin" \
-	"$mkiso_live/usr/sbin" "$mkiso_live/root" "$mkiso_live/mnt" \
-	"$mkiso_live/proc" "$mkiso_live/sys" "$mkiso_live/dev" \
-	"$mkiso_live/tmp" "$mkiso_live/run" "$mkiso_live/etc/sps" \
-	"$mkiso_live/usr/src/sps" "$mkiso_live/var/cache/sps" \
-	"$mkiso_live/var/lib/sps" "$mkiso_live/var/tmp/sps"
+mkdir -p "$mkiso_live/usr/bin" "$mkiso_live/usr/sbin" "$mkiso_live/root" \
+	"$mkiso_live/mnt" "$mkiso_live/proc" "$mkiso_live/sys" \
+	"$mkiso_live/dev" "$mkiso_live/tmp" "$mkiso_live/run" \
+	"$mkiso_live/etc/sps" "$mkiso_live/usr/src/sps" \
+	"$mkiso_live/var/cache/sps" "$mkiso_live/var/lib/sps" \
+	"$mkiso_live/var/tmp/sps"
+mkiso_install_base_filesystem
+mkiso_ensure_usr_merge
 
 if [ -z "$mkiso_busybox" ]; then
 	for mkiso_bb in /tmp/sps-wave/busybox.static \
@@ -1175,34 +1392,23 @@ install -m 0644 "$mkiso_libdir/issue" "$mkiso_live/etc/issue"
 printf '%s\n' live >"$mkiso_live/etc/sps/live"
 printf '%s\n' splux-live >"$mkiso_live/etc/hostname"
 mkiso_stamp_os_release
-printf '%s\n' 'root:x:0:0:root:/root:/bin/sh' >"$mkiso_live/etc/passwd"
-printf '%s\n' \
-	'root:x:0:' \
-	'tty:x:5:' \
-	'disk:x:6:' \
-	'audio:x:17:' \
-	'video:x:18:root' \
-	'input:x:71:root' \
-	'render:x:107:root' \
-	>"$mkiso_live/etc/group"
-printf '%s\n' \
-	'127.0.0.1 localhost splux-live' \
-	'::1 localhost splux-live' \
-	>"$mkiso_live/etc/hosts"
+mkiso_write_live_accounts
 # Do not copy the host nsswitch.conf: this builder uses mdns modules the
 # live disc does not ship. Without a file, glibc still looks at 127.0.0.1
 # when resolv.conf is missing, so live DNS looks like it "does not exist".
-printf '%s\n' \
-	'passwd: files' \
-	'group: files' \
-	'shadow: files' \
-	'hosts: files dns' \
-	'networks: files' \
-	'protocols: files' \
-	'services: files' \
-	'ethers: files' \
-	'rpc: files' \
-	>"$mkiso_live/etc/nsswitch.conf"
+if [ ! -s "$mkiso_live/etc/nsswitch.conf" ]; then
+	printf '%s\n' \
+		'passwd: files' \
+		'group: files' \
+		'shadow: files' \
+		'hosts: files dns' \
+		'networks: files' \
+		'protocols: files' \
+		'services: files' \
+		'ethers: files' \
+		'rpc: files' \
+		>"$mkiso_live/etc/nsswitch.conf"
+fi
 printf '%s\n' \
 	'nameserver 1.1.1.1' \
 	'nameserver 8.8.8.8' \
@@ -1211,9 +1417,6 @@ if [ -f "$mkiso_libdir/udhcpc-script" ]; then
 	install -m 0755 "$mkiso_libdir/udhcpc-script" \
 		"$mkiso_live/etc/sps/udhcpc-script"
 fi
-# Empty password on the live console only.
-printf '%s\n' 'root::0:0:99999:7:::' >"$mkiso_live/etc/shadow"
-chmod 600 "$mkiso_live/etc/shadow"
 
 printf '%s\n' \
 	'db /var/lib/sps' \
diff --git a/lib/mkiso/filesystem.recipe b/lib/mkiso/filesystem.recipe
new file mode 100644
index 0000000..37cc108
--- /dev/null
+++ b/lib/mkiso/filesystem.recipe
@@ -0,0 +1,58 @@
+# SPS-owned base filesystem hierarchy and initial static configuration.
+name        filesystem
+version     1.0
+release     2
+arch        any
+description Base filesystem hierarchy and static system configuration
+
+install     for directory in dev etc home media mnt opt proc root run run/lock \
+            srv sys tmp usr usr/bin usr/include usr/lib usr/libexec usr/sbin \
+            usr/share usr/src var \
+            var/cache var/empty var/lib var/log var/spool var/tmp; do \
+                mkdir -p "$PKG/$directory"; \
+            done
+install     chmod 0700 "$PKG/root" "$PKG/var/empty"
+install     chmod 0755 "$PKG/run/lock"
+install     chmod 1777 "$PKG/tmp" "$PKG/var/tmp"
+install     ln -s usr/bin "$PKG/bin"
+install     ln -s usr/lib "$PKG/lib"
+install     ln -s usr/sbin "$PKG/sbin"
+install     ln -s ../run "$PKG/var/run"
+install     ln -s ../run/lock "$PKG/var/lock"
+install     ln -s ../proc/self/mounts "$PKG/etc/mtab"
+install     printf '%s\n' \
+            '# Static filesystems are configured here.' \
+            > "$PKG/etc/fstab"
+install     printf '%s\n' \
+            '127.0.0.1 localhost' \
+            '::1 localhost' \
+            > "$PKG/etc/hosts"
+install     printf '%s\n' \
+            'passwd: files' \
+            'group: files' \
+            'shadow: files' \
+            'hosts: files dns' \
+            'networks: files' \
+            'services: files' \
+            'protocols: files' \
+            'rpc: files' \
+            > "$PKG/etc/nsswitch.conf"
+install     printf '%s\n' \
+            'root:x:0:0:root:/root:/bin/sh' \
+            'nobody:x:65534:65534:Unprivileged User:/:/usr/bin/nologin' \
+            > "$PKG/etc/passwd"
+install     printf '%s\n' \
+            'root:x:0:' \
+            'nogroup:x:65534:' \
+            > "$PKG/etc/group"
+install     printf '%s\n' \
+            'root:!:0:0:99999:7:::' \
+            'nobody:!:0:0:99999:7:::' \
+            > "$PKG/etc/shadow"
+install     printf '%s\n' \
+            'root:!::' \
+            'nogroup:!::' \
+            > "$PKG/etc/gshadow"
+install     chmod 0644 "$PKG/etc/group" "$PKG/etc/hosts" \
+            "$PKG/etc/nsswitch.conf" "$PKG/etc/passwd"
+install     chmod 0600 "$PKG/etc/gshadow" "$PKG/etc/shadow"
diff --git a/lib/mkiso/live-plasma b/lib/mkiso/live-plasma
index 7000669..5c69ade 100644
--- a/lib/mkiso/live-plasma
+++ b/lib/mkiso/live-plasma
@@ -23,6 +23,8 @@ export QML2_IMPORT_PATH=/usr/lib64/qt6/qml
 export LIBGL_DRIVERS_PATH=/usr/lib64/dri:/usr/lib/dri
 export GBM_BACKENDS_PATH=/usr/lib64/gbm:/usr/lib/gbm
 export XCURSOR_THEME=breeze_cursors
+export MOZ_ENABLE_WAYLAND=1
+export MOZ_ALLOW_DOWNGRADE=1
 # KWin is the compositor. QT_QPA_PLATFORM=wayland makes Qt try to
 # connect to a display that does not exist yet, so kwin_wayland dies
 # with "Failed to create wl_display" and plasmashell follows.
@@ -133,6 +135,9 @@ if command -v dbus-daemon >/dev/null 2>&1; then
 else
 	printf '%s\n' "SPS: dbus-daemon is not on PATH; Plasma needs it."
 fi
+if [ -x /usr/lib/polkit-1/polkitd ]; then
+	/usr/lib/polkit-1/polkitd --no-debug >/run/sps-polkitd.log 2>&1 &
+fi
 if command -v seatd >/dev/null 2>&1; then
 	seatd -g video >/dev/null 2>&1 &
 	n=0
diff --git a/lib/mkiso/live-plasma-session b/lib/mkiso/live-plasma-session
index 1d245c6..891a593 100644
--- a/lib/mkiso/live-plasma-session
+++ b/lib/mkiso/live-plasma-session
@@ -12,6 +12,8 @@ export XDG_SESSION_CLASS=user
 export XDG_SESSION_DESKTOP=KDE
 export XDG_CURRENT_DESKTOP=KDE
 export DESKTOP_SESSION=plasma
+export MOZ_ENABLE_WAYLAND=1
+export MOZ_ALLOW_DOWNGRADE=1
 
 if command -v kded6 >/dev/null 2>&1; then
 	kded6 >/run/kded6.log 2>&1 &
@@ -24,6 +26,28 @@ fi
 if [ -x /usr/libexec/kactivitymanagerd ]; then
 	/usr/libexec/kactivitymanagerd >/run/kactivity.log 2>&1 &
 fi
+if [ -x /usr/libexec/kf6/kiod6 ]; then
+	/usr/libexec/kf6/kiod6 >/run/kiod6.log 2>&1 &
+fi
+if command -v pipewire >/dev/null 2>&1; then
+	pipewire >/run/sps-pipewire.log 2>&1 &
+fi
+if command -v wireplumber >/dev/null 2>&1; then
+	wireplumber >/run/sps-wireplumber.log 2>&1 &
+fi
+if command -v pipewire-pulse >/dev/null 2>&1; then
+	pipewire-pulse >/run/sps-pipewire-pulse.log 2>&1 &
+fi
+if [ -x /usr/libexec/xdg-desktop-portal ]; then
+	/usr/libexec/xdg-desktop-portal >/run/sps-portal.log 2>&1 &
+fi
+if [ -x /usr/libexec/xdg-desktop-portal-kde ]; then
+	/usr/libexec/xdg-desktop-portal-kde >/run/sps-portal-kde.log 2>&1 &
+fi
+if [ -x /usr/libexec/polkit-kde-authentication-agent-1 ]; then
+	/usr/libexec/polkit-kde-authentication-agent-1 \
+		>/run/sps-polkit-agent.log 2>&1 &
+fi
 
 if command -v plasma-welcome >/dev/null 2>&1; then
 	(
diff --git a/lib/mkiso/live-rc b/lib/mkiso/live-rc
index 77e8449..acdd0ea 100644
--- a/lib/mkiso/live-rc
+++ b/lib/mkiso/live-rc
@@ -175,6 +175,9 @@ then
 		fi
 	fi
 fi
+if [ -x /usr/lib/polkit-1/polkitd ]; then
+	/usr/lib/polkit-1/polkitd --no-debug >/run/sps-polkitd.log 2>&1 &
+fi
 
 cat /etc/issue 2>/dev/null || :
 cat /etc/motd 2>/dev/null || :
diff --git a/lib/mkiso/plasma-bins b/lib/mkiso/plasma-bins
index b778b4f..83ae2ca 100644
--- a/lib/mkiso/plasma-bins
+++ b/lib/mkiso/plasma-bins
@@ -62,3 +62,16 @@
 /usr/libexec/xdg-desktop-portal-kde
 /usr/libexec/xdg-document-portal
 /usr/libexec/xdg-permission-store
+/usr/bin/firefox
+/usr/lib64/firefox/firefox-bin
+/usr/bin/pkexec
+/usr/lib/polkit-1/polkitd
+/usr/libexec/polkit-kde-authentication-agent-1
+/usr/bin/gwenview
+/usr/bin/okular
+/usr/bin/spectacle
+/usr/bin/ark
+/usr/bin/kcalc
+/usr/bin/kcharselect
+/usr/bin/kfind
+/usr/bin/partitionmanager
diff --git a/lib/mkiso/plasma-trees b/lib/mkiso/plasma-trees
index b7c299e..d9c679b 100644
--- a/lib/mkiso/plasma-trees
+++ b/lib/mkiso/plasma-trees
@@ -55,3 +55,25 @@
 /usr/lib64/spa-0.2
 /usr/share/pipewire
 /usr/share/wireplumber
+/usr/share/systemsettings
+/usr/share/kpackage
+/usr/share/kcmkeys
+/usr/share/kcmmouse
+/usr/share/kcmsolidactions
+/usr/share/kcm_networkmanagement
+/usr/share/kcm_recentFiles
+/usr/share/solid
+/usr/share/kio
+/usr/share/kxmlgui5
+/usr/share/knsrcfiles
+/usr/share/plasma5support
+/usr/share/glib-2.0
+/usr/share/gtk-3.0
+/usr/lib64/gtk-3.0
+/usr/lib64/gdk-pixbuf-2.0
+/usr/lib64/gio
+/usr/lib/polkit-1
+/etc/polkit-1
+/etc/xdg/menus
+/usr/lib64/firefox
+/usr/share/xdg-desktop-portal
diff --git a/tests/test_mkiso.sh b/tests/test_mkiso.sh
index b5aa390..7ed048c 100755
--- a/tests/test_mkiso.sh
+++ b/tests/test_mkiso.sh
@@ -48,6 +48,11 @@ fi
 [ -f "$layout/etc/sps/live" ] || fail 'live marker missing'
 [ -f "$layout/etc/motd" ] || fail 'motd missing'
 [ -x "$layout/sbin/init" ] || fail 'live init missing'
+[ -L "$layout/bin" ] || fail 'live /bin must be a usr-merge symlink'
+[ "$(readlink "$layout/bin")" = usr/bin ] ||
+	fail 'live /bin must point at usr/bin'
+[ -d "$layout/var/lib/sps/installed/filesystem" ] ||
+	fail 'live image must record filesystem as installed'
 [ -x "$layout/etc/sps/live-rc" ] || fail 'live-rc missing'
 [ -f "$layout/etc/inittab" ] || fail 'inittab missing'
 [ "$(cat "$layout/etc/sps/init")" = systemd ] || fail 'live default init is not systemd'
@@ -295,8 +300,23 @@ grep -q 'qt6/plugins/plasma' "$mkiso" ||
 	fail 'plasma ISO must close the Plasma applet plugin dependency graph'
 grep -q 'qt6/plugins/kwin' "$mkiso" ||
 	fail 'plasma ISO must close the KWin plugin dependency graph'
-grep -q libtaskmanager "$mkiso" ||
-	fail 'plasma ISO must verify libtaskmanager for the activity switcher'
+grep -q /usr/share/systemsettings "$project_dir/lib/mkiso/plasma-trees" ||
+	fail 'plasma-trees must include System Settings categories'
+grep -q /usr/bin/firefox "$project_dir/lib/mkiso/plasma-bins" ||
+	fail 'plasma-bins must include firefox'
+grep -q /usr/lib64/firefox "$project_dir/lib/mkiso/plasma-trees" ||
+	fail 'plasma-trees must include the Firefox runtime tree'
+grep -q pipewire "$project_dir/lib/mkiso/live-plasma-session" ||
+	fail 'live Plasma session must start pipewire'
+grep -q polkitd "$project_dir/lib/mkiso/live-rc" ||
+	fail 'live-rc must start polkitd'
+grep -q polkit-kde-authentication-agent \
+	"$project_dir/lib/mkiso/live-plasma-session" ||
+	fail 'live Plasma session must start the KDE polkit agent'
+grep -q qt6/plugins/kf6 "$mkiso" ||
+	fail 'plasma ISO must close KF6 plugin libraries'
+grep -q mkiso_install_base_filesystem "$mkiso" ||
+	fail 'mkiso must install filesystem so live sget can own /bin'
 grep -q 'xkeyboard-config-2/rules/evdev' "$mkiso" ||
 	fail 'plasma ISO must verify the XKB evdev rules used by KWin'
 grep -q XCURSOR_THEME "$project_dir/lib/mkiso/live-plasma" ||