diff --git a/0001-Extract-stats-functions-from-the-qemu-driver.patch b/0001-Extract-stats-functions-from-the-qemu-driver.patch new file mode 100644 index 0000000..bcaac6e --- /dev/null +++ b/0001-Extract-stats-functions-from-the-qemu-driver.patch @@ -0,0 +1,571 @@ +From 6609ed5a377c3beaf8389e870b6851856cee42c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Thu, 4 Jan 2018 12:04:07 +0100 +Subject: [PATCH 1/3] Extract stats functions from the qemu driver + +Some of the qemu functions getting statistics can easily be reused in +other drivers. Create a conf/domain_stats.[ch] pair to host some of +them. +--- + src/Makefile.am | 1 + + src/conf/domain_stats.c | 139 +++++++++++++++++++++++++++++++++++++++++ + src/conf/domain_stats.h | 64 +++++++++++++++++++ + src/libvirt_private.syms | 4 ++ + src/qemu/qemu_driver.c | 158 +++-------------------------------------------- + src/util/vircgroup.c | 46 ++++++++++++++ + src/util/vircgroup.h | 4 ++ + 7 files changed, 265 insertions(+), 151 deletions(-) + create mode 100644 src/conf/domain_stats.c + create mode 100644 src/conf/domain_stats.h + +diff --git a/src/Makefile.am b/src/Makefile.am +index 166c9a8e9..25f913a5f 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -404,6 +404,7 @@ DOMAIN_CONF_SOURCES = \ + conf/domain_conf.c conf/domain_conf.h \ + conf/domain_audit.c conf/domain_audit.h \ + conf/domain_nwfilter.c conf/domain_nwfilter.h \ ++ conf/domain_stats.c conf/domain_stats.h \ + conf/virsavecookie.c conf/virsavecookie.h \ + conf/snapshot_conf.c conf/snapshot_conf.h \ + conf/numa_conf.c conf/numa_conf.h \ +diff --git a/src/conf/domain_stats.c b/src/conf/domain_stats.c +new file mode 100644 +index 000000000..beb3c09d5 +--- /dev/null ++++ b/src/conf/domain_stats.c +@@ -0,0 +1,139 @@ ++/* ++ * domain_stats.c: domain stats extraction helpers ++ * ++ * Copyright (C) 2006-2016 Red Hat, Inc. ++ * Copyright (C) 2006-2008 Daniel P. Berrange ++ * Copyright (c) 2018 SUSE LINUX Products GmbH, Nuernberg, Germany. ++ * ++ * 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 ++ * . ++ * ++ * Author: Daniel P. Berrange ++ */ ++ ++#include ++ ++#include ++ ++#include "virlog.h" ++#include "domain_stats.h" ++#include "virtypedparam.h" ++#include "virnetdevtap.h" ++#include "virnetdevopenvswitch.h" ++ ++#define VIR_FROM_THIS VIR_FROM_DOMAIN ++ ++VIR_LOG_INIT("conf.domain_stats"); ++ ++int ++virDomainStatsGetState(virDomainObjPtr dom, ++ virDomainStatsRecordPtr record, ++ int *maxparams) ++{ ++ if (virTypedParamsAddInt(&record->params, ++ &record->nparams, ++ maxparams, ++ "state.state", ++ dom->state.state) < 0) ++ return -1; ++ ++ if (virTypedParamsAddInt(&record->params, ++ &record->nparams, ++ maxparams, ++ "state.reason", ++ dom->state.reason) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++#define STATS_ADD_NET_PARAM(record, maxparams, num, name, value) \ ++do { \ ++ char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ ++ snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ ++ "net.%zu.%s", num, name); \ ++ if (value >= 0 && virTypedParamsAddULLong(&(record)->params, \ ++ &(record)->nparams, \ ++ maxparams, \ ++ param_name, \ ++ value) < 0) \ ++ return -1; \ ++} while (0) ++ ++int ++virDomainStatsGetInterface(virDomainObjPtr dom, ++ virDomainStatsRecordPtr record, ++ int *maxparams) ++{ ++ size_t i; ++ struct _virDomainInterfaceStats tmp; ++ int ret = -1; ++ ++ if (!virDomainObjIsActive(dom)) ++ return 0; ++ ++ VIR_DOMAIN_STATS_ADD_COUNT_PARAM(record, maxparams, "net", dom->def->nnets); ++ ++ /* Check the path is one of the domain's network interfaces. */ ++ for (i = 0; i < dom->def->nnets; i++) { ++ virDomainNetDefPtr net = dom->def->nets[i]; ++ virDomainNetType actualType; ++ ++ if (!net->ifname) ++ continue; ++ ++ memset(&tmp, 0, sizeof(tmp)); ++ ++ actualType = virDomainNetGetActualType(net); ++ ++ VIR_DOMAIN_STATS_ADD_NAME_PARAM(record, maxparams, ++ "net", "name", i, net->ifname); ++ ++ if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { ++ if (virNetDevOpenvswitchInterfaceStats(net->ifname, &tmp) < 0) { ++ virResetLastError(); ++ continue; ++ } ++ } else { ++ if (virNetDevTapInterfaceStats(net->ifname, &tmp, ++ !virDomainNetTypeSharesHostView(net)) < 0) { ++ virResetLastError(); ++ continue; ++ } ++ } ++ ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "rx.bytes", tmp.rx_bytes); ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "rx.pkts", tmp.rx_packets); ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "rx.errs", tmp.rx_errs); ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "rx.drop", tmp.rx_drop); ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "tx.bytes", tmp.tx_bytes); ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "tx.pkts", tmp.tx_packets); ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "tx.errs", tmp.tx_errs); ++ STATS_ADD_NET_PARAM(record, maxparams, i, ++ "tx.drop", tmp.tx_drop); ++ } ++ ++ ret = 0; ++ cleanup: ++ return ret; ++} ++ ++#undef STATS_ADD_NET_PARAM +diff --git a/src/conf/domain_stats.h b/src/conf/domain_stats.h +new file mode 100644 +index 000000000..42f8cb6d3 +--- /dev/null ++++ b/src/conf/domain_stats.h +@@ -0,0 +1,64 @@ ++/* ++ * domain_stats.h: domain stats extraction helpers ++ * ++ * Copyright (C) 2006-2016 Red Hat, Inc. ++ * Copyright (C) 2006-2008 Daniel P. Berrange ++ * Copyright (c) 2018 SUSE LINUX Products GmbH, Nuernberg, Germany. ++ * ++ * 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 ++ * . ++ * ++ * Author: Daniel P. Berrange ++ */ ++#ifndef __DOMAIN_STATS_H ++# define __DOMAIN_STATS_H ++ ++# include "internal.h" ++# include "domain_conf.h" ++ ++ ++# define VIR_DOMAIN_STATS_ADD_COUNT_PARAM(record, maxparams, type, count) \ ++do { \ ++ char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ ++ snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "%s.count", type); \ ++ if (virTypedParamsAddUInt(&(record)->params, \ ++ &(record)->nparams, \ ++ maxparams, \ ++ param_name, \ ++ count) < 0) \ ++ goto cleanup; \ ++} while (0) ++ ++# define VIR_DOMAIN_STATS_ADD_NAME_PARAM(record, maxparams, type, subtype, num, name) \ ++do { \ ++ char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ ++ snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ ++ "%s.%zu.%s", type, num, subtype); \ ++ if (virTypedParamsAddString(&(record)->params, \ ++ &(record)->nparams, \ ++ maxparams, \ ++ param_name, \ ++ name) < 0) \ ++ goto cleanup; \ ++} while (0) ++ ++int virDomainStatsGetState(virDomainObjPtr dom, ++ virDomainStatsRecordPtr record, ++ int *maxparams); ++ ++int virDomainStatsGetInterface(virDomainObjPtr dom, ++ virDomainStatsRecordPtr record, ++ int *maxparams); ++ ++#endif /* __DOMAIN_STATS_H */ +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index bc8cc1fba..2e22abcec 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -630,6 +630,9 @@ virDomainConfNWFilterRegister; + virDomainConfNWFilterTeardown; + virDomainConfVMNWFilterTeardown; + ++# conf/domain_stats.h ++virDomainStatsGetInterface; ++virDomainStatsGetState; + + # conf/interface_conf.h + virInterfaceDefFormat; +@@ -1468,6 +1471,7 @@ virCgroupGetMemoryUsage; + virCgroupGetMemSwapHardLimit; + virCgroupGetMemSwapUsage; + virCgroupGetPercpuStats; ++virCgroupGetStatsCpu; + virCgroupHasController; + virCgroupHasEmptyTasks; + virCgroupKill; +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index a203c9297..f60436e4c 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -72,6 +72,7 @@ + #include "viralloc.h" + #include "viruuid.h" + #include "domain_conf.h" ++#include "domain_stats.h" + #include "domain_audit.h" + #include "node_device_conf.h" + #include "virpci.h" +@@ -19380,21 +19381,7 @@ qemuDomainGetStatsState(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + int *maxparams, + unsigned int privflags ATTRIBUTE_UNUSED) + { +- if (virTypedParamsAddInt(&record->params, +- &record->nparams, +- maxparams, +- "state.state", +- dom->state.state) < 0) +- return -1; +- +- if (virTypedParamsAddInt(&record->params, +- &record->nparams, +- maxparams, +- "state.reason", +- dom->state.reason) < 0) +- return -1; +- +- return 0; ++ return virDomainStatsGetState(dom, record, maxparams); + } + + +@@ -19417,37 +19404,7 @@ qemuDomainGetStatsCpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + unsigned int privflags ATTRIBUTE_UNUSED) + { + qemuDomainObjPrivatePtr priv = dom->privateData; +- unsigned long long cpu_time = 0; +- unsigned long long user_time = 0; +- unsigned long long sys_time = 0; +- int err = 0; +- +- if (!priv->cgroup) +- return 0; +- +- err = virCgroupGetCpuacctUsage(priv->cgroup, &cpu_time); +- if (!err && virTypedParamsAddULLong(&record->params, +- &record->nparams, +- maxparams, +- "cpu.time", +- cpu_time) < 0) +- return -1; +- +- err = virCgroupGetCpuacctStat(priv->cgroup, &user_time, &sys_time); +- if (!err && virTypedParamsAddULLong(&record->params, +- &record->nparams, +- maxparams, +- "cpu.user", +- user_time) < 0) +- return -1; +- if (!err && virTypedParamsAddULLong(&record->params, +- &record->nparams, +- maxparams, +- "cpu.system", +- sys_time) < 0) +- return -1; +- +- return 0; ++ return virCgroupGetStatsCpu(priv->cgroup, record, maxparams); + } + + static int +@@ -19624,44 +19581,6 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver, + return ret; + } + +-#define QEMU_ADD_COUNT_PARAM(record, maxparams, type, count) \ +-do { \ +- char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ +- snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "%s.count", type); \ +- if (virTypedParamsAddUInt(&(record)->params, \ +- &(record)->nparams, \ +- maxparams, \ +- param_name, \ +- count) < 0) \ +- goto cleanup; \ +-} while (0) +- +-#define QEMU_ADD_NAME_PARAM(record, maxparams, type, subtype, num, name) \ +-do { \ +- char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ +- snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ +- "%s.%zu.%s", type, num, subtype); \ +- if (virTypedParamsAddString(&(record)->params, \ +- &(record)->nparams, \ +- maxparams, \ +- param_name, \ +- name) < 0) \ +- goto cleanup; \ +-} while (0) +- +-#define QEMU_ADD_NET_PARAM(record, maxparams, num, name, value) \ +-do { \ +- char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ +- snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ +- "net.%zu.%s", num, name); \ +- if (value >= 0 && virTypedParamsAddULLong(&(record)->params, \ +- &(record)->nparams, \ +- maxparams, \ +- param_name, \ +- value) < 0) \ +- return -1; \ +-} while (0) +- + static int + qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + virDomainObjPtr dom, +@@ -19669,68 +19588,9 @@ qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + int *maxparams, + unsigned int privflags ATTRIBUTE_UNUSED) + { +- size_t i; +- struct _virDomainInterfaceStats tmp; +- int ret = -1; +- +- if (!virDomainObjIsActive(dom)) +- return 0; +- +- QEMU_ADD_COUNT_PARAM(record, maxparams, "net", dom->def->nnets); +- +- /* Check the path is one of the domain's network interfaces. */ +- for (i = 0; i < dom->def->nnets; i++) { +- virDomainNetDefPtr net = dom->def->nets[i]; +- virDomainNetType actualType; +- +- if (!net->ifname) +- continue; +- +- memset(&tmp, 0, sizeof(tmp)); +- +- actualType = virDomainNetGetActualType(net); +- +- QEMU_ADD_NAME_PARAM(record, maxparams, +- "net", "name", i, net->ifname); +- +- if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { +- if (virNetDevOpenvswitchInterfaceStats(net->ifname, &tmp) < 0) { +- virResetLastError(); +- continue; +- } +- } else { +- if (virNetDevTapInterfaceStats(net->ifname, &tmp, +- !virDomainNetTypeSharesHostView(net)) < 0) { +- virResetLastError(); +- continue; +- } +- } +- +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "rx.bytes", tmp.rx_bytes); +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "rx.pkts", tmp.rx_packets); +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "rx.errs", tmp.rx_errs); +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "rx.drop", tmp.rx_drop); +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "tx.bytes", tmp.tx_bytes); +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "tx.pkts", tmp.tx_packets); +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "tx.errs", tmp.tx_errs); +- QEMU_ADD_NET_PARAM(record, maxparams, i, +- "tx.drop", tmp.tx_drop); +- } +- +- ret = 0; +- cleanup: +- return ret; ++ return virDomainStatsGetInterface(dom, record, maxparams); + } + +-#undef QEMU_ADD_NET_PARAM +- + #define QEMU_ADD_BLOCK_PARAM_UI(record, maxparams, num, name, value) \ + do { \ + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ +@@ -19852,10 +19712,10 @@ qemuDomainGetStatsOneBlock(virQEMUDriverPtr driver, + if (disk->info.alias) + alias = qemuDomainStorageAlias(disk->info.alias, backing_idx); + +- QEMU_ADD_NAME_PARAM(record, maxparams, "block", "name", block_idx, ++ VIR_DOMAIN_STATS_ADD_NAME_PARAM(record, maxparams, "block", "name", block_idx, + disk->dst); + if (virStorageSourceIsLocalStorage(src) && src->path) +- QEMU_ADD_NAME_PARAM(record, maxparams, "block", "path", ++ VIR_DOMAIN_STATS_ADD_NAME_PARAM(record, maxparams, "block", "path", + block_idx, src->path); + if (backing_idx) + QEMU_ADD_BLOCK_PARAM_UI(record, maxparams, block_idx, "backingIndex", +@@ -19971,7 +19831,7 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver, + * after the iteration than it is to iterate twice; but we still + * want count listed first. */ + count_index = record->nparams; +- QEMU_ADD_COUNT_PARAM(record, maxparams, "block", 0); ++ VIR_DOMAIN_STATS_ADD_COUNT_PARAM(record, maxparams, "block", 0); + + for (i = 0; i < dom->def->ndisks; i++) { + virDomainDiskDefPtr disk = dom->def->disks[i]; +@@ -20005,10 +19865,6 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver, + + #undef QEMU_ADD_BLOCK_PARAM_ULL + +-#undef QEMU_ADD_NAME_PARAM +- +-#undef QEMU_ADD_COUNT_PARAM +- + static int + qemuDomainGetStatsPerfOneEvent(virPerfPtr perf, + virPerfEventType type, +diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c +index 0a31947b0..04ef4c1a7 100644 +--- a/src/util/vircgroup.c ++++ b/src/util/vircgroup.c +@@ -4122,6 +4122,44 @@ virCgroupControllerAvailable(int controller) + return ret; + } + ++int ++virCgroupGetStatsCpu(virCgroupPtr cgroup, ++ virDomainStatsRecordPtr record, ++ int *maxparams) ++{ ++ unsigned long long cpu_time = 0; ++ unsigned long long user_time = 0; ++ unsigned long long sys_time = 0; ++ int err = 0; ++ ++ if (!cgroup) ++ return 0; ++ ++ err = virCgroupGetCpuacctUsage(cgroup, &cpu_time); ++ if (!err && virTypedParamsAddULLong(&record->params, ++ &record->nparams, ++ maxparams, ++ "cpu.time", ++ cpu_time) < 0) ++ return -1; ++ ++ err = virCgroupGetCpuacctStat(cgroup, &user_time, &sys_time); ++ if (!err && virTypedParamsAddULLong(&record->params, ++ &record->nparams, ++ maxparams, ++ "cpu.user", ++ user_time) < 0) ++ return -1; ++ if (!err && virTypedParamsAddULLong(&record->params, ++ &record->nparams, ++ maxparams, ++ "cpu.system", ++ sys_time) < 0) ++ return -1; ++ ++ return 0; ++} ++ + #else /* !VIR_CGROUP_SUPPORTED */ + + bool +@@ -4899,6 +4937,14 @@ virCgroupControllerAvailable(int controller ATTRIBUTE_UNUSED) + { + return false; + } ++ ++int ++virCgroupGetStatsCpu(virCgroupPtr cgroup, ++ virDomainStatsRecordPtr record, ++ int *maxparams) ++{ ++ return 0; ++} + #endif /* !VIR_CGROUP_SUPPORTED */ + + +diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h +index d83392767..2ebdf9505 100644 +--- a/src/util/vircgroup.h ++++ b/src/util/vircgroup.h +@@ -297,4 +297,8 @@ int virCgroupSetOwner(virCgroupPtr cgroup, + int virCgroupHasEmptyTasks(virCgroupPtr cgroup, int controller); + + bool virCgroupControllerAvailable(int controller); ++ ++int virCgroupGetStatsCpu(virCgroupPtr cgroup, ++ virDomainStatsRecordPtr record, ++ int *maxparams); + #endif /* __VIR_CGROUP_H__ */ +-- +2.15.1 + diff --git a/0002-lxc-implement-connectGetAllDomainStats.patch b/0002-lxc-implement-connectGetAllDomainStats.patch new file mode 100644 index 0000000..6c62c7a --- /dev/null +++ b/0002-lxc-implement-connectGetAllDomainStats.patch @@ -0,0 +1,177 @@ +From 1a2be7098cf5acfd893153abb52b65e69631dcec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Tue, 2 Jan 2018 14:44:39 +0100 +Subject: [PATCH 2/3] lxc: implement connectGetAllDomainStats + +LXC containers can also provide some statistics. Allow users to fetch +them using the existing API. +--- + src/lxc/lxc_driver.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 138 insertions(+) + +diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c +index b3447100f..10667c134 100644 +--- a/src/lxc/lxc_driver.c ++++ b/src/lxc/lxc_driver.c +@@ -81,6 +81,7 @@ + #include "viraccessapichecklxc.h" + #include "virhostdev.h" + #include "netdev_bandwidth_conf.h" ++#include "domain_stats.h" + + #define VIR_FROM_THIS VIR_FROM_LXC + +@@ -5485,6 +5486,142 @@ lxcDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags) + return ret; + } + ++static int ++lxcDomainGetStatsCpu(virDomainObjPtr dom, ++ virDomainStatsRecordPtr record, ++ int *maxparams) ++{ ++ virLXCDomainObjPrivatePtr priv = dom->privateData; ++ return virCgroupGetStatsCpu(priv->cgroup, record, maxparams); ++} ++ ++typedef int ++(*lxcDomainGetStatsFunc)(virDomainObjPtr dom, ++ virDomainStatsRecordPtr record, ++ int *maxparams); ++ ++struct lxcDomainGetStatsWorker { ++ lxcDomainGetStatsFunc func; ++ unsigned int stats; ++}; ++ ++static struct lxcDomainGetStatsWorker lxcDomainGetStatsWorkers[] = { ++ { virDomainStatsGetState, VIR_DOMAIN_STATS_STATE }, ++ { lxcDomainGetStatsCpu, VIR_DOMAIN_STATS_CPU_TOTAL }, ++ { virDomainStatsGetInterface, VIR_DOMAIN_STATS_INTERFACE }, ++ { NULL, 0 } ++}; ++ ++static int ++lxcDomainGetStats(virConnectPtr conn, ++ virDomainObjPtr dom, ++ unsigned int stats, ++ virDomainStatsRecordPtr *record) ++{ ++ int maxparams = 0; ++ virDomainStatsRecordPtr tmp; ++ size_t i; ++ int ret = -1; ++ ++ if (VIR_ALLOC(tmp) < 0) ++ goto cleanup; ++ ++ for (i = 0; lxcDomainGetStatsWorkers[i].func; i++) { ++ if (stats & lxcDomainGetStatsWorkers[i].stats) { ++ if (lxcDomainGetStatsWorkers[i].func(dom, tmp, &maxparams) < 0) ++ goto cleanup; ++ } ++ } ++ ++ if (!(tmp->dom = virGetDomain(conn, dom->def->name, ++ dom->def->uuid, dom->def->id))) ++ goto cleanup; ++ ++ *record = tmp; ++ tmp = NULL; ++ ret = 0; ++ ++ cleanup: ++ if (tmp) { ++ virTypedParamsFree(tmp->params, tmp->nparams); ++ VIR_FREE(tmp); ++ } ++ ++ return ret; ++} ++ ++static int ++lxcConnectGetAllDomainStats(virConnectPtr conn, ++ virDomainPtr *doms, ++ unsigned int ndoms, ++ unsigned int stats, ++ virDomainStatsRecordPtr **retStats, ++ unsigned int flags) ++{ ++ virLXCDriverPtr driver = conn->privateData; ++ virDomainObjPtr *vms = NULL; ++ virDomainObjPtr vm; ++ size_t nvms; ++ virDomainStatsRecordPtr *tmpstats = NULL; ++ int nstats = 0; ++ size_t i; ++ int ret = -1; ++ unsigned int lflags = flags & (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE | ++ VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT | ++ VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE); ++ ++ virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE | ++ VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT | ++ VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE, -1); ++ ++ if (virConnectGetAllDomainStatsEnsureACL(conn) < 0) ++ return -1; ++ ++ /* TODO Check stats support */ ++ ++ if (ndoms) { ++ if (virDomainObjListConvert(driver->domains, conn, doms, ndoms, &vms, ++ &nvms, virConnectGetAllDomainStatsCheckACL, ++ lflags, true) < 0) ++ return -1; ++ } else { ++ if (virDomainObjListCollect(driver->domains, conn, &vms, &nvms, ++ virConnectGetAllDomainStatsCheckACL, ++ lflags) < 0) ++ return -1; ++ } ++ ++ if (VIR_ALLOC_N(tmpstats, nvms + 1) < 0) ++ return -1; ++ ++ for (i = 0; i < nvms; i++) { ++ virDomainStatsRecordPtr tmp = NULL; ++ vm = vms[i]; ++ ++ virObjectLock(vm); ++ ++ if (lxcDomainGetStats(conn, vm, stats, &tmp) < 0) { ++ virObjectUnlock(vm); ++ goto cleanup; ++ } ++ ++ if (tmp) ++ tmpstats[nstats++] = tmp; ++ ++ virObjectUnlock(vm); ++ } ++ ++ *retStats = tmpstats; ++ tmpstats = NULL; ++ ++ ret = nstats; ++ ++ cleanup: ++ virDomainStatsRecordListFree(tmpstats); ++ virObjectListFreeCount(vms, nvms); ++ ++ return ret; ++} + + /* Function Tables */ + static virHypervisorDriver lxcHypervisorDriver = { +@@ -5579,6 +5716,7 @@ static virHypervisorDriver lxcHypervisorDriver = { + .nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */ + .nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */ + .domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */ ++ .connectGetAllDomainStats = lxcConnectGetAllDomainStats, /* 3.11.0 */ + }; + + static virConnectDriver lxcConnectDriver = { +-- +2.15.1 + diff --git a/6b3d716e-keycodemap-py3.patch b/6b3d716e-keycodemap-py3.patch new file mode 100644 index 0000000..4dca7ed --- /dev/null +++ b/6b3d716e-keycodemap-py3.patch @@ -0,0 +1,94 @@ +From 6b3d716e2b6472eb7189d3220552280ef3d832ce Mon Sep 17 00:00:00 2001 +From: Daniel P. Berrange +Date: Fri, 12 Jan 2018 13:53:44 +0000 +Subject: [PATCH] Fix compat with py3 dict keys/values data types + +Signed-off-by: Daniel P. Berrange +--- + tools/keymap-gen | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/tools/keymap-gen b/tools/keymap-gen +index d4594b4..f0269e3 100755 +--- a/tools/keymap-gen ++++ b/tools/keymap-gen +@@ -356,19 +356,19 @@ class LanguageSrcGenerator(LanguageGenerator): + + if frommapname in database.ENUM_COLUMNS: + fromtype = self.TYPE_ENUM +- elif type(tolinux.keys()[0]) == str: ++ elif type(list(tolinux.keys())[0]) == str: + fromtype = self.TYPE_STRING + else: + fromtype = self.TYPE_INT + + if tomapname in database.ENUM_COLUMNS: + totype = self.TYPE_ENUM +- elif type(fromlinux.values()[0]) == str: ++ elif type(list(fromlinux.values())[0]) == str: + totype = self.TYPE_STRING + else: + totype = self.TYPE_INT + +- keys = tolinux.keys() ++ keys = list(tolinux.keys()) + keys.sort() + if fromtype == self.TYPE_INT: + keys = range(keys[-1] + 1) +@@ -402,7 +402,7 @@ class LanguageSrcGenerator(LanguageGenerator): + raise Exception("Unknown map %s, expected one of %s" % ( + mapname, ", ".join(database.mapto.keys()))) + +- keys = database.mapto[Database.MAP_LINUX].keys() ++ keys = list(database.mapto[Database.MAP_LINUX].keys()) + keys.sort() + names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys] + +@@ -411,7 +411,7 @@ class LanguageSrcGenerator(LanguageGenerator): + + if mapname in database.ENUM_COLUMNS: + totype = self.TYPE_ENUM +- elif type(database.mapto[mapname].values()[0]) == str: ++ elif type(list(database.mapto[mapname].values())[0]) == str: + totype = self.TYPE_STRING + else: + totype = self.TYPE_INT +@@ -440,7 +440,7 @@ class LanguageSrcGenerator(LanguageGenerator): + if varname is None: + varname = "name_map_%s_to_%s" % (frommapname, tomapname) + +- keys = tolinux.keys() ++ keys = list(tolinux.keys()) + keys.sort() + if type(keys[0]) == int: + keys = range(keys[-1] + 1) +@@ -470,7 +470,7 @@ class LanguageSrcGenerator(LanguageGenerator): + raise Exception("Unknown map %s, expected one of %s" % ( + mapname, ", ".join(database.mapname.keys()))) + +- keys = database.mapto[Database.MAP_LINUX].keys() ++ keys = list(database.mapto[Database.MAP_LINUX].keys()) + keys.sort() + names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys] + +@@ -514,7 +514,7 @@ class LanguageDocGenerator(LanguageGenerator): + raise Exception("Unknown map %s, expected one of %s" % ( + mapname, ", ".join(database.mapname.keys()))) + +- keys = database.mapto[Database.MAP_LINUX].keys() ++ keys = list(database.mapto[Database.MAP_LINUX].keys()) + keys.sort() + names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys] + +@@ -537,7 +537,7 @@ class LanguageDocGenerator(LanguageGenerator): + mapname, ", ".join(database.mapfrom.keys()))) + + tolinux = database.mapfrom[mapname] +- keys = tolinux.keys() ++ keys = list(tolinux.keys()) + keys.sort() + if mapname in database.mapname: + names = database.mapname[mapname] +-- +libgit2 0.26.0 + diff --git a/759b4d1b-virlog-determine-the-hostname-on-startup-CVE-2018-67.patch b/759b4d1b-virlog-determine-the-hostname-on-startup-CVE-2018-67.patch new file mode 100644 index 0000000..d14d104 --- /dev/null +++ b/759b4d1b-virlog-determine-the-hostname-on-startup-CVE-2018-67.patch @@ -0,0 +1,65 @@ +From 759b4d1b0fe5f4d84d98b99153dfa7ac289dd167 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Sat, 27 Jan 2018 23:43:58 +0100 +Subject: [PATCH] virlog: determine the hostname on startup CVE-2018-6764 + +At later point it might not be possible or even safe to use getaddrinfo(). It +can in turn result in a load of NSS module. + +Notably, on a LXC container startup we may find ourselves with the guest +filesystem already having replaced the host one. Loading a NSS module +from the guest tree would allow a malicous guest to escape the +confinement of its container environment because libvirt will not yet +have locked it down. +--- + src/util/virlog.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/src/util/virlog.c b/src/util/virlog.c +index 68439b919..9105337ce 100644 +--- a/src/util/virlog.c ++++ b/src/util/virlog.c +@@ -64,6 +64,7 @@ + VIR_LOG_INIT("util.log"); + + static regex_t *virLogRegex; ++static char *virLogHostname; + + + #define VIR_LOG_DATE_REGEX "[0-9]{4}-[0-9]{2}-[0-9]{2}" +@@ -271,6 +272,12 @@ virLogOnceInit(void) + VIR_FREE(virLogRegex); + } + ++ /* We get and remember the hostname early, because at later time ++ * it might not be possible to load NSS modules via getaddrinfo() ++ * (e.g. at container startup the host filesystem will not be ++ * accessible anymore. */ ++ virLogHostname = virGetHostnameQuiet(); ++ + virLogUnlock(); + return 0; + } +@@ -466,17 +473,14 @@ static int + virLogHostnameString(char **rawmsg, + char **msg) + { +- char *hostname = virGetHostnameQuiet(); + char *hoststr; + +- if (!hostname) ++ if (!virLogHostname) + return -1; + +- if (virAsprintfQuiet(&hoststr, "hostname: %s", hostname) < 0) { +- VIR_FREE(hostname); ++ if (virAsprintfQuiet(&hoststr, "hostname: %s", virLogHostname) < 0) { + return -1; + } +- VIR_FREE(hostname); + + if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, hoststr) < 0) { + VIR_FREE(hoststr); +-- +2.15.1 + diff --git a/apibuild-py3.patch b/apibuild-py3.patch new file mode 100644 index 0000000..7779809 --- /dev/null +++ b/apibuild-py3.patch @@ -0,0 +1,989 @@ +Index: libvirt-4.0.0/docs/apibuild.py +=================================================================== +--- libvirt-4.0.0.orig/docs/apibuild.py ++++ libvirt-4.0.0/docs/apibuild.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python2 ++#!/usr/bin/env python3 + # + # This is the API builder, it parses the C sources and build the + # API formal description in XML. +@@ -119,18 +119,18 @@ hidden_macros = { + } + + def escape(raw): +- raw = string.replace(raw, '&', '&') +- raw = string.replace(raw, '<', '<') +- raw = string.replace(raw, '>', '>') +- raw = string.replace(raw, "'", ''') +- raw = string.replace(raw, '"', '"') ++ raw = raw.replace('&', '&') ++ raw = raw.replace('<', '<') ++ raw = raw.replace('>', '>') ++ raw = raw.replace("'", ''') ++ raw = raw.replace('"', '"') + return raw + + def uniq(items): + d = {} + for item in items: + d[item]=1 +- k = d.keys() ++ k = list(d.keys()) + k.sort() + return k + +@@ -150,8 +150,8 @@ class identifier: + else: + self.conditionals = conditionals[:] + if self.name == debugsym and not quiet: +- print "=> define %s : %s" % (debugsym, (module, type, info, +- extra, conditionals)) ++ print("=> define %s : %s" % (debugsym, (module, type, info, ++ extra, conditionals))) + + def __repr__(self): + r = "%s %s:" % (self.type, self.name) +@@ -160,11 +160,11 @@ class identifier: + if self.module is not None: + r = r + " from %s" % (self.module) + if self.info is not None: +- r = r + " " + `self.info` ++ r = r + " " + repr(self.info) + if self.extra is not None: +- r = r + " " + `self.extra` ++ r = r + " " + repr(self.extra) + if self.conditionals is not None: +- r = r + " " + `self.conditionals` ++ r = r + " " + repr(self.conditionals) + return r + + +@@ -210,8 +210,8 @@ class identifier: + def update(self, header, module, type = None, info = None, extra=None, + conditionals=None): + if self.name == debugsym and not quiet: +- print "=> update %s : %s" % (debugsym, (module, type, info, +- extra, conditionals)) ++ print("=> update %s : %s" % (debugsym, (module, type, info, ++ extra, conditionals))) + if header is not None and self.header is None: + self.set_header(module) + if module is not None and (self.module is None or self.header == self.module): +@@ -243,7 +243,7 @@ class index: + def warning(self, msg): + global warnings + warnings = warnings + 1 +- print msg ++ print(msg) + + def add_ref(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None): + if name[0:2] == '__': +@@ -263,7 +263,7 @@ class index: + self.references[name] = d + + if name == debugsym and not quiet: +- print "New ref: %s" % (d) ++ print("New ref: %s" % (d)) + + return d + +@@ -304,7 +304,7 @@ class index: + self.warning("Unable to register type ", type) + + if name == debugsym and not quiet: +- print "New symbol: %s" % (d) ++ print("New symbol: %s" % (d)) + + return d + +@@ -314,9 +314,9 @@ class index: + # macro might be used to override functions or variables + # definitions + # +- if self.macros.has_key(id): ++ if id in self.macros: + del self.macros[id] +- if self.functions.has_key(id): ++ if id in self.functions: + self.warning("function %s from %s redeclared in %s" % ( + id, self.functions[id].header, idx.functions[id].header)) + else: +@@ -327,30 +327,30 @@ class index: + # macro might be used to override functions or variables + # definitions + # +- if self.macros.has_key(id): ++ if id in self.macros: + del self.macros[id] +- if self.variables.has_key(id): ++ if id in self.variables: + self.warning("variable %s from %s redeclared in %s" % ( + id, self.variables[id].header, idx.variables[id].header)) + else: + self.variables[id] = idx.variables[id] + self.identifiers[id] = idx.variables[id] + for id in idx.structs.keys(): +- if self.structs.has_key(id): ++ if id in self.structs: + self.warning("struct %s from %s redeclared in %s" % ( + id, self.structs[id].header, idx.structs[id].header)) + else: + self.structs[id] = idx.structs[id] + self.identifiers[id] = idx.structs[id] + for id in idx.unions.keys(): +- if self.unions.has_key(id): +- print "union %s from %s redeclared in %s" % ( +- id, self.unions[id].header, idx.unions[id].header) ++ if id in self.unions: ++ print("union %s from %s redeclared in %s" % ( ++ id, self.unions[id].header, idx.unions[id].header)) + else: + self.unions[id] = idx.unions[id] + self.identifiers[id] = idx.unions[id] + for id in idx.typedefs.keys(): +- if self.typedefs.has_key(id): ++ if id in self.typedefs: + self.warning("typedef %s from %s redeclared in %s" % ( + id, self.typedefs[id].header, idx.typedefs[id].header)) + else: +@@ -361,20 +361,20 @@ class index: + # macro might be used to override functions or variables + # definitions + # +- if self.variables.has_key(id): ++ if id in self.variables: + continue +- if self.functions.has_key(id): ++ if id in self.functions: + continue +- if self.enums.has_key(id): ++ if id in self.enums: + continue +- if self.macros.has_key(id): ++ if id in self.macros: + self.warning("macro %s from %s redeclared in %s" % ( + id, self.macros[id].header, idx.macros[id].header)) + else: + self.macros[id] = idx.macros[id] + self.identifiers[id] = idx.macros[id] + for id in idx.enums.keys(): +- if self.enums.has_key(id): ++ if id in self.enums: + self.warning("enum %s from %s redeclared in %s" % ( + id, self.enums[id].header, idx.enums[id].header)) + else: +@@ -383,7 +383,7 @@ class index: + + def merge_public(self, idx): + for id in idx.functions.keys(): +- if self.functions.has_key(id): ++ if id in self.functions: + # check that function condition agrees with header + if idx.functions[id].conditionals != \ + self.functions[id].conditionals: +@@ -407,9 +407,9 @@ class index: + if id.static == 0: + public = public + 1 + if count != public: +- print " %d %s , %d public" % (count, type, public) ++ print(" %d %s , %d public" % (count, type, public)) + elif count != 0: +- print " %d public %s" % (count, type) ++ print(" %d public %s" % (count, type)) + + + def analyze(self): +@@ -437,16 +437,16 @@ class CLexer: + if not line: + return None + self.lineno = self.lineno + 1 +- line = string.lstrip(line) +- line = string.rstrip(line) ++ line = line.lstrip() ++ line = line.rstrip() + if line == '': + continue + while line[-1] == '\\': + line = line[:-1] + n = self.input.readline() + self.lineno = self.lineno + 1 +- n = string.lstrip(n) +- n = string.rstrip(n) ++ n = n.lstrip() ++ n = n.rstrip() + if not n: + break + else: +@@ -460,9 +460,9 @@ class CLexer: + self.tokens.insert(0, token) + + def debug(self): +- print "Last token: ", self.last +- print "Token queue: ", self.tokens +- print "Line %d end: " % (self.lineno), self.line ++ print("Last token: ", self.last) ++ print("Token queue: ", self.tokens) ++ print("Line %d end: " % (self.lineno), self.line) + + def token(self): + while self.tokens == []: +@@ -475,8 +475,8 @@ class CLexer: + return None + + if line[0] == '#': +- self.tokens = map((lambda x: ('preproc', x)), +- string.split(line)) ++ self.tokens = list(map((lambda x: ('preproc', x)), ++ line.split())) + + # We might have whitespace between the '#' and preproc + # macro name, so instead of having a single token element +@@ -569,21 +569,21 @@ class CLexer: + while i < l: + o = ord(line[i]) + if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \ +- (o >= 48 and o <= 57) or string.find( +- " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1: ++ (o >= 48 and o <= 57) or \ ++ " \t(){}:;,+-*/%&!|[]=><".find(line[i]) == -1: + i = i + 1 + else: + break + self.tokens.append(('name', line[s:i])) + continue +- if string.find("(){}:;,[]", line[i]) != -1: ++ if "(){}:;,[]".find(line[i]) != -1: + # if line[i] == '(' or line[i] == ')' or line[i] == '{' or \ + # line[i] == '}' or line[i] == ':' or line[i] == ';' or \ + # line[i] == ',' or line[i] == '[' or line[i] == ']': + self.tokens.append(('sep', line[i])) + i = i + 1 + continue +- if string.find("+-*><=/%&!|.", line[i]) != -1: ++ if "+-*><=/%&!|.".find(line[i]) != -1: + # if line[i] == '+' or line[i] == '-' or line[i] == '*' or \ + # line[i] == '>' or line[i] == '<' or line[i] == '=' or \ + # line[i] == '/' or line[i] == '%' or line[i] == '&' or \ +@@ -596,7 +596,7 @@ class CLexer: + + j = i + 1 + if j < l and ( +- string.find("+-*><=/%&!|", line[j]) != -1): ++ "+-*><=/%&!|".find(line[j]) != -1): + # line[j] == '+' or line[j] == '-' or line[j] == '*' or \ + # line[j] == '>' or line[j] == '<' or line[j] == '=' or \ + # line[j] == '/' or line[j] == '%' or line[j] == '&' or \ +@@ -612,7 +612,7 @@ class CLexer: + o = ord(line[i]) + if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \ + (o >= 48 and o <= 57) or ( +- string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1): ++ " \t(){}:;,+-*/%&!|[]=><".find(line[i]) == -1): + # line[i] != ' ' and line[i] != '\t' and + # line[i] != '(' and line[i] != ')' and + # line[i] != '{' and line[i] != '}' and +@@ -691,27 +691,27 @@ class CParser: + warnings = warnings + 1 + if self.no_error: + return +- print msg ++ print(msg) + + def error(self, msg, token=-1): + if self.no_error: + return + +- print "Parse Error: " + msg ++ print("Parse Error: " + msg) + if token != -1: +- print "Got token ", token ++ print("Got token ", token) + self.lexer.debug() + sys.exit(1) + + def debug(self, msg, token=-1): +- print "Debug: " + msg ++ print("Debug: " + msg) + if token != -1: +- print "Got token ", token ++ print("Got token ", token) + self.lexer.debug() + + def parseTopComment(self, comment): + res = {} +- lines = string.split(comment, "\n") ++ lines = comment.split("\n") + item = None + for line in lines: + line = line.lstrip().lstrip('*').lstrip() +@@ -722,7 +722,7 @@ class CParser: + line = m.group(2).lstrip() + + if item: +- if res.has_key(item): ++ if item in res: + res[item] = res[item] + " " + line + else: + res[item] = line +@@ -760,10 +760,10 @@ class CParser: + self.comment = self.comment + com + token = self.lexer.token() + +- if string.find(self.comment, "DOC_DISABLE") != -1: ++ if self.comment.find("DOC_DISABLE") != -1: + self.stop_error() + +- if string.find(self.comment, "DOC_ENABLE") != -1: ++ if self.comment.find("DOC_ENABLE") != -1: + self.start_error() + + return token +@@ -786,7 +786,7 @@ class CParser: + if not quiet: + self.warning("Missing * in type comment for %s" % (name)) + return((args, desc)) +- lines = string.split(self.comment, '\n') ++ lines = self.comment.split('\n') + if lines[0] == '*': + del lines[0] + if lines[0] != "* %s:" % (name): +@@ -802,11 +802,11 @@ class CParser: + l = lines[0] + while len(l) > 0 and l[0] == '*': + l = l[1:] +- l = string.strip(l) ++ l = l.strip() + desc = desc + " " + l + del lines[0] + +- desc = string.strip(desc) ++ desc = desc.strip() + + if quiet == 0: + if desc == "": +@@ -821,7 +821,7 @@ class CParser: + + if name[0:2] == '__': + quiet = 1 +- if ignored_macros.has_key(name): ++ if name in ignored_macros: + quiet = 1 + + args = [] +@@ -835,7 +835,7 @@ class CParser: + if not quiet: + self.warning("Missing * in macro comment for %s" % (name)) + return((args, desc)) +- lines = string.split(self.comment, '\n') ++ lines = self.comment.split('\n') + if lines[0] == '*': + del lines[0] + if lines[0] != "* %s:" % (name): +@@ -849,9 +849,9 @@ class CParser: + while len(lines) > 0 and lines[0][0:3] == '* @': + l = lines[0][3:] + try: +- (arg, desc) = string.split(l, ':', 1) +- desc=string.strip(desc) +- arg=string.strip(arg) ++ (arg, desc) = l.split(':', 1) ++ desc=desc.strip() ++ arg=arg.strip() + except: + if not quiet: + self.warning("Misformatted macro comment for %s" % (name)) +@@ -859,11 +859,11 @@ class CParser: + del lines[0] + continue + del lines[0] +- l = string.strip(lines[0]) ++ l = lines[0].strip() + while len(l) > 2 and l[0:3] != '* @': + while l[0] == '*': + l = l[1:] +- desc = desc + ' ' + string.strip(l) ++ desc = desc + ' ' + l.strip() + del lines[0] + if len(lines) == 0: + break +@@ -876,11 +876,11 @@ class CParser: + l = lines[0] + while len(l) > 0 and l[0] == '*': + l = l[1:] +- l = string.strip(l) ++ l = l.strip() + desc = desc + " " + l + del lines[0] + +- desc = string.strip(desc) ++ desc = desc.strip() + + if quiet == 0: + if desc == "": +@@ -900,7 +900,7 @@ class CParser: + quiet = 1 + if name[0:2] == '__': + quiet = 1 +- if ignored_functions.has_key(name): ++ if name in ignored_functions: + quiet = 1 + + (ret, args) = description +@@ -915,7 +915,7 @@ class CParser: + if not quiet: + self.warning("Missing * in function comment for %s" % (name)) + return(((ret[0], retdesc), args, desc)) +- lines = string.split(self.comment, '\n') ++ lines = self.comment.split('\n') + if lines[0] == '*': + del lines[0] + if lines[0] != "* %s:" % (name): +@@ -930,9 +930,9 @@ class CParser: + while len(lines) > 0 and lines[0][0:3] == '* @': + l = lines[0][3:] + try: +- (arg, desc) = string.split(l, ':', 1) +- desc=string.strip(desc) +- arg=string.strip(arg) ++ (arg, desc) = l.split(':', 1) ++ desc=desc.strip() ++ arg=arg.strip() + except: + if not quiet: + self.warning("Misformatted function comment for %s" % (name)) +@@ -940,11 +940,11 @@ class CParser: + del lines[0] + continue + del lines[0] +- l = string.strip(lines[0]) ++ l = lines[0].strip() + while len(l) > 2 and l[0:3] != '* @': + while l[0] == '*': + l = l[1:] +- desc = desc + ' ' + string.strip(l) ++ desc = desc + ' ' + l.strip() + del lines[0] + if len(lines) == 0: + break +@@ -975,16 +975,16 @@ class CParser: + l = l[i:] + if len(l) >= 6 and l[0:7] == "Returns": + try: +- l = string.split(l, ' ', 1)[1] ++ l = l.split(' ', 1)[1] + except: + l = "" +- retdesc = string.strip(l) ++ retdesc = l.strip() + del lines[0] + while len(lines) > 0: + l = lines[0] + while len(l) > 0 and l[0] == '*': + l = l[1:] +- l = string.strip(l) ++ l = l.strip() + retdesc = retdesc + " " + l + del lines[0] + else: +@@ -996,8 +996,8 @@ class CParser: + + if desc is None: + desc = "" +- retdesc = string.strip(retdesc) +- desc = string.strip(desc) ++ retdesc = retdesc.strip() ++ desc = desc.strip() + + if quiet == 0: + # +@@ -1018,7 +1018,7 @@ class CParser: + + def parsePreproc(self, token): + if debug: +- print "=> preproc ", token, self.lexer.tokens ++ print("=> preproc ", token, self.lexer.tokens) + name = token[1] + if name == "#include": + token = self.lexer.token() +@@ -1043,7 +1043,7 @@ class CParser: + lst.append(token[1]) + token = self.lexer.token() + try: +- name = string.split(name, '(') [0] ++ name = name.split('(') [0] + except: + pass + +@@ -1080,7 +1080,7 @@ class CParser: + apstr = self.lexer.tokens[0][1] + try: + self.defines.append(apstr) +- if string.find(apstr, 'ENABLED') != -1: ++ if apstr.find('ENABLED') != -1: + self.conditionals.append("defined(%s)" % apstr) + except: + pass +@@ -1088,7 +1088,7 @@ class CParser: + apstr = self.lexer.tokens[0][1] + try: + self.defines.append(apstr) +- if string.find(apstr, 'ENABLED') != -1: ++ if apstr.find('ENABLED') != -1: + self.conditionals.append("!defined(%s)" % apstr) + except: + pass +@@ -1100,17 +1100,17 @@ class CParser: + apstr = apstr + tok[1] + try: + self.defines.append(apstr) +- if string.find(apstr, 'ENABLED') != -1: ++ if apstr.find('ENABLED') != -1: + self.conditionals.append(apstr) + except: + pass + elif name == "#else": + if self.conditionals != [] and \ +- string.find(self.defines[-1], 'ENABLED') != -1: ++ self.defines[-1].find('ENABLED') != -1: + self.conditionals[-1] = "!(%s)" % self.conditionals[-1] + elif name == "#endif": + if self.conditionals != [] and \ +- string.find(self.defines[-1], 'ENABLED') != -1: ++ self.defines[-1].find('ENABLED') != -1: + self.conditionals = self.conditionals[:-1] + self.defines = self.defines[:-1] + token = self.lexer.token() +@@ -1146,7 +1146,7 @@ class CParser: + while token is not None and token[1] != ";": + token = self.lexer.token() + return token +- elif token[0] == "name" and ignored_words.has_key(token[1]): ++ elif token[0] == "name" and token[1] in ignored_words: + (n, info) = ignored_words[token[1]] + i = 0 + while i < n: +@@ -1156,7 +1156,7 @@ class CParser: + continue + else: + if debug: +- print "=> ", token ++ print("=> ", token) + return token + return None + +@@ -1178,7 +1178,7 @@ class CParser: + name = token[1] + signature = self.signature + if signature is not None: +- type = string.split(type, '(')[0] ++ type = type.split('(')[0] + d = self.mergeFunctionComment(name, + ((type, None), signature), 1) + self.index_add(name, self.filename, not self.is_header, +@@ -1385,7 +1385,7 @@ class CParser: + self.cleanupComment() + if name is not None: + if self.comment is not None: +- comment = string.strip(self.comment) ++ comment = self.comment.strip() + self.comment = None + self.enums.append((name, value, comment)) + name = token[1] +@@ -2025,7 +2025,7 @@ class CParser: + + def parse(self): + if not quiet: +- print "Parsing %s" % (self.filename) ++ print("Parsing %s" % (self.filename)) + token = self.token() + while token is not None: + if token[0] == 'name': +@@ -2046,13 +2046,13 @@ class docBuilder: + self.path = path + self.directories = directories + if name == "libvirt": +- self.includes = includes + included_files.keys() ++ self.includes = includes + list(included_files.keys()) + elif name == "libvirt-qemu": +- self.includes = includes + qemu_included_files.keys() ++ self.includes = includes + list(qemu_included_files.keys()) + elif name == "libvirt-lxc": +- self.includes = includes + lxc_included_files.keys() ++ self.includes = includes + list(lxc_included_files.keys()) + elif name == "libvirt-admin": +- self.includes = includes + admin_included_files.keys() ++ self.includes = includes + list(admin_included_files.keys()) + self.modules = {} + self.headers = {} + self.idx = index() +@@ -2064,44 +2064,44 @@ class docBuilder: + def warning(self, msg): + global warnings + warnings = warnings + 1 +- print msg ++ print(msg) + + def error(self, msg): + self.errors += 1 +- print >>sys.stderr, "Error:", msg ++ print("Error:", msg, file=sys.stderr) + + def indexString(self, id, str): + if str is None: + return +- str = string.replace(str, "'", ' ') +- str = string.replace(str, '"', ' ') +- str = string.replace(str, "/", ' ') +- str = string.replace(str, '*', ' ') +- str = string.replace(str, "[", ' ') +- str = string.replace(str, "]", ' ') +- str = string.replace(str, "(", ' ') +- str = string.replace(str, ")", ' ') +- str = string.replace(str, "<", ' ') +- str = string.replace(str, '>', ' ') +- str = string.replace(str, "&", ' ') +- str = string.replace(str, '#', ' ') +- str = string.replace(str, ",", ' ') +- str = string.replace(str, '.', ' ') +- str = string.replace(str, ';', ' ') +- tokens = string.split(str) ++ str = str.replace("'", ' ') ++ str = str.replace('"', ' ') ++ str = str.replace("/", ' ') ++ str = str.replace('*', ' ') ++ str = str.replace("[", ' ') ++ str = str.replace("]", ' ') ++ str = str.replace("(", ' ') ++ str = str.replace(")", ' ') ++ str = str.replace("<", ' ') ++ str = str.replace('>', ' ') ++ str = str.replace("&", ' ') ++ str = str.replace('#', ' ') ++ str = str.replace(",", ' ') ++ str = str.replace('.', ' ') ++ str = str.replace(';', ' ') ++ tokens = str.split() + for token in tokens: + try: + c = token[0] +- if string.find(string.letters, c) < 0: ++ if string.ascii_letters.find(c) < 0: + pass + elif len(token) < 3: + pass + else: +- lower = string.lower(token) ++ lower = token.lower() + # TODO: generalize this a bit + if lower == 'and' or lower == 'the': + pass +- elif self.xref.has_key(token): ++ elif token in self.xref: + self.xref[token].append(id) + else: + self.xref[token] = [id] +@@ -2110,7 +2110,7 @@ class docBuilder: + + def analyze(self): + if not quiet: +- print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys())) ++ print("Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))) + self.idx.analyze() + + def scanHeaders(self): +@@ -2134,7 +2134,7 @@ class docBuilder: + for file in files: + skip = 1 + for incl in self.includes: +- if string.find(file, incl) != -1: ++ if file.find(incl) != -1: + skip = 0 + break + if skip == 0: +@@ -2143,7 +2143,7 @@ class docBuilder: + for file in files: + skip = 1 + for incl in self.includes: +- if string.find(file, incl) != -1: ++ if file.find(incl) != -1: + skip = 0 + break + if skip == 0: +@@ -2225,7 +2225,7 @@ class docBuilder: + output.write(" \n") +@@ -2271,7 +2271,7 @@ class docBuilder: + def serialize_function(self, output, name): + id = self.idx.functions[name] + if name == debugsym and not quiet: +- print "=>", id ++ print("=>", id) + + # NB: this is consumed by a regex in 'getAPIFilenames' in hvsupport.pl + output.write(" <%s name='%s' file='%s' module='%s'>\n" % (id.type, +@@ -2294,7 +2294,7 @@ class docBuilder: + if ret[0] is not None: + if ret[0] == "void": + output.write(" \n") +- elif (ret[1] is None or ret[1] == '') and not ignored_functions.has_key(name): ++ elif (ret[1] is None or ret[1] == '') and not name in ignored_functions: + self.error("Missing documentation for return of function `%s'" % name) + else: + output.write(" \n" % ( +@@ -2304,7 +2304,7 @@ class docBuilder: + if param[0] == 'void': + continue + if (param[2] is None or param[2] == ''): +- if ignored_functions.has_key(name): ++ if name in ignored_functions: + output.write(" \n" % (param[1], param[0])) + else: + self.error("Missing documentation for arg `%s' of function `%s'" % (param[1], name)) +@@ -2312,8 +2312,8 @@ class docBuilder: + output.write(" \n" % (param[1], param[0], escape(param[2]))) + self.indexString(name, param[2]) + except: +- print >>sys.stderr, "Exception:", sys.exc_info()[1] +- self.warning("Failed to save function %s info: %s" % (name, `id.info`)) ++ print("Exception:", sys.exc_info()[1], file=sys.stderr) ++ self.warning("Failed to save function %s info: %s" % (name, repr(id.info))) + output.write(" \n" % (id.type)) + + def serialize_exports(self, output, file): +@@ -2324,65 +2324,65 @@ class docBuilder: + for data in ('Summary', 'Description', 'Author'): + try: + output.write(" <%s>%s\n" % ( +- string.lower(data), ++ data.lower(), + escape(dict.info[data]), +- string.lower(data))) ++ data.lower())) + except: + self.warning("Header %s lacks a %s description" % (module, data)) +- if dict.info.has_key('Description'): ++ if 'Description' in dict.info: + desc = dict.info['Description'] +- if string.find(desc, "DEPRECATED") != -1: ++ if desc.find("DEPRECATED") != -1: + output.write(" \n") + +- ids = dict.macros.keys() ++ ids = list(dict.macros.keys()) + ids.sort() + for id in uniq(ids): + # Macros are sometime used to masquerade other types. +- if dict.functions.has_key(id): ++ if id in dict.functions: + continue +- if dict.variables.has_key(id): ++ if id in dict.variables: + continue +- if dict.typedefs.has_key(id): ++ if id in dict.typedefs: + continue +- if dict.structs.has_key(id): ++ if id in dict.structs: + continue +- if dict.unions.has_key(id): ++ if id in dict.unions: + continue +- if dict.enums.has_key(id): ++ if id in dict.enums: + continue + output.write(" \n" % (id)) +- ids = dict.enums.keys() ++ ids = list(dict.enums.keys()) + ids.sort() + for id in uniq(ids): + output.write(" \n" % (id)) +- ids = dict.typedefs.keys() ++ ids = list(dict.typedefs.keys()) + ids.sort() + for id in uniq(ids): + output.write(" \n" % (id)) +- ids = dict.structs.keys() ++ ids = list(dict.structs.keys()) + ids.sort() + for id in uniq(ids): + output.write(" \n" % (id)) +- ids = dict.variables.keys() ++ ids = list(dict.variables.keys()) + ids.sort() + for id in uniq(ids): + output.write(" \n" % (id)) +- ids = dict.functions.keys() ++ ids = list(dict.functions.keys()) + ids.sort() + for id in uniq(ids): + output.write(" \n" % (id)) + output.write(" \n") + + def serialize_xrefs_files(self, output): +- headers = self.headers.keys() ++ headers = list(self.headers.keys()) + headers.sort() + for file in headers: + module = self.modulename_file(file) + output.write(" \n" % (module)) + dict = self.headers[file] +- ids = uniq(dict.functions.keys() + dict.variables.keys() + \ +- dict.macros.keys() + dict.typedefs.keys() + \ +- dict.structs.keys() + dict.enums.keys()) ++ ids = uniq(list(dict.functions.keys()) + list(dict.variables.keys()) + \ ++ list(dict.macros.keys()) + list(dict.typedefs.keys()) + \ ++ list(dict.structs.keys()) + list(dict.enums.keys())) + ids.sort() + for id in ids: + output.write(" \n" % (id)) +@@ -2398,13 +2398,13 @@ class docBuilder: + for param in params: + if param[0] == 'void': + continue +- if funcs.has_key(param[0]): ++ if param[0] in funcs: + funcs[param[0]].append(name) + else: + funcs[param[0]] = [name] + except: + pass +- typ = funcs.keys() ++ typ = list(funcs.keys()) + typ.sort() + for type in typ: + if type == '' or type == 'void' or type == "int" or \ +@@ -2428,13 +2428,13 @@ class docBuilder: + (ret, params, desc) = id.info + if ret[0] == "void": + continue +- if funcs.has_key(ret[0]): ++ if ret[0] in funcs: + funcs[ret[0]].append(name) + else: + funcs[ret[0]] = [name] + except: + pass +- typ = funcs.keys() ++ typ = list(funcs.keys()) + typ.sort() + for type in typ: + if type == '' or type == 'void' or type == "int" or \ +@@ -2449,7 +2449,7 @@ class docBuilder: + + def serialize_xrefs_alpha(self, output): + letter = None +- ids = self.idx.identifiers.keys() ++ ids = list(self.idx.identifiers.keys()) + ids.sort() + for id in ids: + if id[0] != letter: +@@ -2462,7 +2462,7 @@ class docBuilder: + output.write(" \n") + + def serialize_xrefs_references(self, output): +- typ = self.idx.identifiers.keys() ++ typ = list(self.idx.identifiers.keys()) + typ.sort() + for id in typ: + idf = self.idx.identifiers[id] +@@ -2474,7 +2474,7 @@ class docBuilder: + + def serialize_xrefs_index(self, output): + index = self.xref +- typ = index.keys() ++ typ = list(index.keys()) + typ.sort() + letter = None + count = 0 +@@ -2542,34 +2542,34 @@ class docBuilder: + def serialize(self): + filename = "%s/%s-api.xml" % (self.path, self.name) + if not quiet: +- print "Saving XML description %s" % (filename) ++ print("Saving XML description %s" % (filename)) + output = open(filename, "w") + output.write('\n') + output.write("\n" % self.name) + output.write(" \n") +- headers = self.headers.keys() ++ headers = list(self.headers.keys()) + headers.sort() + for file in headers: + self.serialize_exports(output, file) + output.write(" \n") + output.write(" \n") +- macros = self.idx.macros.keys() ++ macros = list(self.idx.macros.keys()) + macros.sort() + for macro in macros: + self.serialize_macro(output, macro) +- enums = self.idx.enums.keys() ++ enums = list(self.idx.enums.keys()) + enums.sort() + for enum in enums: + self.serialize_enum(output, enum) +- typedefs = self.idx.typedefs.keys() ++ typedefs = list(self.idx.typedefs.keys()) + typedefs.sort() + for typedef in typedefs: + self.serialize_typedef(output, typedef) +- variables = self.idx.variables.keys() ++ variables = list(self.idx.variables.keys()) + variables.sort() + for variable in variables: + self.serialize_variable(output, variable) +- functions = self.idx.functions.keys() ++ functions = list(self.idx.functions.keys()) + functions.sort() + for function in functions: + self.serialize_function(output, function) +@@ -2578,12 +2578,13 @@ class docBuilder: + output.close() + + if self.errors > 0: +- print >>sys.stderr, "apibuild.py: %d error(s) encountered during generation" % self.errors ++ print("apibuild.py: %d error(s) encountered during generation" % self.errors, ++ file=sys.stderr) + sys.exit(3) + + filename = "%s/%s-refs.xml" % (self.path, self.name) + if not quiet: +- print "Saving XML Cross References %s" % (filename) ++ print("Saving XML Cross References %s" % (filename)) + output = open(filename, "w") + output.write('\n') + output.write("\n" % self.name) +@@ -2596,7 +2597,7 @@ class app: + def warning(self, msg): + global warnings + warnings = warnings + 1 +- print msg ++ print(msg) + + def rebuild(self, name): + if name not in ["libvirt", "libvirt-qemu", "libvirt-lxc", "libvirt-admin"]: +@@ -2609,7 +2610,7 @@ class app: + builddir = None + if glob.glob(srcdir + "/../src/libvirt.c") != [] : + if not quiet: +- print "Rebuilding API description for %s" % name ++ print("Rebuilding API description for %s" % name) + dirs = [srcdir + "/../src", + srcdir + "/../src/util", + srcdir + "/../include/libvirt"] +@@ -2619,7 +2620,7 @@ class app: + builder = docBuilder(name, srcdir, dirs, []) + elif glob.glob("src/libvirt.c") != [] : + if not quiet: +- print "Rebuilding API description for %s" % name ++ print("Rebuilding API description for %s" % name) + builder = docBuilder(name, srcdir, + ["src", "src/util", "include/libvirt"], + []) diff --git a/c2dc6698-fix-deadlock-obtaining-hostname.patch b/c2dc6698-fix-deadlock-obtaining-hostname.patch new file mode 100644 index 0000000..b6bf51d --- /dev/null +++ b/c2dc6698-fix-deadlock-obtaining-hostname.patch @@ -0,0 +1,121 @@ +From c2dc6698c88fb591639e542c8ecb0076c54f3dfb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Mon, 12 Feb 2018 10:03:08 +0000 +Subject: [PATCH] log: fix deadlock obtaining hostname (related CVE-2018-6764) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The fix for CVE-2018-6764 introduced a potential deadlock scenario +that gets triggered by the NSS module when virGetHostname() calls +getaddrinfo to resolve the hostname: + + #0 0x00007f6e714b57e7 in futex_wait + #1 futex_wait_simple + #2 __pthread_once_slow + #3 0x00007f6e71d16e7d in virOnce + #4 0x00007f6e71d0997c in virLogInitialize + #5 0x00007f6e71d0a09a in virLogVMessage + #6 0x00007f6e71d09ffd in virLogMessage + #7 0x00007f6e71d0db22 in virObjectNew + #8 0x00007f6e71d0dbf1 in virObjectLockableNew + #9 0x00007f6e71d0d3e5 in virMacMapNew + #10 0x00007f6e71cdc50a in findLease + #11 0x00007f6e71cdcc56 in _nss_libvirt_gethostbyname4_r + #12 0x00007f6e724631fc in gaih_inet + #13 0x00007f6e72464697 in __GI_getaddrinfo + #14 0x00007f6e71d19e81 in virGetHostnameImpl + #15 0x00007f6e71d1a057 in virGetHostnameQuiet + #16 0x00007f6e71d09936 in virLogOnceInit + #17 0x00007f6e71d09952 in virLogOnce + #18 0x00007f6e714b5829 in __pthread_once_slow + #19 0x00007f6e71d16e7d in virOnce + #20 0x00007f6e71d0997c in virLogInitialize + #21 0x00007f6e71d0a09a in virLogVMessage + #22 0x00007f6e71d09ffd in virLogMessage + #23 0x00007f6e71d0db22 in virObjectNew + #24 0x00007f6e71d0dbf1 in virObjectLockableNew + #25 0x00007f6e71d0d3e5 in virMacMapNew + #26 0x00007f6e71cdc50a in findLease + #27 0x00007f6e71cdc839 in _nss_libvirt_gethostbyname3_r + #28 0x00007f6e71cdc724 in _nss_libvirt_gethostbyname2_r + #29 0x00007f6e7248f72f in __gethostbyname2_r + #30 0x00007f6e7248f494 in gethostbyname2 + #31 0x000056348c30c36d in hosts_keys + #32 0x000056348c30b7d2 in main + +Fortunately the extra stuff virGetHostname does is totally irrelevant to +the needs of the logging code, so we can just inline a call to the +native hostname() syscall directly. + +Signed-off-by: Daniel P. Berrangé +--- + cfg.mk | 2 +- + src/util/virlog.c | 20 ++++++++++++++------ + 2 files changed, 15 insertions(+), 7 deletions(-) + +Index: libvirt-4.0.0/cfg.mk +=================================================================== +--- libvirt-4.0.0.orig/cfg.mk ++++ libvirt-4.0.0/cfg.mk +@@ -1183,7 +1183,7 @@ _src2=src/(util/vircommand|libvirt|lxc/l + exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ + (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$) + +-exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/virutil\.c$$ ++exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/vir(util|log)\.c$$ + + exclude_file_name_regexp--sc_prohibit_internal_functions = \ + ^src/(util/(viralloc|virutil|virfile)\.[hc]|esx/esx_vi\.c)$$ +Index: libvirt-4.0.0/src/util/virlog.c +=================================================================== +--- libvirt-4.0.0.orig/src/util/virlog.c ++++ libvirt-4.0.0/src/util/virlog.c +@@ -64,7 +64,7 @@ + VIR_LOG_INIT("util.log"); + + static regex_t *virLogRegex; +-static char *virLogHostname; ++static char virLogHostname[HOST_NAME_MAX+1]; + + + #define VIR_LOG_DATE_REGEX "[0-9]{4}-[0-9]{2}-[0-9]{2}" +@@ -261,6 +261,8 @@ virLogPriorityString(virLogPriority lvl) + static int + virLogOnceInit(void) + { ++ int r; ++ + if (virMutexInit(&virLogMutex) < 0) + return -1; + +@@ -275,8 +277,17 @@ virLogOnceInit(void) + /* We get and remember the hostname early, because at later time + * it might not be possible to load NSS modules via getaddrinfo() + * (e.g. at container startup the host filesystem will not be +- * accessible anymore. */ +- virLogHostname = virGetHostnameQuiet(); ++ * accessible anymore. ++ * Must not use virGetHostname though as that causes re-entrancy ++ * problems if it triggers logging codepaths ++ */ ++ r = gethostname(virLogHostname, sizeof(virLogHostname)); ++ if (r == -1) { ++ ignore_value(virStrcpy(virLogHostname, ++ "(unknown)", sizeof(virLogHostname))); ++ } else { ++ NUL_TERMINATE(virLogHostname); ++ } + + virLogUnlock(); + return 0; +@@ -475,9 +486,6 @@ virLogHostnameString(char **rawmsg, + { + char *hoststr; + +- if (!virLogHostname) +- return -1; +- + if (virAsprintfQuiet(&hoststr, "hostname: %s", virLogHostname) < 0) { + return -1; + } diff --git a/libvirt.changes b/libvirt.changes index 07f0313..26d5b52 100644 --- a/libvirt.changes +++ b/libvirt.changes @@ -1,3 +1,18 @@ +------------------------------------------------------------------- +Fri Feb 9 13:28:14 UTC 2018 - cbosdonnat@suse.com + +- Remove all uses of python2 during the build (bsc#1080034) + 6b3d716e-keycodemap-py3.patch + apibuild-py3.patch +- Determine hostname early to avoid code injection + in lxc driver. (bsc#1080042) + 759b4d1b-virlog-determine-the-hostname-on-startup-CVE-2018-67.patch + c2dc6698-fix-deadlock-obtaining-hostname.patch +- Add basic support of connectGetAllDomainStats for lxc driver + (fate#323742) + 0001-Extract-stats-functions-from-the-qemu-driver.patch + 0002-lxc-implement-connectGetAllDomainStats.patch + ------------------------------------------------------------------- Fri Jan 26 15:44:30 UTC 2018 - jfehlig@suse.com diff --git a/libvirt.spec b/libvirt.spec index 9f6e84a..f0926c0 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -236,7 +236,7 @@ BuildRequires: libxml2-devel BuildRequires: libxslt BuildRequires: ncurses-devel BuildRequires: perl -BuildRequires: python +BuildRequires: python3 BuildRequires: readline-devel # perl XPath is needed since we have a patch touching files that cause # hvsupport.html to be regenerated @@ -322,6 +322,9 @@ Patch1: 71d56a39-nodedev-fix-parse-PCI-address.patch Patch2: 68eed56b-conf-smbios-oem-strings.patch Patch3: 76977061-qemu-smbios-oem-strings.patch Patch4: 0c710a37-libxl-resume-lock-on-mig-failure.patch +Patch5: 6b3d716e-keycodemap-py3.patch +Patch6: 759b4d1b-virlog-determine-the-hostname-on-startup-CVE-2018-67.patch +Patch7: c2dc6698-fix-deadlock-obtaining-hostname.patch # Patches pending upstream review Patch100: libxl-dom-reset.patch Patch101: network-don-t-use-dhcp-authoritative-on-static-netwo.patch @@ -332,6 +335,9 @@ Patch152: libvirt-power8-models.patch Patch153: ppc64le-canonical-name.patch Patch154: libxl-set-migration-constraints.patch Patch155: libxl-set-cach-mode.patch +Patch156: 0001-Extract-stats-functions-from-the-qemu-driver.patch +Patch157: 0002-lxc-implement-connectGetAllDomainStats.patch +Patch158: apibuild-py3.patch # Our patches Patch200: suse-libvirtd-disable-tls.patch Patch201: suse-libvirtd-sysconfig-settings.patch @@ -912,6 +918,12 @@ libvirt plugin for NSS for translating domain names into IP addresses. %patch2 -p1 %patch3 -p1 %patch4 -p1 +# it is submodule in git +pushd src/keycodemapdb +%patch5 -p1 +popd +%patch6 -p1 +%patch7 -p1 %patch100 -p1 %patch101 -p1 %patch150 -p1 @@ -920,6 +932,9 @@ libvirt plugin for NSS for translating domain names into IP addresses. %patch153 -p1 %patch154 -p1 %patch155 -p1 +%patch156 -p1 +%patch157 -p1 +%patch158 -p1 %patch200 -p1 %patch201 -p1 %patch202 -p1 @@ -1064,6 +1079,7 @@ LOADERS="$LOADERS:/usr/share/qemu/aavmf-aarch64-code.bin:/usr/share/qemu/aavmf-a autoreconf -f -i export CFLAGS="%{optflags}" +export PYTHON=%{_bindir}/python3 %configure --disable-static \ %{?arg_xen} \ %{?arg_qemu} \