If the agent is set to daemonize but for whatever reason fails to
init the channel, the error message is lost. Worse, the agent
daemonizes needlessly and returns success. For instance:
# qemu-ga -m virtio-serial \
-p /dev/nonexistent_device \
-f /run/qemu-ga.pid \
-t /run \
-d
# echo $?
0
This makes it needlessly hard for init scripts to detect a
failure in qemu-ga startup. Though, they shouldn't pass '-d' in
the first place.
Let's open the channel first and only after that become a daemon.
Related bug: https://bugs.gentoo.org/810628
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
---
qga/main.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/qga/main.c b/qga/main.c
index 68ea7f275a..35f061b5ea 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1430,7 +1430,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
if (config->daemonize) {
/* delay opening/locking of pidfile till filesystems are unfrozen */
s->deferred_options.pid_filepath = config->pid_filepath;
- become_daemon(NULL);
}
if (config->log_filepath) {
/* delay opening the log file till filesystems are unfrozen */
@@ -1438,9 +1437,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
}
ga_disable_logging(s);
} else {
- if (config->daemonize) {
- become_daemon(config->pid_filepath);
- }
if (config->log_filepath) {
FILE *log_file = ga_open_logfile(config->log_filepath);
if (!log_file) {
@@ -1487,6 +1483,20 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
ga_apply_command_filters(s);
+ if (!channel_init(s, s->config->method, s->config->channel_path,
+ s->socket_activation ? FIRST_SOCKET_ACTIVATION_FD : -1)) {
+ g_critical("failed to initialize guest agent channel");
+ return NULL;
+ }
+
+ if (config->daemonize) {
+ if (ga_is_frozen(s)) {
+ become_daemon(NULL);
+ } else {
+ become_daemon(config->pid_filepath);
+ }
+ }
+
ga_state = s;
return s;
}
@@ -1513,8 +1523,9 @@ static void cleanup_agent(GAState *s)
static int run_agent_once(GAState *s)
{
- if (!channel_init(s, s->config->method, s->config->channel_path,
- s->socket_activation ? FIRST_SOCKET_ACTIVATION_FD : -1)) {
+ if (!s->channel &&
+ channel_init(s, s->config->method, s->config->channel_path,
+ s->socket_activation ? FIRST_SOCKET_ACTIVATION_FD : -1)) {
g_critical("failed to initialize guest agent channel");
return EXIT_FAILURE;
}
@@ -1523,6 +1534,7 @@ static int run_agent_once(GAState *s)
if (s->channel) {
ga_channel_free(s->channel);
+ s->channel = NULL;
}
return EXIT_SUCCESS;
--
2.45.2
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
On Tue, Jan 7, 2025 at 4:52 PM Michal Privoznik <mprivozn@redhat.com> wrote:
> If the agent is set to daemonize but for whatever reason fails to
> init the channel, the error message is lost. Worse, the agent
> daemonizes needlessly and returns success. For instance:
>
> # qemu-ga -m virtio-serial \
> -p /dev/nonexistent_device \
> -f /run/qemu-ga.pid \
> -t /run \
> -d
> # echo $?
> 0
>
> This makes it needlessly hard for init scripts to detect a
> failure in qemu-ga startup. Though, they shouldn't pass '-d' in
> the first place.
>
> Let's open the channel first and only after that become a daemon.
>
> Related bug: https://bugs.gentoo.org/810628
>
> Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
> Reviewed-by: Ján Tomko <jtomko@redhat.com>
> ---
> qga/main.c | 24 ++++++++++++++++++------
> 1 file changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/qga/main.c b/qga/main.c
> index 68ea7f275a..35f061b5ea 100644
> --- a/qga/main.c
> +++ b/qga/main.c
> @@ -1430,7 +1430,6 @@ static GAState *initialize_agent(GAConfig *config,
> int socket_activation)
> if (config->daemonize) {
> /* delay opening/locking of pidfile till filesystems are
> unfrozen */
> s->deferred_options.pid_filepath = config->pid_filepath;
> - become_daemon(NULL);
> }
> if (config->log_filepath) {
> /* delay opening the log file till filesystems are unfrozen */
> @@ -1438,9 +1437,6 @@ static GAState *initialize_agent(GAConfig *config,
> int socket_activation)
> }
> ga_disable_logging(s);
> } else {
> - if (config->daemonize) {
> - become_daemon(config->pid_filepath);
> - }
> if (config->log_filepath) {
> FILE *log_file = ga_open_logfile(config->log_filepath);
> if (!log_file) {
> @@ -1487,6 +1483,20 @@ static GAState *initialize_agent(GAConfig *config,
> int socket_activation)
>
> ga_apply_command_filters(s);
>
> + if (!channel_init(s, s->config->method, s->config->channel_path,
> + s->socket_activation ? FIRST_SOCKET_ACTIVATION_FD :
> -1)) {
> + g_critical("failed to initialize guest agent channel");
> + return NULL;
> + }
> +
> + if (config->daemonize) {
> + if (ga_is_frozen(s)) {
> + become_daemon(NULL);
> + } else {
> + become_daemon(config->pid_filepath);
> + }
> + }
> +
> ga_state = s;
> return s;
> }
> @@ -1513,8 +1523,9 @@ static void cleanup_agent(GAState *s)
>
> static int run_agent_once(GAState *s)
> {
> - if (!channel_init(s, s->config->method, s->config->channel_path,
> - s->socket_activation ? FIRST_SOCKET_ACTIVATION_FD :
> -1)) {
> + if (!s->channel &&
> + channel_init(s, s->config->method, s->config->channel_path,
> + s->socket_activation ? FIRST_SOCKET_ACTIVATION_FD :
> -1)) {
> g_critical("failed to initialize guest agent channel");
> return EXIT_FAILURE;
> }
> @@ -1523,6 +1534,7 @@ static int run_agent_once(GAState *s)
>
> if (s->channel) {
> ga_channel_free(s->channel);
> + s->channel = NULL;
> }
>
> return EXIT_SUCCESS;
> --
> 2.45.2
>
>
© 2016 - 2026 Red Hat, Inc.