fix(lib): ini_set n'écrase plus app.ini si awk échoue, insertion avant les lignes vides

Deux corrections dans ini_set() suite à la review de #24 :

- Le mv s'exécutait même si awk avait échoué en cours de route (OOM,
  signal, valeur exotique) : $tmp, créé par la redirection avant
  qu'awk ne tourne, pouvait être tronqué ou vide et venait quand même
  écraser le fichier original. mv est maintenant gaté sur le code de
  retour d'awk : en cas d'échec, $tmp est supprimé, une erreur est
  logguée, et la fonction retourne 1 sans toucher au fichier d'origine.

- L'insertion d'une clé juste avant l'en-tête de section suivante
  atterrissait après la ou les lignes vides de fin de section plutôt
  qu'avant, rendant le fichier plus difficile à lire au fil des appels
  répétés. Les lignes vides rencontrées section active/clé pas encore
  trouvée sont désormais bufferisées et réémises juste après la clé
  insérée (ou en fin de fichier si la section n'est jamais refermée),
  sans toucher à l'ordre dans tous les autres cas.
This commit is contained in:
Damien
2026-08-01 11:18:48 +02:00
parent 905166d1cc
commit 1217b26ff9
+33 -3
View File
@@ -159,12 +159,27 @@ ini_set() {
chmod "$(stat -c '%a' "$file")" "$tmp" 2>/dev/null || true
chown "$(stat -c '%u:%g' "$file")" "$tmp" 2>/dev/null || true
awk -v section="$section" -v key="$key" -v value="$value" '
# awk writes into $tmp regardless of its own exit status — a mid-stream
# death (OOM, signal, an exotic value tripping the regex) would still
# leave a truncated-but-nonempty $tmp for `mv` to install over $file.
# Gate the mv on awk's exit code so a failure leaves the original config
# untouched instead of silently destroying it.
if ! awk -v section="$section" -v key="$key" -v value="$value" '
# Blank lines are buffered rather than printed immediately while a
# section is still awaiting insertion: without this, a key inserted
# right before the next section header lands *after* that section'"'"'s
# trailing blank line(s) instead of before them. Flushed as soon as
# either a non-blank line or the insertion itself happens, so this
# never reorders anything except relative to that pending insertion.
function flush_blanks() {
while (blank_count > 0) { print ""; blank_count-- }
}
/^\[.*\]$/ {
if (in_section && !done) {
printf "%s = %s\n", key, value
done = 1
}
flush_blanks()
cur = $0
gsub(/^\[|\]$/, "", cur)
in_section = (cur == section)
@@ -173,11 +188,21 @@ ini_set() {
next
}
{
if (in_section && !done && match($0, "^[ \t]*" key "[ \t]*=")) {
if (in_section && !done) {
if (match($0, "^[ \t]*" key "[ \t]*=")) {
flush_blanks()
printf "%s = %s\n", key, value
done = 1
next
}
if ($0 ~ /^[ \t]*$/) {
blank_count++
next
}
flush_blanks()
print
next
}
print
}
END {
@@ -185,13 +210,18 @@ ini_set() {
printf "%s = %s\n", key, value
done = 1
}
flush_blanks()
if (!section_found) {
if (NR > 0) print ""
printf "[%s]\n", section
printf "%s = %s\n", key, value
}
}
' "$file" > "$tmp"
' "$file" > "$tmp"; then
rm -f "$tmp"
log_error "ini_set: awk failed on ${file} (${section}.${key}), config left untouched."
return 1
fi
mv "$tmp" "$file"
}