Files
qemu-qemu-1/scripts/qemu-guest-agent/fsfreeze-hook
Peter Maydell 08497afcb2 scripts/qemu-guest-agent/fsfreeze-hook: Fix syslog-fallback logic
In the fsfreeze script we attempt to implement "log to a file if we
can, and fall back to syslog if we cannot".  We do this with:

  [ ! -w "$LOGFILE" ] && USE_SYSLOG=1
  touch "$LOGFILE" >/dev/null 2>&1 || USE_SYSLOG=1

This has a weird behaviour if it is run in a setup where we have
permissions that would allow us to write to $LOGFILE but it does not
currently exist.  On the first execution, the '-w' fails and so we
set USE_SYSLOG=1.  But since we also do the "touch $LOGFILE" step we
create an empty logfile.  Then on the second time the script is
executed, we see a writeable logfile and will use it.  The effect is
"log to syslog once, then to the logfile thereafter", which is not
likely to be what anybody wants.

Update the condition of the first check to only pick syslog if
the logfile exists but is not writable. This means that:
 * if the logfile doesn't exist but we are able to create it,
   we will create it and use it
 * if the logfile already exists and we can write to it,
   we will use it
 * if the logfile already exists but we can't write to it,
   we will fall back to syslog
 * if the logfile doesn't exist and we can't create it,
   we will fall back to syslog

Cc: qemu-stable@nongnu.org
Fixes: 85978dfb6b ("qemu-ga: Optimize freeze-hook script logic of logging error")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Link: https://lore.kernel.org/qemu-devel/20260317094806.1944053-4-peter.maydell@linaro.org
Signed-off-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
2026-03-27 19:55:01 +02:00

77 lines
2.8 KiB
Bash
Executable File

#!/bin/sh
# This script is executed when the guest agent receives fsfreeze-freeze and
# fsfreeze-thaw commands, provided that the --fsfreeze-hook (-F) option of
# qemu-ga is specified and the script is placed in /etc/qemu/fsfreeze-hook or in
# the path specified together with -F. When the agent receives fsfreeze-freeze
# requests, this script is called with "freeze" as its argument before the
# filesystem is frozen. And for fsfreeze-thaw requests, it is called with "thaw"
# as its argument after the filesystem is thawed.
LOGFILE=/var/log/qga-fsfreeze-hook.log
FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d
# Check whether file $1 is a backup or rpm-generated file and should be ignored
is_ignored_file() {
case "$1" in
*~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample | *.dpkg-old | *.dpkg-new | *.dpkg-tmp | *.dpkg-dist | *.dpkg-bak | *.dpkg-backup | *.dpkg-remove)
return 0 ;;
esac
return 1
}
USE_SYSLOG=0
# if log file exists but is not writable, fallback to syslog
[ -e "$LOGFILE" ] && [ ! -w "$LOGFILE" ] && USE_SYSLOG=1
# try to update log file and fallback to syslog if it fails
touch "$LOGFILE" >/dev/null 2>&1 || USE_SYSLOG=1
# Ensure the log file is writable, fallback to syslog if not
log_message() {
if [ "$USE_SYSLOG" -eq 0 ]; then
printf "%s: %s\n" "$(date)" "$1" >>"$LOGFILE"
else
logger -t qemu-ga-freeze-hook "$1"
fi
}
# Iterate executables in directory "fsfreeze-hook.d" with the specified args
[ ! -d "$FSFREEZE_D" ] && exit 0
for file in "$FSFREEZE_D"/* ; do
is_ignored_file "$file" && continue
[ -x "$file" ] || continue
log_message "Executing $file $*"
if [ "$USE_SYSLOG" -eq 0 ]; then
"$file" "$@" >>"$LOGFILE" 2>&1
STATUS=$?
else
# We want to pipe the output of $file through 'logger' and also
# capture its exit status. Since we are a POSIX script we can't
# use PIPESTATUS, so instead this is a trick borrowed from
# https://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another/70675#70675
# which uses command-groups and redirection to get the exit status.
# This is equivalent to
# "$file" "$@" 2>&1 | logger -t qemu-ga-freeze-hook
# plus setting the exit status of the pipe to the exit
# status of the first command rather than the last one.
{ { { {
"$file" "$@" 2>&1 3>&- 4>&-
echo $? >&3
} | logger -t qemu-ga-freeze-hook >&4
} 3>&1
} | { read -r xs ; exit "$xs"; }
} 4>&1
STATUS=$?
fi
if [ "$STATUS" -ne 0 ]; then
log_message "Error: $file finished with status=$STATUS"
else
log_message "$file finished successfully"
fi
done
exit 0