Compare commits

...
Author SHA1 Message Date
Clayton Craft 4290b88bd3 oem-intel: add i915 DMC fw to initramfs
Intel >=gen9 GPUs require DMC firmware to support some runtime low power
states, it's loaded when i915 starts so let's make sure it's in the
initramfs.

Also see: https://www.kernel.org/doc/html/latest/gpu/i915.html#dmc-firmware-support
2024-06-18 09:46:04 -07:00
Caleb Connolly 07e0335f6b postmarketos-initramfs: switch to udev and kmod
mdev is slow and missing features, it also requires that we load all the
modules that we include at once making the boot process slower.

udev is required for unl0kr (and buffyboard), it can also load modules
on demand (and asynchronously). Making the boot process considerably
faster on devices, especially for generic images where we have lots of
drivers for different display panels in the initramfs.

Additionally, import full fat modprobe from the kmod package, this is
required to support compressed modules.

This brings us more in line with other distros and generally improves
compatibility.

If devices use broken kernel modules which don't correctly define
modalias', these drivers may not be loaded by udev. This should be fixed
by defining the missing modalias statements in the driver.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 21:46:26 -07:00
Clayton Craft 5fab1d6d0a device-*: depend on initramfs-minimal for devices with small boot
[ci:ignore-count]
2024-06-17 14:07:45 -07:00
Caleb Connolly 119d51a111 postmarketos-initramfs: debug-shell 3.0
This incorprates the debug-shell functionality directly into the
initramfs, so it's no longer necessary to build and boot a custom
initramfs in order to debug your device.

Additionally, the behaviour of the debug-shell is entirely reworked, It
now creates an ACM serial gadget which can be accessed via any normal
terminal emulator (picocom, minicom, etc; or PuTTY on windows). Rather
than just invoking sh, the debug-shell now creates a respawning getty on
both the new virtual console and the active console (this will either be
the UART console or tty0/1).

It is necessary to spawn these shells via getty since the logging rework
means we can no longer assume that stdin/out/err reference a TTY.

In addition to the above, it is now possible to trigger a log dump by
holding volume up during boot. This can be useful for helping users
debug their devices if the issue doesn't result in a failure that can be
detected in the initramfs.

With these changes, the console-shell and debug-shell hook packages are
reduced to only adding the additional tools/features. console-shell is
still required for fbkeyboard, and debug-shell for the setup_usb_storage
tool.

Co-Developed-by: Clayton Craft <craftyguy@postmarketos.org>
Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:45 -07:00
Caleb Connolly d261a87c03 postmarketos-initramfs: handle empty hooks dir
For some reason globbing doesn't work properly for empty directories,
adjust the check in run_hooks to ensure the directory both exists and
contains something, otherwise we get an error about
"/hooks-cleanup/*.sh" not existing.

