@@ -60,6 +60,7 @@ INITRAMFS_REQUIRED_LIST="/etc/uki/initramfs-required.txt"
6060INITRAMFS_FORBIDDEN_LIST=" /etc/uki/initramfs-forbidden.txt"
6161INITRAMFS_STATE_DIR=" /var/lib/uki-build"
6262INITRAMFS_STRICT_DIFF=0
63+ CMDLINE_MIN_TOKENS=3
6364
6465# =============================================================================
6566# ── SCRIPT INTERNALS ───────────────────────────────────────────────────────
@@ -85,6 +86,83 @@ sanitize_cmdline() {
8586 sed -E ' s/(^| )BOOT_IMAGE=[^ ]*//g; s/(^| )initrd=[^ ]*//g; s/(^| )rd\.driver\.blacklist=[^ ]*//g; s/ +/ /g; s/^ //; s/ $//'
8687}
8788
89+ count_cmdline_tokens () {
90+ local cmdline=" $1 "
91+ awk ' {print NF}' <<< " $cmdline"
92+ }
93+
94+ extract_root_uuid () {
95+ local cmdline=" $1 " token
96+ for token in $cmdline ; do
97+ if [[ " $token " =~ ^root= UUID= ([^[:space:]]+)$ ]]; then
98+ echo " ${BASH_REMATCH[1]} "
99+ return 0
100+ fi
101+ done
102+ return 1
103+ }
104+
105+ major_version () {
106+ local version=" $1 "
107+ echo " ${version%% .* } "
108+ }
109+
110+ get_os_version_id () {
111+ local version_id=" "
112+ if [[ -r /etc/os-release ]]; then
113+ version_id=$( awk -F= ' $1=="VERSION_ID" {gsub(/"/,"",$2); print $2}' /etc/os-release)
114+ fi
115+ echo " $version_id "
116+ }
117+
118+ validate_root_uuid_against_blkid () {
119+ local cmdline=" $1 " source=" $2 " detected=" $3 " uuid
120+
121+ if ! uuid=$( extract_root_uuid " $cmdline " ) ; then
122+ return 0
123+ fi
124+
125+ if [[ " $uuid " == " REPLACE-ME" ]]; then
126+ die " Refusing to continue: cmdline from ${source} still contains root=UUID=REPLACE-ME."
127+ fi
128+
129+ if ! blkid -t " UUID=$uuid " > /dev/null 2>&1 ; then
130+ if [[ " $detected " == " 1" ]]; then
131+ die " Detected cmdline from ${source} references root UUID '${uuid} ', but blkid cannot find it."
132+ fi
133+ die " Configured cmdline references root UUID '${uuid} ', but blkid cannot find it."
134+ fi
135+ }
136+
137+ warn_if_cmdline_short () {
138+ local cmdline=" $1 " source=" $2 " token_count
139+ token_count=$( count_cmdline_tokens " $cmdline " )
140+ if (( token_count < CMDLINE_MIN_TOKENS )) ; then
141+ warn " Cmdline from ${source} looks unusually short after sanitization (${token_count} token(s)): ${cmdline} "
142+ fi
143+ }
144+
145+ persist_cmdline_metadata () {
146+ local cmdline=" $1 " source=" $2 " version_id=" $3 "
147+ local metadata_dir=" ${INITRAMFS_STATE_DIR} /cmdline"
148+
149+ mkdir -p " $metadata_dir "
150+ printf ' %s\n' " $cmdline " > " ${metadata_dir} /effective-cmdline"
151+ printf ' %s\n' " $source " > " ${metadata_dir} /source"
152+ printf ' %s\n' " $version_id " > " ${metadata_dir} /version-id"
153+ date -u +%Y-%m-%dT%H:%M:%SZ > " ${metadata_dir} /updated-at"
154+ }
155+
156+ validate_final_cmdline () {
157+ local cmdline=" $1 " source=" $2 " detected=" $3 "
158+
159+ [[ " $cmdline " =~ (^| [[:space:]])root= UUID= REPLACE-ME($| [[:space:]]) ]] \
160+ && die " Refusing to build UKI with placeholder cmdline token root=UUID=REPLACE-ME."
161+
162+ warn_if_cmdline_short " $cmdline " " $source "
163+ validate_root_uuid_against_blkid " $cmdline " " $source " " $detected "
164+ }
165+
88166read_grub_cmdline () {
89167 local file line value
90168
@@ -104,13 +182,49 @@ read_grub_cmdline() {
104182}
105183
106184get_effective_cmdline () {
107- local proc_cmdline kernel_cmdline grub_cmdline
185+ local proc_cmdline kernel_cmdline grub_cmdline cached_cmdline
186+ local cmdline_source=" configured CMDLINE" detected_cmdline=0
187+ local metadata_dir=" ${INITRAMFS_STATE_DIR} /cmdline"
188+ local current_version_id cached_version_id current_major cached_major
189+
190+ current_version_id=$( get_os_version_id)
191+ current_major=$( major_version " $current_version_id " )
192+
193+ if [[ -r " ${metadata_dir} /version-id" ]]; then
194+ cached_version_id=$( < " ${metadata_dir} /version-id" )
195+ cached_major=$( major_version " $cached_version_id " )
196+ if [[ -n " $cached_major " && -n " $current_major " && " $cached_major " != " $current_major " ]]; then
197+ warn " Fedora major VERSION_ID changed (${cached_version_id} -> ${current_version_id} ); forcing fresh cmdline detection."
198+ cached_cmdline=" "
199+ elif [[ -r " ${metadata_dir} /effective-cmdline" ]]; then
200+ cached_cmdline=$( < " ${metadata_dir} /effective-cmdline" )
201+ fi
202+ elif [[ -r " ${metadata_dir} /effective-cmdline" ]]; then
203+ cached_cmdline=$( < " ${metadata_dir} /effective-cmdline" )
204+ fi
108205
109206 if [[ " $AUTO_DETECT_CMDLINE " -eq 1 ]]; then
207+ if [[ -n " ${cached_cmdline:- } " ]]; then
208+ cached_cmdline=$( printf ' %s\n' " $cached_cmdline " | sanitize_cmdline | xargs || true)
209+ if [[ -n " $cached_cmdline " ]]; then
210+ info " Using cached cmdline metadata from ${metadata_dir} /effective-cmdline"
211+ cmdline_source=" cached metadata"
212+ detected_cmdline=1
213+ validate_final_cmdline " $cached_cmdline " " $cmdline_source " " $detected_cmdline "
214+ persist_cmdline_metadata " $cached_cmdline " " $cmdline_source " " $current_version_id "
215+ echo " $cached_cmdline "
216+ return 0
217+ fi
218+ fi
219+
110220 if [[ -r /proc/cmdline ]]; then
111221 proc_cmdline=$( sanitize_cmdline < /proc/cmdline | xargs || true)
112222 if [[ -n " $proc_cmdline " && " $proc_cmdline " =~ (root=| rd.luks.uuid=| rootfstype=) ]]; then
113223 info " Using cmdline from /proc/cmdline"
224+ cmdline_source=" /proc/cmdline"
225+ detected_cmdline=1
226+ validate_final_cmdline " $proc_cmdline " " $cmdline_source " " $detected_cmdline "
227+ persist_cmdline_metadata " $proc_cmdline " " $cmdline_source " " $current_version_id "
114228 echo " $proc_cmdline "
115229 return 0
116230 fi
@@ -120,6 +234,10 @@ get_effective_cmdline() {
120234 kernel_cmdline=$( sanitize_cmdline < /etc/kernel/cmdline | xargs || true)
121235 if [[ -n " $kernel_cmdline " && " $kernel_cmdline " =~ (root=| rd.luks.uuid=| rootfstype=) ]]; then
122236 info " Using cmdline from /etc/kernel/cmdline"
237+ cmdline_source=" /etc/kernel/cmdline"
238+ detected_cmdline=1
239+ validate_final_cmdline " $kernel_cmdline " " $cmdline_source " " $detected_cmdline "
240+ persist_cmdline_metadata " $kernel_cmdline " " $cmdline_source " " $current_version_id "
123241 echo " $kernel_cmdline "
124242 return 0
125243 fi
@@ -130,6 +248,10 @@ get_effective_cmdline() {
130248 grub_cmdline=$( printf ' %s\n' " $grub_cmdline " | sanitize_cmdline | xargs || true)
131249 if [[ -n " $grub_cmdline " && " $grub_cmdline " =~ (root=| rd.luks.uuid=| rootfstype=) ]]; then
132250 info " Using cmdline from GRUB configuration"
251+ cmdline_source=" GRUB configuration"
252+ detected_cmdline=1
253+ validate_final_cmdline " $grub_cmdline " " $cmdline_source " " $detected_cmdline "
254+ persist_cmdline_metadata " $grub_cmdline " " $cmdline_source " " $current_version_id "
133255 echo " $grub_cmdline "
134256 return 0
135257 fi
@@ -138,6 +260,9 @@ get_effective_cmdline() {
138260 warn " Auto-detect enabled, but no bootable cmdline was detected. Falling back to configured CMDLINE."
139261 fi
140262
263+ validate_final_cmdline " $CMDLINE " " $cmdline_source " " $detected_cmdline "
264+ persist_cmdline_metadata " $CMDLINE " " $cmdline_source " " $current_version_id "
265+
141266 echo " $CMDLINE "
142267}
143268
@@ -460,6 +585,7 @@ INITRAMFS_REQUIRED_LIST="__INITRAMFS_REQUIRED_LIST__"
460585INITRAMFS_FORBIDDEN_LIST="__INITRAMFS_FORBIDDEN_LIST__"
461586INITRAMFS_STATE_DIR="__INITRAMFS_STATE_DIR__"
462587INITRAMFS_STRICT_DIFF=__INITRAMFS_STRICT_DIFF__
588+ CMDLINE_MIN_TOKENS=__CMDLINE_MIN_TOKENS__
463589# ─────────────────────────────────────────────────────────────────────────────
464590
465591RED='\e[31;1m'; GRN='\e[32;1m'; YLW='\e[33;1m'; RST='\e[0m'
@@ -600,6 +726,83 @@ sanitize_cmdline() {
600726 sed -E 's/(^| )BOOT_IMAGE=[^ ]*//g; s/(^| )initrd=[^ ]*//g; s/(^| )rd\.driver\.blacklist=[^ ]*//g; s/ +/ /g; s/^ //; s/ $//'
601727}
602728
729+ count_cmdline_tokens() {
730+ local cmdline="$1"
731+ awk '{print NF}' <<<"$cmdline"
732+ }
733+
734+ extract_root_uuid() {
735+ local cmdline="$1" token
736+ for token in $cmdline; do
737+ if [[ "$token" =~ ^root=UUID=([^[:space:]]+)$ ]]; then
738+ echo "${BASH_REMATCH[1]}"
739+ return 0
740+ fi
741+ done
742+ return 1
743+ }
744+
745+ major_version() {
746+ local version="$1"
747+ echo "${version%%.*}"
748+ }
749+
750+ get_os_version_id() {
751+ local version_id=""
752+ if [[ -r /etc/os-release ]]; then
753+ version_id=$(awk -F= '$1=="VERSION_ID" {gsub(/"/,"",$2); print $2}' /etc/os-release)
754+ fi
755+ echo "$version_id"
756+ }
757+
758+ validate_root_uuid_against_blkid() {
759+ local cmdline="$1" source="$2" detected="$3" uuid
760+
761+ if ! uuid=$(extract_root_uuid "$cmdline"); then
762+ return 0
763+ fi
764+
765+ if [[ "$uuid" == "REPLACE-ME" ]]; then
766+ die "Refusing to continue: cmdline from ${source} still contains root=UUID=REPLACE-ME."
767+ fi
768+
769+ if ! blkid -t "UUID=$uuid" >/dev/null 2>&1; then
770+ if [[ "$detected" == "1" ]]; then
771+ die "Detected cmdline from ${source} references root UUID '${uuid}', but blkid cannot find it."
772+ fi
773+ die "Configured cmdline references root UUID '${uuid}', but blkid cannot find it."
774+ fi
775+ }
776+
777+ warn_if_cmdline_short() {
778+ local cmdline="$1" source="$2" token_count
779+ token_count=$(count_cmdline_tokens "$cmdline")
780+ if (( token_count < CMDLINE_MIN_TOKENS )); then
781+ warn "Cmdline from ${source} looks unusually short after sanitization (${token_count} token(s)): ${cmdline}"
782+ fi
783+ }
784+
785+ persist_cmdline_metadata() {
786+ local cmdline="$1" source="$2" version_id="$3"
787+ local metadata_dir="${INITRAMFS_STATE_DIR}/cmdline"
788+
789+ mkdir -p "$metadata_dir"
790+ printf '%s\n' "$cmdline" > "${metadata_dir}/effective-cmdline"
791+ printf '%s\n' "$source" > "${metadata_dir}/source"
792+ printf '%s\n' "$version_id" > "${metadata_dir}/version-id"
793+ date -u +%Y-%m-%dT%H:%M:%SZ > "${metadata_dir}/updated-at"
794+ }
795+
796+ validate_final_cmdline() {
797+ local cmdline="$1" source="$2" detected="$3"
798+
799+ [[ "$cmdline" =~ (^|[[:space:]])root=UUID=REPLACE-ME($|[[:space:]]) ]] \
800+ && die "Refusing to build UKI with placeholder cmdline token root=UUID=REPLACE-ME."
801+
802+ warn_if_cmdline_short "$cmdline" "$source"
803+ validate_root_uuid_against_blkid "$cmdline" "$source" "$detected"
804+ }
805+
603806read_grub_cmdline() {
604807 local file line value
605808
@@ -619,13 +822,49 @@ read_grub_cmdline() {
619822}
620823
621824get_effective_cmdline() {
622- local proc_cmdline kernel_cmdline grub_cmdline
825+ local proc_cmdline kernel_cmdline grub_cmdline cached_cmdline
826+ local cmdline_source="configured CMDLINE" detected_cmdline=0
827+ local metadata_dir="${INITRAMFS_STATE_DIR}/cmdline"
828+ local current_version_id cached_version_id current_major cached_major
829+
830+ current_version_id=$(get_os_version_id)
831+ current_major=$(major_version "$current_version_id")
623832
624833 if [[ "$AUTO_DETECT_CMDLINE" -eq 1 ]]; then
834+ if [[ -r "${metadata_dir}/version-id" ]]; then
835+ cached_version_id=$(<"${metadata_dir}/version-id")
836+ cached_major=$(major_version "$cached_version_id")
837+ if [[ -n "$cached_major" && -n "$current_major" && "$cached_major" != "$current_major" ]]; then
838+ warn "Fedora major VERSION_ID changed (${cached_version_id} -> ${current_version_id}); forcing fresh cmdline detection."
839+ cached_cmdline=""
840+ elif [[ -r "${metadata_dir}/effective-cmdline" ]]; then
841+ cached_cmdline=$(<"${metadata_dir}/effective-cmdline")
842+ fi
843+ elif [[ -r "${metadata_dir}/effective-cmdline" ]]; then
844+ cached_cmdline=$(<"${metadata_dir}/effective-cmdline")
845+ fi
846+
847+ if [[ -n "${cached_cmdline:-}" ]]; then
848+ cached_cmdline=$(printf '%s\n' "$cached_cmdline" | sanitize_cmdline | xargs || true)
849+ if [[ -n "$cached_cmdline" ]]; then
850+ info "Using cached cmdline metadata from ${metadata_dir}/effective-cmdline"
851+ cmdline_source="cached metadata"
852+ detected_cmdline=1
853+ validate_final_cmdline "$cached_cmdline" "$cmdline_source" "$detected_cmdline"
854+ persist_cmdline_metadata "$cached_cmdline" "$cmdline_source" "$current_version_id"
855+ echo "$cached_cmdline"
856+ return 0
857+ fi
858+ fi
859+
625860 if [[ -r /proc/cmdline ]]; then
626861 proc_cmdline=$(sanitize_cmdline < /proc/cmdline | xargs || true)
627862 if [[ -n "$proc_cmdline" && "$proc_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
628863 info "Using cmdline from /proc/cmdline: ${proc_cmdline}"
864+ cmdline_source="/proc/cmdline"
865+ detected_cmdline=1
866+ validate_final_cmdline "$proc_cmdline" "$cmdline_source" "$detected_cmdline"
867+ persist_cmdline_metadata "$proc_cmdline" "$cmdline_source" "$current_version_id"
629868 echo "$proc_cmdline"
630869 return 0
631870 fi
@@ -635,6 +874,10 @@ get_effective_cmdline() {
635874 kernel_cmdline=$(sanitize_cmdline < /etc/kernel/cmdline | xargs || true)
636875 if [[ -n "$kernel_cmdline" && "$kernel_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
637876 info "Using cmdline from /etc/kernel/cmdline: ${kernel_cmdline}"
877+ cmdline_source="/etc/kernel/cmdline"
878+ detected_cmdline=1
879+ validate_final_cmdline "$kernel_cmdline" "$cmdline_source" "$detected_cmdline"
880+ persist_cmdline_metadata "$kernel_cmdline" "$cmdline_source" "$current_version_id"
638881 echo "$kernel_cmdline"
639882 return 0
640883 fi
@@ -645,6 +888,10 @@ get_effective_cmdline() {
645888 grub_cmdline=$(printf '%s\n' "$grub_cmdline" | sanitize_cmdline | xargs || true)
646889 if [[ -n "$grub_cmdline" && "$grub_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
647890 info "Using cmdline from GRUB configuration: ${grub_cmdline}"
891+ cmdline_source="GRUB configuration"
892+ detected_cmdline=1
893+ validate_final_cmdline "$grub_cmdline" "$cmdline_source" "$detected_cmdline"
894+ persist_cmdline_metadata "$grub_cmdline" "$cmdline_source" "$current_version_id"
648895 echo "$grub_cmdline"
649896 return 0
650897 fi
@@ -653,6 +900,8 @@ get_effective_cmdline() {
653900 warn "Auto-detect enabled, but no bootable cmdline was detected. Falling back to configured CMDLINE: ${CMDLINE}"
654901 fi
655902
903+ validate_final_cmdline "$CMDLINE" "$cmdline_source" "$detected_cmdline"
904+ persist_cmdline_metadata "$CMDLINE" "$cmdline_source" "$current_version_id"
656905 info "Using configured cmdline: ${CMDLINE}"
657906 echo "$CMDLINE"
658907}
@@ -845,6 +1094,7 @@ BUILDBODY
8451094 -e " s|__INITRAMFS_FORBIDDEN_LIST__|${INITRAMFS_FORBIDDEN_LIST} |g" \
8461095 -e " s|__INITRAMFS_STATE_DIR__|${INITRAMFS_STATE_DIR} |g" \
8471096 -e " s|__INITRAMFS_STRICT_DIFF__|${INITRAMFS_STRICT_DIFF} |g" \
1097+ -e " s|__CMDLINE_MIN_TOKENS__|${CMDLINE_MIN_TOKENS} |g" \
8481098 " $BUILD_SCRIPT "
8491099
8501100 chmod 0755 " $BUILD_SCRIPT "
@@ -954,15 +1204,6 @@ phase_initial_build() {
9541204 hr
9551205 info " Phase 6: Building UKI for current kernel: $( uname -r) "
9561206
957- if [[ " $AUTO_DETECT_CMDLINE " -eq 0 && " $CMDLINE " == " root=UUID=REPLACE-ME rw quiet rhgb" ]]; then
958- warn " ────────────────────────────────────────────────────────────"
959- warn " AUTO_DETECT_CMDLINE is disabled and CMDLINE is still placeholder text."
960- warn " Set CMDLINE to a real root=... value, or enable AUTO_DETECT_CMDLINE=1."
961- warn " ────────────────────────────────────────────────────────────"
962- read -r -p " Continue with placeholder CMDLINE anyway? [y/N] " ans
963- [[ " ${ans,,} " == " y" ]] || { info " Aborted. Set CMDLINE and re-run." ; exit 0; }
964- fi
965-
9661207 " $BUILD_SCRIPT " " $( uname -r) "
9671208}
9681209
0 commit comments