Add a preprocessor, replacing the placeholder for manpages, and run initrd scripts through it

This commit is contained in:
наб 2020-12-06 22:47:48 +01:00
parent 768b21c2e7
commit ec666beb85
No known key found for this signature in database
GPG Key ID: BCFD0B018D2658F1
7 changed files with 179 additions and 103 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@
!*Makefile
!*.sublime-project
!*.md
!*.awk
!src
!src/**
!man

View File

@ -30,8 +30,9 @@ INCAR := $(foreach l,$(foreach l,,$(l)/include),-isystemext/$(l)) $(foreach l,,-
VERAR := $(foreach l,TZPFMS,-D$(l)_VERSION='$($(l)_VERSION)')
BINARY_SOURCES := $(sort $(wildcard $(SRCDIR)bin/*.cpp $(SRCDIR)bin/**/*.cpp))
COMMON_SOURCES := $(filter-out $(BINARY_SOURCES),$(sort $(wildcard $(SRCDIR)*.cpp $(SRCDIR)**/*.cpp $(SRCDIR)**/**/*.cpp $(SRCDIR)**/**/**/*.cpp)))
SHELLCHECK_SOURCES := $(sort $(shell grep -lR '#!/bin/.*sh' $(INITRDDIR)))
MANPAGE_HEADERS := $(sort $(wildcard $(MANDIR)*.h))
MANPAGE_SOURCES := $(sort $(wildcard $(MANDIR)*.md.pp))
INITRD_HEADERS := $(sort $(wildcard $(INITRDDIR)*.h))
.PHONY : all clean build shellcheck i-t dracut man
@ -40,14 +41,16 @@ MANPAGE_SOURCES := $(sort $(wildcard $(MANDIR)*.md.pp))
all : build man shellcheck i-t dracut
shellcheck : i-t dracut
find $(OUTDIR)initramfs-tools/ $(OUTDIR)dracut -name '*.sh' -exec echo $(SHELLCHECK) --exclude SC1091 {} + | sh -x
clean :
rm -rf $(OUTDIR)
build : $(subst $(SRCDIR)bin/,$(OUTDIR),$(subst .cpp,$(EXE),$(BINARY_SOURCES)))
man : $(OUTDIR)man/index.txt
shellcheck : $(BLDDIR)shellcheck-stamp
i-t : $(OUTDIR)initramfs-tools
dracut : $(OUTDIR)dracut
i-t : $(OUTDIR)initramfs-tools/usr/share/initramfs-tools/hooks/tzpfms $(OUTDIR)initramfs-tools/usr/share/tzpfms/initramfs-tools-zfs-patch.sh
dracut : $(patsubst $(INITRDDIR)dracut/%,$(OUTDIR)dracut/usr/lib/dracut/modules.d/91tzpfms/%,$(sort $(wildcard $(INITRDDIR)dracut/*.sh)))
$(OUTDIR)man/index.txt : $(MANDIR)index.txt $(patsubst $(MANDIR)%.pp,$(OUTDIR)man/%,$(MANPAGE_SOURCES))
@ -56,19 +59,13 @@ $(OUTDIR)man/index.txt : $(MANDIR)index.txt $(patsubst $(MANDIR)%.pp,$(OUTDIR)ma
$(RONN) --organization="tzpfms developers" $(filter-out $<,$^)
$(RONN) --organization="tzpfms developers" -f $(filter-out $<,$^)
$(BLDDIR)shellcheck-stamp : $(SHELLCHECK_SOURCES)
$(OUTDIR)initramfs-tools/usr/share/initramfs-tools/hooks/tzpfms: $(INITRDDIR)initramfs-tools/hook $(INITRD_HEADERS)
@mkdir -p $(dir $@)
$(SHELLCHECK) --exclude SC1091 $^
@date > $@
$(AWK) -f pp.awk $< > $@
$(OUTDIR)initramfs-tools : $(INITRDDIR)initramfs-tools
@mkdir -p $@/usr/share/initramfs-tools/hooks $@/usr/share/tzpfms
ln $^/hook $@/usr/share/initramfs-tools/hooks/tzpfms
ln $^/zfs-patch.sh $@/usr/share/tzpfms/initramfs-tools-zfs-patch.sh
$(OUTDIR)dracut : $(INITRDDIR)dracut
@mkdir -p $@/usr/lib/dracut/modules.d/91tzpfms
ln $(wildcard $^/*) $@/usr/lib/dracut/modules.d/91tzpfms
$(OUTDIR)initramfs-tools/usr/share/tzpfms/initramfs-tools-zfs-patch.sh: $(INITRDDIR)initramfs-tools/zfs-patch.sh $(INITRD_HEADERS)
@mkdir -p $(dir $@)
$(AWK) -f pp.awk $< > $@
$(OUTDIR)%$(EXE) : $(subst $(SRCDIR),$(OBJDIR),$(subst .cpp,$(OBJ),$(SRCDIR)bin/%.cpp $(COMMON_SOURCES)))
@ -84,6 +81,10 @@ $(BLDDIR)test/%$(OBJ) : $(TSTDIR)%.cpp
@mkdir -p $(dir $@)
$(CXX) $(CXXAR) $(INCAR) -I$(SRCDIR) $(VERAR) -c -o$@ $^
$(OUTDIR)man/%.md : $(MANDIR)%.md.pp $(sort $(wildcard $(MANDIR)*.h))
$(OUTDIR)man/%.md : $(MANDIR)%.md.pp $(MANPAGE_HEADERS)
@mkdir -p $(dir $@)
$(AWK) '/^#include/ {gsub("\"", "", $$2); while((getline inc < ("$(dir $<)" $$2)) == 1) print inc; next} {print}' $< > $@
$(AWK) -f pp.awk $< > $@
$(OUTDIR)dracut/usr/lib/dracut/modules.d/91tzpfms/% : $(INITRDDIR)dracut/% $(INITRD_HEADERS)
@mkdir -p $(dir $@)
$(AWK) -f pp.awk $< > $@

View File

@ -2,6 +2,9 @@
# SPDX-License-Identifier: MIT
#include "../mount.h"
# Only run on systemd systems, mimicking zfs-dracut's zfs-load-key.sh, TODO: "see mount-zfs.sh for non-systemd systems"
[ -d /run/systemd ] || exit 0
@ -30,33 +33,7 @@ else
fi
# This sucks a lot of ass, since we don't know the questions or the amount thereof beforehand
# (0-2 (owner hierarchy/ownership + sealed object, both optional) best-case and 0-6 worst-case (both entered wrong twice)).
# Plymouth doesn't allow us to actually check what the splash status was, and ioctl(KDGETMODE) isn't reliable;
# ideally, we'd only clear the screen if we were making the switch, but not if the user was already switched to the log output.
# Instead, clear if there's a "quiet", leave alone otherwise, and always restore;
# cmdline option "plymouth.ignore-show-splash" can be used to disable splashes altogether, if desired.
#
# There's a similar but distinct version of both of these in initramfs-tools/zfs-patch.sh
with_promptable_tty() {
if command -v plymouth > /dev/null && plymouth --ping; then
plymouth hide-splash
grep -q 'quiet' /proc/cmdline && printf '\033c' > /dev/console
"$@" < /dev/console > /dev/console 2>&1; ret="$?"
plymouth show-splash
else
# Mimic /scripts/zfs#decrypt_fs(): setting "printk" temporarily to "7" will allow prompt even if kernel option "quiet"
printk="$(awk '{print $1}' /proc/sys/kernel/printk)"
[ "$printk" = "7" ] || echo 7 > /proc/sys/kernel/printk
"$@" < /dev/console > /dev/console 2>&1; ret="$?"
[ "$printk" = "7" ] || echo 7 > /proc/sys/kernel/printk
fi
return "$ret"
}
WITH_PROMPTABLE_TTY{< /dev/console > /dev/console 2>&1}
# If pool encryption is active and the zfs command understands '-o encryption'
@ -71,9 +48,9 @@ if [ "$(zpool list -H -o feature@encryption "$(echo "$BOOTFS" | awk -F/ '{print
fi
if command -v zfs-tpm1x-load-key > /dev/null && ! [ "$(zfs-tpm-list -Hub TPM1.X "$ENCRYPTIONROOT")" = "" ]; then
[ -z "$TZPFMS_TPM1X" ] && command -v tcsd > /dev/null && tcsd -f &
POTENTIALLY_START_TCSD{}
with_promptable_tty zfs-tpm1x-load-key "$ENCRYPTIONROOT"; err="$?"
[ -z "$TZPFMS_TPM1X" ] && command -v tcsd > /dev/null && kill %+
POTENTIALLY_KILL_TCSD{}
exit "$err"
fi

View File

@ -1,13 +1,17 @@
#!/bin/sh
# SPDX-License-Identifier: MIT
#include "../mount.h"
# Included into /scripts/zfs in the initrd, replacing the original decrypt_fs(), now available as __tzpfms__decrypt_fs()
decrypt_fs() {
fs="$1"
# Bail early if we don't have even the common binaries
if ! command -v zfs-tpm-list > /dev/null; then
__tzpfms__decrypt_fs "${fs}"
__tzpfms__decrypt_fs "$fs"
return
fi
@ -24,36 +28,9 @@ decrypt_fs() {
fi
if command -v zfs-tpm1x-load-key > /dev/null && ! [ "$(zfs-tpm-list -Hub TPM1.X "$ENCRYPTIONROOT")" = "" ]; then
[ -z "$TZPFMS_TPM1X" ] && command -v tcsd > /dev/null && {
ip l | awk -F '[[:space:]]*:[[:space:]]*' '{if($2 == "lo") exit $3 ~ /UP/}'
lo_was_up="$?"
if [ "$lo_was_up" = "0" ]; then
ip l set up dev lo
while ! ip a show dev lo | grep -qE '::1|127.0.0.1'; do sleep 0.1; done
fi
if [ "${quiet:-n}" = "y" ]; then
tcsd -f > /tcsd.log 2>&1 &
else
tcsd -f &
fi
tcsd_port="$(awk -F '[[:space:]]*=[[:space:]]*' '!/^[[:space:]]*#/ && !/^$/ && $1 ~ /port$/ {gsub(/[[:space:]]/, "", $2); print $2}' /etc/tcsd.conf)"
i=0; while [ "$i" -lt 100 ] && ! netstat -lt | grep -q "${tcsd_port:-30003}"; do sleep 0.1; i="$((i + 1))"; done
[ "$i" = 100 ] && echo "Couldn't start tcsd!" >&2
}
POTENTIALLY_START_TCSD{}
with_promptable_tty zfs-tpm1x-load-key "$ENCRYPTIONROOT"; err="$?"
[ -z "$TZPFMS_TPM1X" ] && command -v tcsd > /dev/null && {
kill %+
if [ "$lo_was_up" = "0" ]; then
ip l set down dev lo
# ::1 removed automatically
ip a del 127.0.0.1/8 dev lo 2>/dev/null
fi
}
POTENTIALLY_KILL_TCSD{}
return "$err"
fi
@ -65,30 +42,5 @@ decrypt_fs() {
return 0
}
# This sucks a lot of ass, since we don't know the questions or the amount thereof beforehand
# (0-2 (owner hierarchy/ownership + sealed object, both optional) best-case and 0-6 worst-case (both entered wrong twice)).
# Plymouth doesn't allow us to actually check what the splash status was, and ioctl(KDGETMODE) isn't reliable;
# ideally, we'd only clear the screen if we were making the switch, but not if the user was already switched to the log output.
# Instead, clear if there's a "quiet", leave alone otherwise, and always restore;
# cmdline option "plymouth.ignore-show-splash" can be used to disable splashes altogether, if desired.
#
# There's a similar but distinct version of this and the code above in dracut/tzpfms-load-key.sh
with_promptable_tty() {
if command -v plymouth > /dev/null && plymouth --ping; then
plymouth hide-splash
[ "${quiet:-n}" = "y" ] && printf '\033c'
"$@"; ret="$?"
plymouth show-splash
else
# Mimic /scripts/zfs#decrypt_fs(): setting "printk" temporarily to "7" will allow prompt even if kernel option "quiet"
printk="$(awk '{print $1}' /proc/sys/kernel/printk)"
[ "$printk" = "7" ] || echo 7 > /proc/sys/kernel/printk
"$@"; ret="$?"
[ "$printk" = "7" ] || echo "$printk" > /proc/sys/kernel/printk
fi
return "$ret"
}
WITH_PROMPTABLE_TTY{ }

64
initrd/mount.h Executable file
View File

@ -0,0 +1,64 @@
# SPDX-License-Identifier: MIT
#define WITH_PROMPTABLE_TTY(REDIREXIONS)
# This sucks a lot of ass, since we don't know the questions or the amount thereof beforehand
# (0-2 (owner hierarchy/ownership + sealed object, both optional) best-case and 0-6 worst-case (both entered wrong twice)).
# Plymouth doesn't allow us to actually check what the splash status was, and ioctl(KDGETMODE) isn't reliable;
# ideally, we'd only clear the screen if we were making the switch, but not if the user was already switched to the log output.
# Instead, clear if there's a "quiet", leave alone otherwise, and always restore;
# cmdline option "plymouth.ignore-show-splash" can be used to disable splashes altogether, if desired.
with_promptable_tty() {
if command -v plymouth > /dev/null && plymouth --ping; then
plymouth hide-splash
[ "${quiet:-n}" = "y" ] && printf '\033c'
"$@" REDIREXIONS; ret="$?"
plymouth show-splash
else
# Mimic /scripts/zfs#decrypt_fs(): setting "printk" temporarily to "7" will allow prompt even if kernel option "quiet"
printk="$(awk '{print $1}' /proc/sys/kernel/printk)"
[ "$printk" = "7" ] || echo 7 > /proc/sys/kernel/printk
"$@" REDIREXIONS; ret="$?"
[ "$printk" = "7" ] || echo "$printk" > /proc/sys/kernel/printk
fi
return "$ret"
}
#endefine
#define POTENTIALLY_START_TCSD()
[ -z "$TZPFMS_TPM1X" ] && command -v tcsd > /dev/null && {
ip l | awk -F '[[:space:]]*:[[:space:]]*' '{if($2 == "lo") exit $3 ~ /UP/}'
lo_was_up="$?"
if [ "$lo_was_up" = "0" ]; then
ip l set up dev lo
while ! ip a show dev lo | grep -qE '::1|127.0.0.1'; do sleep 0.1; done
fi
if [ "${quiet:-n}" = "y" ]; then
tcsd -f > /tcsd.log 2>&1 &
else
tcsd -f &
fi
tcsd_port="$(awk -F '[[:space:]]*=[[:space:]]*' '!/^[[:space:]]*#/ && !/^$/ && $1 ~ /port$/ {gsub(/[[:space:]]/, "", $2); print $2}' /etc/tcsd.conf)"
i=0; while [ "$i" -lt 100 ] && ! netstat -lt | grep -q "${tcsd_port:-30003}"; do sleep 0.1; i="$((i + 1))"; done
[ "$i" = 100 ] && echo "Couldn't start tcsd!" >&2
}
#endefine
#define POTENTIALLY_KILL_TCSD()
[ -z "$TZPFMS_TPM1X" ] && command -v tcsd > /dev/null && {
kill %+
if [ "$lo_was_up" = "0" ]; then
ip l set down dev lo
# ::1 removed automatically
ip a del 127.0.0.1/8 dev lo 2>/dev/null
fi
}
#endefine

81
pp.awk Executable file
View File

@ -0,0 +1,81 @@
# SPDX-License-Identifier: MIT
# This is similar to the C preprocessor, but very /very/ bad:
# * macros expand with macroname{arg1, arg2}, because it doesn't break syntax highlighting, and
# * macros end definition with #endefine instead of using line continuations, which plays better with syntax highlighting.
BEGIN {
dir = ARGV[1]
sub(/[^\/]+$/, "", dir)
incfile = ""
}
function input() {
if(NF == 2 && $1 == "#include") {
gsub(/"/, "", $2)
incfile = dir $2
while((getline < incfile) == 1)
input()
incfile = ""
} else if(NF >= 2 && $1 == "#define") {
split($2, nameargs, "(")
macroname = nameargs[1]
gsub(/[\(,]/, "", nameargs[2])
if(nameargs[2] != ")") {
last = nameargs[2] ~ /\)$/
sub(/\)/, "", nameargs[2])
macro_args[macroname,1] = nameargs[2]
for(i = 3; !last; ++i) {
last = $i ~ /\)$/
sub(/[,\)]/, "", $i)
macro_args[macroname,i - 2] = $i
}
}
while(1) {
if(incfile == "")
getline
else
getline < incfile
if($0 == "#endefine")
break
macro_contents[macroname] = macro_contents[macroname] $0 "\n"
}
} else {
for(macroname in macro_contents) {
if(pos = index($0, macroname "{")) {
epos = pos + index(substr($0, pos), "}")
pref = substr($0, 1, pos - 1)
postf = substr($0, epos)
arg_str = substr($0, pos + length(macroname) + 1, epos - (pos + length(macroname) + 1) - 1)
split(arg_str, args, /,[[:space:]]/)
body = macro_contents[macroname]
for(i in args) {
gsub(/\\/, "\\\\", args[i])
gsub(/&/, "\\\\&", args[i])
gsub(macro_args[macroname,i], args[i], body)
}
$0 = pref body postf
}
}
print
}
}
{
input()
}

View File

@ -39,7 +39,7 @@
"follow_symlinks": true,
"name": "Build scripts",
"path": ".",
"file_include_patterns": [".build.yml", "*Makefile"],
"file_include_patterns": [".build.yml", "*Makefile", "*.awk"],
"folder_exclude_patterns": ["*"]
},
]