44# Shared functions and configuration for the atomic-upgrade system.
55# Sourced by: atomic-upgrade, atomic-gc, atomic-rebuild-uki, atomic-guard
66
7- # ── Library directory ──────────────────────────────────────────────
8-
9- if [[ -z " ${LIBDIR:- } " ]]; then
10- LIBDIR=" /usr/lib/atomic"
11- fi
7+ _ATOMIC_LIB_DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) "
128
139# ── Project version ────────────────────────────────────────────────
1410
@@ -32,62 +28,25 @@ KERNEL_PARAMS="rw slab_nomerge init_on_alloc=1 page_alloc.shuffle=1 pti=on vsysc
3228# Default chroot command (overridden by config or CLI -- CHROOT_COMMAND...)
3329CHROOT_COMMAND=" /usr/bin/pacman -Syu"
3430
35- # ── Config loading (safe parser, no arbitrary code execution ) ───────
31+ # ── Config loading (delegates to Python for proper quote handling ) ───────
3632
3733CONFIG_FILE=" ${CONFIG_FILE:-/ etc/ atomic.conf} "
3834
3935load_config () {
4036 [[ -f " $CONFIG_FILE " ]] || return 0
4137
42- # Refuse to load config not owned by root
43- local owner
44- owner =$( stat -c %u " $CONFIG_FILE " 2> /dev/null )
45- if [[ " $owner " != " 0 " ]] ; then
46- echo " ERROR: $CONFIG_FILE not owned by root (owner uid : $owner ) " >&2
38+ local shell_output config_err
39+ if ! shell_output= $( CONFIG_FILE= " ${CONFIG_FILE} " python3 " ${_ATOMIC_LIB_DIR} /config.py " shell 2> /dev/null ) ; then
40+ config_err =$( CONFIG_FILE= " ${CONFIG_FILE} " python3 " ${_ATOMIC_LIB_DIR} /config.py " shell 2>&1 ) || true
41+ echo " ERROR: Failed to parse config with config.py " >&2
42+ echo " ERROR: Details : ${config_err :- unknown} " >&2
4743 return 1
4844 fi
4945
50- # Whitelist of allowed config keys
51- local -a allowed=(BTRFS_MOUNT NEW_ROOT ESP KEEP_GENERATIONS MAPPER_NAME KERNEL_PARAMS KERNEL_PKG CHROOT_COMMAND SBCTL_SIGN UPGRADE_GUARD HOME_COPY_FILES)
52-
5346 while IFS=' =' read -r key value; do
54- # Strip leading/trailing whitespace from key
55- key=" ${key# " ${key%% [![:space:]]* } " } "
56- key=" ${key% " ${key##* [![:space:]]} " } "
57- # Trim leading/trailing whitespace from value
58- value=" ${value# " ${value%% [![:space:]]* } " } "
59- value=" ${value% " ${value##* [![:space:]]} " } "
60-
61- # Strip inline comments: everything after ' #' (space-hash).
62- # Limitation: values containing literal ' #' are truncated.
63- # Quoted values do not protect against this. For kernel params
64- # and paths used in this config, this is not a practical concern.
65- value=" ${value%% #* } "
66- value=" ${value% " ${value##* [![:space:]]} " } "
67-
68- # Skip comments and blank lines
69- [[ " $key " =~ ^# .*$ || -z "$key" ]] && continue
70-
71- # Check against whitelist
72- local valid= 0
73- for a in " ${allowed[@]} " ; do
74- if [[ " $key " == " $a " ]]; then
75- valid=1
76- break
77- fi
78- done
79-
80- if [[ $valid -eq 1 ]]; then
81- # Strip surrounding quotes (single or double)
82- value=" ${value# \" } "
83- value=" ${value% \" } "
84- value=" ${value# \' } "
85- value=" ${value% \' } "
86- printf -v " $key " ' %s' " $value "
87- else
88- echo " WARN: Unknown config key ignored: $key " >&2
89- fi
90- done < " $CONFIG_FILE "
47+ [[ -z " $key " || " $key " == \# * ]] && continue
48+ printf -v " $key " ' %s' " $value "
49+ done <<< " $shell_output"
9150}
9251
9352# ── Auto-initialization ──────────────────────────────────────────────
@@ -132,7 +91,7 @@ check_dependencies() {
13291 local root_type
13392 root_type=$( python3 -c "
13493import json, importlib.util, sys
135- spec = importlib.util.spec_from_file_location('rootdev', '${LIBDIR } /rootdev.py')
94+ spec = importlib.util.spec_from_file_location('rootdev', '${_ATOMIC_LIB_DIR } /rootdev.py')
13695mod = importlib.util.module_from_spec(spec)
13796spec.loader.exec_module(mod)
13897try:
@@ -150,7 +109,7 @@ except Exception:
150109 return 1
151110 fi
152111 # Verify python helper modules exist
153- for helper in " ${LIBDIR } /fstab.py" " ${LIBDIR } /rootdev.py" ; do
112+ for helper in " ${_ATOMIC_LIB_DIR } /fstab.py" " ${_ATOMIC_LIB_DIR } /rootdev.py" ; do
154113 [[ -f " $helper " ]] || {
155114 echo " ERROR: Missing helper: $helper " >&2
156115 return 1
@@ -280,15 +239,15 @@ verify_uki() {
280239# ── fstab update (delegates to Python for safety) ──────────────────
281240
282241update_fstab () {
283- python3 " ${LIBDIR } /fstab.py" " $@ "
242+ python3 " ${_ATOMIC_LIB_DIR } /fstab.py" " $@ "
284243}
285244
286245# ── fstab /home update ──────────────────────────────────────────
287246# Updates the /home mount entry's subvol= to point to a new subvolume.
288247# Args: $1 = fstab path, $2 = new home subvolume name
289248
290249update_fstab_home () {
291- python3 " ${LIBDIR } /fstab.py" home " $@ "
250+ python3 " ${_ATOMIC_LIB_DIR } /fstab.py" home " $@ "
292251}
293252
294253# ── Home skeleton population ────────────────────────────────────
@@ -394,7 +353,7 @@ get_root_device() {
394353 fi
395354
396355 local dev
397- dev=$( python3 " ${LIBDIR } /rootdev.py" device 2> /dev/null)
356+ dev=$( python3 " ${_ATOMIC_LIB_DIR } /rootdev.py" device 2> /dev/null)
398357 if [[ -n " $dev " && -e " $dev " ]]; then
399358 _ROOT_DEVICE=" $dev "
400359 echo " $dev "
@@ -572,7 +531,7 @@ build_uki() {
572531 fi
573532
574533 local root_cmdline
575- root_cmdline=$( python3 " ${LIBDIR } /rootdev.py" cmdline " $new_subvol " ) || {
534+ root_cmdline=$( python3 " ${_ATOMIC_LIB_DIR } /rootdev.py" cmdline " $new_subvol " ) || {
576535 echo " ERROR: Cannot detect root device for cmdline" >&2
577536 return 1
578537 }
0 commit comments