util: Introduce virDevMapperGetTargets

This helper fetches dependencies for given device mapper target.

At the same time, we need to provide a dummy log function because
by default libdevmapper prints out error messages to stderr which
we need to suppress.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Michal Privoznik 2018-03-26 14:48:07 +02:00
parent 3487973ee0
commit fd9d1e686d
4 changed files with 236 additions and 0 deletions

View File

@ -1670,6 +1670,10 @@ virDBusMessageUnref;
virDBusSetSharedBus;
# util/virdevmapper.h
virDevMapperGetTargets;
# util/virdnsmasq.h
dnsmasqAddDhcpHost;
dnsmasqAddHost;

View File

@ -35,6 +35,8 @@ UTIL_SOURCES = \
util/virdbus.c \
util/virdbus.h \
util/virdbuspriv.h \
util/virdevmapper.c \
util/virdevmapper.h \
util/virdnsmasq.c \
util/virdnsmasq.h \
util/virebtables.c \

199
src/util/virdevmapper.c Normal file
View File

@ -0,0 +1,199 @@
/*
* virdevmapper.c: Functions for handling device mapper
*
* Copyright (C) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Authors:
* Michal Privoznik <mprivozn@redhat.com>
*/
#include <config.h>
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
#elif MAJOR_IN_SYSMACROS
# include <sys/sysmacros.h>
#endif
#ifdef WITH_DEVMAPPER
# include <libdevmapper.h>
#endif
#include "virdevmapper.h"
#include "internal.h"
#include "virthread.h"
#include "viralloc.h"
#include "virstring.h"
#ifdef WITH_DEVMAPPER
static void
virDevMapperDummyLogger(int level ATTRIBUTE_UNUSED,
const char *file ATTRIBUTE_UNUSED,
int line ATTRIBUTE_UNUSED,
int dm_errno ATTRIBUTE_UNUSED,
const char *fmt ATTRIBUTE_UNUSED,
...)
{
return;
}
static int
virDevMapperOnceInit(void)
{
/* Ideally, we would not need this. But libdevmapper prints
* error messages to stderr by default. Sad but true. */
dm_log_with_errno_init(virDevMapperDummyLogger);
return 0;
}
VIR_ONCE_GLOBAL_INIT(virDevMapper)
static int
virDevMapperGetTargetsImpl(const char *path,
char ***devPaths_ret,
unsigned int ttl)
{
struct dm_task *dmt = NULL;
struct dm_deps *deps;
struct dm_info info;
char **devPaths = NULL;
char **recursiveDevPaths = NULL;
size_t i;
int ret = -1;
*devPaths_ret = NULL;
if (virDevMapperInitialize() < 0)
return ret;
if (ttl == 0) {
errno = ELOOP;
return ret;
}
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
return ret;
if (!dm_task_set_name(dmt, path)) {
if (errno == ENOENT) {
/* It's okay, @path is not managed by devmapper =>
* not a devmapper device. */
ret = 0;
}
goto cleanup;
}
dm_task_no_open_count(dmt);
if (!dm_task_run(dmt))
goto cleanup;
if (!dm_task_get_info(dmt, &info))
goto cleanup;
if (!info.exists) {
ret = 0;
goto cleanup;
}
if (!(deps = dm_task_get_deps(dmt)))
goto cleanup;
if (VIR_ALLOC_N_QUIET(devPaths, deps->count + 1) < 0)
goto cleanup;
for (i = 0; i < deps->count; i++) {
if (virAsprintfQuiet(&devPaths[i], "/dev/block/%u:%u",
major(deps->device[i]),
minor(deps->device[i])) < 0)
goto cleanup;
}
recursiveDevPaths = NULL;
for (i = 0; i < deps->count; i++) {
char **tmpPaths;
if (virDevMapperGetTargetsImpl(devPaths[i], &tmpPaths, ttl - 1) < 0)
goto cleanup;
if (tmpPaths &&
virStringListMerge(&recursiveDevPaths, &tmpPaths) < 0) {
virStringListFree(tmpPaths);
goto cleanup;
}
}
if (virStringListMerge(&devPaths, &recursiveDevPaths) < 0)
goto cleanup;
VIR_STEAL_PTR(*devPaths_ret, devPaths);
ret = 0;
cleanup:
virStringListFree(recursiveDevPaths);
virStringListFree(devPaths);
dm_task_destroy(dmt);
return ret;
}
/**
* virDevMapperGetTargets:
* @path: devmapper target
* @devPaths: returned string list of devices
*
* For given @path figure out its targets, and store them in
* @devPaths array. Note, @devPaths is a string list so it's NULL
* terminated.
*
* If @path is not a devmapper device, @devPaths is set to NULL and
* success is returned.
*
* If @path consists of yet another devmapper targets these are
* consulted recursively.
*
* If we don't have permissions to talk to kernel, -1 is returned
* and errno is set to EBADF.
*
* Returns 0 on success,
* -1 otherwise (with errno set, no libvirt error is
* reported)
*/
int
virDevMapperGetTargets(const char *path,
char ***devPaths)
{
const unsigned int ttl = 32;
/* Arbitrary limit on recursion level. A devmapper target can
* consist of devices or yet another targets. If that's the
* case, we have to stop recursion somewhere. */
return virDevMapperGetTargetsImpl(path, devPaths, ttl);
}
#else /* ! WITH_DEVMAPPER */
int
virDevMapperGetTargets(const char *path ATTRIBUTE_UNUSED,
char ***devPaths ATTRIBUTE_UNUSED)
{
errno = ENOSYS;
return -1;
}
#endif /* ! WITH_DEVMAPPER */

31
src/util/virdevmapper.h Normal file
View File

@ -0,0 +1,31 @@
/*
* virdevmapper.h: Functions for handling device mapper
*
* Copyright (C) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Authors:
* Michal Privoznik <mprivozn@redhat.com>
*/
#ifndef __VIR_DEVMAPPER_H__
# define __VIR_DEVMAPPER_H__
int
virDevMapperGetTargets(const char *path,
char ***devPaths);
#endif /* __VIR_DEVMAPPER_H__ */