Merge branch 'master' into master
authorPavel Rochnyak <pavel2000@ngs.ru>
Fri, 5 Jul 2019 16:09:00 +0000 (23:09 +0700)
committerGitHub <noreply@github.com>
Fri, 5 Jul 2019 16:09:00 +0000 (23:09 +0700)
1  2 
src/daemon/configfile.c
src/utils/cmds/cmds_test.c
src/utils/dns/dns.c
src/virt.c

diff --combined src/daemon/configfile.c
@@@ -200,7 -200,7 +200,7 @@@ static int dispatch_global_option(cons
      return global_option_set(ci->key, ci->values[0].value.string, 0);
    else if (ci->values[0].type == OCONFIG_TYPE_NUMBER) {
      char tmp[128];
 -    snprintf(tmp, sizeof(tmp), "%lf", ci->values[0].value.number);
 +    ssnprintf(tmp, sizeof(tmp), "%lf", ci->values[0].value.number);
      return global_option_set(ci->key, tmp, 0);
    } else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN) {
      if (ci->values[0].value.boolean)
@@@ -267,7 -267,8 +267,8 @@@ static int dispatch_loadplugin(oconfig_
  
    /* default to the global interval set before loading this plugin */
    plugin_ctx_t ctx = {
-       .interval = cf_get_default_interval(), .name = strdup(name),
+       .interval = cf_get_default_interval(),
+       .name = strdup(name),
    };
    if (ctx.name == NULL)
      return ENOMEM;
@@@ -311,13 -312,13 +312,13 @@@ static int dispatch_value_plugin(const 
  
      if (ci->values[i].type == OCONFIG_TYPE_STRING)
        status =
 -          snprintf(buffer_ptr, buffer_free, " %s", ci->values[i].value.string);
 +          ssnprintf(buffer_ptr, buffer_free, " %s", ci->values[i].value.string);
      else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
 -      status =
 -          snprintf(buffer_ptr, buffer_free, " %lf", ci->values[i].value.number);
 +      status = ssnprintf(buffer_ptr, buffer_free, " %lf",
 +                         ci->values[i].value.number);
      else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
 -      status = snprintf(buffer_ptr, buffer_free, " %s",
 -                        ci->values[i].value.boolean ? "true" : "false");
 +      status = ssnprintf(buffer_ptr, buffer_free, " %s",
 +                         ci->values[i].value.boolean ? "true" : "false");
  
      if ((status < 0) || (status >= buffer_free))
        return -1;
@@@ -413,9 -414,13 +414,13 @@@ static int dispatch_block_plugin(oconfi
    /* Hm, no complex plugin found. Dispatch the values one by one */
    for (int i = 0, ret = 0; i < ci->children_num; i++) {
      if (ci->children[i].children == NULL) {
-       ret = dispatch_value_plugin(name, ci->children + i);
-       if (ret != 0)
+       oconfig_item_t *child = ci->children + i;
+       ret = dispatch_value_plugin(name, child);
+       if (ret != 0) {
+         ERROR("Plugin %s failed to handle option %s, return code: %i", name,
+               child->key, ret);
          return ret;
+       }
      } else {
        WARNING("There is a `%s' block within the "
                "configuration for the %s plugin. "
@@@ -475,9 -480,9 +480,9 @@@ static int cf_ci_replace_child(oconfig_
      return 0;
    }
  
-   temp = realloc(dst->children,
-                  sizeof(oconfig_item_t) *
-                      (dst->children_num + src->children_num - 1));
+   temp =
+       realloc(dst->children, sizeof(oconfig_item_t) *
+                                  (dst->children_num + src->children_num - 1));
    if (temp == NULL) {
      ERROR("configfile: realloc failed.");
      return -1;
@@@ -516,9 -521,8 +521,8 @@@ static int cf_ci_append_children(oconfi
    if ((src == NULL) || (src->children_num == 0))
      return 0;
  
-   temp =
-       realloc(dst->children,
-               sizeof(oconfig_item_t) * (dst->children_num + src->children_num));
+   temp = realloc(dst->children, sizeof(oconfig_item_t) *
+                                     (dst->children_num + src->children_num));
    if (temp == NULL) {
      ERROR("configfile: realloc failed.");
      return -1;
@@@ -666,7 -670,7 +670,7 @@@ static oconfig_item_t *cf_read_dir(cons
      if ((de->d_name[0] == '.') || (de->d_name[0] == 0))
        continue;
  
 -    status = snprintf(name, sizeof(name), "%s/%s", dir, de->d_name);
 +    status = ssnprintf(name, sizeof(name), "%s/%s", dir, de->d_name);
      if ((status < 0) || ((size_t)status >= sizeof(name))) {
        ERROR("configfile: Not including `%s/%s' because its"
              " name is too long.",
@@@ -806,7 -810,7 +810,7 @@@ static oconfig_item_t *cf_read_generic(
  
    return root;
  } /* oconfig_item_t *cf_read_generic */
- /* #endif HAVE_WORDEXP_H */
  /* #endif HAVE_WORDEXP_H */
  
  #else  /* if !HAVE_WORDEXP_H */
  static oconfig_item_t *cf_read_generic(const char *path, const char *pattern,
@@@ -1235,7 -1239,7 +1239,7 @@@ int cf_util_get_service(const oconfig_i
      P_ERROR("cf_util_get_service: Out of memory.");
      return -1;
    }
 -  snprintf(service, 6, "%i", port);
 +  ssnprintf(service, 6, "%i", port);
  
    sfree(*ret_string);
    *ret_string = service;
   *   Sebastian 'tokkee' Harl <sh at tokkee.org>
   **/
  
+ // clang-format off
+ /*
+  * Explicit order is required or _FILE_OFFSET_BITS will have definition mismatches on Solaris
+  * See Github Issue #3193 for details
+  */
+ #include "utils/common/common.h"
  #include "testing.h"
  #include "utils/cmds/cmds.h"
- #include "utils/common/common.h"
+ // clang-format on
  
  static void error_cb(void *ud, cmd_status_t status, const char *format,
                       va_list ap) {
@@@ -51,114 -57,201 +57,201 @@@ static struct 
  } parse_data[] = {
      /* Valid FLUSH commands. */
      {
-         "FLUSH", NULL, CMD_OK, CMD_FLUSH,
+         "FLUSH",
+         NULL,
+         CMD_OK,
+         CMD_FLUSH,
      },
      {
-         "FLUSH identifier=myhost/magic/MAGIC", NULL, CMD_OK, CMD_FLUSH,
+         "FLUSH identifier=myhost/magic/MAGIC",
+         NULL,
+         CMD_OK,
+         CMD_FLUSH,
      },
      {
-         "FLUSH identifier=magic/MAGIC", &default_host_opts, CMD_OK, CMD_FLUSH,
+         "FLUSH identifier=magic/MAGIC",
+         &default_host_opts,
+         CMD_OK,
+         CMD_FLUSH,
      },
      {
-         "FLUSH timeout=123 plugin=\"A\"", NULL, CMD_OK, CMD_FLUSH,
+         "FLUSH timeout=123 plugin=\"A\"",
+         NULL,
+         CMD_OK,
+         CMD_FLUSH,
      },
      /* Invalid FLUSH commands. */
      {
          /* Missing hostname; no default. */
-         "FLUSH identifier=magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "FLUSH identifier=magic/MAGIC",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
          /* Missing 'identifier' key. */
-         "FLUSH myhost/magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "FLUSH myhost/magic/MAGIC",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
          /* Invalid timeout. */
-         "FLUSH timeout=A", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "FLUSH timeout=A",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
          /* Invalid identifier. */
-         "FLUSH identifier=invalid", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "FLUSH identifier=invalid",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
          /* Invalid option. */
-         "FLUSH invalid=option", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "FLUSH invalid=option",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
  
      /* Valid GETVAL commands. */
      {
-         "GETVAL myhost/magic/MAGIC", NULL, CMD_OK, CMD_GETVAL,
+         "GETVAL myhost/magic/MAGIC",
+         NULL,
+         CMD_OK,
+         CMD_GETVAL,
      },
      {
-         "GETVAL magic/MAGIC", &default_host_opts, CMD_OK, CMD_GETVAL,
+         "GETVAL magic/MAGIC",
+         &default_host_opts,
+         CMD_OK,
+         CMD_GETVAL,
      },
  
      /* Invalid GETVAL commands. */
      {
-         "GETVAL magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "GETVAL magic/MAGIC",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "GETVAL", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "GETVAL",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "GETVAL invalid", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "GETVAL invalid",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
  
      /* Valid LISTVAL commands. */
      {
-         "LISTVAL", NULL, CMD_OK, CMD_LISTVAL,
+         "LISTVAL",
+         NULL,
+         CMD_OK,
+         CMD_LISTVAL,
      },
  
      /* Invalid LISTVAL commands. */
      {
-         "LISTVAL invalid", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "LISTVAL invalid",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
  
      /* Valid PUTVAL commands. */
      {
-         "PUTVAL magic/MAGIC N:42", &default_host_opts, CMD_OK, CMD_PUTVAL,
+         "PUTVAL magic/MAGIC N:42",
+         &default_host_opts,
+         CMD_OK,
+         CMD_PUTVAL,
      },
      {
-         "PUTVAL myhost/magic/MAGIC N:42", NULL, CMD_OK, CMD_PUTVAL,
+         "PUTVAL myhost/magic/MAGIC N:42",
+         NULL,
+         CMD_OK,
+         CMD_PUTVAL,
      },
      {
-         "PUTVAL myhost/magic/MAGIC 1234:42", NULL, CMD_OK, CMD_PUTVAL,
+         "PUTVAL myhost/magic/MAGIC 1234:42",
+         NULL,
+         CMD_OK,
+         CMD_PUTVAL,
      },
      {
-         "PUTVAL myhost/magic/MAGIC 1234:42 2345:23", NULL, CMD_OK, CMD_PUTVAL,
+         "PUTVAL myhost/magic/MAGIC 1234:42 2345:23",
+         NULL,
+         CMD_OK,
+         CMD_PUTVAL,
      },
      {
-         "PUTVAL myhost/magic/MAGIC interval=2 1234:42", NULL, CMD_OK,
+         "PUTVAL myhost/magic/MAGIC interval=2 1234:42",
+         NULL,
+         CMD_OK,
          CMD_PUTVAL,
      },
      {
-         "PUTVAL myhost/magic/MAGIC interval=2 1234:42 interval=5 2345:23", NULL,
-         CMD_OK, CMD_PUTVAL,
+         "PUTVAL myhost/magic/MAGIC interval=2 1234:42 interval=5 2345:23",
+         NULL,
+         CMD_OK,
+         CMD_PUTVAL,
      },
  
      /* Invalid PUTVAL commands. */
      {
-         "PUTVAL magic/MAGIC N:42", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "PUTVAL magic/MAGIC N:42",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "PUTVAL", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "PUTVAL",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "PUTVAL invalid N:42", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "PUTVAL invalid N:42",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "PUTVAL myhost/magic/MAGIC A:42", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "PUTVAL myhost/magic/MAGIC A:42",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "PUTVAL myhost/magic/MAGIC 1234:A", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "PUTVAL myhost/magic/MAGIC 1234:A",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "PUTVAL myhost/magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "PUTVAL myhost/magic/MAGIC",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "PUTVAL 1234:A", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+         "PUTVAL 1234:A",
+         NULL,
+         CMD_PARSE_ERROR,
+         CMD_UNKNOWN,
      },
      {
-         "PUTVAL myhost/magic/UNKNOWN 1234:42", NULL, CMD_PARSE_ERROR,
+         "PUTVAL myhost/magic/UNKNOWN 1234:42",
+         NULL,
+         CMD_PARSE_ERROR,
          CMD_UNKNOWN,
      },
      /*
  
      /* Invalid commands. */
      {
-         "INVALID", NULL, CMD_UNKNOWN_COMMAND, CMD_UNKNOWN,
+         "INVALID",
+         NULL,
+         CMD_UNKNOWN_COMMAND,
+         CMD_UNKNOWN,
      },
      {
-         "INVALID interval=2", NULL, CMD_UNKNOWN_COMMAND, CMD_UNKNOWN,
+         "INVALID interval=2",
+         NULL,
+         CMD_UNKNOWN_COMMAND,
+         CMD_UNKNOWN,
      },
  };
  
@@@ -196,13 -295,14 +295,14 @@@ DEF_TEST(parse) 
      memset(&cmd, 0, sizeof(cmd));
  
      status = cmd_parse(input, &cmd, parse_data[i].opts, &err);
-     ssnprintf(description, sizeof(description), "cmd_parse (\"%s\", opts=%p) = "
-                                                 "%d (type=%d [%s]); want %d "
-                                                 "(type=%d [%s])",
 -    snprintf(description, sizeof(description),
 -             "cmd_parse (\"%s\", opts=%p) = "
 -             "%d (type=%d [%s]); want %d "
 -             "(type=%d [%s])",
 -             parse_data[i].input, parse_data[i].opts, status, cmd.type,
 -             CMD_TO_STRING(cmd.type), parse_data[i].expected_status,
 -             parse_data[i].expected_type,
 -             CMD_TO_STRING(parse_data[i].expected_type));
++    ssnprintf(description, sizeof(description),
++              "cmd_parse (\"%s\", opts=%p) = "
++              "%d (type=%d [%s]); want %d "
++              "(type=%d [%s])",
 +              parse_data[i].input, parse_data[i].opts, status, cmd.type,
 +              CMD_TO_STRING(cmd.type), parse_data[i].expected_status,
 +              parse_data[i].expected_type,
 +              CMD_TO_STRING(parse_data[i].expected_type));
      result = (status == parse_data[i].expected_status) &&
               (cmd.type == parse_data[i].expected_type);
      LOG(result, description);
diff --combined src/utils/dns/dns.c
  #if HAVE_ARPA_INET_H
  #include <arpa/inet.h>
  #endif
- #if HAVE_ARPA_NAMESER_H
- #include <arpa/nameser.h>
- #endif
- #if HAVE_ARPA_NAMESER_COMPAT_H
- #include <arpa/nameser_compat.h>
- #endif
  
  #if HAVE_NETDB_H
  #include <netdb.h>
@@@ -666,253 -660,184 +660,184 @@@ void handle_pcap(u_char *udata, const s
  
  const char *qtype_str(int t) {
    static char buf[32];
+   // clang-format off
+   /*
+   Built (with minor cleanup) from glibc-2.29 by
+     cat resolv/arpa/nameser.h | grep "ns_t_" | \
+     perl -ne '/ns_t_(\S+)\ =\ (\d+)/; print "  case $2:\n    return \"".uc($1)."\";\n";'
+   */
+   // clang-format on
    switch (t) {
- #if (defined(__NAMESER)) && (__NAMESER >= 19991001)
-   case ns_t_a:
+   case 1:
      return "A";
-   case ns_t_ns:
+   case 2:
      return "NS";
-   case ns_t_md:
+   case 3:
      return "MD";
-   case ns_t_mf:
+   case 4:
      return "MF";
-   case ns_t_cname:
+   case 5:
      return "CNAME";
-   case ns_t_soa:
+   case 6:
      return "SOA";
-   case ns_t_mb:
+   case 7:
      return "MB";
-   case ns_t_mg:
+   case 8:
      return "MG";
-   case ns_t_mr:
+   case 9:
      return "MR";
-   case ns_t_null:
+   case 10:
      return "NULL";
-   case ns_t_wks:
+   case 11:
      return "WKS";
-   case ns_t_ptr:
+   case 12:
      return "PTR";
-   case ns_t_hinfo:
+   case 13:
      return "HINFO";
-   case ns_t_minfo:
+   case 14:
      return "MINFO";
-   case ns_t_mx:
+   case 15:
      return "MX";
-   case ns_t_txt:
+   case 16:
      return "TXT";
-   case ns_t_rp:
+   case 17:
      return "RP";
-   case ns_t_afsdb:
+   case 18:
      return "AFSDB";
-   case ns_t_x25:
+   case 19:
      return "X25";
-   case ns_t_isdn:
+   case 20:
      return "ISDN";
-   case ns_t_rt:
+   case 21:
      return "RT";
-   case ns_t_nsap:
+   case 22:
      return "NSAP";
-   case ns_t_nsap_ptr:
+   case 23:
      return "NSAP-PTR";
-   case ns_t_sig:
+   case 24:
      return "SIG";
-   case ns_t_key:
+   case 25:
      return "KEY";
-   case ns_t_px:
+   case 26:
      return "PX";
-   case ns_t_gpos:
+   case 27:
      return "GPOS";
-   case ns_t_aaaa:
+   case 28:
      return "AAAA";
-   case ns_t_loc:
+   case 29:
      return "LOC";
-   case ns_t_nxt:
+   case 30:
      return "NXT";
-   case ns_t_eid:
+   case 31:
      return "EID";
-   case ns_t_nimloc:
+   case 32:
      return "NIMLOC";
-   case ns_t_srv:
+   case 33:
      return "SRV";
-   case ns_t_atma:
+   case 34:
      return "ATMA";
-   case ns_t_naptr:
+   case 35:
      return "NAPTR";
-   case ns_t_opt:
-     return "OPT";
- #if __NAMESER >= 19991006
-   case ns_t_kx:
+   case 36:
      return "KX";
-   case ns_t_cert:
+   case 37:
      return "CERT";
-   case ns_t_a6:
+   case 38:
      return "A6";
-   case ns_t_dname:
+   case 39:
      return "DNAME";
-   case ns_t_sink:
+   case 40:
      return "SINK";
-   case ns_t_tsig:
-     return "TSIG";
- #endif
- #if __NAMESER >= 20090302
-   case ns_t_apl:
+   case 41:
+     return "OPT";
+   case 42:
      return "APL";
-   case ns_t_ds:
+   case 43:
      return "DS";
-   case ns_t_sshfp:
+   case 44:
      return "SSHFP";
-   case ns_t_ipseckey:
+   case 45:
      return "IPSECKEY";
-   case ns_t_rrsig:
+   case 46:
      return "RRSIG";
-   case ns_t_nsec:
+   case 47:
      return "NSEC";
-   case ns_t_dnskey:
+   case 48:
      return "DNSKEY";
-   case ns_t_dhcid:
+   case 49:
      return "DHCID";
-   case ns_t_nsec3:
+   case 50:
      return "NSEC3";
-   case ns_t_nsec3param:
+   case 51:
      return "NSEC3PARAM";
-   case ns_t_hip:
+   case 52:
+     return "TLSA";
+   case 53:
+     return "SMIMEA";
+   case 55:
      return "HIP";
-   case ns_t_spf:
+   case 56:
+     return "NINFO";
+   case 57:
+     return "RKEY";
+   case 58:
+     return "TALINK";
+   case 59:
+     return "CDS";
+   case 60:
+     return "CDNSKEY";
+   case 61:
+     return "OPENPGPKEY";
+   case 62:
+     return "CSYNC";
+   case 99:
      return "SPF";
-   case ns_t_ixfr:
+   case 100:
+     return "UINFO";
+   case 101:
+     return "UID";
+   case 102:
+     return "GID";
+   case 103:
+     return "UNSPEC";
+   case 104:
+     return "NID";
+   case 105:
+     return "L32";
+   case 106:
+     return "L64";
+   case 107:
+     return "LP";
+   case 108:
+     return "EUI48";
+   case 109:
+     return "EUI64";
+   case 249:
+     return "TKEY";
+   case 250:
+     return "TSIG";
+   case 251:
      return "IXFR";
- #endif
-   case ns_t_axfr:
+   case 252:
      return "AXFR";
-   case ns_t_mailb:
+   case 253:
      return "MAILB";
-   case ns_t_maila:
+   case 254:
      return "MAILA";
-   case ns_t_any:
+   case 255:
      return "ANY";
- #if __NAMESER >= 19991006
-   case ns_t_zxfr:
-     return "ZXFR";
- #endif
- #if __NAMESER >= 20090302
-   case ns_t_dlv:
+   case 256:
+     return "URI";
+   case 257:
+     return "CAA";
+   case 258:
+     return "AVC";
+   case 32768:
+     return "TA";
+   case 32769:
      return "DLV";
- #endif
- /* #endif __NAMESER >= 19991001 */
- #elif (defined(__BIND)) && (__BIND >= 19950621)
-   case T_A:
-     return "A"; /* 1 ... */
-   case T_NS:
-     return "NS";
-   case T_MD:
-     return "MD";
-   case T_MF:
-     return "MF";
-   case T_CNAME:
-     return "CNAME";
-   case T_SOA:
-     return "SOA";
-   case T_MB:
-     return "MB";
-   case T_MG:
-     return "MG";
-   case T_MR:
-     return "MR";
-   case T_NULL:
-     return "NULL";
-   case T_WKS:
-     return "WKS";
-   case T_PTR:
-     return "PTR";
-   case T_HINFO:
-     return "HINFO";
-   case T_MINFO:
-     return "MINFO";
-   case T_MX:
-     return "MX";
-   case T_TXT:
-     return "TXT";
-   case T_RP:
-     return "RP";
-   case T_AFSDB:
-     return "AFSDB";
-   case T_X25:
-     return "X25";
-   case T_ISDN:
-     return "ISDN";
-   case T_RT:
-     return "RT";
-   case T_NSAP:
-     return "NSAP";
-   case T_NSAP_PTR:
-     return "NSAP_PTR";
-   case T_SIG:
-     return "SIG";
-   case T_KEY:
-     return "KEY";
-   case T_PX:
-     return "PX";
-   case T_GPOS:
-     return "GPOS";
-   case T_AAAA:
-     return "AAAA";
-   case T_LOC:
-     return "LOC";
-   case T_NXT:
-     return "NXT";
-   case T_EID:
-     return "EID";
-   case T_NIMLOC:
-     return "NIMLOC";
-   case T_SRV:
-     return "SRV";
-   case T_ATMA:
-     return "ATMA";
-   case T_NAPTR:
-     return "NAPTR"; /* ... 35 */
- #if (__BIND >= 19960801)
-   case T_KX:
-     return "KX"; /* 36 ... */
-   case T_CERT:
-     return "CERT";
-   case T_A6:
-     return "A6";
-   case T_DNAME:
-     return "DNAME";
-   case T_SINK:
-     return "SINK";
-   case T_OPT:
-     return "OPT";
-   case T_APL:
-     return "APL";
-   case T_DS:
-     return "DS";
-   case T_SSHFP:
-     return "SSHFP";
-   case T_RRSIG:
-     return "RRSIG";
-   case T_NSEC:
-     return "NSEC";
-   case T_DNSKEY:
-     return "DNSKEY"; /* ... 48 */
-   case T_TKEY:
-     return "TKEY"; /* 249 */
- #endif /* __BIND >= 19960801 */
-   case T_TSIG:
-     return "TSIG"; /* 250 ... */
-   case T_IXFR:
-     return "IXFR";
-   case T_AXFR:
-     return "AXFR";
-   case T_MAILB:
-     return "MAILB";
-   case T_MAILA:
-     return "MAILA";
-   case T_ANY:
-     return "ANY"; /* ... 255 */
- #endif /* __BIND >= 19950621 */
    default:
 -    snprintf(buf, sizeof(buf), "#%i", t);
 +    ssnprintf(buf, sizeof(buf), "#%i", t);
      return buf;
    } /* switch (t) */
  }
@@@ -931,74 -856,55 +856,55 @@@ const char *opcode_str(int o) 
    case 5:
      return "Update";
    default:
 -    snprintf(buf, sizeof(buf), "Opcode%d", o);
 +    ssnprintf(buf, sizeof(buf), "Opcode%d", o);
      return buf;
    }
  }
  
  const char *rcode_str(int rcode) {
    static char buf[32];
+   /* RFC2136 rcodes */
+   // clang-format off
+   /*
+   Built (with minor cleanup) from glibc-2.29 by
+     cat resolv/arpa/nameser.h | grep "ns_r_" | \
+     perl -ne '/ns_r_(\S+)\ =\ (\d+)/; print "  case $2:\n    return \"".uc($1)."\";\n";'
+   https://tools.ietf.org/html/rfc2671 assigns EDNS Extended RCODE "16" to "BADVERS"
+   https://tools.ietf.org/html/rfc2845 declares 0..15 as DNS RCODE and 16 is BADSIG.
+   */
+   // clang-format on
    switch (rcode) {
- #if (defined(__NAMESER)) && (__NAMESER >= 19991006)
-   case ns_r_noerror:
-     return "NOERROR";
-   case ns_r_formerr:
+   case 1:
      return "FORMERR";
-   case ns_r_servfail:
+   case 2:
      return "SERVFAIL";
-   case ns_r_nxdomain:
+   case 3:
      return "NXDOMAIN";
-   case ns_r_notimpl:
+   case 4:
      return "NOTIMPL";
-   case ns_r_refused:
+   case 5:
      return "REFUSED";
-   case ns_r_yxdomain:
+   case 6:
      return "YXDOMAIN";
-   case ns_r_yxrrset:
+   case 7:
      return "YXRRSET";
-   case ns_r_nxrrset:
+   case 8:
      return "NXRRSET";
-   case ns_r_notauth:
+   case 9:
      return "NOTAUTH";
-   case ns_r_notzone:
+   case 10:
      return "NOTZONE";
-   case ns_r_max:
+   case 11:
      return "MAX";
-   case ns_r_badsig:
+   case 16:
      return "BADSIG";
-   case ns_r_badkey:
+   case 17:
      return "BADKEY";
-   case ns_r_badtime:
+   case 18:
      return "BADTIME";
- /* #endif __NAMESER >= 19991006 */
- #elif (defined(__BIND)) && (__BIND >= 19950621)
-   case NOERROR:
-     return "NOERROR";
-   case FORMERR:
-     return "FORMERR";
-   case SERVFAIL:
-     return "SERVFAIL";
-   case NXDOMAIN:
-     return "NXDOMAIN";
-   case NOTIMP:
-     return "NOTIMP";
-   case REFUSED:
-     return "REFUSED";
- #if defined(YXDOMAIN) && defined(NXRRSET)
-   case YXDOMAIN:
-     return "YXDOMAIN";
-   case YXRRSET:
-     return "YXRRSET";
-   case NXRRSET:
-     return "NXRRSET";
-   case NOTAUTH:
-     return "NOTAUTH";
-   case NOTZONE:
-     return "NOTZONE";
- #endif /* RFC2136 rcodes */
- #endif /* __BIND >= 19950621 */
    default:
 -    snprintf(buf, sizeof(buf), "RCode%i", rcode);
 +    ssnprintf(buf, sizeof(buf), "RCode%i", rcode);
      return buf;
    }
  } /* const char *rcode_str (int rcode) */
diff --combined src/virt.c
@@@ -610,7 -610,9 +610,9 @@@ enum ex_stats 
  #endif
    ex_stats_disk_allocation = 1 << 10,
    ex_stats_disk_capacity = 1 << 11,
-   ex_stats_disk_physical = 1 << 12
+   ex_stats_disk_physical = 1 << 12,
+   ex_stats_memory = 1 << 13,
+   ex_stats_vcpu = 1 << 14
  };
  
  static unsigned int extra_stats = ex_stats_none;
@@@ -641,6 -643,8 +643,8 @@@ static const struct ex_stats_item ex_st
      {"disk_allocation", ex_stats_disk_allocation},
      {"disk_capacity", ex_stats_disk_capacity},
      {"disk_physical", ex_stats_disk_physical},
+     {"memory", ex_stats_memory},
+     {"vcpu", ex_stats_vcpu},
      {NULL, ex_stats_none},
  };
  
@@@ -942,7 -946,8 +946,8 @@@ static void memory_stats_submit(gauge_
                                 "last_update",    "disk_caches"};
  
    if ((tag_index < 0) || (tag_index >= (int)STATIC_ARRAY_SIZE(tags))) {
-     ERROR("virt plugin: Array index out of bounds: tag_index = %d", tag_index);
+     ERROR(PLUGIN_NAME " plugin: Array index out of bounds: tag_index = %d",
+           tag_index);
      return;
    }
  
@@@ -972,7 -977,7 +977,7 @@@ static double cpu_ns_to_percent(unsigne
    }
  
    DEBUG(PLUGIN_NAME " plugin: node_cpus=%u cpu_time_old=%" PRIu64
-                     " cpu_time_new=%" PRIu64 "cpu_time_diff=%" PRIu64
+                     " cpu_time_new=%" PRIu64 " cpu_time_diff=%" PRIu64
                      " time_diff_sec=%f percent=%f",
          node_cpus, (uint64_t)cpu_time_old, (uint64_t)cpu_time_new,
          (uint64_t)cpu_time_diff, time_diff_sec, percent);
@@@ -1004,7 -1009,7 +1009,7 @@@ static void vcpu_submit(derive_t value
                          const char *type) {
    char type_instance[DATA_MAX_NAME_LEN];
  
 -  snprintf(type_instance, sizeof(type_instance), "%d", vcpu_nr);
 +  ssnprintf(type_instance, sizeof(type_instance), "%d", vcpu_nr);
    submit(dom, type, type_instance, &(value_t){.derive = value}, 1);
  }
  
@@@ -1026,8 -1031,8 +1031,8 @@@ static void disk_block_stats_submit(str
    }
  
    char flush_type_instance[DATA_MAX_NAME_LEN];
 -  snprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s",
 -           type_instance);
 +  ssnprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s",
 +            type_instance);
  
    if ((bstats->bi.rd_req != -1) && (bstats->bi.wr_req != -1))
      submit_derive2("disk_ops", (derive_t)bstats->bi.rd_req,
@@@ -1130,8 -1135,8 +1135,8 @@@ static void domain_state_submit_notif(v
    const char *reason_str = "N/A";
  #endif
  
 -  snprintf(msg, sizeof(msg), "Domain state: %s. Reason: %s", state_str,
 -           reason_str);
 +  ssnprintf(msg, sizeof(msg), "Domain state: %s. Reason: %s", state_str,
 +            reason_str);
  
    int severity;
    switch (state) {
@@@ -1519,8 -1524,8 +1524,8 @@@ static int lv_domain_block_stats(virDom
  
    virTypedParameterPtr params = calloc(nparams, sizeof(*params));
    if (params == NULL) {
-     ERROR("virt plugin: alloc(%i) for block=%s parameters failed.", nparams,
-           path);
+     ERROR(PLUGIN_NAME " plugin: alloc(%i) for block=%s parameters failed.",
+           nparams, path);
      return -1;
    }
  
@@@ -1560,8 -1565,17 +1565,17 @@@ static int get_perf_events(virDomainPt
    int status =
        virDomainListGetStats(domain_array, VIR_DOMAIN_STATS_PERF, &stats, 0);
    if (status == -1) {
-     ERROR("virt plugin: virDomainListGetStats failed with status %i.", status);
-     return status;
+     ERROR(PLUGIN_NAME " plugin: virDomainListGetStats failed with status %i.",
+           status);
+     virErrorPtr err = virGetLastError();
+     if (err->code == VIR_ERR_NO_SUPPORT) {
+       ERROR(PLUGIN_NAME
+             " plugin: Disabled unsupported ExtraStats selector: perf");
+       extra_stats &= ~(ex_stats_perf);
+     }
+     return -1;
    }
  
    for (int i = 0; i < status; ++i)
@@@ -1578,15 -1592,13 +1592,14 @@@ static void vcpu_pin_submit(virDomainPt
      char type_instance[DATA_MAX_NAME_LEN];
      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);
 +    ssnprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu,
 +              cpu);
      submit(dom, "cpu_affinity", type_instance, &(value_t){.gauge = is_set}, 1);
    }
  }
  
  static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
    int max_cpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
-   int cpu_map_len = VIR_CPU_MAPLEN(max_cpus);
  
    virVcpuInfoPtr vinfo = calloc(nr_virt_cpu, sizeof(*vinfo));
    if (vinfo == NULL) {
      return -1;
    }
  
-   unsigned char *cpumaps = calloc(nr_virt_cpu, cpu_map_len);
-   if (cpumaps == NULL) {
-     ERROR(PLUGIN_NAME " plugin: calloc failed.");
-     sfree(vinfo);
-     return -1;
+   int cpu_map_len = 0;
+   unsigned char *cpumaps = NULL;
+   if (extra_stats & ex_stats_vcpupin) {
+     cpu_map_len = VIR_CPU_MAPLEN(max_cpus);
+     cpumaps = calloc(nr_virt_cpu, cpu_map_len);
+     if (cpumaps == NULL) {
+       ERROR(PLUGIN_NAME " plugin: calloc failed.");
+       sfree(vinfo);
+       return -1;
+     }
    }
  
    int status =
    if (status < 0) {
      ERROR(PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
            status);
+     virErrorPtr err = virGetLastError();
+     if (err->code == VIR_ERR_NO_SUPPORT) {
+       if (extra_stats & ex_stats_vcpu)
+         ERROR(PLUGIN_NAME
+               " plugin: Disabled unsupported ExtraStats selector: vcpu");
+       if (extra_stats & ex_stats_vcpupin)
+         ERROR(PLUGIN_NAME
+               " plugin: Disabled unsupported ExtraStats selector: vcpupin");
+       extra_stats &= ~(ex_stats_vcpu | ex_stats_vcpupin);
+     }
      sfree(cpumaps);
      sfree(vinfo);
-     return status;
+     return -1;
    }
  
    for (int i = 0; i < nr_virt_cpu; ++i) {
-     vcpu_submit(vinfo[i].cpuTime, domain, vinfo[i].number, "virt_vcpu");
+     if (extra_stats & ex_stats_vcpu)
+       vcpu_submit(vinfo[i].cpuTime, domain, vinfo[i].number, "virt_vcpu");
      if (extra_stats & ex_stats_vcpupin)
        vcpu_pin_submit(domain, max_cpus, i, cpumaps, cpu_map_len);
    }
@@@ -1627,6 -1658,14 +1659,14 @@@ static int get_pcpu_stats(virDomainPtr 
    int nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
    if (nparams < 0) {
      VIRT_ERROR(conn, "getting the CPU params count");
+     virErrorPtr err = virGetLastError();
+     if (err->code == VIR_ERR_NO_SUPPORT) {
+       ERROR(PLUGIN_NAME
+             " plugin: Disabled unsupported ExtraStats selector: pcpu");
+       extra_stats &= ~(ex_stats_pcpu);
+     }
      return -1;
    }
  
@@@ -1709,17 -1748,25 +1749,25 @@@ static int get_memory_stats(virDomainPt
    virDomainMemoryStatPtr minfo =
        calloc(VIR_DOMAIN_MEMORY_STAT_NR, sizeof(*minfo));
    if (minfo == NULL) {
-     ERROR("virt plugin: calloc failed.");
+     ERROR(PLUGIN_NAME " plugin: calloc failed.");
      return -1;
    }
  
    int mem_stats =
        virDomainMemoryStats(domain, minfo, VIR_DOMAIN_MEMORY_STAT_NR, 0);
    if (mem_stats < 0) {
-     ERROR("virt plugin: virDomainMemoryStats failed with mem_stats %i.",
+     ERROR(PLUGIN_NAME " plugin: virDomainMemoryStats failed with mem_stats %i.",
            mem_stats);
      sfree(minfo);
-     return mem_stats;
+     virErrorPtr err = virGetLastError();
+     if (err->code == VIR_ERR_NO_SUPPORT) {
+       ERROR(PLUGIN_NAME
+             " plugin: Disabled unsupported ExtraStats selector: memory");
+       extra_stats &= ~(ex_stats_memory);
+     }
+     return -1;
    }
  
    derive_t swap_in = -1;
@@@ -1776,6 -1823,15 +1824,15 @@@ static int get_disk_err(virDomainPtr do
    if (disk_err_count == -1) {
      ERROR(PLUGIN_NAME
            " plugin: failed to get preferred size of disk errors array");
+     virErrorPtr err = virGetLastError();
+     if (err->code == VIR_ERR_NO_SUPPORT) {
+       ERROR(PLUGIN_NAME
+             " plugin: Disabled unsupported ExtraStats selector: disk_err");
+       extra_stats &= ~(ex_stats_disk_err);
+     }
      return -1;
    }
  
@@@ -1822,6 -1878,24 +1879,24 @@@ static int get_block_device_stats(struc
            0) {
          ERROR(PLUGIN_NAME " plugin: virDomainGetBlockInfo failed for path: %s",
                block_dev->path);
+         virErrorPtr err = virGetLastError();
+         if (err->code == VIR_ERR_NO_SUPPORT) {
+           if (extra_stats & ex_stats_disk_allocation)
+             ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats "
+                               "selector: disk_allocation");
+           if (extra_stats & ex_stats_disk_capacity)
+             ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats "
+                               "selector: disk_capacity");
+           if (extra_stats & ex_stats_disk_physical)
+             ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats "
+                               "selector: disk_physical");
+           extra_stats &= ~(ex_stats_disk_allocation | ex_stats_disk_capacity |
+                            ex_stats_disk_physical);
+         }
          return -1;
        }
      }
@@@ -1908,7 -1982,15 +1983,15 @@@ static int get_fs_info(virDomainPtr dom
    if (mount_points_cnt == -1) {
      ERROR(PLUGIN_NAME " plugin: virDomainGetFSInfo failed: %d",
            mount_points_cnt);
-     return mount_points_cnt;
+     virErrorPtr err = virGetLastError();
+     if (err->code == VIR_ERR_NO_SUPPORT) {
+       ERROR(PLUGIN_NAME
+             " plugin: Disabled unsupported ExtraStats selector: fs_info");
+       extra_stats &= ~(ex_stats_fs_info);
+     }
+     return -1;
    }
  
    for (int i = 0; i < mount_points_cnt; ++i) {
@@@ -1955,7 -2037,6 +2038,6 @@@ static void job_stats_submit(virDomainP
  }
  
  static int get_job_stats(virDomainPtr domain) {
-   int ret = 0;
    int job_type = 0;
    int nparams = 0;
    virTypedParameterPtr params = NULL;
                    ? VIR_DOMAIN_JOB_STATS_COMPLETED
                    : 0;
  
-   ret = virDomainGetJobStats(domain, &job_type, &params, &nparams, flags);
+   int ret = virDomainGetJobStats(domain, &job_type, &params, &nparams, flags);
    if (ret != 0) {
      ERROR(PLUGIN_NAME " plugin: virDomainGetJobStats failed: %d", ret);
-     return ret;
+     virErrorPtr err = virGetLastError();
+     // VIR_ERR_INVALID_ARG returned when VIR_DOMAIN_JOB_STATS_COMPLETED flag is
+     // not supported by driver
+     if (err->code == VIR_ERR_NO_SUPPORT || err->code == VIR_ERR_INVALID_ARG) {
+       if (extra_stats & ex_stats_job_stats_completed)
+         ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats selector: "
+                           "job_stats_completed");
+       if (extra_stats & ex_stats_job_stats_background)
+         ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats selector: "
+                           "job_stats_background");
+       extra_stats &=
+           ~(ex_stats_job_stats_completed | ex_stats_job_stats_background);
+     }
+     return -1;
    }
  
    DEBUG(PLUGIN_NAME " plugin: job_type=%d nparams=%d", job_type, nparams);
    }
  
    virTypedParamsFree(params, nparams);
-   return ret;
+   return 0;
  }
  #endif /* HAVE_JOB_STATS */
  
@@@ -2019,8 -2114,10 +2115,10 @@@ static int get_domain_metrics(domain_t 
  
    memory_submit(domain->ptr, (gauge_t)info.memory * 1024);
  
-   GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
-   GET_STATS(get_memory_stats, "memory stats", domain->ptr);
+   if (extra_stats & (ex_stats_vcpu | ex_stats_vcpupin))
+     GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
+   if (extra_stats & ex_stats_memory)
+     GET_STATS(get_memory_stats, "memory stats", domain->ptr);
  
  #ifdef HAVE_PERF_STATS
    if (extra_stats & ex_stats_perf)
@@@ -2107,6 -2204,9 +2205,9 @@@ static int domain_lifecycle_event_cb(__
    return 0;
  }
  
+ static void virt_eventloop_timeout_cb(int timer ATTRIBUTE_UNUSED,
+                                       void *timer_info) {}
  static int register_event_impl(void) {
    if (virEventRegisterDefaultImpl() < 0) {
      virErrorPtr err = virGetLastError();
      return -1;
    }
  
+   if (virEventAddTimeout(CDTIME_T_TO_MS(plugin_get_interval()),
+                          virt_eventloop_timeout_cb, NULL, NULL) < 0) {
+     virErrorPtr err = virGetLastError();
+     ERROR(PLUGIN_NAME " plugin: virEventAddTimeout failed: %s",
+           err && err->message ? err->message : "Unknown error");
+     return -1;
+   }
    return 0;
  }
  
@@@ -2311,6 -2419,21 +2420,21 @@@ static int lv_read(user_data_t *ud) 
      return 0;
    }
  
+   int ret = virConnectIsAlive(conn);
+   if (ret == 0) { /* Connection lost */
+     if (inst->id == 0) {
+       c_complain(LOG_ERR, &conn_complain,
+                  PLUGIN_NAME " plugin: Lost connection.");
+       if (!persistent_notification)
+         stop_event_loop(&notif_thread);
+       lv_disconnect();
+       last_refresh = 0;
+     }
+     return -1;
+   }
    time_t t;
    time(&t);
  
@@@ -2397,7 -2520,7 +2521,7 @@@ static int lv_init_instance(size_t i, p
  
    memset(lv_ud, 0, sizeof(*lv_ud));
  
 -  snprintf(inst->tag, sizeof(inst->tag), "%s-%" PRIsz, PLUGIN_NAME, i);
 +  ssnprintf(inst->tag, sizeof(inst->tag), "%s-%" PRIsz, PLUGIN_NAME, i);
    inst->id = i;
  
    user_data_t *ud = &(lv_ud->ud);
@@@ -2467,8 -2590,8 +2591,8 @@@ static int lv_domain_get_tag(xmlXPathCo
      goto done;
    }
  
 -  snprintf(xpath_str, sizeof(xpath_str), "/domain/metadata/%s:%s/text()",
 -           METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_ELEMENT);
 +  ssnprintf(xpath_str, sizeof(xpath_str), "/domain/metadata/%s:%s/text()",
 +            METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_ELEMENT);
    xpath_obj = xmlXPathEvalExpression((xmlChar *)xpath_str, xpath_ctx);
    if (xpath_obj == NULL) {
      ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) failed on domain %s",
@@@ -2670,7 -2793,7 +2794,7 @@@ static void lv_add_network_interfaces(s
        break;
      case if_number: {
        char number_string[4];
 -      snprintf(number_string, sizeof(number_string), "%d", itf_number);
 +      ssnprintf(number_string, sizeof(number_string), "%d", itf_number);
        if (ignore_device_match(il_interface_devices, domname, number_string) !=
            0)
          device_ignored = true;
@@@ -2971,7 -3094,7 +3095,7 @@@ static int add_interface_device(struct 
    }
  
    char number_string[21];
 -  snprintf(number_string, sizeof(number_string), "interface-%u", number);
 +  ssnprintf(number_string, sizeof(number_string), "interface-%u", number);
    char *number_copy = strdup(number_string);
    if (!number_copy) {
      sfree(path_copy);
@@@ -3010,7 -3133,7 +3134,7 @@@ static int ignore_device_match(ignoreli
      ERROR(PLUGIN_NAME " plugin: malloc failed.");
      return 0;
    }
 -  snprintf(name, n, "%s:%s", domname, devpath);
 +  ssnprintf(name, n, "%s:%s", domname, devpath);
    int r = ignorelist_match(il, name);
    sfree(name);
    return r;