#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
+#include <stdbool.h>
/* Plugin name */
#define PLUGIN_NAME "virt"
+/* Secure strcat macro assuring null termination. Parameter (n) is the size of
+ buffer (d), allowing this macro to be safe for static and dynamic buffers */
+#define SSTRNCAT(d, s, n) \
+ do { \
+ size_t _l = strlen(d); \
+ sstrncpy((d) + _l, (s), (n)-_l); \
+ } while (0)
+
#ifdef LIBVIR_CHECK_VERSION
#if LIBVIR_CHECK_VERSION(0, 9, 2)
in some systems which actually have virConnectListAllDomains()
we can't detect this.
*/
-#ifdef LIBVIR_CHECK_VERSION
#if LIBVIR_CHECK_VERSION(0, 10, 2)
#define HAVE_LIST_ALL_DOMAINS 1
#endif
-#endif
#if LIBVIR_CHECK_VERSION(1, 0, 1)
#define HAVE_DOM_REASON_PAUSED_SNAPSHOT 1
#endif /* LIBVIR_CHECK_VERSION */
+/* structure used for aggregating notification-thread data*/
+typedef struct virt_notif_thread_s {
+ pthread_t event_loop_tid;
+ int domain_event_cb_id;
+ pthread_mutex_t active_mutex; /* protects 'is_active' member access*/
+ bool is_active;
+} virt_notif_thread_t;
+
static const char *config_keys[] = {"Connection",
"RefreshInterval",
NULL};
/* PersistentNotification is false by default */
-static _Bool persistent_notification = 0;
+static bool persistent_notification = false;
-/* libvirt event loop */
-static pthread_t event_loop_tid;
-
-static int domain_event_cb_id;
+/* Thread used for handling libvirt notifications events */
+static virt_notif_thread_t notif_thread;
const char *domain_states[] = {
[VIR_DOMAIN_NOSTATE] = "no state",
case VIR_DOMAIN_EVENT_SHUTDOWN:
ret = VIR_DOMAIN_SHUTDOWN;
break;
+#ifdef HAVE_DOM_STATE_PMSUSPENDED
case VIR_DOMAIN_EVENT_PMSUSPENDED:
ret = VIR_DOMAIN_PMSUSPENDED;
break;
+#endif
+#ifdef HAVE_DOM_REASON_CRASHED
case VIR_DOMAIN_EVENT_CRASHED:
ret = VIR_DOMAIN_CRASHED;
break;
+#endif
default:
ret = VIR_DOMAIN_NOSTATE;
}
return ret;
}
+#ifdef HAVE_DOM_REASON
static int map_domain_event_detail_to_reason(int event, int detail) {
int ret;
switch (event) {
case VIR_DOMAIN_EVENT_STARTED_BOOTED: /* Normal startup from boot */
ret = VIR_DOMAIN_RUNNING_BOOTED;
break;
- case VIR_DOMAIN_EVENT_STARTED_MIGRATED: /* Incoming migration from another host */
+ case VIR_DOMAIN_EVENT_STARTED_MIGRATED: /* Incoming migration from another
+ host */
ret = VIR_DOMAIN_RUNNING_MIGRATED;
break;
case VIR_DOMAIN_EVENT_STARTED_RESTORED: /* Restored from a state file */
case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT: /* Restored from snapshot */
ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT;
break;
+#ifdef HAVE_DOM_REASON_RUNNING_WAKEUP
case VIR_DOMAIN_EVENT_STARTED_WAKEUP: /* Started due to wakeup event */
ret = VIR_DOMAIN_RUNNING_WAKEUP;
break;
+#endif
default:
ret = VIR_DOMAIN_RUNNING_UNKNOWN;
}
break;
case VIR_DOMAIN_EVENT_SUSPENDED:
switch (detail) {
- case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: /* Normal suspend due to admin pause */
+ case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: /* Normal suspend due to admin
+ pause */
ret = VIR_DOMAIN_PAUSED_USER;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: /* Suspended for offline migration */
+ case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: /* Suspended for offline
+ migration */
ret = VIR_DOMAIN_PAUSED_MIGRATION;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: /* Suspended due to a disk I/O error */
+ case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: /* Suspended due to a disk I/O
+ error */
ret = VIR_DOMAIN_PAUSED_IOERROR;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: /* Suspended due to a watchdog firing */
+ case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: /* Suspended due to a watchdog
+ firing */
ret = VIR_DOMAIN_PAUSED_WATCHDOG;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: /* Restored from paused state file */
+ case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: /* Restored from paused state
+ file */
ret = VIR_DOMAIN_PAUSED_UNKNOWN;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: /* Restored from paused snapshot */
+ case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: /* Restored from paused
+ snapshot */
ret = VIR_DOMAIN_PAUSED_FROM_SNAPSHOT;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: /* Suspended after failure during libvirt API call */
+ case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: /* Suspended after failure during
+ libvirt API call */
ret = VIR_DOMAIN_PAUSED_UNKNOWN;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: /* Suspended for post-copy migration */
+#ifdef HAVE_DOM_REASON_POSTCOPY
+ case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: /* Suspended for post-copy
+ migration */
ret = VIR_DOMAIN_PAUSED_POSTCOPY;
break;
- case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: /* Suspended after failed post-copy */
+ case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: /* Suspended after failed
+ post-copy */
ret = VIR_DOMAIN_PAUSED_POSTCOPY_FAILED;
break;
+#endif
default:
ret = VIR_DOMAIN_PAUSED_UNKNOWN;
}
break;
case VIR_DOMAIN_EVENT_RESUMED:
switch (detail) {
- case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: /* Normal resume due to admin unpause */
+ case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: /* Normal resume due to admin
+ unpause */
ret = VIR_DOMAIN_RUNNING_UNPAUSED;
break;
- case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: /* Resumed for completion of migration */
+ case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: /* Resumed for completion of
+ migration */
ret = VIR_DOMAIN_RUNNING_MIGRATED;
break;
case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT: /* Resumed from snapshot */
ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT;
break;
- case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY: /* Resumed, but migration is still running in post-copy mode */
+#ifdef HAVE_DOM_REASON_POSTCOPY
+ case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY: /* Resumed, but migration is still
+ running in post-copy mode */
ret = VIR_DOMAIN_RUNNING_POSTCOPY;
break;
+#endif
default:
ret = VIR_DOMAIN_RUNNING_UNKNOWN;
}
break;
case VIR_DOMAIN_EVENT_SHUTDOWN:
switch (detail) {
- case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown sequence */
+ case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown
+ sequence */
ret = VIR_DOMAIN_SHUTDOWN_USER;
break;
default:
ret = VIR_DOMAIN_SHUTDOWN_UNKNOWN;
}
break;
+#ifdef HAVE_DOM_STATE_PMSUSPENDED
case VIR_DOMAIN_EVENT_PMSUSPENDED:
switch (detail) {
- case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: /* Guest was PM suspended to memory */
+ case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: /* Guest was PM suspended to
+ memory */
ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN;
break;
case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK: /* Guest was PM suspended to disk */
ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN;
}
break;
+#endif
case VIR_DOMAIN_EVENT_CRASHED:
switch (detail) {
case VIR_DOMAIN_EVENT_CRASHED_PANICKED: /* Guest was panicked */
return ret;
}
-#ifdef HAVE_DOM_REASON
#define DOMAIN_STATE_REASON_MAX_SIZE 20
const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = {
[VIR_DOMAIN_NOSTATE][VIR_DOMAIN_NOSTATE_UNKNOWN] =
[VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_POSTCOPY] =
"running in post-copy migration mode",
#endif
-
[VIR_DOMAIN_BLOCKED][VIR_DOMAIN_BLOCKED_UNKNOWN] =
"the reason is unknown",
[VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY_FAILED] =
"paused after failed post-copy",
#endif
-
[VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_UNKNOWN] =
"the reason is unknown",
[VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_USER] =
} while (0)
/* Connection. */
-static virConnectPtr conn = 0;
-static char *conn_string = NULL;
+static virConnectPtr conn;
+static char *conn_string;
static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC;
/* Node information required for %CPU */
static int interval = 60;
/* List of domains, if specified. */
-static ignorelist_t *il_domains = NULL;
+static ignorelist_t *il_domains;
/* List of block devices, if specified. */
-static ignorelist_t *il_block_devices = NULL;
+static ignorelist_t *il_block_devices;
/* List of network interface devices, if specified. */
-static ignorelist_t *il_interface_devices = NULL;
+static ignorelist_t *il_interface_devices;
static int ignore_device_match(ignorelist_t *, const char *domname,
const char *devpath);
typedef struct domain_s {
virDomainPtr ptr;
virDomainInfo info;
- _Bool active;
+ bool active;
} domain_t;
struct lv_read_state {
static void free_domains(struct lv_read_state *state);
static int add_domain(struct lv_read_state *state, virDomainPtr dom,
- _Bool active);
+ bool active);
static void free_block_devices(struct lv_read_state *state);
static int add_block_device(struct lv_read_state *state, virDomainPtr dom,
};
/* BlockDeviceFormatBasename */
-_Bool blockdevice_format_basename = 0;
+static bool blockdevice_format_basename;
static enum bd_field blockdevice_format = target;
static enum if_field interface_format = if_name;
}
static void init_value_list(value_list_t *vl, virDomainPtr dom) {
- int n;
const char *name;
char uuid[VIR_UUID_STRING_BUFLEN];
if (hostname_format[i] == hf_none)
continue;
- n = DATA_MAX_NAME_LEN - strlen(vl->host) - 2;
-
- if (i > 0 && n >= 1) {
- strncat(vl->host, ":", 1);
- n--;
- }
+ if (i > 0)
+ SSTRNCAT(vl->host, ":", sizeof(vl->host));
switch (hostname_format[i]) {
case hf_none:
break;
case hf_hostname:
- strncat(vl->host, hostname_g, n);
+ SSTRNCAT(vl->host, hostname_g, sizeof(vl->host));
break;
case hf_name:
name = virDomainGetName(dom);
if (name)
- strncat(vl->host, name, n);
+ SSTRNCAT(vl->host, name, sizeof(vl->host));
break;
case hf_uuid:
if (virDomainGetUUIDString(dom, uuid) == 0)
- strncat(vl->host, uuid, n);
+ SSTRNCAT(vl->host, uuid, sizeof(vl->host));
break;
}
}
- vl->host[sizeof(vl->host) - 1] = '\0';
-
/* Construct the plugin instance field according to PluginInstanceFormat. */
for (int i = 0; i < PLGINST_MAX_FIELDS; ++i) {
if (plugin_instance_format[i] == plginst_none)
continue;
- n = sizeof(vl->plugin_instance) - strlen(vl->plugin_instance) - 2;
-
- if (i > 0 && n >= 1) {
- strncat(vl->plugin_instance, ":", 1);
- n--;
- }
+ if (i > 0)
+ SSTRNCAT(vl->plugin_instance, ":", sizeof(vl->plugin_instance));
switch (plugin_instance_format[i]) {
case plginst_none:
case plginst_name:
name = virDomainGetName(dom);
if (name)
- strncat(vl->plugin_instance, name, n);
+ SSTRNCAT(vl->plugin_instance, name, sizeof(vl->plugin_instance));
break;
case plginst_uuid:
if (virDomainGetUUIDString(dom, uuid) == 0)
- strncat(vl->plugin_instance, uuid, n);
+ SSTRNCAT(vl->plugin_instance, uuid, sizeof(vl->plugin_instance));
break;
}
}
- vl->plugin_instance[sizeof(vl->plugin_instance) - 1] = '\0';
-
} /* void init_value_list */
static int init_notif(notification_t *notif, const virDomainPtr domain,
}
static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) {
- if ((state < 0) || (state >= STATIC_ARRAY_SIZE(domain_states))) {
+ if ((state < 0) || ((size_t)state >= STATIC_ARRAY_SIZE(domain_states))) {
ERROR(PLUGIN_NAME ": Array index out of bounds: state=%d", state);
return;
}
char msg[DATA_MAX_NAME_LEN];
const char *state_str = domain_states[state];
#ifdef HAVE_DOM_REASON
- if ((reason < 0) || (reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) {
+ if ((reason < 0) ||
+ ((size_t)reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) {
ERROR(PLUGIN_NAME ": Array index out of bounds: reason=%d", reason);
return;
}
return 0;
}
if (strcasecmp(key, "BlockDeviceFormatBasename") == 0) {
- blockdevice_format_basename = IS_TRUE(value);
+ blockdevice_format_basename = IS_TRUE(value) ? true : false;
return 0;
}
if (strcasecmp(key, "InterfaceDevice") == 0) {
unsigned char *cpu_maps, int cpu_map_len) {
for (int cpu = 0; cpu < max_cpus; ++cpu) {
char type_instance[DATA_MAX_NAME_LEN];
- _Bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu) ? 1 : 0;
+ bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu);
snprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu, cpu);
submit(dom, "cpu_affinity", type_instance, &(value_t){.gauge = is_set}, 1);
#define NM_ADD_STR_ITEMS(_items, _size) \
do { \
- for (int _i = 0; _i < _size; ++_i) { \
+ for (size_t _i = 0; _i < _size; ++_i) { \
DEBUG(PLUGIN_NAME \
" plugin: Adding notification metadata name=%s value=%s", \
_items[_i].name, _items[_i].value); \
{.name = "name", .value = fs_info->name},
{.name = "fstype", .value = fs_info->fstype}};
- for (int i = 0; i < fs_info->ndevAlias; ++i) {
+ for (size_t i = 0; i < fs_info->ndevAlias; ++i) {
fs_dev_alias[i].name = "devAlias";
fs_dev_alias[i].value = fs_info->devAlias[i];
}
return 0;
}
-static int domain_lifecycle_event_cb(__attribute__((unused)) virConnectPtr conn,
+static int domain_lifecycle_event_cb(__attribute__((unused)) virConnectPtr con_,
virDomainPtr dom, int event, int detail,
__attribute__((unused)) void *opaque) {
int domain_state = map_domain_event_to_state(event);
- int domain_reason = map_domain_event_detail_to_reason(event, detail);
+ int domain_reason = 0; /* 0 means UNKNOWN reason for any state */
+#ifdef HAVE_DOM_REASON
+ domain_reason = map_domain_event_detail_to_reason(event, detail);
+#endif
domain_state_submit_notif(dom, domain_state, domain_reason);
return 0;
return 0;
}
+static void virt_notif_thread_set_active(virt_notif_thread_t *thread_data,
+ const bool active) {
+ assert(thread_data != NULL);
+ pthread_mutex_lock(&thread_data->active_mutex);
+ thread_data->is_active = active;
+ pthread_mutex_unlock(&thread_data->active_mutex);
+}
+
+static bool virt_notif_thread_is_active(virt_notif_thread_t *thread_data) {
+ bool active = false;
+
+ assert(thread_data != NULL);
+ pthread_mutex_lock(&thread_data->active_mutex);
+ active = thread_data->is_active;
+ pthread_mutex_unlock(&thread_data->active_mutex);
+
+ return active;
+}
+
/* worker function running default event implementation */
-static void *event_loop_worker(__attribute__((unused)) void *arg) {
- while (1) {
+static void *event_loop_worker(void *arg) {
+ virt_notif_thread_t *thread_data = (virt_notif_thread_t *)arg;
+
+ while (virt_notif_thread_is_active(thread_data)) {
if (virEventRunDefaultImpl() < 0) {
virErrorPtr err = virGetLastError();
ERROR(PLUGIN_NAME " plugin: failed to run event loop: %s\n",
return NULL;
}
+static int virt_notif_thread_init(virt_notif_thread_t *thread_data) {
+ int ret;
+
+ assert(thread_data != NULL);
+ ret = pthread_mutex_init(&thread_data->active_mutex, NULL);
+ if (ret != 0) {
+ ERROR(PLUGIN_NAME ": Failed to initialize mutex, err %u", ret);
+ return ret;
+ }
+
+ /**
+ * '0' and positive integers are meaningful ID's, therefore setting
+ * domain_event_cb_id to '-1'
+ */
+ thread_data->domain_event_cb_id = -1;
+ pthread_mutex_lock(&thread_data->active_mutex);
+ thread_data->is_active = false;
+ pthread_mutex_unlock(&thread_data->active_mutex);
+
+ return 0;
+}
+
/* register domain event callback and start event loop thread */
-static int start_event_loop(void) {
- domain_event_cb_id = virConnectDomainEventRegisterAny(
+static int start_event_loop(virt_notif_thread_t *thread_data) {
+ assert(thread_data != NULL);
+ thread_data->domain_event_cb_id = virConnectDomainEventRegisterAny(
conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE,
VIR_DOMAIN_EVENT_CALLBACK(domain_lifecycle_event_cb), NULL, NULL);
- if (domain_event_cb_id == -1) {
+ if (thread_data->domain_event_cb_id == -1) {
ERROR(PLUGIN_NAME " plugin: error while callback registering");
return -1;
}
- if (pthread_create(&event_loop_tid, NULL, event_loop_worker, NULL)) {
+ virt_notif_thread_set_active(thread_data, 1);
+ if (pthread_create(&thread_data->event_loop_tid, NULL, event_loop_worker,
+ thread_data)) {
ERROR(PLUGIN_NAME " plugin: failed event loop thread creation");
- virConnectDomainEventDeregisterAny(conn, domain_event_cb_id);
+ virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
return -1;
}
}
/* stop event loop thread and deregister callback */
-static void stop_event_loop(void) {
- if (pthread_cancel(event_loop_tid) != 0)
- ERROR(PLUGIN_NAME " plugin: cancelling thread %lu failed",
- event_loop_tid);
-
- if (pthread_join(event_loop_tid, NULL) != 0)
- ERROR(PLUGIN_NAME " plugin: stopping thread %lu failed",
- event_loop_tid);
-
- if (conn != NULL && domain_event_cb_id != -1)
- virConnectDomainEventDeregisterAny(conn, domain_event_cb_id);
+static void stop_event_loop(virt_notif_thread_t *thread_data) {
+ /* stopping loop and de-registering event handler*/
+ virt_notif_thread_set_active(thread_data, 0);
+ if (conn != NULL && thread_data->domain_event_cb_id != -1)
+ virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
+
+ if (pthread_join(notif_thread.event_loop_tid, NULL) != 0)
+ ERROR(PLUGIN_NAME " plugin: stopping notification thread failed");
}
static int persistent_domains_state_notification(void) {
int status = 0;
int n;
#ifdef HAVE_LIST_ALL_DOMAINS
- virDomainPtr *domains;
+ virDomainPtr *domains = NULL;
n = virConnectListAllDomains(conn, &domains,
- VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT);
+ VIR_CONNECT_LIST_DOMAINS_PERSISTENT);
if (n < 0) {
VIRT_ERROR(conn, "reading list of persistent domains");
status = -1;
- }
- else {
+ } else {
DEBUG(PLUGIN_NAME " plugin: getting state of %i persistent domains", n);
/* Fetch each persistent domain's state and notify it */
int n_notified = n;
ERROR(PLUGIN_NAME " plugin: could not notify state of domain %s",
virDomainGetName(domains[i]));
}
+ virDomainFree(domains[i]);
}
sfree(domains);
if (n > 0) {
int *domids;
/* Get list of domains. */
- domids = malloc(sizeof(*domids) * n);
+ domids = calloc(n, sizeof(*domids));
if (domids == NULL) {
- ERROR(PLUGIN_NAME " plugin: malloc failed.");
+ ERROR(PLUGIN_NAME " plugin: calloc failed.");
return -1;
}
n = virConnectListDomains(conn, domids, n);
continue;
}
status = virDomainGetInfo(dom, &info);
- if (status != 0) {
+ if (status == 0)
+ /* virDomainGetState is not available. Submit 0, which corresponds to
+ * unknown reason. */
+ domain_state_submit_notif(dom, info.state, 0);
+ else
ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
status);
- continue;
- }
- /* virDomainGetState is not available. Submit 0, which corresponds to
- * unknown reason. */
- domain_state_submit_notif(dom, info.state, 0);
+
+ virDomainFree(dom);
}
sfree(domids);
}
inst = ud->data;
state = &inst->read_state;
- _Bool reconnect = conn == NULL ? 1 : 0;
+ bool reconnect = conn == NULL ? true : false;
/* event implementation must be registered before connection is opened */
if (inst->id == 0) {
if (!persistent_notification && reconnect)
return -1;
if (!persistent_notification && reconnect && conn != NULL)
- if (start_event_loop() != 0)
+ if (start_event_loop(¬if_thread) != 0)
return -1;
}
/* Need to refresh domain or device lists? */
if ((last_refresh == (time_t)0) ||
((interval > 0) && ((last_refresh + interval) <= t))) {
- if (inst->id == 0 && persistent_notification) {
- int status = persistent_domains_state_notification();
- if (status != 0)
- DEBUG(PLUGIN_NAME " plugin: persistent_domains_state_notifications " \
- "returned with status %i", status);
- }
if (refresh_lists(inst) != 0) {
if (inst->id == 0) {
if (!persistent_notification)
- stop_event_loop();
+ stop_event_loop(¬if_thread);
lv_disconnect();
}
return -1;
last_refresh = t;
}
- #if COLLECT_DEBUG
- for (int i = 0; i < state->nr_domains; ++i)
- DEBUG(PLUGIN_NAME " plugin: domain %s",
- virDomainGetName(state->domains[i].ptr));
- for (int i = 0; i < state->nr_block_devices; ++i)
- DEBUG(PLUGIN_NAME " plugin: block device %d %s:%s",
- i, virDomainGetName(state->block_devices[i].dom),
- state->block_devices[i].path);
- for (int i = 0; i < state->nr_interface_devices; ++i)
- DEBUG(PLUGIN_NAME " plugin: interface device %d %s:%s",
- i, virDomainGetName(state->interface_devices[i].dom),
- state->interface_devices[i].path);
- #endif
+ /* persistent domains state notifications are handled by instance 0 */
+ if (inst->id == 0 && persistent_notification) {
+ int status = persistent_domains_state_notification();
+ if (status != 0)
+ DEBUG(PLUGIN_NAME " plugin: persistent_domains_state_notifications "
+ "returned with status %i",
+ status);
+ }
+
+#if COLLECT_DEBUG
+ for (int i = 0; i < state->nr_domains; ++i)
+ DEBUG(PLUGIN_NAME " plugin: domain %s",
+ virDomainGetName(state->domains[i].ptr));
+ for (int i = 0; i < state->nr_block_devices; ++i)
+ DEBUG(PLUGIN_NAME " plugin: block device %d %s:%s", i,
+ virDomainGetName(state->block_devices[i].dom),
+ state->block_devices[i].path);
+ for (int i = 0; i < state->nr_interface_devices; ++i)
+ DEBUG(PLUGIN_NAME " plugin: interface device %d %s:%s", i,
+ virDomainGetName(state->interface_devices[i].dom),
+ state->interface_devices[i].path);
+#endif
/* Get domains' metrics */
for (int i = 0; i < state->nr_domains; ++i) {
domain_t *dom = &state->domains[i];
- int status;
+ int status = 0;
if (dom->active)
status = get_domain_metrics(dom);
+#ifdef HAVE_DOM_REASON
else
status = get_domain_state(dom->ptr);
+#endif
if (status != 0)
ERROR(PLUGIN_NAME " failed to get metrics for domain=%s",
DEBUG(PLUGIN_NAME " plugin: starting event loop");
- if (!persistent_notification)
- if (start_event_loop() != 0)
+ if (!persistent_notification) {
+ virt_notif_thread_init(¬if_thread);
+ if (start_event_loop(¬if_thread) != 0)
return -1;
+ }
DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances);
virDomainPtr *domains, *domains_inactive;
int m = virConnectListAllDomains(conn, &domains_inactive,
VIR_CONNECT_LIST_DOMAINS_INACTIVE);
- n = virConnectListAllDomains(conn, &domains,
- VIR_CONNECT_LIST_DOMAINS_ACTIVE);
+ n = virConnectListAllDomains(conn, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE);
#else
int *domids;
/* Get list of domains. */
- domids = malloc(sizeof(*domids) * n);
+ domids = calloc(n, sizeof(*domids));
if (domids == NULL) {
- ERROR(PLUGIN_NAME " plugin: malloc failed.");
+ ERROR(PLUGIN_NAME " plugin: calloc failed.");
return -1;
}
#ifndef HAVE_LIST_ALL_DOMAINS
sfree(domids);
#else
+ for (int i = 0; i < m; ++i)
+ virDomainFree(domains_inactive[i]);
sfree(domains_inactive);
#endif
return -1;
for (int i = 0; i < m; ++i)
if (add_domain(state, domains_inactive[i], 0) < 0) {
ERROR(PLUGIN_NAME " plugin: malloc failed.");
+ virDomainFree(domains_inactive[i]);
+ domains_inactive[i] = NULL;
continue;
}
#endif
}
#endif
+ if (add_domain(state, dom, 1) < 0) {
+ /*
+ * When domain is already tracked, then there is
+ * no problem with memory handling (will be freed
+ * with the rest of domains cached data)
+ * But in case of error like this (error occurred
+ * before adding domain to track) we have to take
+ * care it ourselves and call virDomainFree
+ */
+ ERROR(PLUGIN_NAME " plugin: malloc failed.");
+ virDomainFree(dom);
+ goto cont;
+ }
+
name = virDomainGetName(dom);
if (name == NULL) {
VIRT_ERROR(conn, "virDomainGetName");
if (!lv_instance_include_domain(inst, name, tag))
goto cont;
- if (add_domain(state, dom, 1) < 0) {
- ERROR(PLUGIN_NAME " plugin: malloc failed.");
- goto cont;
- }
-
/* Block devices. */
const char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
if (blockdevice_format == source)
}
#ifdef HAVE_LIST_ALL_DOMAINS
+ /* NOTE: domains_active and domains_inactive data will be cleared during
+ refresh of all domains (inside lv_clean_read_state function) so we need
+ to free here only allocated arrays */
sfree(domains);
sfree(domains_inactive);
#else
}
static int add_domain(struct lv_read_state *state, virDomainPtr dom,
- _Bool active) {
+ bool active) {
domain_t *new_ptr;
int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1);
struct interface_device *new_ptr;
int new_size =
sizeof(state->interface_devices[0]) * (state->nr_interface_devices + 1);
- char *path_copy, *address_copy, number_string[15];
+ char *path_copy, *address_copy, number_string[21];
if ((path == NULL) || (address == NULL))
return EINVAL;
static int ignore_device_match(ignorelist_t *il, const char *domname,
const char *devpath) {
char *name;
- int n, r;
+ int r;
if ((domname == NULL) || (devpath == NULL))
return 0;
- n = strlen(domname) + strlen(devpath) + 2;
+ size_t n = strlen(domname) + strlen(devpath) + 2;
name = malloc(n);
if (name == NULL) {
ERROR(PLUGIN_NAME " plugin: malloc failed.");
DEBUG(PLUGIN_NAME " plugin: stopping event loop");
if (!persistent_notification)
- stop_event_loop();
+ stop_event_loop(¬if_thread);
lv_disconnect();