/ # mkdir blah
/ # for x in blah/*; do echo $x; done
blah/*
/ # touch blah/beep
/ # for x in blah/*; do echo $x; done
blah/beep

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:45 -07:00
Caleb Connolly 24999443a4 postmarketos-initramfs: depend on mdevd
I somehow hit a case where this wasn't installed and
/lib/mdev/persistent-storage wasn't available. Let's just explicitly
depend on mdevd...

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:44 -07:00
Caleb Connolly 47773ebfd0 main/iskey: new aport
iskey is a tiny tool that reports if any of the given keys are pressed.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:44 -07:00
Caleb Connolly 6aec0e1c42 postmarketos-initramfs: mount subpartitions after hooks
This step is the most likely to go wrong or have issues, and it has side
effects which can make it difficult to run multiple times on one boot.
Move it to after hooks so that e.g. when dropping to a debug shell, we
land before the first call.

This also makes booting to hooks a faster in many cases.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:44 -07:00
Caleb Connolly 6e069d6b15 postmarketos-initramfs: use dd to allocate logs image
fallocate seems to cause some strange behaviour where the logs.img file
is treated like it's empty. Given it's small and in a ramdisk let's just
create it with dd instead.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:44 -07:00
Caleb Connolly 8fae43b536 postmarketos-initramfs: check if UDC is configured before clearing
This fixes the annoying "sh: write error" and "Couldn't write to clear
UDC" messages that happen on every single boot.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:44 -07:00
Caleb Connolly 9ee2f1e4b7 postmarketos-initramfs: make CONFIGFS global
This variable is being used in more places, just make it global.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:44 -07:00
Caleb Connolly 56f1d6bfba postmarketos-initramfs: log to kernel ringbuffer
Rework logging to always log the initramfs output to the kernel
ringbuffer and deprecate PMOS_NO_OUTPUT_REDIRECT in favour of following
the kernel loglevel.

I know it seems silly to use syslogd for this, but it's necessary to
buffer writes to /dev/kmsg per-line if we want to correctly set the log
level, and "tee" does not do this (it will write multiple lines at once,
resulting in "<14>" prints in the ringbuffer). The main advantage to
this is that we won't have kernel logs cut in half by initramfs logs
anymore, everything will be nicely line buffered!

The previous logging solution of multiple "tail" commands would actually
fail to log up to the last few lines before a crash due to how tail
works (it polls the file and buffers lines).

I attempted something like this before, but I stopped after running into
ratelimiting issues. These are now resolved by configuring the
printk_devkmsg sysctl.

Dropping PMOS_NO_OUTPUT_REDIRECT:

The general motivations behind PMOS_NO_OUTPUT_REDIRECT was to avoid
cluttering up the console with initramfs logs when they aren't wanted;
this is now handled instead by the kernels logging facility. We log to
the ringbuffer at LOGLEVEL_INFO, so if "quiet" is specified on the
cmdline (or the loglevel is otherwise set above info) then initramfs
logs will also not be shown.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:44 -07:00
Caleb Connolly 8f9d2a29f3 postmarketos-initramfs: fork -minimal variant
We plan to make a lot of changes to the initramfs which will require
incresaing the size. There are some devices that have literally no free
space for this, so make a -minimal initramfs fork that can continue to
support those while we update the regular initramfs.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
2024-06-17 14:07:43 -07:00
27 changed files with 1573 additions and 202 deletions

No files matched your search

-1
View File
@@ -21,7 +21,6 @@ sh_files="
./main/postmarketos-installkernel/installkernel-pmos
./main/postmarketos-initramfs/init.sh
./main/postmarketos-initramfs/init_functions.sh
./main/postmarketos-mkinitfs-hook-debug-shell/20-debug-shell.sh
./main/postmarketos-mkinitfs-hook-debug-shell/setup_usb_storage.sh
./main/postmarketos-mkinitfs-hook-netboot/netboot.sh
./main/ttyescape/*.post-install
@@ -3,7 +3,7 @@
pkgname=device-google-peach-pit
pkgdesc="Samsung Chromebook 2 (11.6 inch)"
pkgver=6
pkgrel=1
pkgrel=2
url="https://postmarketos.org"
license="MIT"
arch="armv7"
@@ -14,6 +14,7 @@ depends="
linux-postmarketos-exynos5
postmarketos-base
postmarketos-cros-common
postmarketos-initramfs-minimal
"
makedepends="devicepkg-dev"
source="
+2 -1
View File
@@ -3,7 +3,7 @@
pkgname=device-google-snow
pkgdesc="Samsung Chromebook"
pkgver=6
pkgrel=1
pkgrel=2
url="https://postmarketos.org"
license="MIT"
arch="armv7"
@@ -14,6 +14,7 @@ depends="
linux-postmarketos-exynos5
postmarketos-base
postmarketos-cros-common
postmarketos-initramfs-minimal
"
makedepends="devicepkg-dev"
source="
@@ -0,0 +1,2 @@
# DMC fw is required on newer GPUs to enable lower power states
/lib/firmware/i915/*_dmc*
+9 -3
View File
@@ -1,8 +1,8 @@
# Maintainer: Clayton Craft <clayton@craftyguy.net>
pkgname=oem-intel
pkgdesc="Intel device support"
pkgver=3
pkgrel=1
pkgver=4
pkgrel=0
url="https://postmarketos.org"
license="MIT"
arch="x86_64"
@@ -18,11 +18,16 @@ subpackages="
$pkgname-libva
$pkgname-vulkan
"
source="00-oem-intel.modules"
source="
00-oem-intel.modules
00-oem-intel-i915-firmware.files
"
package() {
install -Dm644 00-oem-intel.modules \
-t "$pkgdir"/usr/share/mkinitfs/modules
install -Dm644 00-oem-intel-i915-firmware.files \
-t "$pkgdir"/usr/share/mkinitfs/files
}
libva() {
@@ -43,4 +48,5 @@ vulkan() {
sha512sums="
48b8c0454c8c80e7ad0ebd139c01790eed3fbd4265bf4ce64882d354b091ac7f63084eaf2b00d1244a7a692c73fa900193724577f9a8d753fa8b6743fe1c8990 00-oem-intel.modules
c17f5c505e0e280a9e51ac1b4264e7703b744fd3831d75ce95f41be4755ae4ccd24b7ca09ba1e236df499a5e748c64a0d2054c9d55d8c8c713fa8c5646ed9a3c 00-oem-intel-i915-firmware.files
"
@@ -3,7 +3,7 @@
pkgname=device-google-peach-pi
pkgdesc="Samsung Chromebook 2 (13.3 inch)"
pkgver=6
pkgrel=1
pkgrel=2
url="https://postmarketos.org"
license="MIT"
arch="armv7"
@@ -14,6 +14,7 @@ depends="
linux-postmarketos-exynos5
postmarketos-base
postmarketos-cros-common
postmarketos-initramfs-minimal
"
makedepends="devicepkg-dev"
source="
+2 -1
View File
@@ -2,7 +2,7 @@
pkgname=device-google-spring
pkgdesc="HP Chromebook 11 G1"
pkgver=2
pkgrel=1
pkgrel=2
url="https://postmarketos.org"
license="MIT"
arch="armv7"
@@ -13,6 +13,7 @@ depends="
linux-postmarketos-exynos5
postmarketos-base
postmarketos-cros-common
postmarketos-initramfs-minimal
"
makedepends="devicepkg-dev"
source="deviceinfo modules-initfs"
+2 -1
View File
@@ -2,7 +2,7 @@
pkgname=device-samsung-klte
pkgdesc="Samsung Galaxy S5 (G900F/G9006/G9008/G9009W)"
pkgver=7
pkgrel=0
pkgrel=1
url="https://postmarketos.org"
license="MIT"
arch="armv7"
@@ -11,6 +11,7 @@ depends="
lk2nd-msm8974
mkbootimg
postmarketos-base
postmarketos-initramfs-minimal
swclock-offset
"
makedepends="devicepkg-dev"
+34
View File
@@ -0,0 +1,34 @@
# Maintainer: Caleb Connolly <caleb@postmarketos.org>
pkgname=iskey
pkgver=1
pkgrel=0
pkgdesc="Tiny tool to check if a key is pressed"
url="https://postmarketos.org"
arch="all"
license="GPL-2.0"
makedepends="meson linux-headers libevdev-dev"
options="!check"
_commit="4bc43d2bbf424ca90e11b3ed0c56e925898a130d"
source="https://gitlab.com/postmarketOS/buffybox/-/archive/$_commit/buffybox-$_commit.tar.gz"
# We're only building the iskey utility
builddir="$srcdir/buffybox-$_commit/iskey"
build() {
abuild-meson . output
meson compile -C output
}
package() {
install -Dm755 output/iskey \
"$pkgdir"/usr/bin/iskey
# Make sure updates to this package trigger mkinitfs
touch iskey
install -Dm644 iskey \
"$pkgdir"/usr/share/mkinitfs-triggers/iskey
}
sha512sums="
d255a04e1c0bb98af579d5bce4fad4e618d39c5d9b5cd78299fc9ae30e33132af0e9d899df5d1754acc8b1ca2ff790dda072b14d1e41993a588537b23ebea032 buffybox-4bc43d2bbf424ca90e11b3ed0c56e925898a130d.tar.gz
"
+4 -2
View File
@@ -1,10 +1,11 @@
pkgname=postmarketos-base
pkgver=32
pkgrel=4
pkgrel=5
pkgdesc="Meta package for minimal postmarketOS base"
url="https://postmarketos.org"
arch="noarch"
license="GPL-3.0-or-later"
makedepends="postmarketos-initramfs"
depends="
alpine-base
devicepkg-utils>=0.2.0
@@ -12,7 +13,8 @@ depends="
logbookd
openssh
postmarketos-bootsplash
postmarketos-initramfs
postmarketos-ramdisk
postmarketos-mvcfg
postmarketos-keys
sudo-virt
zram-init
@@ -0,0 +1,23 @@
aes
btrfs
crc32_generic
crc32c_generic
dm-crypt
dm_crypt
evdev
ext4
f2fs
kernel/arch/*/crypto/
kernel/crypto/
kernel/fs/overlayfs/
libaes
loop
nls_ascii
nls_cp437
nls_iso8859_1
nls_utf8
usb_f_rndis
usb_f_ncm
usb-storage
vfat
xts
@@ -0,0 +1,12 @@
/bin
/boot
/dev
/etc
/lib
/proc
/run
/sbin
/sys
/sysroot
/tmp
/usr
@@ -0,0 +1,14 @@
/bin/busybox
/bin/busybox-extras
/bin/sh
/etc/deviceinfo
/etc/unudhcpd.conf
/lib/mdev/persistent-storage
/sbin/blkid
/usr/bin/unudhcpd
/usr/sbin/kpartx
/usr/share/deviceinfo/deviceinfo
/usr/share/initramfs/init.sh:/init
/usr/share/initramfs/init_functions.sh:/init_functions.sh
/usr/share/initramfs/mdev.conf:/etc/mdev.conf
/usr/share/misc/source_deviceinfo
@@ -0,0 +1,8 @@
/lib/libz.so.1
/sbin/btrfs
/sbin/dmsetup
/sbin/e2fsck
/sbin/switch_root
/usr/sbin/parted
/usr/sbin/resize2fs
/usr/sbin/resize.f2fs
@@ -0,0 +1,97 @@
# WARNING: this package is deprecated and currently unmaintained. It should
# only be used on devices that do not have space for the full size ramdisk.
pkgname=postmarketos-initramfs-minimal
pkgver=2.5.6
pkgrel=0
pkgdesc="Deprecated minimal initramfs for space constrained devices"
url="https://postmarketos.org"
options="!check" # no tests
provides="postmarketos-ramdisk"
provider_priority=1
depends="
blkid
btrfs-progs
busybox-extras
bzip2
cryptsetup
device-mapper
devicepkg-utils>=0.2.0
e2fsprogs
e2fsprogs-extra
f2fs-tools
lz4
mdev-conf
multipath-tools
parted
postmarketos-fde-unlocker
postmarketos-mkinitfs>=2.2
unudhcpd
util-linux-misc
xz
"
source="
00-default.modules
00-initramfs-base.dirs
00-initramfs-base.files
00-initramfs-extra-base.files
init.sh
init_functions.sh
unudhcpd.conf
mdev.conf
"
arch="noarch"
license="GPL-2.0-or-later"
build() {
mkdir -p "$builddir"
# Replace <<INITRAMFS_PKG_VERSION>> with the actual version
sed "s|<<INITRAMFS_PKG_VERSION>>|$pkgver-r$pkgrel|" \
"$srcdir/init.sh" > "$builddir/init.sh"
}
package() {
install -Dm644 "$srcdir/unudhcpd.conf" \
"$pkgdir/etc/unudhcpd.conf"
install -Dm644 "$srcdir/init_functions.sh" \
"$pkgdir/usr/share/initramfs/init_functions.sh"
install -Dm755 "$builddir/init.sh" \
"$pkgdir/usr/share/initramfs/init.sh"
install -Dm644 "$srcdir"/00-initramfs-base.dirs \
-t "$pkgdir"/usr/share/mkinitfs/dirs/
mkdir -p "$pkgdir"/etc/mkinitfs/dirs
install -Dm644 "$srcdir"/00-default.modules \
-t "$pkgdir"/usr/share/mkinitfs/modules/
mkdir -p "$pkgdir"/etc/mkinitfs/modules
install -Dm644 "$srcdir"/00-initramfs-base.files \
-t "$pkgdir"/usr/share/mkinitfs/files/
mkdir -p "$pkgdir"/etc/mkinitfs/files
install -Dm644 "$srcdir"/00-initramfs-extra-base.files \
-t "$pkgdir"/usr/share/mkinitfs/files-extra/
mkdir -p "$pkgdir"/etc/mkinitfs/files-extra
install -Dm644 "$srcdir"/mdev.conf \
-t "$pkgdir"/usr/share/initramfs/
mkdir -p "$pkgdir"/usr/share/mkinitfs/hooks
mkdir -p "$pkgdir"/usr/share/mkinitfs/hooks-extra
mkdir -p "$pkgdir"/etc/mkinitfs/hooks
mkdir -p "$pkgdir"/etc/mkinitfs/hooks-extra
}
sha512sums="
59be0649ed87a72d93624bd8a2e3f8c99a0f32f7b7a26f99436de782beba55671472c269eeee86440efc87e0d7148a0bb335fa537791092e73878ca21330544a 00-default.modules
5b364300f31c91fd0591eb0715f67cbf5383f45246a5fb9f34b79f7cb2e3b15768b2130e5f32f816cc169950f988c1beabc879ba31645c58ce131a288dbc071d 00-initramfs-base.dirs
ab41b45b0613f25a61114ed8c8b92bc53c60838f6e2e0ba18c76e5369b2984e6023a0661887692673aca3f647f268c468a468f6b1ac424cfee609017a89481dd 00-initramfs-base.files
8a4adad3785af474b36a09a05f6a3b2c4b4f43aac331a53b903abfa51ea12be1e3d1d807b7a6e66a1346815f3b0044daf8cd62e21e2dc75d2db13ee265a72985 00-initramfs-extra-base.files
b1462989633c65a102e7ae7ced9c41a00673b4c7434cd3fe16c229c39bb870d7e850b0d317487191b7d7ca32c75b2eed1561b1facf405bd4d876d32c71badcf3 init.sh
8ff684e8245217cc9461297bce55dd8b417f0478ef38cdbddf7662f9ecc4324ca09e75978261084e00f5a1f2e36cc3b25a609a9bdca4addc5a60d3c370cbdb90 init_functions.sh
ba3275a9af788c7c782322a22a0f144d5e50e3498ea6886486a29331f23ae89cd32d500a3635cfa7cab369afba92edc18aeca64ccbf0cd589061cce23d15b46c unudhcpd.conf
675e7d5bee39b2df7d322117f8dcaccc274d61beaf4d50ead19bbf2109446d64b1c0aa0c5b4f9846eb6c1c403418f28f6364eff4537ba41120fbfcbc484b7da7 mdev.conf
"
@@ -0,0 +1,97 @@
#!/bin/sh
# shellcheck disable=SC1091
IN_CI="false"
[ -e /hooks/10-verbose-initfs.sh ] && set -x
[ -e /hooks/05-ci.sh ] && IN_CI="true"
[ -e /etc/unudhcpd.conf ] && . /etc/unudhcpd.conf
. ./init_functions.sh
. /usr/share/misc/source_deviceinfo
[ -e /etc/os-release ] && . /etc/os-release
# provide a default for os-release's VERSION in case the file doesn't exist
VERSION="${VERSION:-unknown}"
# This is set during packaging and is used when triaging bug reports
INITRAMFS_PKG_VERSION="<<INITRAMFS_PKG_VERSION>>"
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
/bin/busybox --install -s
/bin/busybox-extras --install -s
# Mount everything, set up logging, modules, mdev
mount_proc_sys_dev
setup_log
setup_firmware_path
if [ "$IN_CI" = "false" ]; then
# shellcheck disable=SC2154
load_modules /lib/modules/initramfs.load "libcomposite"
setup_framebuffer
show_splash "Loading..."
setup_mdev
setup_dynamic_partitions "${deviceinfo_super_partitions:=}"
mount_subpartitions
else
# loads all modules
setup_udev
fi
run_hooks /hooks
if [ "$IN_CI" = "true" ]; then
echo "PMOS: CI tests done, disabling console and looping forever"
dmesg -n 1
fail_halt_boot
fi
# Always run dhcp daemon/usb networking for now (later this should only
# be enabled, when having the debug-shell hook installed for debugging,
# or get activated after the initramfs is done with an OpenRC service).
setup_usb_network
start_unudhcpd
wait_boot_partition
mount_boot_partition /boot
extract_initramfs_extra /boot/initramfs-extra
setup_udev
run_hooks /hooks-extra
# For testing the mass storage gadget log export function. We use a flag
# file on /boot so that we can test it on all devices as modifying the
# kernel cmdline is not always possible.
if [ -e /boot/.pmos_export_logs ]; then
echo "PMOS: Exporting logs via mass storage gadget"
show_splash "Exporting boot logs..."
# Delete the flag so we don't soft-brick the device by always booting
# to the log export mode.
mount -o remount,rw /boot
rm -f /boot/.pmos_export_logs
fail_halt_boot
fi
wait_root_partition
delete_old_install_partition
resize_root_partition
unlock_root_partition
resize_root_filesystem
mount_root_partition
# Mount boot partition into sysroot, so OpenRC doesn't need to do it (#664)
umount /boot
mount_boot_partition /sysroot/boot "rw"
init="/sbin/init"
setup_bootchart2
# Switch root
killall telnetd mdev udevd msm-fb-refresher 2>/dev/null
# shellcheck disable=SC2093
exec switch_root /sysroot "$init"
echo "ERROR: switch_root failed!"
echo "Looping forever. Install and use the debug-shell hook to debug this."
echo "For more information, see <https://postmarketos.org/debug-shell>"
fail_halt_boot
@@ -0,0 +1,907 @@
#!/bin/sh
# This file will be in /init_functions.sh inside the initramfs.
ROOT_PARTITION_UNLOCKED=0
ROOT_PARTITION_RESIZED=0
PMOS_BOOT=""
PMOS_ROOT=""
# Redirect stdout and stderr to logfile
setup_log() {
local log_to_console=""
grep -q PMOS_NO_OUTPUT_REDIRECT /proc/cmdline && log_to_console="true"
echo "### postmarketOS initramfs ###"
if [ -z "$log_to_console" ]; then
echo "Add PMOS_NO_OUTPUT_REDIRECT to your kernel command line"
echo "to enable initramfs logging to console (e.g. for serial)."
fi
# Start redirect
exec >/pmOS_init.log 2>&1
echo "### postmarketOS initramfs ###"
# Pipe logs to console if PMOS_NO_OUTPUT_REDIRECT is set
if [ -n "$log_to_console" ]; then
tail -f /pmOS_init.log > /dev/console &
fi
# Pipe logs to pmsg if PMOS_NO_OUTPUT_REDIRECT is set and /dev/pmsg0 is available
if [ -n "$log_to_console" ] && [ -e "/dev/pmsg0" ]; then
tail -f /pmOS_init.log > /dev/pmsg0 &
fi
}
mount_proc_sys_dev() {
# mdev
mount -t proc -o nodev,noexec,nosuid proc /proc || echo "Couldn't mount /proc"
mount -t sysfs -o nodev,noexec,nosuid sysfs /sys || echo "Couldn't mount /sys"
mount -t devtmpfs -o mode=0755,nosuid dev /dev || echo "Couldn't mount /dev"
mount -t tmpfs -o nosuid,nodev,mode=0755 run /run || echo "Couldn't mount /run"
mkdir /config
mount -t configfs -o nodev,noexec,nosuid configfs /config
# /dev/pts (needed for telnet)
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
}
setup_firmware_path() {
# Add the postmarketOS-specific path to the firmware search paths.
# This should be sufficient on kernel 3.10+, before that we need
# the kernel calling udev (and in our case /usr/lib/firmwareload.sh)
# to load the firmware for the kernel.
echo "Configuring kernel firmware image search path"
SYS=/sys/module/firmware_class/parameters/path
if ! [ -e "$SYS" ]; then
echo "Kernel does not support setting the firmware image search path. Skipping."
return
fi
# shellcheck disable=SC3037
echo -n /lib/firmware/postmarketos >$SYS
}
# shellcheck disable=SC3043
load_modules() {
local file="$1"
local modules="$2"
[ -f "$file" ] && modules="$modules $(grep -v ^\# "$file")"
# shellcheck disable=SC2086
modprobe -a $modules
}
setup_mdev() {
# Start mdev daemon
mdev -d
}
setup_udev() {
# Use udev to coldplug all devices so that they can be used via libinput (e.g.
# by unl0kr). This is the same series of steps performed by the udev,
# udev-trigger and udev-settle RC services. See also:
# - https://git.alpinelinux.org/aports/tree/main/eudev/setup-udev
# - https://git.alpinelinux.org/aports/tree/main/udev-init-scripts/APKBUILD
if command -v udevd > /dev/null && command -v udevadm > /dev/null; then
udevd -d
udevadm trigger --type=devices --action=add
udevadm settle
fi
}
get_uptime_seconds() {
# Get the current system uptime in seconds - ignore the two decimal places.
awk -F '.' '{print $1}' /proc/uptime
}
setup_dynamic_partitions() {
command -v make-dynpart-mappings > /dev/null || return
attempt_start=$(get_uptime_seconds)
wait_seconds=10
slot_number=0
for super_partition in $1; do
# Wait for mdev
echo "Waiting for super partition $super_partition..."
while [ ! -b "$super_partition" ]; do
if [ "$(get_uptime_seconds)" -ge $(( attempt_start + wait_seconds )) ]; then
echo "ERROR: Super partition $super_partition failed to show up!"
return;
fi
sleep 0.1
done
make-dynpart-mappings "$super_partition" "$slot_number"
slot_number=$(( slot_number + 1 ))
done
}
mount_subpartitions() {
try_parts="/dev/disk/by-partlabel/userdata /dev/disk/by-partlabel/system* /dev/mapper/system*"
android_parts=""
for x in $try_parts; do
[ -e "$x" ] && android_parts="$android_parts $x"
done
attempt_start=$(get_uptime_seconds)
wait_seconds=10
echo "Trying to mount subpartitions for $wait_seconds seconds..."
while [ -z "$(find_boot_partition)" ]; do
partitions="$android_parts $(grep -v "loop\|ram" < /proc/diskstats |\
sed 's/\(\s\+[0-9]\+\)\+\s\+//;s/ .*//;s/^/\/dev\//')"
for partition in $partitions; do
case "$(kpartx -l "$partition" 2>/dev/null | wc -l)" in
2)
echo "Mount subpartitions of $partition"
kpartx -afs "$partition"
# Ensure that this was the *correct* subpartition
# Some devices have mmc partitions that appear to have
# subpartitions, but aren't our subpartition.
if [ -n "$(find_boot_partition)" ]; then
break
fi
kpartx -d "$partition"
continue
;;
*)
continue
;;
esac
done
if [ "$(get_uptime_seconds)" -ge $(( attempt_start + wait_seconds )) ]; then
echo "ERROR: failed to mount subpartitions!"
return;
fi
sleep 0.1;
done
}
# Rewrite /dev/dm-X paths to /dev/mapper/...
pretty_dm_path() {
dm="$1"
n="${dm#/dev/dm-}"
# If the substitution didn't do anything, then we're done
[ "$n" = "$dm" ] && echo "$dm" && return
# Get the name of the device mapper device
name="/dev/mapper/$(cat "/sys/class/block/dm-${n}/dm/name")"
echo "$name"
}
find_root_partition() {
[ -n "$PMOS_ROOT" ] && echo "$PMOS_ROOT" && return
# The partition layout is one of the following:
# a) boot, root partitions on sdcard
# b) boot, root partition on the "system" partition (which has its
# own partition header! so we have partitions on partitions!)
#
# mount_subpartitions() must get executed before calling
# find_root_partition(), so partitions from b) also get found.
# Short circuit all autodetection logic if pmos_root= or
# pmos_root_uuid= is supplied on the kernel cmdline
# shellcheck disable=SC2013
if [ "$ROOT_PARTITION_UNLOCKED" = 0 ]; then
for x in $(cat /proc/cmdline); do
if ! [ "$x" = "${x#pmos_root_uuid=}" ]; then
path="$(blkid --uuid "${x#pmos_root_uuid=}")"
if [ -n "$path" ]; then
PMOS_ROOT="$path"
break
fi
fi
done
if [ -z "$PMOS_ROOT" ]; then
for x in $(cat /proc/cmdline); do
if ! [ "$x" = "${x#pmos_root=}" ]; then
path="${x#pmos_root=}"
if [ -e "$path" ]; then
PMOS_ROOT="$path"
break
fi
fi
done
fi
# On-device installer: before postmarketOS is installed,
# we want to use the installer partition as root. It is the
# partition behind pmos_root. pmos_root will either point to
# reserved space, or to an unfinished installation.
# p1: boot
# p2: (reserved space) <--- pmos_root
# p3: pmOS_install
# Details: https://postmarketos.org/on-device-installer
if [ -n "$PMOS_ROOT" ]; then
next="$(echo "$PMOS_ROOT" | sed 's/2$/3/')"
# If the next partition is labeled pmOS_install (and
# not pmOS_deleteme), then postmarketOS is not
# installed yet.
if blkid | grep "$next" | grep -q pmOS_install; then
PMOS_ROOT="$next"
fi
fi
fi
if [ -z "$PMOS_ROOT" ]; then
for id in pmOS_install pmOS_root; do
PMOS_ROOT="$(blkid --label "$id")"
[ -n "$PMOS_ROOT" ] && break
done
fi
# Search for luks partition.
# Note: This should always be after the filesystem search, since this
# function may be called after the luks partition is unlocked and we don't
# want to keep returning the luks partition if a valid root filesystem
# exists
if [ -z "$PMOS_ROOT" ]; then
PMOS_ROOT="$(blkid | grep "crypto_LUKS" | cut -d ":" -f 1 | head -n 1)"
fi
PMOS_ROOT=$(pretty_dm_path "$PMOS_ROOT")
echo "$PMOS_ROOT"
}
find_boot_partition() {
[ -n "$PMOS_BOOT" ] && echo "$PMOS_BOOT" && return
# First check for pmos_boot_uuid on the cmdline
# this should be set on all new installs.
# shellcheck disable=SC2013
for x in $(cat /proc/cmdline); do
if ! [ "$x" = "${x#pmos_boot_uuid=}" ]; then
# Check if there is a partition with a matching UUID
path="$(blkid --uuid "${x#pmos_boot_uuid=}")"
if [ -n "$path" ]; then
PMOS_BOOT="$path"
break
else
# Don't fall back to anything if the given UUID wasn't
# found
return
fi
fi
done
if [ -z "$PMOS_BOOT" ]; then
# shellcheck disable=SC2013
for x in $(cat /proc/cmdline); do
if ! [ "$x" = "${x#pmos_boot=}" ]; then
# If the boot partition is specified explicitly
# then we need to check if it's a valid path, and
# fall back if not...
path="${x#pmos_boot=}"
if [ -e "$path" ]; then
PMOS_BOOT="$path"
break
else
# Don't fall back to anything if the given path doesn't
# exist
return
fi
fi
done
fi
# Finally fall back to searching by label
if [ -z "$PMOS_BOOT" ]; then
# * "pmOS_i_boot" installer boot partition (fits 11 chars for fat32)
# * "pmOS_inst_boot" old installer boot partition (backwards compat)
# * "pmOS_boot" boot partition after installation
for p in pmOS_i_boot pmOS_inst_boot pmOS_boot; do
PMOS_BOOT="$(blkid --label "$p")"
[ -n "$PMOS_BOOT" ] && break
done
fi
PMOS_BOOT=$(pretty_dm_path "$PMOS_BOOT")
echo "$PMOS_BOOT"
}
get_partition_type() {
partition="$1"
blkid "$partition" | sed 's/^.*TYPE="\([a-zA-z0-9_]*\)".*$/\1/'
}
# $1: path
# $2: set to "rw" for read-write
# Mount the boot partition. It gets mounted twice, first at /boot (ro), then at
# /sysroot/boot (rw), after root has been mounted at /sysroot, so we can
# switch_root to /sysroot and have the boot partition properly mounted.
mount_boot_partition() {
partition=$(find_boot_partition)
if [ "$2" = "rw" ]; then
mount_opts=""
echo "Mount boot partition ($partition) to $1 (read-write)"
else
mount_opts="-o ro"
echo "Mount boot partition ($partition) to $1 (read-only)"
fi
type="$(get_partition_type "$partition")"
case "$type" in
ext*)
echo "Detected ext filesystem"
modprobe ext4
# ext2 might be handled by the ext2 or ext4 kernel module
# so let mount detect that automatically by omitting -t
;;
vfat)
echo "Detected vfat filesystem"
modprobe vfat
mount_opts="-t vfat $mount_opts"
;;
*) echo "WARNING: Detected unsupported '$type' filesystem ($partition)." ;;
esac
# shellcheck disable=SC2086
mount $mount_opts "$partition" "$1"
}
# $1: initramfs-extra path
extract_initramfs_extra() {
initramfs_extra="$1"
if [ ! -e "$initramfs_extra" ]; then
echo "ERROR: initramfs-extra not found!"
show_splash "ERROR: initramfs-extra not found\\nhttps://postmarketos.org/troubleshooting"
fail_halt_boot
fi
echo "Extract $initramfs_extra"
# uncompressed:
# cpio -di < "$initramfs_extra"
gzip -d -c "$initramfs_extra" | cpio -iu
}
wait_boot_partition() {
while [ -z "$(find_boot_partition)" ]; do
show_splash "ERROR: boot partition not found, retrying...\\nhttps://postmarketos.org/troubleshooting"
echo "Could not find the boot partition."
echo "If your install is on a removable disk, maybe you need to insert it?"
echo "Trying again..."
sleep 1
done
}
wait_root_partition() {
while [ -z "$(find_root_partition)" ]; do
show_splash "ERROR: root partition not found, retrying...\\nhttps://postmarketos.org/troubleshooting"
echo "Could not find the rootfs."
echo "If your install is on a removable disk, maybe you need to insert it?"
echo "Trying again..."
sleep 1
done
}
delete_old_install_partition() {
# The on-device installer leaves a "pmOS_deleteme" (p3) partition after
# successful installation, located after "pmOS_root" (p2). Delete it,
# so we can use the space.
partition="$(find_root_partition | sed 's/2$/3/')"
if ! blkid "$partition" | grep -q pmOS_deleteme; then
return
fi
device="$(echo "$partition" | sed -E 's/p?3$//')"
echo "First boot after running on-device installer - deleting old" \
"install partition: $partition"
parted -s "$device" rm 3
}
# $1: path to device
has_unallocated_space() {
# Check if there is unallocated space at the end of the device
parted -s "$1" print free | tail -n2 | \
head -n1 | grep -qi "free space"
}
resize_root_partition() {
partition=$(find_root_partition)
# Do not resize the installer partition
if [ "$(blkid --label pmOS_install)" = "$partition" ]; then
echo "Resize root partition: skipped (on-device installer)"
return
fi
# Only resize the partition if it's inside the device-mapper, which means
# that the partition is stored as a subpartition inside another one.
# In this case we want to resize it to use all the unused space of the
# external partition.
if [ -z "${partition##"/dev/mapper/"*}" ] || [ -z "${partition##"/dev/dm-"*}" ]; then
# Get physical device
partition_dev=$(dmsetup deps -o blkdevname "$partition" | \
awk -F "[()]" '{print "/dev/"$2}')
if has_unallocated_space "$partition_dev"; then
echo "Resize root partition ($partition)"
# unmount subpartition, resize and remount it
kpartx -d "$partition"
parted -f -s "$partition_dev" resizepart 2 100%
kpartx -afs "$partition_dev"
ROOT_PARTITION_RESIZED=1
else
echo "Not resizing root partition ($partition): no free space left"
fi
# Resize the root partition (non-subpartitions). Usually we do not want
# this, except for QEMU devices and non-android devices (e.g.
# PinePhone). For them, it is fine to use the whole storage device and
# so we pass PMOS_FORCE_PARTITION_RESIZE as kernel parameter.
elif grep -q PMOS_FORCE_PARTITION_RESIZE /proc/cmdline; then
partition_dev="$(echo "$partition" | sed -E 's/p?2$//')"
if has_unallocated_space "$partition_dev"; then
echo "Resize root partition ($partition)"
parted -f -s "$partition_dev" resizepart 2 100%
partprobe
ROOT_PARTITION_RESIZED=1
else
echo "Not resizing root partition ($partition): no free space left"
fi
# Resize the root partition (non-subpartitions) on Chrome OS devices.
# Match $deviceinfo_cgpt_kpart not being empty instead of cmdline
# because it does not make sense here as all these devices use the same
# partitioning methods. This also resizes third partition instead of
# second, because these devices have an additional kernel partition
# at the start.
elif [ -n "$deviceinfo_cgpt_kpart" ]; then
partition_dev="$(echo "$partition" | sed -E 's/p?3$//')"
if has_unallocated_space "$partition_dev"; then
echo "Resize root partition ($partition)"
parted -f -s "$partition_dev" resizepart 3 100%
partprobe
ROOT_PARTITION_RESIZED=1
else
echo "Not resizing root partition ($partition): no free space left"
fi
else
echo "Unable to resize root partition: failed to find qualifying partition"
fi
}
unlock_root_partition() {
command -v cryptsetup >/dev/null || return
partition="$(find_root_partition)"
if cryptsetup isLuks "$partition"; then
# Make sure the splash doesn't interfere
hide_splash
tried=0
until cryptsetup status root | grep -qwi active; do
fde-unlock "$partition" "$tried"
tried=$((tried + 1))
done
ROOT_PARTITION_UNLOCKED=1
# Show again the loading splashscreen
show_splash "Loading..."
fi
}
resize_root_filesystem() {
if [ "$ROOT_PARTITION_RESIZED" = 1 ]; then
show_splash "Resizing filesystem during initial boot..."
partition="$(find_root_partition)"
touch /etc/mtab # see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=673323
type="$(get_partition_type "$partition")"
case "$type" in
ext4)
echo "Resize 'ext4' root filesystem ($partition)"
modprobe ext4
resize2fs -f "$partition"
;;
f2fs)
echo "Resize 'f2fs' root filesystem ($partition)"
modprobe f2fs
resize.f2fs "$partition"
;;
btrfs)
echo "Resize 'btrfs' root filesystem ($partition)"
modprobe btrfs
resize_root_filesystem_tmp_btrfs="$(mktemp -d)"
mount -t btrfs "$partition" "$resize_root_filesystem_tmp_btrfs"
btrfs filesystem resize max "$resize_root_filesystem_tmp_btrfs"
umount "$resize_root_filesystem_tmp_btrfs"
unset resize_root_filesystem_tmp_btrfs
;;
*) echo "WARNING: Can not resize '$type' filesystem ($partition)." ;;
esac
show_splash "Loading..."
fi
}
mount_root_partition() {
partition="$(find_root_partition)"
rootfsopts=""
# shellcheck disable=SC2013
for x in $(cat /proc/cmdline); do
[ "$x" = "${x#pmos_rootfsopts=}" ] && continue
# Prepend a comma because this will be appended to "ro" below
rootfsopts=",${x#pmos_rootfsopts=}"
done
echo "Mount root partition ($partition) to /sysroot (read-only) with options ${rootfsopts#,}"
type="$(get_partition_type "$partition")"
echo "Detected $type filesystem"
if ! { [ "$type" = "ext4" ] || [ "$type" = "f2fs" ] || [ "$type" = "btrfs" ]; } then
echo "ERROR: Detected unsupported '$type' filesystem ($partition)."
show_splash "ERROR: unsupported '$type' filesystem ($partition)\\nhttps://postmarketos.org/troubleshooting"
fail_halt_boot
fi
if ! modprobe "$type"; then
echo "INFO: unable to load module '$type' - maybe it's built in"
fi
if ! mount -t "$type" -o ro"$rootfsopts" "$partition" /sysroot; then
echo "ERROR: unable to mount root partition!"
show_splash "ERROR: unable to mount root partition\\nhttps://postmarketos.org/troubleshooting"
fail_halt_boot
fi
if ! [ -e /sysroot/usr ]; then
echo "ERROR: root partition appeared to mount but does not contain a root filesystem!"
show_splash "ERROR: root partition does not contain a root filesystem\\nhttps://postmarketos.org/troubleshooting"
fail_halt_boot
fi
}
# $1: path to the hooks dir
run_hooks() {
scriptsdir="$1"
if ! [ -d "$scriptsdir" ]; then
return
fi
for hook in "$scriptsdir"/*.sh; do
echo "Running initramfs hook: $hook"
sh "$hook"
done
}
setup_usb_network_android() {
# Only run, when we have the android usb driver
SYS=/sys/class/android_usb/android0
if ! [ -e "$SYS" ]; then
echo " /sys/class/android_usb does not exist, skipping android_usb"
return
fi
echo " Setting up an USB gadget through android_usb"
usb_idVendor="$(echo "${deviceinfo_usb_idVendor:-0x18D1}" | sed "s/0x//g")" # default: Google Inc.
usb_idProduct="$(echo "${deviceinfo_usb_idProduct:-0xD001}" | sed "s/0x//g")" # default: Nexus 4 (fastboot)
# Do the setup
echo "0" >"$SYS/enable"
echo "$usb_idVendor" >"$SYS/idVendor"
echo "$usb_idProduct" >"$SYS/idProduct"
echo "rndis" >"$SYS/functions"
echo "1" >"$SYS/enable"
}
setup_usb_configfs_udc() {
# Check if there's an USB Device Controller
local _udc_dev="${deviceinfo_usb_network_udc:-}"
if [ -z "$_udc_dev" ]; then
_udc_dev=$(ls /sys/class/udc)
if [ -z "$_udc_dev" ]; then
echo " No USB Device Controller available"
return
fi
fi
# Remove any existing UDC to avoid "write error: Resource busy" when setting UDC again
echo "" > /config/usb_gadget/g1/UDC || echo " Couldn't write to clear UDC"
# Link the gadget instance to an USB Device Controller. This activates the gadget.
# See also: https://gitlab.com/postmarketOS/pmbootstrap/issues/338
echo "$_udc_dev" > /config/usb_gadget/g1/UDC || echo " Couldn't write new UDC"
}
# $1: if set, skip writing to the UDC
setup_usb_network_configfs() {
# See: https://www.kernel.org/doc/Documentation/usb/gadget_configfs.txt
CONFIGFS=/config/usb_gadget
local skip_udc="$1"
if ! [ -e "$CONFIGFS" ]; then
echo " /config/usb_gadget does not exist, skipping configfs usb gadget"
return
fi
# Default values for USB-related deviceinfo variables
usb_idVendor="${deviceinfo_usb_idVendor:-0x18D1}" # default: Google Inc.
usb_idProduct="${deviceinfo_usb_idProduct:-0xD001}" # default: Nexus 4 (fastboot)
usb_serialnumber="${deviceinfo_usb_serialnumber:-postmarketOS}"
usb_network_function="${deviceinfo_usb_network_function:-ncm.usb0}"
usb_network_function_fallback="rndis.usb0"
echo " Setting up an USB gadget through configfs"
# Create an usb gadet configuration
mkdir $CONFIGFS/g1 || echo " Couldn't create $CONFIGFS/g1"
echo "$usb_idVendor" > "$CONFIGFS/g1/idVendor"
echo "$usb_idProduct" > "$CONFIGFS/g1/idProduct"
# Create english (0x409) strings
mkdir $CONFIGFS/g1/strings/0x409 || echo " Couldn't create $CONFIGFS/g1/strings/0x409"
# shellcheck disable=SC2154
echo "$deviceinfo_manufacturer" > "$CONFIGFS/g1/strings/0x409/manufacturer"
echo "$usb_serialnumber" > "$CONFIGFS/g1/strings/0x409/serialnumber"
# shellcheck disable=SC2154
echo "$deviceinfo_name" > "$CONFIGFS/g1/strings/0x409/product"
# Create network function.
if ! mkdir $CONFIGFS/g1/functions/"$usb_network_function"; then
echo " Couldn't create $CONFIGFS/g1/functions/$usb_network_function"
# Try the fallback function next
if mkdir $CONFIGFS/g1/functions/"$usb_network_function_fallback"; then
usb_network_function="$usb_network_function_fallback"
else
echo " Couldn't create $CONFIGFS/g1/functions/$usb_network_function_fallback"
fi
fi
# Create configuration instance for the gadget
mkdir $CONFIGFS/g1/configs/c.1 \
|| echo " Couldn't create $CONFIGFS/g1/configs/c.1"
mkdir $CONFIGFS/g1/configs/c.1/strings/0x409 \
|| echo " Couldn't create $CONFIGFS/g1/configs/c.1/strings/0x409"
echo "USB network" > $CONFIGFS/g1/configs/c.1/strings/0x409/configuration \
|| echo " Couldn't write configration name"
# Link the network instance to the configuration
ln -s $CONFIGFS/g1/functions/"$usb_network_function" $CONFIGFS/g1/configs/c.1 \
|| echo " Couldn't symlink $usb_network_function"
# If an argument was supplied then skip writing to the UDC (only used for mass storage
# log recovery)
if [ -z "$skip_udc" ]; then
setup_usb_configfs_udc
fi
}
setup_usb_network() {
# Only run once
_marker="/tmp/_setup_usb_network"
[ -e "$_marker" ] && return
touch "$_marker"
echo "Setup usb network"
# Run all usb network setup functions (add more below!)
setup_usb_network_android
setup_usb_network_configfs
}
start_unudhcpd() {
# Only run once
[ "$(pidof unudhcpd)" ] && return
# Skip if disabled
# shellcheck disable=SC2154
if [ "$deviceinfo_disable_dhcpd" = "true" ]; then
echo "NOTE: start of dhcpd is disabled (deviceinfo_disable_dhcpd)"
return
fi
local host_ip="${unudhcpd_host_ip:-172.16.42.1}"
local client_ip="${unudhcpd_client_ip:-172.16.42.2}"
echo "Starting unudhcpd with server ip $host_ip, client ip: $client_ip"
# Get usb interface
usb_network_function="${deviceinfo_usb_network_function:-ncm.usb0}"
usb_network_function_fallback="rndis.usb0"
if [ -n "$(cat /config/usb_gadget/g1/UDC)" ]; then
INTERFACE="$(
cat "/config/usb_gadget/g1/functions/$usb_network_function/ifname" 2>/dev/null ||
cat "/config/usb_gadget/g1/functions/$usb_network_function_fallback/ifname" 2>/dev/null ||
echo ''
)"
else
INTERFACE=""
fi
if [ -n "$INTERFACE" ]; then
ifconfig "$INTERFACE" "$host_ip"
elif ifconfig rndis0 "$host_ip" 2>/dev/null; then
INTERFACE=rndis0
elif ifconfig usb0 "$host_ip" 2>/dev/null; then
INTERFACE=usb0
elif ifconfig eth0 "$host_ip" 2>/dev/null; then
INTERFACE=eth0
fi
if [ -z "$INTERFACE" ]; then
echo " Could not find an interface to run a dhcp server on"
echo " Interfaces:"
ip link
return
fi
echo " Using interface $INTERFACE"
echo " Starting the DHCP daemon"
(
unudhcpd -i "$INTERFACE" -s "$host_ip" -c "$client_ip"
) &
}
# $1: Message to show
show_splash() {
# Skip for non-framebuffer devices
# shellcheck disable=SC2154
if [ "$deviceinfo_no_framebuffer" = "true" ]; then
echo "NOTE: Skipping framebuffer splashscreen (deviceinfo_no_framebuffer)"
return
fi
# Disable splash
if grep -q PMOS_NOSPLASH /proc/cmdline; then
return
fi
hide_splash
# shellcheck disable=SC2154,SC2059
/usr/bin/pbsplash -s /usr/share/pbsplash/pmos-logo-text.svg \
-b "$VERSION | Linux $(uname -r) | $deviceinfo_codename" \
-m "$(printf "$1")" >/dev/null &
}
hide_splash() {
killall pbsplash 2>/dev/null
while pgrep pbsplash >/dev/null; do
sleep 0.01
done
}
set_framebuffer_mode() {
[ -e "/sys/class/graphics/fb0/modes" ] || return
[ -z "$(cat /sys/class/graphics/fb0/mode)" ] || return
_mode="$(cat /sys/class/graphics/fb0/modes)"
echo "Setting framebuffer mode to: $_mode"
echo "$_mode" > /sys/class/graphics/fb0/mode
}
setup_framebuffer() {
# Skip for non-framebuffer devices
# shellcheck disable=SC2154
if [ "$deviceinfo_no_framebuffer" = "true" ]; then
echo "NOTE: Skipping framebuffer setup (deviceinfo_no_framebuffer)"
return
fi
# Wait for /dev/fb0
for _ in $(seq 1 100); do
[ -e "/dev/fb0" ] && break
sleep 0.1
done
if ! [ -e "/dev/fb0" ]; then
echo "ERROR: /dev/fb0 did not appear after waiting 10 seconds!"
echo "If your device does not have a framebuffer, disable this with:"
echo "no_framebuffer=true in <https://postmarketos.org/deviceinfo>"
return
fi
set_framebuffer_mode
}
setup_bootchart2() {
if grep -q PMOS_BOOTCHART2 /proc/cmdline; then
if [ -f "/sysroot/sbin/bootchartd" ]; then
# shellcheck disable=SC2034
init="/sbin/bootchartd"
echo "remounting /sysroot as rw for /sbin/bootchartd"
mount -o remount, rw /sysroot
# /dev/null may not exist at the first boot after
# the root filesystem has been created.
[ -c /sysroot/dev/null ] && return
echo "creating /sysroot/dev/null for /sbin/bootchartd"
mknod -m 666 "/sysroot/dev/null" c 1 3
else
echo "WARNING: bootchart2 is not installed."
fi
fi
}
mkhash() {
sha256sum "$1" | cut -d " " -f 1
}
# Create a small disk image and copy logs to it so they can be exposed via mass storage
create_logs_disk() {
local loop_dev="$1"
local upload_file=""
echo "Creating logs disk"
fallocate -l 32M /tmp/logs.img
# The log device used is assumed to be $loop_dev
losetup -f /tmp/logs.img
mkfs.vfat -n "PMOS_LOGS" "$loop_dev"
mkdir -p /tmp/logs
mount "$loop_dev" /tmp/logs
# Copy logs
cp /pmOS_init.log /tmp/logs/pmOS_init.txt
dmesg > /tmp/logs/dmesg.txt
blkid > /tmp/logs/blkid.txt
cat /proc/cmdline > /tmp/logs/cmdline.txt
cat /proc/partitions > /tmp/logs/partitions.txt
# Include FDT if it exists
[ -e /sys/firmware/fdt ] && cp /sys/firmware/fdt /tmp/logs/fdt.dtb
# Additional info about the initramfs
{
echo "initramfs-version: $INITRAMFS_PKG_VERSION"
# Take hashes of the initramfs files so we can be sure they weren't modified inadvertantly
echo "init-hash: $(mkhash /init)"
echo "init-functions-hash: $(mkhash /init_functions.sh)"
} >> /tmp/logs/_info
# Create a tar file with all the logs. We don't include the date because on many devices
# (especially Qualcomm) the RTC is likely wrong.
upload_file="${deviceinfo_codename}-${VERSION}-$(uname -r).tar.gz"
# Done in a subshell to not change the working directory of init
(cd /tmp/logs || ( echo "Couldn't cd to /tmp/logs"; return ); tar -cv ./* | gzip -6 -c > "/tmp/$upload_file")
mv "/tmp/$upload_file" /tmp/logs/
# Create a README with instructions on how to report an issue
cat > /tmp/logs/README.txt <<-EOF
Something went wrong and your device did not boot properly. If this was unexpected
then please open a new issue by visiting
https://gitlab.com/postmarketOS/pmaports/-/issues/new
and attach the following file by dragging it onto the page:
* $upload_file
You are running postmarketOS $VERSION on kernel $(uname -r).
EOF
# Unmount
umount /tmp/logs
}
# Make logs available via mass storage gadget
export_logs() {
local loop_dev=""
usb_mass_storage_function="mass_storage.0"
active_udc="$(cat /config/usb_gadget/g1/UDC)"
loop_dev="$(losetup -f)"
create_logs_disk "$loop_dev"
echo "Making logs available via mass storage"
# Set up network gadget if not already done
if [ -z "$active_udc" ]; then
setup_usb_network_configfs "skip_udc"
else
# Unset UDC
echo "" > /config/usb_gadget/g1/UDC
fi
mkdir "$CONFIGFS"/g1/functions/"$usb_mass_storage_function" || return
echo "$loop_dev" > "$CONFIGFS"/g1/functions/"$usb_mass_storage_function"/lun.0/file
ln -s "$CONFIGFS"/g1/functions/"$usb_mass_storage_function" \
"$CONFIGFS"/g1/configs/c.1 || return
setup_usb_configfs_udc
}
fail_halt_boot() {
export_logs
echo "Looping forever"
while true; do
sleep 1
done
}
@@ -0,0 +1,6 @@
# This configuration file is used by the initramfs to run unudhcpd.
# It is *not* used directly by unudhcpd!
# Note: The initramfs must be recreated by running the 'mkinitfs' command
# for changes here to be applied/used during boot.
unudhcpd_host_ip=172.16.42.1
unudhcpd_client_ip=172.16.42.2
@@ -3,12 +3,21 @@
/bin/sh
/etc/deviceinfo
/etc/unudhcpd.conf
/lib/mdev/persistent-storage
/sbin/blkid
/usr/bin/iskey
/sbin/modprobe
/usr/bin/unudhcpd
/usr/sbin/kpartx
/usr/share/deviceinfo/deviceinfo
/usr/share/initramfs/init.sh:/init
/usr/share/initramfs/init_functions.sh:/init_functions.sh
/usr/share/initramfs/mdev.conf:/etc/mdev.conf
/usr/share/misc/source_deviceinfo
/usr/bin/buffyboard
/usr/share/consolefonts/ter-128n.psf.gz
/usr/bin/iskey
/usr/share/libinput/*.quirks
/bin/udevadm
/sbin/udevd
/etc/udev/rules.d
/lib/udev/rules.d
/lib/udev/scsi_id
+9 -10
View File
@@ -1,11 +1,13 @@
# Maintainer: Oliver Smith <ollieparanoid@postmarketos.org>
# Co-Maintainer: Clayton Craft <clayton@craftyguy.net>
pkgname=postmarketos-initramfs
pkgver=2.7.1
pkgver=3.1.0
pkgrel=0
pkgdesc="Base files for the postmarketOS initramfs / initramfs-extra"
url="https://postmarketos.org"
options="!check" # no tests
provides="postmarketos-ramdisk"
provider_priority=10
depends="
blkid
btrfs-progs
@@ -17,12 +19,14 @@ depends="
e2fsprogs
e2fsprogs-extra
f2fs-tools
iskey
kmod
lz4
mdev-conf
multipath-tools
parted
postmarketos-fde-unlocker
postmarketos-mkinitfs>=2.2
udev
unudhcpd
util-linux-misc
xz
@@ -35,7 +39,6 @@ source="
init.sh
init_functions.sh
unudhcpd.conf
mdev.conf
"
arch="noarch"
license="GPL-2.0-or-later"
@@ -74,9 +77,6 @@ package() {
-t "$pkgdir"/usr/share/mkinitfs/files-extra/
mkdir -p "$pkgdir"/etc/mkinitfs/files-extra
install -Dm644 "$srcdir"/mdev.conf \
-t "$pkgdir"/usr/share/initramfs/
mkdir -p "$pkgdir"/usr/share/mkinitfs/hooks
mkdir -p "$pkgdir"/usr/share/mkinitfs/hooks-extra
mkdir -p "$pkgdir"/etc/mkinitfs/hooks
@@ -86,10 +86,9 @@ package() {
sha512sums="
59be0649ed87a72d93624bd8a2e3f8c99a0f32f7b7a26f99436de782beba55671472c269eeee86440efc87e0d7148a0bb335fa537791092e73878ca21330544a 00-default.modules
9c0e8f6f61d5da191e03a1aa9d5d0ceb5baf1eae6dbb9bfb0af59817783525119ac8394b135f303f7b6434a3eab0b49185fb90379e06823db847a4999c75ce33 00-initramfs-base.dirs
ab41b45b0613f25a61114ed8c8b92bc53c60838f6e2e0ba18c76e5369b2984e6023a0661887692673aca3f647f268c468a468f6b1ac424cfee609017a89481dd 00-initramfs-base.files
97ca55f536fc98dd6d1f92094666ef4ea0ef19c1e31eba3a1b6fbf4ff8ebecad0a9abb0b15c6681500e423822aa401acc9675e08a1c00e062535ca2a2bfe18c2 00-initramfs-base.files
8a4adad3785af474b36a09a05f6a3b2c4b4f43aac331a53b903abfa51ea12be1e3d1d807b7a6e66a1346815f3b0044daf8cd62e21e2dc75d2db13ee265a72985 00-initramfs-extra-base.files
102cb49a5b44282afee7808945c69e9bb9310677efeefc681d92217f0399a90fcbb37eb9ac7aed89cc27c324780298c7c2de6de2bdb89a77499faad1c312e539 init.sh
091cb54268a8b5a0f2793c64e3eb633d5f6aee084ab2b6fcdb39c56404c97e1256294d48cd991e39e067a5b4defc4c20a82005c74a470e97577cbe8339a5348d init_functions.sh
72fe843a9889de9197eb9aec98da4da45db3275146b2aa20c94a31e7a1a1e0a6699418193f2fface964a4ecfad97a99d0a5891610d1934d1d308aabb8b651f8a init.sh
1d3337ace7611853579945dc6563556ced66f386a7f906835425bac9e45c7734682b85b381656dfd5d3b0a727a39e5718e77f0d19af42562c199df25ea9fda59 init_functions.sh
ba3275a9af788c7c782322a22a0f144d5e50e3498ea6886486a29331f23ae89cd32d500a3635cfa7cab369afba92edc18aeca64ccbf0cd589061cce23d15b46c unudhcpd.conf
675e7d5bee39b2df7d322117f8dcaccc274d61beaf4d50ead19bbf2109446d64b1c0aa0c5b4f9846eb6c1c403418f28f6364eff4537ba41120fbfcbc484b7da7 mdev.conf
"
+39 -16
View File
@@ -2,6 +2,7 @@
# shellcheck disable=SC1091
IN_CI="false"
LOG_PREFIX="[pmOS-rd]"
[ -e /hooks/10-verbose-initfs.sh ] && set -x
@@ -27,17 +28,13 @@ setup_log
setup_firmware_path
if [ "$IN_CI" = "false" ]; then
# shellcheck disable=SC2154
load_modules /lib/modules/initramfs.load "libcomposite"
setup_framebuffer
show_splash "Loading..."
setup_mdev
setup_dynamic_partitions "${deviceinfo_super_partitions:=}"
mount_subpartitions
else
# loads all modules
setup_udev
fi
setup_udev
setup_dynamic_partitions "${deviceinfo_super_partitions:=}"
run_hooks /hooks
if [ "$IN_CI" = "true" ]; then
@@ -46,16 +43,20 @@ if [ "$IN_CI" = "true" ]; then
fail_halt_boot
fi
# Always run dhcp daemon/usb networking for now (later this should only
# be enabled, when having the debug-shell hook installed for debugging,
# or get activated after the initramfs is done with an OpenRC service).
setup_usb_network
start_unudhcpd
if grep -q "pmos.debug-shell" /proc/cmdline; then
debug_shell
fi
check_keys
mount_subpartitions
wait_boot_partition
mount_boot_partition /boot
extract_initramfs_extra /boot/initramfs-extra
setup_udev
run_hooks /hooks-extra
# For testing the mass storage gadget log export function. We use a flag
@@ -88,12 +89,34 @@ setup_bootchart2
# Switch root
run_hooks /hooks-cleanup
killall mdev udevd 2>/dev/null
echo "Switching root"
# Restore stdout and stderr to their original values if they
# were stashed
if [ -e "/proc/1/fd/3" ]; then
exec 1>&3 2>&4
elif ! grep -q "pmos.debug-shell" /proc/cmdline; then
echo "$LOG_PREFIX Disabling console output again (use 'pmos.debug-shell' to keep it enabled)"
exec >/dev/null 2>&1
fi
# Re-enable kmsg ratelimiting (might have been disabled for logging)
echo ratelimit > /proc/sys/kernel/printk_devkmsg
killall mdev udevd syslogd 2>/dev/null
# Kill any getty shells that might be running
for pid in $(pidof sh); do
if ! [ "$pid" = "1" ]; then
kill -9 "$pid"
fi
done
# shellcheck disable=SC2093
exec switch_root /sysroot "$init"
echo "ERROR: switch_root failed!"
echo "Looping forever. Install and use the debug-shell hook to debug this."
echo "For more information, see <https://postmarketos.org/debug-shell>"
echo "$LOG_PREFIX ERROR: switch_root failed!" > /dev/kmsg
echo "$LOG_PREFIX Looping forever. Install and use the debug-shell hook to debug this." > /dev/kmsg
echo "$LOG_PREFIX For more information, see <https://postmarketos.org/debug-shell>" > /dev/kmsg
fail_halt_boot
+287 -56
View File
@@ -5,31 +5,65 @@ ROOT_PARTITION_RESIZED=0
PMOS_BOOT=""
PMOS_ROOT=""
CONFIGFS="/config/usb_gadget"
CONFIGFS_ACM_FUNCTION="acm.usb0"
HOST_IP="${unudhcpd_host_ip:-172.16.42.1}"
deviceinfo_getty=""
deviceinfo_name=""
deviceinfo_codename=""
# Redirect stdout and stderr to logfile
setup_log() {
local log_to_console=""
local console
console="$(cat /sys/devices/virtual/tty/console/active)"
local warn_null_console=""
grep -q PMOS_NO_OUTPUT_REDIRECT /proc/cmdline && log_to_console="true"
echo "### postmarketOS initramfs ###"
if [ -z "$log_to_console" ]; then
echo "Add PMOS_NO_OUTPUT_REDIRECT to your kernel command line"
echo "to enable initramfs logging to console (e.g. for serial)."
# Stash fd1/2 so we can restore them before switch_root, but only if the
# console is not null
if [ -n "$console" ] ; then
# The kernel logs go to the console, and we log to the kernel. Avoid printing everything
# twice.
console="/dev/null"
exec 3>&1 4>&2
else
# Setting console=null is a trick used on quite a few pmOS devices. However it is generally a really
# bad idea since it makes it impossible to debug kernel panics, and it makes our job logging in the
# initramfs a lot harder. Let's encourage people to stop using this by printing a warning to dmesg
# and logging to every console we can.
# Instead folks should add 'quiet' or 'silent' to the kernel cmdline to disable logging.
console="/dev/$(echo "$deviceinfo_getty" | cut -d';' -f1)"
if ! [ -e "$console" ]; then
console="/dev/null"
fi
warn_null_console="true"
fi
# Start redirect
exec >/pmOS_init.log 2>&1
echo "### postmarketOS initramfs ###"
# Disable kmsg ratelimiting for userspace (it gets re-enabled again before switch_root)
echo on > /proc/sys/kernel/printk_devkmsg
# Pipe logs to console if PMOS_NO_OUTPUT_REDIRECT is set
if [ -n "$log_to_console" ]; then
tail -f /pmOS_init.log > /dev/console &
# Spawn syslogd to log to the kernel
syslogd -K
local pmsg="/dev/pmsg0"
if ! [ -e "$pmsg" ]; then
pmsg="/dev/null"
fi
# Pipe logs to pmsg if PMOS_NO_OUTPUT_REDIRECT is set and /dev/pmsg0 is available
if [ -n "$log_to_console" ] && [ -e "/dev/pmsg0" ]; then
tail -f /pmOS_init.log > /dev/pmsg0 &
# Redirect to a subshell which outputs to the logfile as well
# as to the kernel ringbuffer and pstore (if available).
# Process substitution is technically non-POSIX, but is supported by busybox
# shellcheck disable=SC3001
exec > >(tee /pmOS_init.log "$pmsg" "$console" | logger -t "$LOG_PREFIX" -p user.info) 2>&1
if [ -n "$warn_null_console" ]; then
# Log to the display as well just to be sure.
echo "postmarketOS: ****************************************************" | tee /dev/tty1
echo "WARNING: 'console=null' on kernel cmdline. This is NOT supported!" | tee /dev/tty1
echo "WARNING: Use 'quiet' instead if you want to disable logging." | tee /dev/tty1
echo "WARNING: Logging initramfs output to $console, as a fallback." | tee /dev/tty1
echo "postmarketOS: ****************************************************" | tee /dev/tty1
fi
}
@@ -46,6 +80,9 @@ mount_proc_sys_dev() {
# /dev/pts (needed for telnet)
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
# This is required for process substitution to work (as used in setup_log())
ln -s /proc/self/fd /dev/fd
}
setup_firmware_path() {
@@ -63,31 +100,19 @@ setup_firmware_path() {
echo -n /lib/firmware/postmarketos >$SYS
}
# shellcheck disable=SC3043
load_modules() {
local file="$1"
local modules="$2"
[ -f "$file" ] && modules="$modules $(grep -v ^\# "$file")"
# shellcheck disable=SC2086
modprobe -a $modules
}
setup_mdev() {
# Start mdev daemon
mdev -d
}
setup_udev() {
# Use udev to coldplug all devices so that they can be used via libinput (e.g.
# by unl0kr). This is the same series of steps performed by the udev,
if ! command -v udevd > /dev/null || ! command -v udevadm > /dev/null; then
echo "ERROR: udev not found!"
return
fi
# This is the same series of steps performed by the udev,
# udev-trigger and udev-settle RC services. See also:
# - https://git.alpinelinux.org/aports/tree/main/eudev/setup-udev
# - https://git.alpinelinux.org/aports/tree/main/udev-init-scripts/APKBUILD
if command -v udevd > /dev/null && command -v udevadm > /dev/null; then
udevd -d
udevadm trigger --type=devices --action=add
udevadm settle
fi
udevd -d --resolve-names=never
udevadm trigger --type=devices --action=add
udevadm settle
}
get_uptime_seconds() {
@@ -581,7 +606,7 @@ mount_root_partition() {
run_hooks() {
scriptsdir="$1"
if ! [ -d "$scriptsdir" ]; then
if [ -z "$(ls -A "$scriptsdir")" ]; then
return
fi
@@ -625,20 +650,21 @@ setup_usb_configfs_udc() {
fi
# Remove any existing UDC to avoid "write error: Resource busy" when setting UDC again
echo "" > /config/usb_gadget/g1/UDC || echo " Couldn't write to clear UDC"
if [ "$(wc -w <$CONFIGFS/g1/UDC)" -gt 0 ]; then
echo "" > "$CONFIGFS"/g1/UDC || echo " Couldn't write to clear UDC"
fi
# Link the gadget instance to an USB Device Controller. This activates the gadget.
# See also: https://gitlab.com/postmarketOS/pmbootstrap/issues/338
echo "$_udc_dev" > /config/usb_gadget/g1/UDC || echo " Couldn't write new UDC"
echo "$_udc_dev" > "$CONFIGFS"/g1/UDC || echo " Couldn't write new UDC"
}
# $1: if set, skip writing to the UDC
setup_usb_network_configfs() {
# See: https://www.kernel.org/doc/Documentation/usb/gadget_configfs.txt
CONFIGFS=/config/usb_gadget
local skip_udc="$1"
if ! [ -e "$CONFIGFS" ]; then
echo " /config/usb_gadget does not exist, skipping configfs usb gadget"
echo "$CONFIGFS does not exist, skipping configfs usb gadget"
return
fi
@@ -716,29 +742,28 @@ start_unudhcpd() {
return
fi
local host_ip="${unudhcpd_host_ip:-172.16.42.1}"
local client_ip="${unudhcpd_client_ip:-172.16.42.2}"
echo "Starting unudhcpd with server ip $host_ip, client ip: $client_ip"
echo "Starting unudhcpd with server ip $HOST_IP, client ip: $client_ip"
# Get usb interface
usb_network_function="${deviceinfo_usb_network_function:-ncm.usb0}"
usb_network_function_fallback="rndis.usb0"
if [ -n "$(cat /config/usb_gadget/g1/UDC)" ]; then
if [ -n "$(cat $CONFIGFS/g1/UDC)" ]; then
INTERFACE="$(
cat "/config/usb_gadget/g1/functions/$usb_network_function/ifname" 2>/dev/null ||
cat "/config/usb_gadget/g1/functions/$usb_network_function_fallback/ifname" 2>/dev/null ||
cat "$CONFIGFS/g1/functions/$usb_network_function/ifname" 2>/dev/null ||
cat "$CONFIGFS/g1/functions/$usb_network_function_fallback/ifname" 2>/dev/null ||
echo ''
)"
else
INTERFACE=""
fi
if [ -n "$INTERFACE" ]; then
ifconfig "$INTERFACE" "$host_ip"
elif ifconfig rndis0 "$host_ip" 2>/dev/null; then
ifconfig "$INTERFACE" "$HOST_IP"
elif ifconfig rndis0 "$HOST_IP" 2>/dev/null; then
INTERFACE=rndis0
elif ifconfig usb0 "$host_ip" 2>/dev/null; then
elif ifconfig usb0 "$HOST_IP" 2>/dev/null; then
INTERFACE=usb0
elif ifconfig eth0 "$host_ip" 2>/dev/null; then
elif ifconfig eth0 "$HOST_IP" 2>/dev/null; then
INTERFACE=eth0
fi
@@ -752,10 +777,215 @@ start_unudhcpd() {
echo " Using interface $INTERFACE"
echo " Starting the DHCP daemon"
(
unudhcpd -i "$INTERFACE" -s "$host_ip" -c "$client_ip"
unudhcpd -i "$INTERFACE" -s "$HOST_IP" -c "$client_ip"
) &
}
setup_usb_acm_configfs() {
active_udc="$(cat $CONFIGFS/g1/UDC)"
if ! [ -e "$CONFIGFS" ]; then
echo " $CONFIGFS does not exist, can't set up serial gadget"
return 1
fi
# unset UDC
echo "" > $CONFIGFS/g1/UDC
# Create acm function
mkdir "$CONFIGFS/g1/functions/$CONFIGFS_ACM_FUNCTION" \
|| echo " Couldn't create $CONFIGFS/g1/functions/$CONFIGFS_ACM_FUNCTION"
# Link the acm function to the configuration
ln -s "$CONFIGFS/g1/functions/$CONFIGFS_ACM_FUNCTION" "$CONFIGFS/g1/configs/c.1" \
|| echo " Couldn't symlink $CONFIGFS_ACM_FUNCTION"
return 0
}
# Spawn a subshell to restart the getty if it exits
# $1: tty
run_getty() {
{
# Due to how the Linux host ACM driver works, we need to wait
# for data to be sent from the host before spawning the getty.
# Otherwise our README message will be echo'd back all garbled.
# On Linux in particular, there is a hack we can use: by writing
# something to the port, it will be echo'd back at the moment the
# port on the host side is opened, so user input won't even be
# needed in most cases. For more info see the blog posts at:
# https://michael.stapelberg.ch/posts/2021-04-27-linux-usb-virtual-serial-cdc-acm/
# https://connolly.tech/posts/2024_04_15-broken-connections/
if [ "$1" = "ttyGS0" ]; then
echo " " > /dev/ttyGS0
# shellcheck disable=SC3061
read -r < /dev/ttyGS0
fi
while /sbin/getty -n -l /sbin/pmos_getty "$1" 115200 vt100; do
sleep 0.2
done
} &
}
debug_shell() {
echo "Entering debug shell"
# if we have a UDC it's already been configured for USB networking
local have_udc
have_udc="$(cat $CONFIGFS/g1/UDC)"
if [ -n "$have_udc" ]; then
setup_usb_acm_configfs
fi
# mount pstore, if possible
if [ -d /sys/fs/pstore ]; then
mount -t pstore pstore /sys/fs/pstore || true
fi
mount -t debugfs none /sys/kernel/debug || true
# make a symlink like Android recoveries do
ln -s /sys/kernel/debug /d
cat <<-EOF > /README
postmarketOS debug shell
https://postmarketos.org/debug-shell
Device: $deviceinfo_name ($deviceinfo_codename)
Kernel: $(uname -r)
OS ver: $VERSION
initrd: $INITRAMFS_PKG_VERSION
Run 'pmos_continue_boot' to continue booting.
EOF
# Add pmos_logdump message only if relevant
if [ -n "$have_udc" ]; then
echo "Run 'pmos_logdump' to generate a log dump and expose it over USB." >> /README
fi
if [ -n "$have_udc" ] && [ -f /usr/bin/setup_usb_storage ]; then
cat <<-EOF >> /README
You can expose storage devices over USB with
'setup_usb_storage /dev/DEVICE'
EOF
fi
# Display some info
cat <<-EOF > /etc/profile
cat /README
. /init_functions.sh
EOF
cat <<-EOF > /sbin/pmos_getty
#!/bin/sh
/bin/sh -l
EOF
chmod +x /sbin/pmos_getty
cat <<-EOF > /sbin/pmos_continue_boot
#!/bin/sh
echo "Continuing boot..."
touch /tmp/continue_boot
pkill -f telnetd.*:23
while sleep 1; do :; done
EOF
chmod +x /sbin/pmos_continue_boot
cat <<-EOF > /sbin/pmos_logdump
#!/bin/sh
echo "Dumping logs, check for a new mass storage device"
touch /tmp/dump_logs
EOF
chmod +x /sbin/pmos_logdump
# Get the console (ttyX) associated with /dev/console
local active_console
active_console="$(cat /sys/devices/virtual/tty/tty0/active)"
# Get a list of all active TTYs include serial ports
local serial_ports
serial_ports="$(cat /sys/devices/virtual/tty/console/active)"
# Get the getty device too (might not be active)
local getty
getty="$(echo "$deviceinfo_getty" | cut -d';' -f1)"
# Run getty's on the consoles
for tty in $serial_ports; do
# Some ports we handle explicitly below to make sure we don't
# accidentally spawn two getty's on them
if echo "tty0 tty1 ttyGS0 $getty" | grep -q "$tty" ; then
continue
fi
run_getty "$tty"
done
if [ -n "$getty" ]; then
run_getty "$getty"
fi
# Rewrite tty to tty1 if tty0 is active
if [ "$active_console" = "tty0" ]; then
active_console="tty1"
fi
# Getty on the display
hide_splash
run_getty "$active_console"
# And on the usb acm port (if it exists)
if [ -e /dev/ttyGS0 ]; then
run_getty ttyGS0
fi
# To avoid racing with the host PC opening the ACM port, we spawn
# the getty first. See the comment in run_getty for more details.
setup_usb_configfs_udc
# Spawn telnetd for those who prefer it. ACM gadget mode is not
# supported on some old kernels so this exists as a fallback.
telnetd -b "${HOST_IP}:23" -l /sbin/pmos_getty &
# wait until we get the signal to continue boot
while ! [ -e /tmp/continue_boot ]; do
sleep 0.2
if [ -e /tmp/dump_logs ]; then
rm -f /tmp/dump_logs
export_logs
fi
done
# Remove the ACM gadget device
# FIXME: would be nice to have a way to keep this on and
# pipe kernel/init logs to it.
rm -f $CONFIGFS/g1/configs/c.1/"$CONFIGFS_ACM_FUNCTION"
rmdir $CONFIGFS/g1/functions/"$CONFIGFS_ACM_FUNCTION"
setup_usb_configfs_udc
show_splash "Loading..."
pkill -f fbkeyboard || true
}
# Check if the user is pressing a key and either drop to a shell or halt boot as applicable
check_keys() {
{
# If the user is pressing either the left control key or the volume down
# key then drop to a debug shell.
if iskey KEY_LEFTCTRL KEY_VOLUMEDOWN; then
debug_shell
# If instead they're pressing left shift or volume up, then fail boot
# and dump logs
elif iskey KEY_LEFTSHIFT KEY_VOLUMEUP; then
fail_halt_boot
fi
touch /tmp/debug_shell_exited
} &
while ! [ -e /tmp/debug_shell_exited ]; do
sleep 1
done
}
# $1: Message to show
show_splash() {
# Skip for non-framebuffer devices
@@ -847,7 +1077,7 @@ create_logs_disk() {
local upload_file=""
echo "Creating logs disk"
fallocate -l 32M /tmp/logs.img
dd if=/dev/zero of=/tmp/logs.img bs=1M count=32
# The log device used is assumed to be $loop_dev
losetup -f /tmp/logs.img
mkfs.vfat -n "PMOS_LOGS" "$loop_dev"
@@ -900,7 +1130,7 @@ create_logs_disk() {
export_logs() {
local loop_dev=""
usb_mass_storage_function="mass_storage.0"
active_udc="$(cat /config/usb_gadget/g1/UDC)"
active_udc="$(cat $CONFIGFS/g1/UDC)"
loop_dev="$(losetup -f)"
@@ -913,7 +1143,7 @@ export_logs() {
setup_usb_network_configfs "skip_udc"
else
# Unset UDC
echo "" > /config/usb_gadget/g1/UDC
echo "" > $CONFIGFS/g1/UDC
fi
mkdir "$CONFIGFS"/g1/functions/"$usb_mass_storage_function" || return
@@ -928,6 +1158,7 @@ export_logs() {
fail_halt_boot() {
export_logs
debug_shell
echo "Looping forever"
while true; do
sleep 1
@@ -1,18 +1,16 @@
# Maintainer: Ferenc Bakonyi <bakonyi.ferenc@gmail.com>
pkgname=postmarketos-mkinitfs-hook-console-shell
pkgver=0.3.1
pkgver=0.4.0
pkgrel=0
pkgdesc="Root console shell in the initramfs (security hole, for debugging only)"
url="https://postmarketos.org"
depends="postmarketos-mkinitfs devicepkg-utils fbdebug evtest linuxconsoletools reboot-mode fbkeyboard font-dejavu"
source="console-shell.sh console-shell.files console-shell.modules"
source="console-shell.files console-shell.modules"
arch="noarch"
license="GPL-2.0-or-later"
options="!check" # No tests
package() {
install -Dm644 "$srcdir"/console-shell.sh \
"$pkgdir"/usr/share/mkinitfs/hooks/30-console-shell.sh
install -Dm644 "$srcdir"/console-shell.files \
"$pkgdir"/usr/share/mkinitfs/files/30-console-shell.files
install -Dm644 "$srcdir"/console-shell.modules \
@@ -20,7 +18,6 @@ package() {
}
sha512sums="
0753bf2e2bb011309a906db08b5fc13dba90e55bd5d11c8da0c34c89faf04dbf5915785cc0ed2a164f2e4c5fede06c7e80b5f592f4deb306cf5cec2371ef88f9 console-shell.sh
17b65cb24103e4c1459ae72bc036c1f06cdfcccf480389ecf6a28253d104b9b06d394cf53314a1ef4ace4ffc88b6b1384ef4894b7270d6b2cfdfc83592e12b2c console-shell.files
a9b069ed121ffeee887e0583d8cb46035ecf1fa90a26a4ecb3aa11ff03178b2b08621f6676db6b2350f290694c04aabcf36f2ce3e0813a76dde9a33555edb112 console-shell.modules
"
@@ -1,20 +0,0 @@
#!/bin/sh
# shellcheck disable=SC1091
. ./init_functions.sh
. /usr/share/misc/source_deviceinfo
# mount pstore, if possible
if [ -d /sys/fs/pstore ]; then
mount -t pstore pstore /sys/fs/pstore || true
fi
if tty -s; then
tty=/dev/tty0
modprobe uinput
fbkeyboard -r $(cat /sys/class/graphics/fbcon/rotate) 2>$tty &
echo "Exit the shell to continue booting:" > $tty
sh +m <$tty >$tty 2>$tty
pkill -f fbkeyboard
else
echo "No tty attached, exiting."
fi
@@ -1,77 +0,0 @@
#!/bin/sh
# shellcheck disable=SC1091
. ./init_functions.sh
. /usr/share/misc/source_deviceinfo
TELNET_PORT=23
setup_usb_network
start_unudhcpd
show_splash "WARNING: debug-shell is active\\nhttps://postmarketos.org/debug-shell"
echo "Create 'pmos_continue_boot' script"
{
echo "#!/bin/sh"
#Disable any active usb mass storage
echo "if [ -d /config/usb_gadget/g1/functions/mass_storage.0 ]; then setup_usb_storage; fi"
echo "pkill -9 -f pmos_shell"
echo "pkill -f pmos_fail_halt_boot"
} >/usr/bin/pmos_continue_boot
chmod +x /usr/bin/pmos_continue_boot
echo "Create 'pmos_shell' script"
{
echo "#!/bin/sh"
echo "sh"
} >/usr/bin/pmos_shell
chmod +x /usr/bin/pmos_shell
echo "Create 'pmos_fail_halt_boot' script"
{
echo "#!/bin/sh"
echo '. /init_functions.sh'
echo "fail_halt_boot"
} >/usr/bin/pmos_fail_halt_boot
chmod +x /usr/bin/pmos_fail_halt_boot
echo "Create debug-shell cleanup script"
{
echo "#!/bin/sh"
# shellcheck disable=SC2016
echo 'kill `cat /run/debug-shell-telnet.pid`'
} > /hooks-cleanup/debug-shell-cleanup.sh
chmod +x /hooks-cleanup/debug-shell-cleanup.sh
echo "Start the telnet daemon"
{
echo "#!/bin/sh"
echo "echo \"Type 'pmos_continue_boot' to continue booting:\""
echo "sh"
} >/telnet_connect.sh
chmod +x /telnet_connect.sh
host_ip="${unudhcpd_host_ip:-172.16.42.1}"
# Run telnetd with -F (foreground) instead of as a daemon so we can get it's PID
telnetd -F -b "${host_ip}:${TELNET_PORT}" -l /telnet_connect.sh &
echo "$!" > /run/debug-shell-telnet.pid
# mount pstore, if possible
if [ -d /sys/fs/pstore ]; then
mount -t pstore pstore /sys/fs/pstore || true
fi
# mount debugfs - very helpful for debugging
mount -t debugfs none /sys/kernel/debug || true
# make a symlink like Android recoveries do
ln -s /sys/kernel/debug /d
echo "---"
echo "WARNING: debug-shell is active on ${host_ip}:${TELNET_PORT}."
echo "This is a security hole! Only use it for debugging, and"
echo "uninstall the debug-shell hook afterwards!"
echo "You can expose storage devices using 'setup_usb_storage /dev/DEVICE'"
echo "---"
pmos_shell
# Show "Loading" splash again when continuing
show_splash "Loading..."
@@ -1,17 +1,15 @@
pkgname=postmarketos-mkinitfs-hook-debug-shell
pkgver=0.6.1
pkgver=0.7.0
pkgrel=0
pkgdesc="Root shell in the initramfs (security hole, for debugging only)"
url="https://postmarketos.org"
depends="postmarketos-mkinitfs devicepkg-utils fbdebug evtest linuxconsoletools reboot-mode libinput libinput-tools"
source="20-debug-shell.sh 20-debug-shell.files setup_usb_storage.sh"
source="20-debug-shell.files setup_usb_storage.sh"
arch="noarch"
license="GPL2"
options="!check"
package() {
install -Dm644 "$srcdir"/20-debug-shell.sh \
"$pkgdir"/usr/share/mkinitfs/hooks/20-debug-shell.sh
install -Dm644 "$srcdir"/20-debug-shell.files \
"$pkgdir"/usr/share/mkinitfs/files/20-debug-shell.files
install -Dm755 "$srcdir"/setup_usb_storage.sh \
@@ -19,7 +17,6 @@ package() {
}
sha512sums="
46c7a77cc07e3f2acb733583a2710ea50366308c1018ead3081f910a243381a52eb2e584f7b11eb159b7fb16891b6d9acf2ffe3ace1588fcce9aad617787f675 20-debug-shell.sh
a739bc47d905d189edb26d9ebfd062023720fefdaab27207471c16d53a9c12ea8b81092a1047d8f2300e42ba500bdf6c5a3343aca55aab5bf8e84d68eb5680ab 20-debug-shell.files
75d485c2e9f352cfd717b7a92753a9dfc4a72526a44bcbb784eacb4ef9011072b3ffa1c42a317c0940598cc076fb6c61676c440e5b188378b19ca08d882c1338 setup_usb_storage.sh
"