Code

add a missing colon and fix indentation
[collectd.git] / src / libvirt.c
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 static const char *config_keys[] = {
36     "Connection",
38     "RefreshInterval",
40     "Domain",
41     "BlockDevice",
42     "InterfaceDevice",
43     "IgnoreSelected",
45     "HostnameFormat",
46     "InterfaceFormat",
48     NULL
49 };
50 #define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
52 /* Connection. */
53 static virConnectPtr conn = 0;
54 static char *conn_string = NULL;
55 static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC;
57 /* Seconds between list refreshes, 0 disables completely. */
58 static int interval = 60;
60 /* List of domains, if specified. */
61 static ignorelist_t *il_domains = NULL;
62 /* List of block devices, if specified. */
63 static ignorelist_t *il_block_devices = NULL;
64 /* List of network interface devices, if specified. */
65 static ignorelist_t *il_interface_devices = NULL;
67 static int ignore_device_match (ignorelist_t *,
68                                 const char *domname, const char *devpath);
70 /* Actual list of domains found on last refresh. */
71 static virDomainPtr *domains = NULL;
72 static int nr_domains = 0;
74 static void free_domains (void);
75 static int add_domain (virDomainPtr dom);
77 /* Actual list of block devices found on last refresh. */
78 struct block_device {
79     virDomainPtr dom;           /* domain */
80     char *path;                 /* name of block device */
81 };
83 static struct block_device *block_devices = NULL;
84 static int nr_block_devices = 0;
86 static void free_block_devices (void);
87 static int add_block_device (virDomainPtr dom, const char *path);
89 /* Actual list of network interfaces found on last refresh. */
90 struct interface_device {
91     virDomainPtr dom;           /* domain */
92     char *path;                 /* name of interface device */
93     char *address;              /* mac address of interface device */
94     char *number;               /* interface device number */
95 };
97 static struct interface_device *interface_devices = NULL;
98 static int nr_interface_devices = 0;
100 static void free_interface_devices (void);
101 static int add_interface_device (virDomainPtr dom, const char *path, const char *address, unsigned int number);
103 /* HostnameFormat. */
104 #define HF_MAX_FIELDS 3
106 enum hf_field {
107     hf_none = 0,
108     hf_hostname,
109     hf_name,
110     hf_uuid
111 };
113 static enum hf_field hostname_format[HF_MAX_FIELDS] =
114     { hf_name };
116 /* InterfaceFormat. */
117 enum if_field {
118     if_address,
119     if_name,
120     if_number
121 };
123 static enum if_field interface_format = if_name;
125 /* Time that we last refreshed. */
126 static time_t last_refresh = (time_t) 0;
128 static int refresh_lists (void);
130 /* ERROR(...) macro for virterrors. */
131 #define VIRT_ERROR(conn,s) do {                 \
132         virErrorPtr err;                        \
133         err = (conn) ? virConnGetLastError ((conn)) : virGetLastError (); \
134         if (err) ERROR ("%s: %s", (s), err->message);                   \
135     } while(0)
137 static void
138 init_value_list (value_list_t *vl, virDomainPtr dom)
140     int i, n;
141     const char *name;
142     char uuid[VIR_UUID_STRING_BUFLEN];
144     vl->interval = interval_g;
146     sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
148     vl->host[0] = '\0';
150     /* Construct the hostname field according to HostnameFormat. */
151     for (i = 0; i < HF_MAX_FIELDS; ++i) {
152         if (hostname_format[i] == hf_none)
153             continue;
155         n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
157         if (i > 0 && n >= 1) {
158             strncat (vl->host, ":", 1);
159             n--;
160         }
162         switch (hostname_format[i]) {
163         case hf_none: break;
164         case hf_hostname:
165             strncat (vl->host, hostname_g, n);
166             break;
167         case hf_name:
168             name = virDomainGetName (dom);
169             if (name)
170                 strncat (vl->host, name, n);
171             break;
172         case hf_uuid:
173             if (virDomainGetUUIDString (dom, uuid) == 0)
174                 strncat (vl->host, uuid, n);
175             break;
176         }
177     }
179     vl->host[sizeof (vl->host) - 1] = '\0';
180 } /* void init_value_list */
182 static void
183 cpu_submit (unsigned long long cpu_time,
184             virDomainPtr dom, const char *type)
186     value_t values[1];
187     value_list_t vl = VALUE_LIST_INIT;
189     init_value_list (&vl, dom);
191     values[0].derive = cpu_time;
193     vl.values = values;
194     vl.values_len = 1;
196     sstrncpy (vl.type, type, sizeof (vl.type));
198     plugin_dispatch_values (&vl);
201 static void
202 vcpu_submit (derive_t cpu_time,
203              virDomainPtr dom, int vcpu_nr, const char *type)
205     value_t values[1];
206     value_list_t vl = VALUE_LIST_INIT;
208     init_value_list (&vl, dom);
210     values[0].derive = cpu_time;
211     vl.values = values;
212     vl.values_len = 1;
214     sstrncpy (vl.type, type, sizeof (vl.type));
215     ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
217     plugin_dispatch_values (&vl);
220 static void
221 submit_derive2 (const char *type, derive_t v0, derive_t v1,
222              virDomainPtr dom, const char *devname)
224     value_t values[2];
225     value_list_t vl = VALUE_LIST_INIT;
227     init_value_list (&vl, dom);
229     values[0].derive = v0;
230     values[1].derive = v1;
231     vl.values = values;
232     vl.values_len = 2;
234     sstrncpy (vl.type, type, sizeof (vl.type));
235     sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
237     plugin_dispatch_values (&vl);
238 } /* void submit_derive2 */
240 static int
241 lv_init (void)
243     if (virInitialize () != 0)
244         return -1;
246         return 0;
249 static int
250 lv_config (const char *key, const char *value)
252     if (virInitialize () != 0)
253         return 1;
255     if (il_domains == NULL)
256         il_domains = ignorelist_create (1);
257     if (il_block_devices == NULL)
258         il_block_devices = ignorelist_create (1);
259     if (il_interface_devices == NULL)
260         il_interface_devices = ignorelist_create (1);
262     if (strcasecmp (key, "Connection") == 0) {
263         char *tmp = strdup (value);
264         if (tmp == NULL) {
265             ERROR ("libvirt plugin: Connection strdup failed.");
266             return 1;
267         }
268         sfree (conn_string);
269         conn_string = tmp;
270         return 0;
271     }
273     if (strcasecmp (key, "RefreshInterval") == 0) {
274         char *eptr = NULL;
275         interval = strtol (value, &eptr, 10);
276         if (eptr == NULL || *eptr != '\0') return 1;
277         return 0;
278     }
280     if (strcasecmp (key, "Domain") == 0) {
281         if (ignorelist_add (il_domains, value)) return 1;
282         return 0;
283     }
284     if (strcasecmp (key, "BlockDevice") == 0) {
285         if (ignorelist_add (il_block_devices, value)) return 1;
286         return 0;
287     }
288     if (strcasecmp (key, "InterfaceDevice") == 0) {
289         if (ignorelist_add (il_interface_devices, value)) return 1;
290         return 0;
291     }
293     if (strcasecmp (key, "IgnoreSelected") == 0) {
294         if (IS_TRUE (value))
295         {
296             ignorelist_set_invert (il_domains, 0);
297             ignorelist_set_invert (il_block_devices, 0);
298             ignorelist_set_invert (il_interface_devices, 0);
299         }
300         else
301         {
302             ignorelist_set_invert (il_domains, 1);
303             ignorelist_set_invert (il_block_devices, 1);
304             ignorelist_set_invert (il_interface_devices, 1);
305         }
306         return 0;
307     }
309     if (strcasecmp (key, "HostnameFormat") == 0) {
310         char *value_copy;
311         char *fields[HF_MAX_FIELDS];
312         int i, n;
314         value_copy = strdup (value);
315         if (value_copy == NULL) {
316             ERROR ("libvirt plugin: strdup failed.");
317             return -1;
318         }
320         n = strsplit (value_copy, fields, HF_MAX_FIELDS);
321         if (n < 1) {
322             sfree (value_copy);
323             ERROR ("HostnameFormat: no fields");
324             return -1;
325         }
327         for (i = 0; i < n; ++i) {
328             if (strcasecmp (fields[i], "hostname") == 0)
329                 hostname_format[i] = hf_hostname;
330             else if (strcasecmp (fields[i], "name") == 0)
331                 hostname_format[i] = hf_name;
332             else if (strcasecmp (fields[i], "uuid") == 0)
333                 hostname_format[i] = hf_uuid;
334             else {
335                 sfree (value_copy);
336                 ERROR ("unknown HostnameFormat field: %s", fields[i]);
337                 return -1;
338             }
339         }
340         sfree (value_copy);
342         for (i = n; i < HF_MAX_FIELDS; ++i)
343             hostname_format[i] = hf_none;
345         return 0;
346     }
348     if (strcasecmp (key, "InterfaceFormat") == 0) {
349         if (strcasecmp (value, "name") == 0)
350             interface_format = if_name;
351         else if (strcasecmp (value, "address") == 0)
352             interface_format = if_address;
353         else if (strcasecmp (value, "number") == 0)
354             interface_format = if_number;
355         else {
356             ERROR ("unknown InterfaceFormat: %s", value);
357             return -1;
358         }
359         return 0;
360     }
362     /* Unrecognised option. */
363     return -1;
366 static int
367 lv_read (void)
369     time_t t;
370     int i;
372     if (conn == NULL) {
373         /* `conn_string == NULL' is acceptable. */
374         conn = virConnectOpenReadOnly (conn_string);
375         if (conn == NULL) {
376             c_complain (LOG_ERR, &conn_complain,
377                     "libvirt plugin: Unable to connect: "
378                     "virConnectOpenReadOnly failed.");
379             return -1;
380         }
381     }
382     c_release (LOG_NOTICE, &conn_complain,
383             "libvirt plugin: Connection established.");
385     time (&t);
387     /* Need to refresh domain or device lists? */
388     if ((last_refresh == (time_t) 0) ||
389             ((interval > 0) && ((last_refresh + interval) <= t))) {
390         if (refresh_lists () != 0) {
391             if (conn != NULL)
392                 virConnectClose (conn);
393             conn = NULL;
394             return -1;
395         }
396         last_refresh = t;
397     }
399 #if 0
400     for (i = 0; i < nr_domains; ++i)
401         fprintf (stderr, "domain %s\n", virDomainGetName (domains[i]));
402     for (i = 0; i < nr_block_devices; ++i)
403         fprintf  (stderr, "block device %d %s:%s\n",
404                   i, virDomainGetName (block_devices[i].dom),
405                   block_devices[i].path);
406     for (i = 0; i < nr_interface_devices; ++i)
407         fprintf (stderr, "interface device %d %s:%s\n",
408                  i, virDomainGetName (interface_devices[i].dom),
409                  interface_devices[i].path);
410 #endif
412     /* Get CPU usage, VCPU usage for each domain. */
413     for (i = 0; i < nr_domains; ++i) {
414         virDomainInfo info;
415         virVcpuInfoPtr vinfo = NULL;
416         int status;
417         int j;
419         status = virDomainGetInfo (domains[i], &info);
420         if (status != 0)
421         {
422             ERROR ("libvirt plugin: virDomainGetInfo failed with status %i.",
423                     status);
424             continue;
425         }
427         cpu_submit (info.cpuTime, domains[i], "virt_cpu_total");
429         vinfo = malloc (info.nrVirtCpu * sizeof (vinfo[0]));
430         if (vinfo == NULL) {
431             ERROR ("libvirt plugin: malloc failed.");
432             continue;
433         }
435         status = virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
436                 /* cpu map = */ NULL, /* cpu map length = */ 0);
437         if (status < 0)
438         {
439             ERROR ("libvirt plugin: virDomainGetVcpus failed with status %i.",
440                     status);
441             free (vinfo);
442             continue;
443         }
445         for (j = 0; j < info.nrVirtCpu; ++j)
446             vcpu_submit (vinfo[j].cpuTime,
447                     domains[i], vinfo[j].number, "virt_vcpu");
449         sfree (vinfo);
450     }
452     /* Get block device stats for each domain. */
453     for (i = 0; i < nr_block_devices; ++i) {
454         struct _virDomainBlockStats stats;
456         if (virDomainBlockStats (block_devices[i].dom, block_devices[i].path,
457                     &stats, sizeof stats) != 0)
458             continue;
460         if ((stats.rd_req != -1) && (stats.wr_req != -1))
461             submit_derive2 ("disk_ops",
462                     (derive_t) stats.rd_req, (derive_t) stats.wr_req,
463                     block_devices[i].dom, block_devices[i].path);
465         if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
466             submit_derive2 ("disk_octets",
467                     (derive_t) stats.rd_bytes, (derive_t) stats.wr_bytes,
468                     block_devices[i].dom, block_devices[i].path);
469     } /* for (nr_block_devices) */
471     /* Get interface stats for each domain. */
472     for (i = 0; i < nr_interface_devices; ++i) {
473         struct _virDomainInterfaceStats stats;
474         char *display_name = NULL;
477         switch (interface_format) {
478             case if_address:
479                 display_name = interface_devices[i].address;
480                 break;
481             case if_number:
482                 display_name = interface_devices[i].number;
483                 break;
484             case if_name:
485             default:
486                 display_name = interface_devices[i].path;
487         }
489         if (virDomainInterfaceStats (interface_devices[i].dom,
490                     interface_devices[i].path,
491                     &stats, sizeof stats) != 0)
492             continue;
494         if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
495             submit_derive2 ("if_octets",
496                     (derive_t) stats.rx_bytes, (derive_t) stats.tx_bytes,
497                     interface_devices[i].dom, display_name);
499         if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
500             submit_derive2 ("if_packets",
501                     (derive_t) stats.rx_packets, (derive_t) stats.tx_packets,
502                     interface_devices[i].dom, display_name);
504         if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
505             submit_derive2 ("if_errors",
506                     (derive_t) stats.rx_errs, (derive_t) stats.tx_errs,
507                     interface_devices[i].dom, display_name);
509         if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
510             submit_derive2 ("if_dropped",
511                     (derive_t) stats.rx_drop, (derive_t) stats.tx_drop,
512                     interface_devices[i].dom, display_name);
513     } /* for (nr_interface_devices) */
515     return 0;
518 static int
519 refresh_lists (void)
521     int n;
523     n = virConnectNumOfDomains (conn);
524     if (n < 0) {
525         VIRT_ERROR (conn, "reading number of domains");
526         return -1;
527     }
529     if (n > 0) {
530         int i;
531         int *domids;
533         /* Get list of domains. */
534         domids = malloc (sizeof (int) * n);
535         if (domids == 0) {
536             ERROR ("libvirt plugin: malloc failed.");
537             return -1;
538         }
540         n = virConnectListDomains (conn, domids, n);
541         if (n < 0) {
542             VIRT_ERROR (conn, "reading list of domains");
543             sfree (domids);
544             return -1;
545         }
547         free_block_devices ();
548         free_interface_devices ();
549         free_domains ();
551         /* Fetch each domain and add it to the list, unless ignore. */
552         for (i = 0; i < n; ++i) {
553             virDomainPtr dom = NULL;
554             const char *name;
555             char *xml = NULL;
556             xmlDocPtr xml_doc = NULL;
557             xmlXPathContextPtr xpath_ctx = NULL;
558             xmlXPathObjectPtr xpath_obj = NULL;
559             int j;
561             dom = virDomainLookupByID (conn, domids[i]);
562             if (dom == NULL) {
563                 VIRT_ERROR (conn, "virDomainLookupByID");
564                 /* Could be that the domain went away -- ignore it anyway. */
565                 continue;
566             }
568             name = virDomainGetName (dom);
569             if (name == NULL) {
570                 VIRT_ERROR (conn, "virDomainGetName");
571                 goto cont;
572             }
574             if (il_domains && ignorelist_match (il_domains, name) != 0)
575                 goto cont;
577             if (add_domain (dom) < 0) {
578                 ERROR ("libvirt plugin: malloc failed.");
579                 goto cont;
580             }
582             /* Get a list of devices for this domain. */
583             xml = virDomainGetXMLDesc (dom, 0);
584             if (!xml) {
585                 VIRT_ERROR (conn, "virDomainGetXMLDesc");
586                 goto cont;
587             }
589             /* Yuck, XML.  Parse out the devices. */
590             xml_doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, XML_PARSE_NONET);
591             if (xml_doc == NULL) {
592                 VIRT_ERROR (conn, "xmlReadDoc");
593                 goto cont;
594             }
596             xpath_ctx = xmlXPathNewContext (xml_doc);
598             /* Block devices. */
599             xpath_obj = xmlXPathEval
600                 ((xmlChar *) "/domain/devices/disk/target[@dev]",
601                  xpath_ctx);
602             if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
603                 xpath_obj->nodesetval == NULL)
604                 goto cont;
606             for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
607                 xmlNodePtr node;
608                 char *path = NULL;
610                 node = xpath_obj->nodesetval->nodeTab[j];
611                 if (!node) continue;
612                 path = (char *) xmlGetProp (node, (xmlChar *) "dev");
613                 if (!path) continue;
615                 if (il_block_devices &&
616                     ignore_device_match (il_block_devices, name, path) != 0)
617                     goto cont2;
619                 add_block_device (dom, path);
620             cont2:
621                 if (path) xmlFree (path);
622             }
623             xmlXPathFreeObject (xpath_obj);
625             /* Network interfaces. */
626             xpath_obj = xmlXPathEval
627                 ((xmlChar *) "/domain/devices/interface[target[@dev]]",
628                  xpath_ctx);
629             if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
630                 xpath_obj->nodesetval == NULL)
631                 goto cont;
633             xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
635             for (j = 0; j < xml_interfaces->nodeNr; ++j) {
636                 char *path = NULL;
637                 char *address = NULL;
638                 xmlNodePtr xml_interface;
640                 xml_interface = xml_interfaces->nodeTab[j];
641                 if (!xml_interface) continue;
642                 xmlNodePtr child = NULL;
644                 for (child = xml_interface->children; child; child = child->next) {
645                     if (child->type != XML_ELEMENT_NODE) continue;
647                     if (xmlStrEqual(child->name, (const xmlChar *) "target")) {
648                         path = (char *) xmlGetProp (child, (const xmlChar *) "dev");
649                         if (!path) continue;
650                     } else if (xmlStrEqual(child->name, (const xmlChar *) "mac")) {
651                         address = (char *) xmlGetProp (child, (const xmlChar *) "address");
652                         if (!address) continue;
653                     }
654                 }
656                 if (il_interface_devices &&
657                     (ignore_device_match (il_interface_devices, name, path) != 0 ||
658                      ignore_device_match (il_interface_devices, name, address) != 0))
659                     goto cont3;
661                 add_interface_device (dom, path, address, j+1);
662                 cont3:
663                     if (path) xmlFree (path);
664                     if (address) xmlFree (address);
665             }
667         cont:
668             if (xpath_obj) xmlXPathFreeObject (xpath_obj);
669             if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
670             if (xml_doc) xmlFreeDoc (xml_doc);
671             sfree (xml);
672         }
674         sfree (domids);
675     }
677     return 0;
680 static void
681 free_domains ()
683     int i;
685     if (domains) {
686         for (i = 0; i < nr_domains; ++i)
687             virDomainFree (domains[i]);
688         sfree (domains);
689     }
690     domains = NULL;
691     nr_domains = 0;
694 static int
695 add_domain (virDomainPtr dom)
697     virDomainPtr *new_ptr;
698     int new_size = sizeof (domains[0]) * (nr_domains+1);
700     if (domains)
701         new_ptr = realloc (domains, new_size);
702     else
703         new_ptr = malloc (new_size);
705     if (new_ptr == NULL)
706         return -1;
708     domains = new_ptr;
709     domains[nr_domains] = dom;
710     return nr_domains++;
713 static void
714 free_block_devices ()
716     int i;
718     if (block_devices) {
719         for (i = 0; i < nr_block_devices; ++i)
720             sfree (block_devices[i].path);
721         sfree (block_devices);
722     }
723     block_devices = NULL;
724     nr_block_devices = 0;
727 static int
728 add_block_device (virDomainPtr dom, const char *path)
730     struct block_device *new_ptr;
731     int new_size = sizeof (block_devices[0]) * (nr_block_devices+1);
732     char *path_copy;
734     path_copy = strdup (path);
735     if (!path_copy)
736         return -1;
738     if (block_devices)
739         new_ptr = realloc (block_devices, new_size);
740     else
741         new_ptr = malloc (new_size);
743     if (new_ptr == NULL) {
744         sfree (path_copy);
745         return -1;
746     }
747     block_devices = new_ptr;
748     block_devices[nr_block_devices].dom = dom;
749     block_devices[nr_block_devices].path = path_copy;
750     return nr_block_devices++;
753 static void
754 free_interface_devices ()
756     int i;
758     if (interface_devices) {
759         for (i = 0; i < nr_interface_devices; ++i) {
760             sfree (interface_devices[i].path);
761             sfree (interface_devices[i].address);
762             sfree (interface_devices[i].number);
763         }
764         sfree (interface_devices);
765     }
766     interface_devices = NULL;
767     nr_interface_devices = 0;
770 static int
771 add_interface_device (virDomainPtr dom, const char *path, const char *address, unsigned int number)
773     struct interface_device *new_ptr;
774     int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
775     char *path_copy, *address_copy, number_string[15];
777     path_copy = strdup (path);
778     if (!path_copy) return -1;
780     address_copy = strdup (address);
781     if (!address_copy) {
782         sfree(path_copy);
783         return -1;
784     }
786     snprintf(number_string, sizeof (number_string), "interface-%u", number);
788     if (interface_devices)
789         new_ptr = realloc (interface_devices, new_size);
790     else
791         new_ptr = malloc (new_size);
793     if (new_ptr == NULL) {
794         sfree (path_copy);
795         sfree (address_copy);
796         return -1;
797     }
798     interface_devices = new_ptr;
799     interface_devices[nr_interface_devices].dom = dom;
800     interface_devices[nr_interface_devices].path = path_copy;
801     interface_devices[nr_interface_devices].address = address_copy;
802     interface_devices[nr_interface_devices].number = strdup(number_string);
803     return nr_interface_devices++;
806 static int
807 ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
809     char *name;
810     int n, r;
812     n = sizeof (char) * (strlen (domname) + strlen (devpath) + 2);
813     name = malloc (n);
814     if (name == NULL) {
815         ERROR ("libvirt plugin: malloc failed.");
816         return 0;
817     }
818     ssnprintf (name, n, "%s:%s", domname, devpath);
819     r = ignorelist_match (il, name);
820     sfree (name);
821     return r;
824 static int
825 lv_shutdown (void)
827     free_block_devices ();
828     free_interface_devices ();
829     free_domains ();
831     if (conn != NULL)
832         virConnectClose (conn);
833     conn = NULL;
835     ignorelist_free (il_domains);
836     il_domains = NULL;
837     ignorelist_free (il_block_devices);
838     il_block_devices = NULL;
839     ignorelist_free (il_interface_devices);
840     il_interface_devices = NULL;
842     return 0;
845 void
846 module_register (void)
848     plugin_register_config ("libvirt",
849     lv_config,
850     config_keys, NR_CONFIG_KEYS);
851     plugin_register_init ("libvirt", lv_init);
852     plugin_register_read ("libvirt", lv_read);
853     plugin_register_shutdown ("libvirt", lv_shutdown);
856 /*
857  * vim: shiftwidth=4 tabstop=8 softtabstop=4 expandtab fdm=marker
858  */