virdnsmasq: Lookup DNSMASQ in PATH

While it's true that our virCommand subsystem is happy with
non-absolute paths, the dnsmasq capability code is not. It stores
the path to dnsmasq within and makes it accessible via
dnsmasqCapsGetBinaryPath(). While strictly speaking no caller
necessarily needs canonicalized path, let's find dnsmasq once and
cache the result.

Therefore, when constructing the capabilities structure look up
the binary path. If DNSMASQ already contains an absolute path
then virFindFileInPath() will simply return a copy.

With this code in place, the virFileIsExecutable() check can be
removed from dnsmasqCapsRefreshInternal() because
virFindFileInPath() already made sure the binary is executable.

But introducing virFindFileInPath() means we have to mock it in
test suite because dnsmasqCaps are created in
networkxml2conftest.

Moreover, we don't need to check for dnsmasq in configure.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
This commit is contained in:
Michal Privoznik 2022-01-10 16:19:31 +01:00
parent 96308ebae9
commit 5c98d1cee0
5 changed files with 30 additions and 13 deletions

View File

@ -813,7 +813,6 @@ endforeach
optional_programs = [ optional_programs = [
'augparse', 'augparse',
'dmidecode', 'dmidecode',
'dnsmasq',
'ebtables', 'ebtables',
'flake8', 'flake8',
'ip', 'ip',

View File

@ -46,6 +46,7 @@
VIR_LOG_INIT("util.dnsmasq"); VIR_LOG_INIT("util.dnsmasq");
#define DNSMASQ "dnsmasq"
#define DNSMASQ_HOSTSFILE_SUFFIX "hostsfile" #define DNSMASQ_HOSTSFILE_SUFFIX "hostsfile"
#define DNSMASQ_ADDNHOSTSFILE_SUFFIX "addnhosts" #define DNSMASQ_ADDNHOSTSFILE_SUFFIX "addnhosts"
@ -650,16 +651,6 @@ dnsmasqCapsRefreshInternal(dnsmasqCaps *caps)
g_autoptr(virCommand) vercmd = NULL; g_autoptr(virCommand) vercmd = NULL;
g_autofree char *version = NULL; g_autofree char *version = NULL;
/* Make sure the binary we are about to try exec'ing exists.
* Technically we could catch the exec() failure, but that's
* in a sub-process so it's hard to feed back a useful error.
*/
if (!virFileIsExecutable(caps->binaryPath)) {
virReportSystemError(errno, _("dnsmasq binary %s is not executable"),
caps->binaryPath);
return -1;
}
vercmd = virCommandNewArgList(caps->binaryPath, "--version", NULL); vercmd = virCommandNewArgList(caps->binaryPath, "--version", NULL);
virCommandSetOutputBuffer(vercmd, &version); virCommandSetOutputBuffer(vercmd, &version);
virCommandAddEnvPassCommon(vercmd); virCommandAddEnvPassCommon(vercmd);
@ -679,7 +670,13 @@ dnsmasqCapsNewEmpty(void)
return NULL; return NULL;
if (!(caps = virObjectNew(dnsmasqCapsClass))) if (!(caps = virObjectNew(dnsmasqCapsClass)))
return NULL; return NULL;
caps->binaryPath = g_strdup(DNSMASQ);
if (!(caps->binaryPath = virFindFileInPath(DNSMASQ))) {
virReportSystemError(ENOENT, "%s",
_("Unable to find 'dnsmasq' binary in $PATH"));
return NULL;
}
return g_steal_pointer(&caps); return g_steal_pointer(&caps);
} }

View File

@ -59,6 +59,7 @@ mock_libs = [
{ 'name': 'domaincapsmock' }, { 'name': 'domaincapsmock' },
{ 'name': 'shunload', 'sources': [ 'shunloadhelper.c' ] }, { 'name': 'shunload', 'sources': [ 'shunloadhelper.c' ] },
{ 'name': 'vircgroupmock' }, { 'name': 'vircgroupmock' },
{ 'name': 'virdnsmasqmock' },
{ 'name': 'virfilecachemock' }, { 'name': 'virfilecachemock' },
{ 'name': 'virfirewallmock' }, { 'name': 'virfirewallmock' },
{ 'name': 'virgdbusmock' }, { 'name': 'virgdbusmock' },

View File

@ -158,4 +158,5 @@ mymain(void)
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
} }
VIR_TEST_MAIN(mymain) VIR_TEST_MAIN_PRELOAD(mymain,
VIR_TEST_MOCK("virdnsmasq"))

19
tests/virdnsmasqmock.c Normal file
View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2022 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <config.h>
#include "internal.h"
#include "virfile.h"
char *
virFindFileInPath(const char *file)
{
if (STREQ_NULLABLE(file, "dnsmasq"))
return g_strdup("/usr/sbin/dnsmasq");
/* We should not need any other binaries so return NULL. */
return NULL;
}