1 /**
2 * collectd - src/libvirt.c
3 * Copyright (C) 2006-2008 Red Hat Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the license is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Richard W.M. Jones <rjones@redhat.com>
20 **/
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "configfile.h"
26 #include "utils_ignorelist.h"
27 #include "utils_complain.h"
29 #include <libvirt/libvirt.h>
30 #include <libvirt/virterror.h>
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #include <libxml/xpath.h>
35 /* Plugin name */
36 #define PLUGIN_NAME "libvirt"
38 static const char *config_keys[] = {
39 "Connection",
41 "RefreshInterval",
43 "Domain",
44 "BlockDevice",
45 "InterfaceDevice",
46 "IgnoreSelected",
48 "HostnameFormat",
49 "InterfaceFormat",
51 "PluginInstanceFormat",
53 NULL
54 };
55 #define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
57 /* Connection. */
58 static virConnectPtr conn = 0;
59 static char *conn_string = NULL;
60 static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC;
62 /* Seconds between list refreshes, 0 disables completely. */
63 static int interval = 60;
65 /* List of domains, if specified. */
66 static ignorelist_t *il_domains = NULL;
67 /* List of block devices, if specified. */
68 static ignorelist_t *il_block_devices = NULL;
69 /* List of network interface devices, if specified. */
70 static ignorelist_t *il_interface_devices = NULL;
72 static int ignore_device_match (ignorelist_t *,
73 const char *domname, const char *devpath);
75 /* Actual list of domains found on last refresh. */
76 static virDomainPtr *domains = NULL;
77 static int nr_domains = 0;
79 static void free_domains (void);
80 static int add_domain (virDomainPtr dom);
82 /* Actual list of block devices found on last refresh. */
83 struct block_device {
84 virDomainPtr dom; /* domain */
85 char *path; /* name of block device */
86 };
88 static struct block_device *block_devices = NULL;
89 static int nr_block_devices = 0;
91 static void free_block_devices (void);
92 static int add_block_device (virDomainPtr dom, const char *path);
94 /* Actual list of network interfaces found on last refresh. */
95 struct interface_device {
96 virDomainPtr dom; /* domain */
97 char *path; /* name of interface device */
98 char *address; /* mac address of interface device */
99 char *number; /* interface device number */
100 };
102 static struct interface_device *interface_devices = NULL;
103 static int nr_interface_devices = 0;
105 static void free_interface_devices (void);
106 static int add_interface_device (virDomainPtr dom, const char *path, const char *address, unsigned int number);
108 /* HostnameFormat. */
109 #define HF_MAX_FIELDS 3
111 enum hf_field {
112 hf_none = 0,
113 hf_hostname,
114 hf_name,
115 hf_uuid
116 };
118 static enum hf_field hostname_format[HF_MAX_FIELDS] =
119 { hf_name };
121 /* PluginInstanceFormat */
122 #define PLGINST_MAX_FIELDS 2
124 enum plginst_field {
125 plginst_none = 0,
126 plginst_name,
127 plginst_uuid
128 };
130 static enum plginst_field plugin_instance_format[PLGINST_MAX_FIELDS] =
131 { plginst_name };
133 /* InterfaceFormat. */
134 enum if_field {
135 if_address,
136 if_name,
137 if_number
138 };
140 static enum if_field interface_format = if_name;
142 /* Time that we last refreshed. */
143 static time_t last_refresh = (time_t) 0;
145 static int refresh_lists (void);
147 /* ERROR(...) macro for virterrors. */
148 #define VIRT_ERROR(conn,s) do { \
149 virErrorPtr err; \
150 err = (conn) ? virConnGetLastError ((conn)) : virGetLastError (); \
151 if (err) ERROR ("%s: %s", (s), err->message); \
152 } while(0)
154 static void
155 init_value_list (value_list_t *vl, virDomainPtr dom)
156 {
157 int i, n;
158 const char *name;
159 char uuid[VIR_UUID_STRING_BUFLEN];
161 sstrncpy (vl->plugin, PLUGIN_NAME, sizeof (vl->plugin));
163 vl->host[0] = '\0';
165 /* Construct the hostname field according to HostnameFormat. */
166 for (i = 0; i < HF_MAX_FIELDS; ++i) {
167 if (hostname_format[i] == hf_none)
168 continue;
170 n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
172 if (i > 0 && n >= 1) {
173 strncat (vl->host, ":", 1);
174 n--;
175 }
177 switch (hostname_format[i]) {
178 case hf_none: break;
179 case hf_hostname:
180 strncat (vl->host, hostname_g, n);
181 break;
182 case hf_name:
183 name = virDomainGetName (dom);
184 if (name)
185 strncat (vl->host, name, n);
186 break;
187 case hf_uuid:
188 if (virDomainGetUUIDString (dom, uuid) == 0)
189 strncat (vl->host, uuid, n);
190 break;
191 }
192 }
194 vl->host[sizeof (vl->host) - 1] = '\0';
196 /* Construct the plugin instance field according to PluginInstanceFormat. */
197 for (i = 0; i < PLGINST_MAX_FIELDS; ++i) {
198 if (plugin_instance_format[i] == plginst_none)
199 continue;
201 n = sizeof(vl->plugin_instance) - strlen (vl->plugin_instance) - 2;
203 if (i > 0 && n >= 1) {
204 strncat (vl->plugin_instance, ":", 1);
205 n--;
206 }
208 switch (plugin_instance_format[i]) {
209 case plginst_none: break;
210 case plginst_name:
211 name = virDomainGetName (dom);
212 if (name)
213 strncat (vl->plugin_instance, name, n);
214 break;
215 case plginst_uuid:
216 if (virDomainGetUUIDString (dom, uuid) == 0)
217 strncat (vl->plugin_instance, uuid, n);
218 break;
219 }
220 }
222 vl->plugin_instance[sizeof (vl->plugin_instance) - 1] = '\0';
224 } /* void init_value_list */
226 static void
227 memory_submit (gauge_t memory, virDomainPtr dom)
228 {
229 value_t values[1];
230 value_list_t vl = VALUE_LIST_INIT;
232 init_value_list (&vl, dom);
234 values[0].gauge = memory;
236 vl.values = values;
237 vl.values_len = 1;
239 sstrncpy (vl.type, "memory", sizeof (vl.type));
240 sstrncpy (vl.type_instance, "total", sizeof (vl.type_instance));
242 plugin_dispatch_values (&vl);
243 }
245 static void
246 cpu_submit (unsigned long long cpu_time,
247 virDomainPtr dom, const char *type)
248 {
249 value_t values[1];
250 value_list_t vl = VALUE_LIST_INIT;
252 init_value_list (&vl, dom);
254 values[0].derive = cpu_time;
256 vl.values = values;
257 vl.values_len = 1;
259 sstrncpy (vl.type, type, sizeof (vl.type));
261 plugin_dispatch_values (&vl);
262 }
264 static void
265 vcpu_submit (derive_t cpu_time,
266 virDomainPtr dom, int vcpu_nr, const char *type)
267 {
268 value_t values[1];
269 value_list_t vl = VALUE_LIST_INIT;
271 init_value_list (&vl, dom);
273 values[0].derive = cpu_time;
274 vl.values = values;
275 vl.values_len = 1;
277 sstrncpy (vl.type, type, sizeof (vl.type));
278 ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
280 plugin_dispatch_values (&vl);
281 }
283 static void
284 submit_derive2 (const char *type, derive_t v0, derive_t v1,
285 virDomainPtr dom, const char *devname)
286 {
287 value_t values[2];
288 value_list_t vl = VALUE_LIST_INIT;
290 init_value_list (&vl, dom);
292 values[0].derive = v0;
293 values[1].derive = v1;
294 vl.values = values;
295 vl.values_len = 2;
297 sstrncpy (vl.type, type, sizeof (vl.type));
298 sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
300 plugin_dispatch_values (&vl);
301 } /* void submit_derive2 */
303 static int
304 lv_init (void)
305 {
306 if (virInitialize () != 0)
307 return -1;
309 return 0;
310 }
312 static int
313 lv_config (const char *key, const char *value)
314 {
315 if (virInitialize () != 0)
316 return 1;
318 if (il_domains == NULL)
319 il_domains = ignorelist_create (1);
320 if (il_block_devices == NULL)
321 il_block_devices = ignorelist_create (1);
322 if (il_interface_devices == NULL)
323 il_interface_devices = ignorelist_create (1);
325 if (strcasecmp (key, "Connection") == 0) {
326 char *tmp = strdup (value);
327 if (tmp == NULL) {
328 ERROR (PLUGIN_NAME " plugin: Connection strdup failed.");
329 return 1;
330 }
331 sfree (conn_string);
332 conn_string = tmp;
333 return 0;
334 }
336 if (strcasecmp (key, "RefreshInterval") == 0) {
337 char *eptr = NULL;
338 interval = strtol (value, &eptr, 10);
339 if (eptr == NULL || *eptr != '\0') return 1;
340 return 0;
341 }
343 if (strcasecmp (key, "Domain") == 0) {
344 if (ignorelist_add (il_domains, value)) return 1;
345 return 0;
346 }
347 if (strcasecmp (key, "BlockDevice") == 0) {
348 if (ignorelist_add (il_block_devices, value)) return 1;
349 return 0;
350 }
351 if (strcasecmp (key, "InterfaceDevice") == 0) {
352 if (ignorelist_add (il_interface_devices, value)) return 1;
353 return 0;
354 }
356 if (strcasecmp (key, "IgnoreSelected") == 0) {
357 if (IS_TRUE (value))
358 {
359 ignorelist_set_invert (il_domains, 0);
360 ignorelist_set_invert (il_block_devices, 0);
361 ignorelist_set_invert (il_interface_devices, 0);
362 }
363 else
364 {
365 ignorelist_set_invert (il_domains, 1);
366 ignorelist_set_invert (il_block_devices, 1);
367 ignorelist_set_invert (il_interface_devices, 1);
368 }
369 return 0;
370 }
372 if (strcasecmp (key, "HostnameFormat") == 0) {
373 char *value_copy;
374 char *fields[HF_MAX_FIELDS];
375 int i, n;
377 value_copy = strdup (value);
378 if (value_copy == NULL) {
379 ERROR (PLUGIN_NAME " plugin: strdup failed.");
380 return -1;
381 }
383 n = strsplit (value_copy, fields, HF_MAX_FIELDS);
384 if (n < 1) {
385 sfree (value_copy);
386 ERROR (PLUGIN_NAME " plugin: HostnameFormat: no fields");
387 return -1;
388 }
390 for (i = 0; i < n; ++i) {
391 if (strcasecmp (fields[i], "hostname") == 0)
392 hostname_format[i] = hf_hostname;
393 else if (strcasecmp (fields[i], "name") == 0)
394 hostname_format[i] = hf_name;
395 else if (strcasecmp (fields[i], "uuid") == 0)
396 hostname_format[i] = hf_uuid;
397 else {
398 sfree (value_copy);
399 ERROR (PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]);
400 return -1;
401 }
402 }
403 sfree (value_copy);
405 for (i = n; i < HF_MAX_FIELDS; ++i)
406 hostname_format[i] = hf_none;
408 return 0;
409 }
411 if (strcasecmp (key, "PluginInstanceFormat") == 0) {
412 char *value_copy;
413 char *fields[PLGINST_MAX_FIELDS];
414 int i, n;
416 value_copy = strdup (value);
417 if (value_copy == NULL) {
418 ERROR (PLUGIN_NAME " plugin: strdup failed.");
419 return -1;
420 }
422 n = strsplit (value_copy, fields, PLGINST_MAX_FIELDS);
423 if (n < 1) {
424 sfree (value_copy);
425 ERROR (PLUGIN_NAME " plugin: PluginInstanceFormat: no fields");
426 return -1;
427 }
429 for (i = 0; i < n; ++i) {
430 if (strcasecmp (fields[i], "name") == 0)
431 plugin_instance_format[i] = plginst_name;
432 else if (strcasecmp (fields[i], "uuid") == 0)
433 plugin_instance_format[i] = plginst_uuid;
434 else {
435 sfree (value_copy);
436 ERROR (PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]);
437 return -1;
438 }
439 }
440 sfree (value_copy);
442 for (i = n; i < PLGINST_MAX_FIELDS; ++i)
443 plugin_instance_format[i] = plginst_none;
445 return 0;
446 }
448 if (strcasecmp (key, "InterfaceFormat") == 0) {
449 if (strcasecmp (value, "name") == 0)
450 interface_format = if_name;
451 else if (strcasecmp (value, "address") == 0)
452 interface_format = if_address;
453 else if (strcasecmp (value, "number") == 0)
454 interface_format = if_number;
455 else {
456 ERROR (PLUGIN_NAME " plugin: unknown InterfaceFormat: %s", value);
457 return -1;
458 }
459 return 0;
460 }
462 /* Unrecognised option. */
463 return -1;
464 }
466 static int
467 lv_read (void)
468 {
469 time_t t;
470 int i;
472 if (conn == NULL) {
473 /* `conn_string == NULL' is acceptable. */
474 conn = virConnectOpenReadOnly (conn_string);
475 if (conn == NULL) {
476 c_complain (LOG_ERR, &conn_complain,
477 PLUGIN_NAME " plugin: Unable to connect: "
478 "virConnectOpenReadOnly failed.");
479 return -1;
480 }
481 }
482 c_release (LOG_NOTICE, &conn_complain,
483 PLUGIN_NAME " plugin: Connection established.");
485 time (&t);
487 /* Need to refresh domain or device lists? */
488 if ((last_refresh == (time_t) 0) ||
489 ((interval > 0) && ((last_refresh + interval) <= t))) {
490 if (refresh_lists () != 0) {
491 if (conn != NULL)
492 virConnectClose (conn);
493 conn = NULL;
494 return -1;
495 }
496 last_refresh = t;
497 }
499 #if 0
500 for (i = 0; i < nr_domains; ++i)
501 fprintf (stderr, "domain %s\n", virDomainGetName (domains[i]));
502 for (i = 0; i < nr_block_devices; ++i)
503 fprintf (stderr, "block device %d %s:%s\n",
504 i, virDomainGetName (block_devices[i].dom),
505 block_devices[i].path);
506 for (i = 0; i < nr_interface_devices; ++i)
507 fprintf (stderr, "interface device %d %s:%s\n",
508 i, virDomainGetName (interface_devices[i].dom),
509 interface_devices[i].path);
510 #endif
512 /* Get CPU usage, memory, VCPU usage for each domain. */
513 for (i = 0; i < nr_domains; ++i) {
514 virDomainInfo info;
515 virVcpuInfoPtr vinfo = NULL;
516 int status;
517 int j;
519 status = virDomainGetInfo (domains[i], &info);
520 if (status != 0)
521 {
522 ERROR (PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
523 status);
524 continue;
525 }
527 cpu_submit (info.cpuTime, domains[i], "virt_cpu_total");
528 memory_submit ((gauge_t) info.memory * 1024, domains[i]);
530 vinfo = malloc (info.nrVirtCpu * sizeof (vinfo[0]));
531 if (vinfo == NULL) {
532 ERROR (PLUGIN_NAME " plugin: malloc failed.");
533 continue;
534 }
536 status = virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
537 /* cpu map = */ NULL, /* cpu map length = */ 0);
538 if (status < 0)
539 {
540 ERROR (PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
541 status);
542 free (vinfo);
543 continue;
544 }
546 for (j = 0; j < info.nrVirtCpu; ++j)
547 vcpu_submit (vinfo[j].cpuTime,
548 domains[i], vinfo[j].number, "virt_vcpu");
550 sfree (vinfo);
551 }
553 /* Get block device stats for each domain. */
554 for (i = 0; i < nr_block_devices; ++i) {
555 struct _virDomainBlockStats stats;
557 if (virDomainBlockStats (block_devices[i].dom, block_devices[i].path,
558 &stats, sizeof stats) != 0)
559 continue;
561 if ((stats.rd_req != -1) && (stats.wr_req != -1))
562 submit_derive2 ("disk_ops",
563 (derive_t) stats.rd_req, (derive_t) stats.wr_req,
564 block_devices[i].dom, block_devices[i].path);
566 if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
567 submit_derive2 ("disk_octets",
568 (derive_t) stats.rd_bytes, (derive_t) stats.wr_bytes,
569 block_devices[i].dom, block_devices[i].path);
570 } /* for (nr_block_devices) */
572 /* Get interface stats for each domain. */
573 for (i = 0; i < nr_interface_devices; ++i) {
574 struct _virDomainInterfaceStats stats;
575 char *display_name = NULL;
578 switch (interface_format) {
579 case if_address:
580 display_name = interface_devices[i].address;
581 break;
582 case if_number:
583 display_name = interface_devices[i].number;
584 break;
585 case if_name:
586 default:
587 display_name = interface_devices[i].path;
588 }
590 if (virDomainInterfaceStats (interface_devices[i].dom,
591 interface_devices[i].path,
592 &stats, sizeof stats) != 0)
593 continue;
595 if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
596 submit_derive2 ("if_octets",
597 (derive_t) stats.rx_bytes, (derive_t) stats.tx_bytes,
598 interface_devices[i].dom, display_name);
600 if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
601 submit_derive2 ("if_packets",
602 (derive_t) stats.rx_packets, (derive_t) stats.tx_packets,
603 interface_devices[i].dom, display_name);
605 if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
606 submit_derive2 ("if_errors",
607 (derive_t) stats.rx_errs, (derive_t) stats.tx_errs,
608 interface_devices[i].dom, display_name);
610 if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
611 submit_derive2 ("if_dropped",
612 (derive_t) stats.rx_drop, (derive_t) stats.tx_drop,
613 interface_devices[i].dom, display_name);
614 } /* for (nr_interface_devices) */
616 return 0;
617 }
619 static int
620 refresh_lists (void)
621 {
622 int n;
624 n = virConnectNumOfDomains (conn);
625 if (n < 0) {
626 VIRT_ERROR (conn, "reading number of domains");
627 return -1;
628 }
630 if (n > 0) {
631 int i;
632 int *domids;
634 /* Get list of domains. */
635 domids = malloc (sizeof (int) * n);
636 if (domids == 0) {
637 ERROR (PLUGIN_NAME " plugin: malloc failed.");
638 return -1;
639 }
641 n = virConnectListDomains (conn, domids, n);
642 if (n < 0) {
643 VIRT_ERROR (conn, "reading list of domains");
644 sfree (domids);
645 return -1;
646 }
648 free_block_devices ();
649 free_interface_devices ();
650 free_domains ();
652 /* Fetch each domain and add it to the list, unless ignore. */
653 for (i = 0; i < n; ++i) {
654 virDomainPtr dom = NULL;
655 const char *name;
656 char *xml = NULL;
657 xmlDocPtr xml_doc = NULL;
658 xmlXPathContextPtr xpath_ctx = NULL;
659 xmlXPathObjectPtr xpath_obj = NULL;
660 int j;
662 dom = virDomainLookupByID (conn, domids[i]);
663 if (dom == NULL) {
664 VIRT_ERROR (conn, "virDomainLookupByID");
665 /* Could be that the domain went away -- ignore it anyway. */
666 continue;
667 }
669 name = virDomainGetName (dom);
670 if (name == NULL) {
671 VIRT_ERROR (conn, "virDomainGetName");
672 goto cont;
673 }
675 if (il_domains && ignorelist_match (il_domains, name) != 0)
676 goto cont;
678 if (add_domain (dom) < 0) {
679 ERROR (PLUGIN_NAME " plugin: malloc failed.");
680 goto cont;
681 }
683 /* Get a list of devices for this domain. */
684 xml = virDomainGetXMLDesc (dom, 0);
685 if (!xml) {
686 VIRT_ERROR (conn, "virDomainGetXMLDesc");
687 goto cont;
688 }
690 /* Yuck, XML. Parse out the devices. */
691 xml_doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, XML_PARSE_NONET);
692 if (xml_doc == NULL) {
693 VIRT_ERROR (conn, "xmlReadDoc");
694 goto cont;
695 }
697 xpath_ctx = xmlXPathNewContext (xml_doc);
699 /* Block devices. */
700 xpath_obj = xmlXPathEval
701 ((xmlChar *) "/domain/devices/disk/target[@dev]",
702 xpath_ctx);
703 if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
704 xpath_obj->nodesetval == NULL)
705 goto cont;
707 for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
708 xmlNodePtr node;
709 char *path = NULL;
711 node = xpath_obj->nodesetval->nodeTab[j];
712 if (!node) continue;
713 path = (char *) xmlGetProp (node, (xmlChar *) "dev");
714 if (!path) continue;
716 if (il_block_devices &&
717 ignore_device_match (il_block_devices, name, path) != 0)
718 goto cont2;
720 add_block_device (dom, path);
721 cont2:
722 if (path) xmlFree (path);
723 }
724 xmlXPathFreeObject (xpath_obj);
726 /* Network interfaces. */
727 xpath_obj = xmlXPathEval
728 ((xmlChar *) "/domain/devices/interface[target[@dev]]",
729 xpath_ctx);
730 if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
731 xpath_obj->nodesetval == NULL)
732 goto cont;
734 xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
736 for (j = 0; j < xml_interfaces->nodeNr; ++j) {
737 char *path = NULL;
738 char *address = NULL;
739 xmlNodePtr xml_interface;
741 xml_interface = xml_interfaces->nodeTab[j];
742 if (!xml_interface) continue;
743 xmlNodePtr child = NULL;
745 for (child = xml_interface->children; child; child = child->next) {
746 if (child->type != XML_ELEMENT_NODE) continue;
748 if (xmlStrEqual(child->name, (const xmlChar *) "target")) {
749 path = (char *) xmlGetProp (child, (const xmlChar *) "dev");
750 if (!path) continue;
751 } else if (xmlStrEqual(child->name, (const xmlChar *) "mac")) {
752 address = (char *) xmlGetProp (child, (const xmlChar *) "address");
753 if (!address) continue;
754 }
755 }
757 if (il_interface_devices &&
758 (ignore_device_match (il_interface_devices, name, path) != 0 ||
759 ignore_device_match (il_interface_devices, name, address) != 0))
760 goto cont3;
762 add_interface_device (dom, path, address, j+1);
763 cont3:
764 if (path) xmlFree (path);
765 if (address) xmlFree (address);
766 }
768 cont:
769 if (xpath_obj) xmlXPathFreeObject (xpath_obj);
770 if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
771 if (xml_doc) xmlFreeDoc (xml_doc);
772 sfree (xml);
773 }
775 sfree (domids);
776 }
778 return 0;
779 }
781 static void
782 free_domains ()
783 {
784 int i;
786 if (domains) {
787 for (i = 0; i < nr_domains; ++i)
788 virDomainFree (domains[i]);
789 sfree (domains);
790 }
791 domains = NULL;
792 nr_domains = 0;
793 }
795 static int
796 add_domain (virDomainPtr dom)
797 {
798 virDomainPtr *new_ptr;
799 int new_size = sizeof (domains[0]) * (nr_domains+1);
801 if (domains)
802 new_ptr = realloc (domains, new_size);
803 else
804 new_ptr = malloc (new_size);
806 if (new_ptr == NULL)
807 return -1;
809 domains = new_ptr;
810 domains[nr_domains] = dom;
811 return nr_domains++;
812 }
814 static void
815 free_block_devices ()
816 {
817 int i;
819 if (block_devices) {
820 for (i = 0; i < nr_block_devices; ++i)
821 sfree (block_devices[i].path);
822 sfree (block_devices);
823 }
824 block_devices = NULL;
825 nr_block_devices = 0;
826 }
828 static int
829 add_block_device (virDomainPtr dom, const char *path)
830 {
831 struct block_device *new_ptr;
832 int new_size = sizeof (block_devices[0]) * (nr_block_devices+1);
833 char *path_copy;
835 path_copy = strdup (path);
836 if (!path_copy)
837 return -1;
839 if (block_devices)
840 new_ptr = realloc (block_devices, new_size);
841 else
842 new_ptr = malloc (new_size);
844 if (new_ptr == NULL) {
845 sfree (path_copy);
846 return -1;
847 }
848 block_devices = new_ptr;
849 block_devices[nr_block_devices].dom = dom;
850 block_devices[nr_block_devices].path = path_copy;
851 return nr_block_devices++;
852 }
854 static void
855 free_interface_devices ()
856 {
857 int i;
859 if (interface_devices) {
860 for (i = 0; i < nr_interface_devices; ++i) {
861 sfree (interface_devices[i].path);
862 sfree (interface_devices[i].address);
863 sfree (interface_devices[i].number);
864 }
865 sfree (interface_devices);
866 }
867 interface_devices = NULL;
868 nr_interface_devices = 0;
869 }
871 static int
872 add_interface_device (virDomainPtr dom, const char *path, const char *address, unsigned int number)
873 {
874 struct interface_device *new_ptr;
875 int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
876 char *path_copy, *address_copy, number_string[15];
878 path_copy = strdup (path);
879 if (!path_copy) return -1;
881 address_copy = strdup (address);
882 if (!address_copy) {
883 sfree(path_copy);
884 return -1;
885 }
887 snprintf(number_string, sizeof (number_string), "interface-%u", number);
889 if (interface_devices)
890 new_ptr = realloc (interface_devices, new_size);
891 else
892 new_ptr = malloc (new_size);
894 if (new_ptr == NULL) {
895 sfree (path_copy);
896 sfree (address_copy);
897 return -1;
898 }
899 interface_devices = new_ptr;
900 interface_devices[nr_interface_devices].dom = dom;
901 interface_devices[nr_interface_devices].path = path_copy;
902 interface_devices[nr_interface_devices].address = address_copy;
903 interface_devices[nr_interface_devices].number = strdup(number_string);
904 return nr_interface_devices++;
905 }
907 static int
908 ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
909 {
910 char *name;
911 int n, r;
913 n = sizeof (char) * (strlen (domname) + strlen (devpath) + 2);
914 name = malloc (n);
915 if (name == NULL) {
916 ERROR (PLUGIN_NAME " plugin: malloc failed.");
917 return 0;
918 }
919 ssnprintf (name, n, "%s:%s", domname, devpath);
920 r = ignorelist_match (il, name);
921 sfree (name);
922 return r;
923 }
925 static int
926 lv_shutdown (void)
927 {
928 free_block_devices ();
929 free_interface_devices ();
930 free_domains ();
932 if (conn != NULL)
933 virConnectClose (conn);
934 conn = NULL;
936 ignorelist_free (il_domains);
937 il_domains = NULL;
938 ignorelist_free (il_block_devices);
939 il_block_devices = NULL;
940 ignorelist_free (il_interface_devices);
941 il_interface_devices = NULL;
943 return 0;
944 }
946 void
947 module_register (void)
948 {
949 plugin_register_config (PLUGIN_NAME,
950 lv_config,
951 config_keys, NR_CONFIG_KEYS);
952 plugin_register_init (PLUGIN_NAME, lv_init);
953 plugin_register_read (PLUGIN_NAME, lv_read);
954 plugin_register_shutdown (PLUGIN_NAME, lv_shutdown);
955 }
957 /*
958 * vim: shiftwidth=4 tabstop=8 softtabstop=4 expandtab fdm=marker
959 */