"Daniel P. Berrange" <berrange@xxxxxxxxxx> wrote: > On Wed, Nov 28, 2007 at 02:18:22PM +0100, Jim Meyering wrote: >> I spotted a few unchecked heap allocations (strdup, malloc, calloc) >> in qemud.c and have fixed it so such failure evokes a proper diagnostic >> rather than e.g., a segfault. > > Yep, good stuff. > >> I've also arranged to free some of the memory upon failure, >> but not all (see comments for why). >> >> In spite of those additions, this patch factors out enough >> duplication that the net change is to remove a few lines from the >> file. Although in general I prefer to factor things out into >> separate functions, in this case, it seemed better to use macros. > > I really don't like the macros, particularly when the macro definitions > are inline to the function. I'd prefer to see these helpers as separate > functions. The compiler is perfectly able to decide whether to inline > the code or not & it makes it more friendly to edit & read when it is > using separate functions. I've rewritten to use fewer macros. In the process, I did a little testing, and will add an automated test to give this code some coverage in a separate patch. Detect heap allocation failure; factor out some duplication. * qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list): (tls_allowed_dn_list): Remove "const", now that we free these. (unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that the latter name can be used as a local string variable, so that the variable name matches the config attribute name. (unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise. (remoteCheckDN, remoteCheckAccess): Adapt to const removal. (qemudDispatchServer): Check for heap allocation failure. (remoteConfigGetStringList): New function, based on code from Dan Berrangé. (CHECK_TYPE): Remove macro. (checkType): New function. (GET_CONF_INT, GET_CONF_STR): New macros. (remoteReadConfigFile): Use new macros to avoid duplication and to check for allocation failure. * src/conf.h (virConfTypeName): New static inline function. * qemud/libvirtd.conf: Add '=' signs to correct invalid syntax in commented out config lines. Distinguish those lines by having no space between '#' and the following character. --- qemud/libvirtd.conf | 50 ++++---- qemud/qemud.c | 378 ++++++++++++++++++++++++++++++--------------------- src/conf.h | 26 ++++- 3 files changed, 273 insertions(+), 181 deletions(-) diff --git a/qemud/libvirtd.conf b/qemud/libvirtd.conf index 51168b8..b427e14 100644 --- a/qemud/libvirtd.conf +++ b/qemud/libvirtd.conf @@ -11,7 +11,7 @@ # using this capability. # # This is enabled by default, uncomment this to disable it -# listen_tls = 0 +#listen_tls = 0 # Listen for unencrypted TCP connections on the public TCP/IP port. # NB, must pass the --listen flag to the libvirtd process for this to @@ -20,19 +20,19 @@ # NB, this is insecure. Do not use except for development. # # This is disabled by default, uncomment this to enable it. -# listen_tcp = 1 +#listen_tcp = 1 # Override the port for accepting secure TLS connections # This can be a port number, or service name # -# tls_port = "16514" +#tls_port = "16514" # Override the port for accepting insecure TCP connections # This can be a port number, or service name -# -# tcp_port = "16509" +# +#tcp_port = "16509" @@ -42,38 +42,38 @@ # stopping the Avahi daemon # # This is enabled by default, uncomment this to disable it -# mdns_adv = 0 +#mdns_adv = 0 # Override the default mDNS advertizement name. This must be # unique on the immediate broadcast network. -# +# # The default is "Virtualization Host HOSTNAME", where HOSTNAME # is subsituted for the short hostname of the machine (without domain) # -# mdns_name "Virtualization Host Joe Demo" +#mdns_name = "Virtualization Host Joe Demo" # Set the UNIX domain socket group ownership. This can be used to # allow a 'trusted' set of users access to management capabilities # without becoming root. -# -# This is restricted to 'root' by default. -# unix_sock_group "libvirt" +# +# This is restricted to 'root' by default. +#unix_sock_group = "libvirt" # Set the UNIX socket permissions for the R/O socket. This is used # for monitoring VM status only # # Default allows any user. If setting group ownership may want to # restrict this to: -# unix_sock_ro_perms "0777" +#unix_sock_ro_perms = "0777" # Set the UNIX socket permissions for the R/W socket. This is used # for full management of VMs # # Default allows only root. If setting group ownership may want to # relax this to: -# unix_sock_rw_perms "octal-perms" "0770" +#unix_sock_rw_perms = "0770" @@ -85,7 +85,7 @@ # # Default is to always verify. Uncommenting this will disable # verification - make sure an IP whitelist is set -# tls_no_verify_certificate 1 +#tls_no_verify_certificate = 1 # Flag to disable verification of client IP address # @@ -94,27 +94,27 @@ # it is easy to spoof source IP. # # Uncommenting this will disable verification -# tls_no_verify_address 1 +#tls_no_verify_address = 1 # Override the default server key file path # -# key_file "/etc/pki/libvirt/private/serverkey.pem" +#key_file = "/etc/pki/libvirt/private/serverkey.pem" # Override the default server certificate file path # -# cert_file "/etc/pki/libvirt/servercert.pem" +#cert_file = "/etc/pki/libvirt/servercert.pem" # Override the default CA certificate path # -# ca_file "/etc/pki/CA/cacert.pem" +#ca_file = "/etc/pki/CA/cacert.pem" # Specify a certificate revocation list. -# +# # Defaults to not using a CRL, uncomment to enable it -# crl_file "/etc/pki/CA/crl.pem" +#crl_file = "/etc/pki/CA/crl.pem" # A whitelist of allowed x509 Distinguished Names -# This list may contain wildcards such as +# This list may contain wildcards such as # # "C=GB,ST=London,L=London,O=Red Hat,CN=*" # @@ -124,18 +124,16 @@ # entirely rather than using empty list to disable these checks # # By default, no DN's are checked -# tls_allowed_dn_list ["DN1", "DN2"] +#tls_allowed_dn_list = ["DN1", "DN2"] # A whitelist of allowed client IP addresses # -# This list may contain wildcards such as 192.168.* See the POSIX fnmatch +# This list may contain wildcards such as 192.168.* See the POSIX fnmatch # function for the format of the wildcards. # # NB If this is an empty list, no client can connect, so comment out # entirely rather than using empty list to disable these checks # # By default, no IP's are checked. This can be IPv4 or IPv6 addresses -# tls_allowed_ip_list ["ip1", "ip2", "ip3"] - - +#tls_allowed_ip_list = ["ip1", "ip2", "ip3"] diff --git a/qemud/qemud.c b/qemud/qemud.c index 5f76a26..9904e4a 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -70,27 +70,27 @@ static int ipsock = 0; /* -l Listen for TCP/IP */ /* Defaults for configuration file elements */ static int listen_tls = 1; static int listen_tcp = 0; -static const char *tls_port = LIBVIRTD_TLS_PORT; -static const char *tcp_port = LIBVIRTD_TCP_PORT; +static char *tls_port = (char *) LIBVIRTD_TLS_PORT; +static char *tcp_port = (char *) LIBVIRTD_TCP_PORT; static gid_t unix_sock_gid = 0; /* Only root by default */ -static int unix_sock_rw_perms = 0700; /* Allow user only */ -static int unix_sock_ro_perms = 0777; /* Allow world */ +static int unix_sock_rw_mask = 0700; /* Allow user only */ +static int unix_sock_ro_mask = 0777; /* Allow world */ #ifdef HAVE_AVAHI static int mdns_adv = 1; -static const char *mdns_name = NULL; +static char *mdns_name = NULL; #endif static int tls_no_verify_certificate = 0; static int tls_no_verify_address = 0; -static const char **tls_allowed_ip_list = 0; -static const char **tls_allowed_dn_list = 0; +static char **tls_allowed_ip_list = NULL; +static char **tls_allowed_dn_list = NULL; -static const char *key_file = LIBVIRT_SERVERKEY; -static const char *cert_file = LIBVIRT_SERVERCERT; -static const char *ca_file = LIBVIRT_CACERT; -static const char *crl_file = ""; +static char *key_file = (char *) LIBVIRT_SERVERKEY; +static char *cert_file = (char *) LIBVIRT_SERVERCERT; +static char *ca_file = (char *) LIBVIRT_CACERT; +static char *crl_file = (char *) ""; static gnutls_certificate_credentials_t x509_cred; static gnutls_dh_params_t dh_params; @@ -407,7 +407,7 @@ static int qemudGoDaemon(void) { status != 0) { return -1; } - + return pid; } } @@ -482,7 +482,7 @@ static int qemudListenUnix(struct qemud_server *server, oldgrp = getgid(); - oldmask = umask(readonly ? ~unix_sock_ro_perms : ~unix_sock_rw_perms); + oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask); if (getuid() == 0) setgid(unix_sock_gid); @@ -649,7 +649,7 @@ static int qemudInitPaths(struct qemud_server *server, char *base = 0; uid_t uid = geteuid(); - + if (!uid) { if (snprintf (sockname, maxlen, "%s/run/libvirt/libvirt-sock", LOCAL_STATE_DIR) >= maxlen) @@ -764,7 +764,7 @@ static struct qemud_server *qemudInitialize(int sigread) { group = libvirtd_mdns_add_group(server->mdns, mdns_name); } - /* + /* * See if there's a TLS enabled port we can advertise. Cowardly * don't bother to advertise TCP since we don't want people using * them for real world apps @@ -777,7 +777,7 @@ static struct qemud_server *qemudInitialize(int sigread) { } sock = sock->next; } - + /* * Add the primary entry - we choose SSH because its most likely to always * be available @@ -840,7 +840,7 @@ remoteCheckDN (gnutls_x509_crt_t cert) { char name[256]; size_t namesize = sizeof name; - const char **wildcards; + char **wildcards; int err; err = gnutls_x509_crt_get_dn (cert, name, &namesize); @@ -928,13 +928,13 @@ remoteCheckCertificate (gnutls_session_t session) gnutls_x509_crt_deinit (cert); return -1; } - + if (gnutls_x509_crt_get_expiration_time (cert) < now) { qemudLog (QEMUD_ERR, "remoteCheckCertificate: the client certificate has expired"); gnutls_x509_crt_deinit (cert); return -1; } - + if (gnutls_x509_crt_get_activation_time (cert) > now) { qemudLog (QEMUD_ERR, "remoteCheckCertificate: the client certificate is not yet activated"); gnutls_x509_crt_deinit (cert); @@ -959,7 +959,7 @@ static int remoteCheckAccess (struct qemud_client *client) { char addr[NI_MAXHOST]; - const char **wildcards; + char **wildcards; int found, err; /* Verify client certificate. */ @@ -1044,6 +1044,8 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket } client = calloc(1, sizeof(struct qemud_client)); + if (client == NULL) + goto cleanup; client->magic = QEMUD_CLIENT_MAGIC; client->fd = fd; client->readonly = sock->readonly; @@ -1505,6 +1507,131 @@ static void qemudCleanup(struct qemud_server *server) { free(server); } +/* Allocate an array of malloc'd strings from the config file, filename + * (used only in diagnostics), using handle "conf". Upon error, return -1 + * and free any allocated memory. Otherwise, save the array in *list_arg + * and return 0. + */ +static int +remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list_arg, + const char *filename) +{ + char **list; + virConfValuePtr p = virConfGetValue (conf, key); + if (!p) + return 0; + + switch (p->type) { + case VIR_CONF_STRING: + list = malloc (2 * sizeof (*list)); + if (list == NULL) { + qemudLog (QEMUD_ERR, + "failed to allocate memory for %s config list", key); + return -1; + } + list[0] = strdup (p->str); + list[1] = NULL; + if (list[0] == NULL) { + qemudLog (QEMUD_ERR, + "failed to allocate memory for %s config list value", + key); + free (list); + return -1; + } + break; + + case VIR_CONF_LIST: { + int i, len = 0; + virConfValuePtr pp; + for (pp = p->list; pp; pp = pp->next) + len++; + list = calloc (1+len, sizeof (*list)); + if (list == NULL) { + qemudLog (QEMUD_ERR, + "failed to allocate memory for %s config list", key); + return -1; + } + for (i = 0, pp = p->list; pp; ++i, pp = pp->next) { + if (pp->type != VIR_CONF_STRING) { + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s:" + " must be a string or list of strings\n", + filename, key); + free (list); + return -1; + } + list[i] = strdup (pp->str); + if (list[i] == NULL) { + int j; + for (j = 0 ; j < i ; j++) + free (list[j]); + free (list); + qemudLog (QEMUD_ERR, "failed to allocate memory" + " for %s config list value", key); + return -1; + } + + } + list[i] = NULL; + break; + } + + default: + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s:" + " must be a string or list of strings\n", + filename, key); + return -1; + } + + *list_arg = list; + return 0; +} + +/* A helper function used by each of the following macros. */ +static int +checkType (virConfValuePtr p, const char *filename, + const char *key, virConfType required_type) +{ + if (p->type != required_type) { + qemudLog (QEMUD_ERR, + "remoteReadConfigFile: %s: %s: invalid type:" + " got %s; expected %s\n", filename, key, + virConfTypeName (p->type), + virConfTypeName (required_type)); + return -1; + } + return 0; +} + +/* If there is no config data for the key, #var_name, then do nothing. + If there is valid data of type VIR_CONF_STRING, and strdup succeeds, + store the result in var_name. Otherwise, (i.e. invalid type, or strdup + failure), give a diagnostic and "goto" the cleanup-and-fail label. */ +#define GET_CONF_STR(conf, filename, var_name) \ + do { \ + virConfValuePtr p = virConfGetValue (conf, #var_name); \ + if (p) { \ + if (checkType (p, filename, #var_name, VIR_CONF_STRING) < 0) \ + goto free_and_fail; \ + (var_name) = strdup (p->str); \ + if ((var_name) == NULL) { \ + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s\n", \ + strerror (errno)); \ + goto free_and_fail; \ + } \ + } \ + } while (0) + +/* Like GET_CONF_STR, but for integral values. */ +#define GET_CONF_INT(conf, filename, var_name) \ + do { \ + virConfValuePtr p = virConfGetValue (conf, #var_name); \ + if (p) { \ + if (checkType (p, filename, #var_name, VIR_CONF_LONG) < 0) \ + goto free_and_fail; \ + (var_name) = p->l; \ + } \ + } while (0) + /* Read the config file if it exists. * Only used in the remote case, hence the name. */ @@ -1513,6 +1640,12 @@ remoteReadConfigFile (const char *filename) { virConfPtr conf; + /* The following variable names must match the corresponding + configuration strings. */ + char *unix_sock_ro_perms = NULL; + char *unix_sock_rw_perms = NULL; + char *unix_sock_group = NULL; + /* Just check the file is readable before opening it, otherwise * libvirt emits an error. */ @@ -1521,166 +1654,103 @@ remoteReadConfigFile (const char *filename) conf = virConfReadFile (filename); if (!conf) return 0; - virConfValuePtr p; - -#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) { \ - qemudLog (QEMUD_ERR, \ - "remoteReadConfigFile: %s: %s: expected type " #typ "\n", \ - filename, (name)); \ - return -1; \ - } - - p = virConfGetValue (conf, "listen_tls"); - CHECK_TYPE ("listen_tls", VIR_CONF_LONG); - listen_tls = p ? p->l : listen_tls; - - p = virConfGetValue (conf, "listen_tcp"); - CHECK_TYPE ("listen_tcp", VIR_CONF_LONG); - listen_tcp = p ? p->l : listen_tcp; - - p = virConfGetValue (conf, "tls_port"); - CHECK_TYPE ("tls_port", VIR_CONF_STRING); - tls_port = p ? strdup (p->str) : tls_port; - - p = virConfGetValue (conf, "tcp_port"); - CHECK_TYPE ("tcp_port", VIR_CONF_STRING); - tcp_port = p ? strdup (p->str) : tcp_port; + GET_CONF_STR (conf, filename, tls_port); + GET_CONF_STR (conf, filename, tcp_port); - p = virConfGetValue (conf, "unix_sock_group"); - CHECK_TYPE ("unix_sock_group", VIR_CONF_STRING); - if (p && p->str) { + GET_CONF_STR (conf, filename, unix_sock_group); + if (unix_sock_group) { if (getuid() != 0) { qemudLog (QEMUD_WARN, "Cannot set group when not running as root"); } else { - struct group *grp = getgrnam(p->str); + struct group *grp = getgrnam(unix_sock_group); if (!grp) { - qemudLog (QEMUD_ERR, "Failed to lookup group '%s'", p->str); - return -1; + qemudLog (QEMUD_ERR, "Failed to lookup group '%s'", + unix_sock_group); + goto free_and_fail; } unix_sock_gid = grp->gr_gid; } + free (unix_sock_group); + unix_sock_group = NULL; } - p = virConfGetValue (conf, "unix_sock_ro_perms"); - CHECK_TYPE ("unix_sock_ro_perms", VIR_CONF_STRING); - if (p && p->str) { - if (xstrtol_i(p->str, NULL, 8, &unix_sock_ro_perms) != 0) { - qemudLog (QEMUD_ERR, "Failed to parse mode '%s'", p->str); - return -1; + GET_CONF_STR (conf, filename, unix_sock_ro_perms); + if (unix_sock_ro_perms) { + if (xstrtol_i (unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) { + qemudLog (QEMUD_ERR, "Failed to parse mode '%s'", + unix_sock_ro_perms); + goto free_and_fail; } + free (unix_sock_ro_perms); + unix_sock_ro_perms = NULL; } - p = virConfGetValue (conf, "unix_sock_rw_perms"); - CHECK_TYPE ("unix_sock_rw_perms", VIR_CONF_STRING); - if (p && p->str) { - if (xstrtol_i(p->str, NULL, 8, &unix_sock_rw_perms) != 0) { - qemudLog (QEMUD_ERR, "Failed to parse mode '%s'", p->str); - return -1; + GET_CONF_STR (conf, filename, unix_sock_rw_perms); + if (unix_sock_rw_perms) { + if (xstrtol_i (unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) { + qemudLog (QEMUD_ERR, "Failed to parse mode '%s'", + unix_sock_rw_perms); + goto free_and_fail; } + free (unix_sock_rw_perms); + unix_sock_rw_perms = NULL; } #ifdef HAVE_AVAHI - p = virConfGetValue (conf, "mdns_adv"); - CHECK_TYPE ("mdns_adv", VIR_CONF_LONG); - mdns_adv = p ? p->l : mdns_adv; - - p = virConfGetValue (conf, "mdns_name"); - CHECK_TYPE ("mdns_name", VIR_CONF_STRING); - mdns_name = p ? strdup (p->str) : NULL; + GET_CONF_INT (conf, filename, mdns_adv); + GET_CONF_STR (conf, filename, mdns_name); #endif - p = virConfGetValue (conf, "tls_no_verify_certificate"); - CHECK_TYPE ("tls_no_verify_certificate", VIR_CONF_LONG); - tls_no_verify_certificate = p ? p->l : tls_no_verify_certificate; - - p = virConfGetValue (conf, "tls_no_verify_address"); - CHECK_TYPE ("tls_no_verify_address", VIR_CONF_LONG); - tls_no_verify_address = p ? p->l : tls_no_verify_address; - - p = virConfGetValue (conf, "key_file"); - CHECK_TYPE ("key_file", VIR_CONF_STRING); - key_file = p ? strdup (p->str) : key_file; - - p = virConfGetValue (conf, "cert_file"); - CHECK_TYPE ("cert_file", VIR_CONF_STRING); - cert_file = p ? strdup (p->str) : cert_file; - - p = virConfGetValue (conf, "ca_file"); - CHECK_TYPE ("ca_file", VIR_CONF_STRING); - ca_file = p ? strdup (p->str) : ca_file; - - p = virConfGetValue (conf, "crl_file"); - CHECK_TYPE ("crl_file", VIR_CONF_STRING); - crl_file = p ? strdup (p->str) : crl_file; - - p = virConfGetValue (conf, "tls_allowed_dn_list"); - if (p) { - switch (p->type) { - case VIR_CONF_STRING: - tls_allowed_dn_list = malloc (2 * sizeof (char *)); - tls_allowed_dn_list[0] = strdup (p->str); - tls_allowed_dn_list[1] = 0; - break; + GET_CONF_INT (conf, filename, tls_no_verify_certificate); + GET_CONF_INT (conf, filename, tls_no_verify_address); - case VIR_CONF_LIST: { - int i, len = 0; - virConfValuePtr pp; - for (pp = p->list; pp; pp = p->next) - len++; - tls_allowed_dn_list = - malloc ((1+len) * sizeof (char *)); - for (i = 0, pp = p->list; pp; ++i, pp = p->next) { - if (pp->type != VIR_CONF_STRING) { - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_dn_list: should be a string or list of strings\n", filename); - return -1; - } - tls_allowed_dn_list[i] = strdup (pp->str); - } - tls_allowed_dn_list[i] = 0; - break; - } + GET_CONF_STR (conf, filename, key_file); + GET_CONF_STR (conf, filename, cert_file); + GET_CONF_STR (conf, filename, ca_file); + GET_CONF_STR (conf, filename, crl_file); - default: - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_dn_list: should be a string or list of strings\n", filename); - return -1; - } - } + if (remoteConfigGetStringList (conf, "tls_allowed_dn_list", + &tls_allowed_dn_list, filename) < 0) + goto free_and_fail; - p = virConfGetValue (conf, "tls_allowed_ip_list"); - if (p) { - switch (p->type) { - case VIR_CONF_STRING: - tls_allowed_ip_list = malloc (2 * sizeof (char *)); - tls_allowed_ip_list[0] = strdup (p->str); - tls_allowed_ip_list[1] = 0; - break; + if (remoteConfigGetStringList (conf, "tls_allowed_ip_list", + &tls_allowed_ip_list, filename) < 0) + goto free_and_fail; - case VIR_CONF_LIST: { - int i, len = 0; - virConfValuePtr pp; - for (pp = p->list; pp; pp = p->next) - len++; - tls_allowed_ip_list = - malloc ((1+len) * sizeof (char *)); - for (i = 0, pp = p->list; pp; ++i, pp = p->next) { - if (pp->type != VIR_CONF_STRING) { - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_ip_list: should be a string or list of strings\n", filename); - return -1; - } - tls_allowed_ip_list[i] = strdup (pp->str); - } - tls_allowed_ip_list[i] = 0; - break; - } + virConfFree (conf); + return 0; - default: - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_ip_list: should be a string or list of strings\n", filename); - return -1; - } + free_and_fail: + virConfFree (conf); + free (mdns_name); + mdns_name = NULL; + free (unix_sock_ro_perms); + free (unix_sock_rw_perms); + free (unix_sock_group); + + /* Don't bother trying to free tcp_port, tls_port, key_file, cert_file, + ca_file, or crl_file, since they are initialized to non-malloc'd + strings. Besides, these are static variables, and callers are + unlikely to call this function more than once, so there wouldn't + even be a real leak. */ + + if (tls_allowed_dn_list) { + int i; + for (i = 0; tls_allowed_dn_list[i]; i++) + free (tls_allowed_dn_list[i]); + free (tls_allowed_dn_list); + tls_allowed_dn_list = NULL; + } + + if (tls_allowed_ip_list) { + int i; + for (i = 0; tls_allowed_ip_list[i]; i++) + free (tls_allowed_ip_list[i]); + free (tls_allowed_ip_list); + tls_allowed_ip_list = NULL; } - virConfFree (conf); - return 0; + return -1; } /* Print command-line usage. */ diff --git a/src/conf.h b/src/conf.h index 7a7ad25..53c9456 100644 --- a/src/conf.h +++ b/src/conf.h @@ -1,7 +1,7 @@ /** * conf.h: parser for a subset of the Python encoded Xen configuration files * - * Copyright (C) 2006 Red Hat, Inc. + * Copyright (C) 2006, 2007 Red Hat, Inc. * * See COPYING.LIB for the License of this software * @@ -28,6 +28,21 @@ typedef enum { VIR_CONF_LIST = 3 /* a list */ } virConfType; +static inline const char * +virConfTypeName (virConfType t) +{ + switch (t) { + case VIR_CONF_LONG: + return "long"; + case VIR_CONF_STRING: + return "string"; + case VIR_CONF_LIST: + return "list"; + default: + return "*unexpected*"; + } +} + /** * virConfValue: * a value from the configuration file @@ -80,3 +95,12 @@ int __virConfWriteMem (char *memory, } #endif #endif /* __VIR_CONF_H__ */ + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ -- 1.5.3.6.961.gecf4 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list