From: Michal Privoznik <mprivozn@redhat.com>
In Bash, the following code does not do what you think it does:
func() {
local var=$(false)
echo $?
}
Here, '0' is echoed even though false is designed to exit with a
non-zero code. This is because in fact the last executed command
is 'local' not 'false' and thus '$?' contains zero as in "yeah,
the variable is successfully declared" [1]. In our libvirt-guest
shell script, there are a few places like this. Now, in next
commit a syntax-check rule is introduced and to keep it simple
(by avoiding multi line grep) it'll deny declaring local
variables and assigning their value via a subshell regardless of
subsequent '$?' check. Thus, this commit may change more than
necessary, strictly speaking. But in the long run, we're on the
safe side.
1: https://www.shellcheck.net/wiki/SC2155
Fixes: 08071ec0f113bb1fe8dcc263cb6bf87529e8b76b
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/839
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
---
tools/libvirt-guests.sh.in | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/tools/libvirt-guests.sh.in b/tools/libvirt-guests.sh.in
index f2db1282ad..f57eda66fe 100644
--- a/tools/libvirt-guests.sh.in
+++ b/tools/libvirt-guests.sh.in
@@ -106,7 +106,9 @@ test_connect()
list_guests() {
local uri="$1"
local persistent="$2"
- local list="$(run_virsh_c "$uri" list --uuid $persistent)"
+ local list=
+
+ list="$(run_virsh_c "$uri" list --uuid $persistent)"
if [ $? -ne 0 ]; then
RETVAL=1
@@ -131,9 +133,10 @@ guest_name() {
guest_is_on() {
local uri="$1"
local uuid="$2"
- local id="$(run_virsh "$uri" domid "$uuid")"
+ local id=
guest_running="false"
+ id="$(run_virsh "$uri" domid "$uuid")"
if [ $? -ne 0 ]; then
RETVAL=1
return 1
@@ -193,7 +196,8 @@ start() {
eval_gettext "Resuming guests on \$uri URI..."; echo
for guest in $list; do
- local name="$(guest_name "$uri" "$guest")"
+ local name=
+ name="$(guest_name "$uri" "$guest")"
eval_gettext "Resuming guest \$name: "
if guest_is_on "$uri" "$guest"; then
if "$guest_running"; then
@@ -226,11 +230,13 @@ suspend_guest()
{
local uri="$1"
local guest="$2"
- local name="$(guest_name "$uri" "$guest")"
- local label="$(eval_gettext "Suspending \$name: ")"
+ local name=
+ local label=
local bypass=
local slept=0
+ name="$(guest_name "$uri" "$guest")"
+ label="$(eval_gettext "Suspending \$name: ")"
test "x$BYPASS_CACHE" = x0 || bypass="--bypass-cache"
printf '%s...\n' "$label"
run_virsh "$uri" managedsave $bypass "$guest" >/dev/null &
@@ -241,7 +247,8 @@ suspend_guest()
slept=$(($slept + 1))
if [ $(($slept % 5)) -eq 0 ]; then
- local progress="$(run_virsh_c "$uri" domjobinfo "$guest" 2>/dev/null | \
+ local progress=
+ progress="$(run_virsh_c "$uri" domjobinfo "$guest" 2>/dev/null | \
awk '/^Data processed:/{print $3, $4}')"
if [ -n "$progress" ]; then
printf '%s%s\n' "$label" "$progress"
@@ -260,12 +267,13 @@ shutdown_guest()
{
local uri="$1"
local guest="$2"
- local name="$(guest_name "$uri" "$guest")"
+ local name=
local timeout="$SHUTDOWN_TIMEOUT"
local check_timeout="false"
local format=
local slept=
+ name="$(guest_name "$uri" "$guest")"
eval_gettext "Starting shutdown on guest: \$name"
echo
retval run_virsh "$uri" shutdown "$guest" >/dev/null || return
@@ -312,8 +320,9 @@ shutdown_guest_async()
{
local uri="$1"
local guest="$2"
- local name="$(guest_name "$uri" "$guest")"
+ local name=
+ name="$(guest_name "$uri" "$guest")"
eval_gettext "Starting shutdown on guest: \$name"
echo
retval run_virsh "$uri" shutdown "$guest" > /dev/null
@@ -365,7 +374,8 @@ print_guests_shutdown()
*" $guest "*) continue;;
esac
- local name="$(guest_name "$uri" "$guest")"
+ local name=
+ name="$(guest_name "$uri" "$guest")"
if [ -n "$name" ]; then
eval_gettext "Shutdown of guest \$name complete."
echo
@@ -482,7 +492,8 @@ stop() {
eval_gettext "Running guests on \$uri URI: "
- local list="$(list_guests "$uri")"
+ local list=
+ list="$(list_guests "$uri")"
if [ $? -eq 0 ]; then
local empty=true
for uuid in $list; do
@@ -498,7 +509,8 @@ stop() {
fi
if "$persistent_only"; then
- local transient="$(list_guests "$uri" "--transient")"
+ local transient=
+ transient="$(list_guests "$uri" "--transient")"
if [ $? -eq 0 ]; then
local empty="true"
local uuid=
--
2.52.0
On Fri, Jan 16, 2026 at 10:22:13AM +0100, Michal Privoznik via Devel wrote:
>From: Michal Privoznik <mprivozn@redhat.com>
>
>In Bash, the following code does not do what you think it does:
>
> func() {
> local var=$(false)
> echo $?
> }
>
>Here, '0' is echoed even though false is designed to exit with a
>non-zero code. This is because in fact the last executed command
>is 'local' not 'false' and thus '$?' contains zero as in "yeah,
>the variable is successfully declared" [1]. In our libvirt-guest
>shell script, there are a few places like this. Now, in next
>commit a syntax-check rule is introduced and to keep it simple
>(by avoiding multi line grep) it'll deny declaring local
>variables and assigning their value via a subshell regardless of
>subsequent '$?' check. Thus, this commit may change more than
>necessary, strictly speaking. But in the long run, we're on the
>safe side.
>
>1: https://www.shellcheck.net/wiki/SC2155
>Fixes: 08071ec0f113bb1fe8dcc263cb6bf87529e8b76b
>Resolves: https://gitlab.com/libvirt/libvirt/-/issues/839
>Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
>---
> tools/libvirt-guests.sh.in | 34 +++++++++++++++++++++++-----------
> 1 file changed, 23 insertions(+), 11 deletions(-)
>
>diff --git a/tools/libvirt-guests.sh.in b/tools/libvirt-guests.sh.in
>index f2db1282ad..f57eda66fe 100644
>--- a/tools/libvirt-guests.sh.in
>+++ b/tools/libvirt-guests.sh.in
>@@ -106,7 +106,9 @@ test_connect()
> list_guests() {
> local uri="$1"
> local persistent="$2"
>- local list="$(run_virsh_c "$uri" list --uuid $persistent)"
>+ local list=
You don't need the equals sign here, just:
local list
list="$(...)"
also everywhere below.
[...]
>@@ -226,11 +230,13 @@ suspend_guest()
> {
> local uri="$1"
> local guest="$2"
>- local name="$(guest_name "$uri" "$guest")"
>- local label="$(eval_gettext "Suspending \$name: ")"
>+ local name=
>+ local label=
> local bypass=
> local slept=0
here you can just remove all `^local ` and start the function with:
local uri guest name label bypass slept progress #(from below) etc.
it would be nicer, I think. If you changed it with a script you could
modify it for all functions, but if you did it manually, then it's a
`good-first-issue` candidate, I guess.
© 2016 - 2026 Red Hat, Inc.