[libvirt] [PATCHv3 2/5] smartcard: add domain conf support

Eric Blake eblake at redhat.com
Wed Jan 26 00:36:55 UTC 2011


* src/conf/domain_conf.h (virDomainSmartcardType): New enum.
(virDomainSmartcardDef, virDomainDeviceCcidAddress): New structs.
(virDomainDef): Include smartcards.
(virDomainSmartcardDefIterator): New typedef.
(virDomainSmartcardDefFree, virDomainSmartcardDefForeach): New
prototypes.
(virDomainControllerType, virDomainDeviceAddressType): Add ccid
enum values.
(virDomainDeviceInfo): Add ccid address type.
* src/conf/domain_conf.c (virDomainSmartcard): Convert between
enum and string.
(virDomainSmartcardDefParseXML, virDomainSmartcardDefFormat)
(virDomainSmartcardDefFree, virDomainDeviceCcidAddressParseXML)
(virDomainDefMaybeAddSmartcardController): New functions.
(virDomainDefParseXML): Parse the new XML.
(virDomainDefFormat): Convert back to XML.
(virDomainDefFree): Clean up.
(virDomainDeviceInfoIterate): Iterate over passthrough aliases.
(virDomainController, virDomainDeviceAddress)
(virDomainDeviceInfoParseXML, virDomainDeviceInfoFormat)
(virDomainDefAddImplicitControllers): Support new values.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): List new function.

Notes:
    v2: first version of patch (v1 was xml proposal only)
    v3: add controller type='ccid' support, extra smartcard element support
---
 cfg.mk                   |    1 +
 src/conf/domain_conf.c   |  396 ++++++++++++++++++++++++++++++++++++++++++++--
 src/conf/domain_conf.h   |   53 ++++++-
 src/libvirt_private.syms |    4 +
 4 files changed, 442 insertions(+), 12 deletions(-)

diff --git a/cfg.mk b/cfg.mk
index 066fa3d..659a414 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -100,6 +100,7 @@ useless_free_options =				\
   --name=virDomainInputDefFree			\
   --name=virDomainNetDefFree			\
   --name=virDomainObjFree			\
+  --name=virDomainSmartcardDefFree		\
   --name=virDomainSnapshotDefFree		\
   --name=virDomainSnapshotObjFree		\
   --name=virDomainSoundDefFree			\
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index f05c865..b1f22f0 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -109,7 +109,8 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
               "none",
               "pci",
               "drive",
-              "virtio-serial")
+              "virtio-serial",
+              "ccid")

 VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
               "block",
@@ -159,7 +160,8 @@ VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
               "fdc",
               "scsi",
               "sata",
-              "virtio-serial")
+              "virtio-serial",
+              "ccid")

 VIR_ENUM_IMPL(virDomainControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST,
               "auto",
@@ -232,6 +234,11 @@ VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
               "telnets",
               "tls")

+VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST,
+              "host",
+              "host-certificates",
+              "passthrough")
+
 VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
               "sb16",
               "es1370",
@@ -693,6 +700,36 @@ void virDomainChrDefFree(virDomainChrDefPtr def)
     VIR_FREE(def);
 }

+void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def)
+{
+    size_t i;
+    if (!def)
+        return;
+
+    switch (def->type) {
+    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
+        VIR_FREE(def->data.host.dev);
+        break;
+
+    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
+        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
+            VIR_FREE(def->data.cert.file[i]);
+        VIR_FREE(def->data.cert.database);
+        break;
+
+    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
+        virDomainChrSourceDefClear(&def->data.passthru);
+        break;
+
+    default:
+        break;
+    }
+
+    virDomainDeviceInfoClear(&def->info);
+
+    VIR_FREE(def);
+}
+
 void virDomainSoundDefFree(virDomainSoundDefPtr def)
 {
     if (!def)
@@ -834,6 +871,10 @@ void virDomainDefFree(virDomainDefPtr def)
         virDomainNetDefFree(def->nets[i]);
     VIR_FREE(def->nets);

+    for (i = 0 ; i < def->nsmartcards ; i++)
+        virDomainSmartcardDefFree(def->smartcards[i]);
+    VIR_FREE(def->smartcards);
+
     for (i = 0 ; i < def->nserials ; i++)
         virDomainChrDefFree(def->serials[i]);
     VIR_FREE(def->serials);
@@ -1198,6 +1239,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
     for (i = 0; i < def->ncontrollers ; i++)
         if (cb(def, &def->controllers[i]->info, opaque) < 0)
             return -1;
+    for (i = 0; i < def->nsmartcards ; i++)
+        if (cb(def, &def->smartcards[i]->info, opaque) < 0)
+            return -1;
     for (i = 0; i < def->nserials ; i++)
         if (cb(def, &def->serials[i]->info, opaque) < 0)
             return -1;
@@ -1240,16 +1284,11 @@ void virDomainDefClearDeviceAliases(virDomainDefPtr def)
 /* Generate a string representation of a device address
  * @param address Device address to stringify
  */
-static int virDomainDeviceInfoFormat(virBufferPtr buf,
-                                     virDomainDeviceInfoPtr info,
-                                     int flags)
+static int ATTRIBUTE_NONNULL(2)
+virDomainDeviceInfoFormat(virBufferPtr buf,
+                          virDomainDeviceInfoPtr info,
+                          int flags)
 {
-    if (!info) {
-        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                             _("missing device information"));
-        return -1;
-    }
-
     if (info->alias &&
         !(flags & VIR_DOMAIN_XML_INACTIVE)) {
         virBufferVSprintf(buf, "      <alias name='%s'/>\n", info->alias);
@@ -1285,6 +1324,12 @@ static int virDomainDeviceInfoFormat(virBufferPtr buf,
                           info->addr.vioserial.port);
         break;

+    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
+        virBufferVSprintf(buf, " controller='%d' slot='%d'",
+                          info->addr.ccid.controller,
+                          info->addr.ccid.slot);
+        break;
+
     default:
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                              _("unknown address type '%d'"), info->type);
@@ -1458,6 +1503,40 @@ cleanup:
     return ret;
 }

+static int
+virDomainDeviceCcidAddressParseXML(xmlNodePtr node,
+                                   virDomainDeviceCcidAddressPtr addr)
+{
+    char *controller, *slot;
+    int ret = -1;
+
+    memset(addr, 0, sizeof(*addr));
+
+    controller = virXMLPropString(node, "controller");
+    slot = virXMLPropString(node, "slot");
+
+    if (controller &&
+        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("Cannot parse <address> 'controller' attribute"));
+        goto cleanup;
+    }
+
+    if (slot &&
+        virStrToLong_ui(slot, NULL, 10, &addr->slot) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("Cannot parse <address> 'slot' attribute"));
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    VIR_FREE(controller);
+    VIR_FREE(slot);
+    return ret;
+}
+
 /* Parse the XML definition for a device address
  * @param node XML nodeset to parse for device address definition
  */
@@ -1526,6 +1605,11 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
             goto cleanup;
         break;

+    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
+        if (virDomainDeviceCcidAddressParseXML(address, &info->addr.ccid) < 0)
+            goto cleanup;
+        break;
+
     default:
         /* Should not happen */
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -3185,6 +3269,152 @@ error:
     goto cleanup;
 }

+static virDomainSmartcardDefPtr
+virDomainSmartcardDefParseXML(xmlNodePtr node,
+                              int flags)
+{
+    xmlNodePtr cur;
+    char *mode = NULL;
+    char *type = NULL;
+    virDomainSmartcardDefPtr def;
+    int i;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    mode = virXMLPropString(node, "mode");
+    if (mode == NULL) {
+        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                             _("missing smartcard device mode"));
+        goto error;
+    }
+    if ((def->type = virDomainSmartcardTypeFromString(mode)) < 0) {
+        virDomainReportError(VIR_ERR_XML_ERROR,
+                             _("unknown smartcard device mode: %s"),
+                             mode);
+        goto error;
+    }
+
+    switch (def->type) {
+    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
+        cur = node->children;
+        while (cur) {
+            if (cur->type == XML_ELEMENT_NODE &&
+                xmlStrEqual(cur->name, BAD_CAST "source")) {
+                def->data.host.dev = virXMLPropString(cur, "dev");
+                if (!def->data.host.dev) {
+                    virReportOOMError();
+                    goto error;
+                }
+                if (*def->data.host.dev != '/') {
+                    virDomainReportError(VIR_ERR_XML_ERROR,
+                                         _("expecting absolute path: %s"),
+                                         def->data.host.dev);
+                    goto error;
+                }
+            }
+            cur = cur->next;
+        }
+        break;
+
+    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
+        i = 0;
+        cur = node->children;
+        while (cur) {
+            if (cur->type == XML_ELEMENT_NODE &&
+                xmlStrEqual(cur->name, BAD_CAST "certificate")) {
+                if (i == 3) {
+                    virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                                         _("host-certificates mode needs "
+                                           "exactly three certificates"));
+                    goto error;
+                }
+                def->data.cert.file[i] = (char *)xmlNodeGetContent(cur);
+                if (!def->data.cert.file[i]) {
+                    virReportOOMError();
+                    goto error;
+                }
+                if (*def->data.cert.file[i] != '/') {
+                    virDomainReportError(VIR_ERR_XML_ERROR,
+                                         _("expecting absolute path: %s"),
+                                         def->data.cert.file[i]);
+                    goto error;
+                }
+                i++;
+            } else if (cur->type == XML_ELEMENT_NODE &&
+                       xmlStrEqual(cur->name, BAD_CAST "database") &&
+                       !def->data.cert.database) {
+                def->data.cert.database = (char *)xmlNodeGetContent(cur);
+                if (!def->data.cert.database) {
+                    virReportOOMError();
+                    goto error;
+                }
+                if (*def->data.cert.database != '/') {
+                    virDomainReportError(VIR_ERR_XML_ERROR,
+                                         _("expecting absolute path: %s"),
+                                         def->data.cert.database);
+                    goto error;
+                }
+            }
+            cur = cur->next;
+        }
+        if (i < 3) {
+            virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                                 _("host-certificates mode needs "
+                                   "exactly three certificates"));
+            goto error;
+        }
+        break;
+
+    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
+        type = virXMLPropString(node, "type");
+        if (type == NULL) {
+            virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                                 _("passthrough mode requires a character "
+                                   "device type attribute"));
+            goto error;
+        }
+        if ((def->data.passthru.type = virDomainChrTypeFromString(type)) < 0) {
+            virDomainReportError(VIR_ERR_XML_ERROR,
+                                 _("unknown type presented to host for "
+                                   "character device: %s"), type);
+            goto error;
+        }
+
+        cur = node->children;
+        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur) < 0)
+            goto error;
+        break;
+
+    default:
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("unknown smartcard mode"));
+        goto error;
+    }
+
+    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
+        goto error;
+    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("Controllers must use the 'ccid' address type"));
+        goto error;
+    }
+
+cleanup:
+    VIR_FREE(mode);
+    VIR_FREE(type);
+
+    return def;
+
+error:
+    virDomainSmartcardDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
 /* Parse the XML definition for a network interface */
 static virDomainInputDefPtr
 virDomainInputDefParseXML(const char *ostype,
@@ -5250,6 +5480,26 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     VIR_FREE(nodes);


+    /* analysis of the smartcard devices */
+    if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract smartcard devices"));
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->smartcards, n) < 0)
+        goto no_memory;
+
+    for (i = 0 ; i < n ; i++) {
+        virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(nodes[i],
+                                                                      flags);
+        if (!card)
+            goto error;
+
+        def->smartcards[def->nsmartcards++] = card;
+    }
+    VIR_FREE(nodes);
+
+
     /* analysis of the character devices */
     if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -5927,6 +6177,45 @@ static int virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
 }


+static int
+virDomainDefMaybeAddSmartcardController(virDomainDefPtr def)
+{
+    /* Look for any smartcard devs */
+    int i;
+
+    for (i = 0 ; i < def->nsmartcards ; i++) {
+        virDomainSmartcardDefPtr smartcard = def->smartcards[i];
+        int idx = 0;
+
+        if (smartcard->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
+            idx = smartcard->info.addr.ccid.controller;
+        } else if (smartcard->info.type
+                   == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+            int j;
+            int max = -1;
+
+            for (j = 0; j < def->nsmartcards; j++) {
+                virDomainDeviceInfoPtr info = &def->smartcards[j]->info;
+                if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID &&
+                    info->addr.ccid.controller == 0 &&
+                    (int) info->addr.ccid.slot > max)
+                    max = info->addr.ccid.slot;
+            }
+            smartcard->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID;
+            smartcard->info.addr.ccid.controller = 0;
+            smartcard->info.addr.ccid.slot = max + 1;
+        }
+
+        if (virDomainDefMaybeAddController(def,
+                                           VIR_DOMAIN_CONTROLLER_TYPE_CCID,
+                                           idx) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
 /*
  * Based on the declared <address/> info for any devices,
  * add neccessary drive controllers which are not already present
@@ -5953,6 +6242,9 @@ int virDomainDefAddImplicitControllers(virDomainDefPtr def)
     if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
         return -1;

+    if (virDomainDefMaybeAddSmartcardController(def) < 0)
+        return -1;
+
     return 0;
 }

@@ -6732,6 +7024,61 @@ virDomainChrDefFormat(virBufferPtr buf,
 }

 static int
+virDomainSmartcardDefFormat(virBufferPtr buf,
+                            virDomainSmartcardDefPtr def,
+                            int flags)
+{
+    const char *mode = virDomainSmartcardTypeToString(def->type);
+    size_t i;
+
+    if (!mode) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected smartcard type %d"), def->type);
+        return -1;
+    }
+
+    virBufferVSprintf(buf, "    <smartcard mode='%s'", mode);
+    switch (def->type) {
+    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
+        if (def->data.host.dev || virDomainDeviceInfoIsSet(&def->info)) {
+            virBufferAddLit(buf, ">\n");
+            if (def->data.host.dev)
+                virBufferEscapeString(buf, "      <source def='%s'/>\n",
+                                      def->data.host.dev);
+        } else {
+            virBufferAddLit(buf, "/>\n");
+            return 0;
+        }
+        break;
+
+    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
+        virBufferAddLit(buf, ">\n");
+        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
+            virBufferEscapeString(buf, "      <certificate>%s</certificate>\n",
+                                  def->data.cert.file[i]);
+        if (def->data.cert.database)
+            virBufferEscapeString(buf, "      <database>%s</database>\n",
+                                  def->data.cert.database);
+        break;
+
+    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
+        if (virDomainChrSourceDefFormat(buf, &def->data.passthru, false,
+                                        flags) < 0)
+            return -1;
+        break;
+
+    default:
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected smartcard type %d"), def->type);
+        return -1;
+    }
+    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+        return -1;
+    virBufferAddLit(buf, "    </smartcard>\n");
+    return 0;
+}
+
+static int
 virDomainSoundDefFormat(virBufferPtr buf,
                         virDomainSoundDefPtr def,
                         int flags)
@@ -7534,6 +7881,10 @@ char *virDomainDefFormat(virDomainDefPtr def,
         if (virDomainNetDefFormat(&buf, def->nets[n], flags) < 0)
             goto cleanup;

+    for (n = 0 ; n < def->nsmartcards ; n++)
+        if (virDomainSmartcardDefFormat(&buf, def->smartcards[n], flags) < 0)
+            goto cleanup;
+
     for (n = 0 ; n < def->nserials ; n++)
         if (virDomainChrDefFormat(&buf, def->serials[n], flags) < 0)
             goto cleanup;
@@ -8612,6 +8963,29 @@ done:
 }


+int virDomainSmartcardDefForeach(virDomainDefPtr def,
+                                 bool abortOnError,
+                                 virDomainSmartcardDefIterator iter,
+                                 void *opaque)
+{
+    int i;
+    int rc = 0;
+
+    for (i = 0 ; i < def->nsmartcards ; i++) {
+        if ((iter)(def,
+                   def->smartcards[i],
+                   opaque) < 0)
+            rc = -1;
+
+        if (abortOnError && rc != 0)
+            goto done;
+    }
+
+done:
+    return rc;
+}
+
+
 int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
                                 bool allowProbing,
                                 bool ignoreOpenFailure,
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 871fa9a..d1ebba9 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -73,6 +73,7 @@ enum virDomainDeviceAddressType {
     VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI,
     VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE,
     VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL,
+    VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID,

     VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST
 };
@@ -102,6 +103,13 @@ struct _virDomainDeviceVirtioSerialAddress {
     unsigned int port;
 };

+typedef struct _virDomainDeviceCcidAddress virDomainDeviceCcidAddress;
+typedef virDomainDeviceCcidAddress *virDomainDeviceCcidAddressPtr;
+struct _virDomainDeviceCcidAddress {
+    unsigned int controller;
+    unsigned int slot;
+};
+
 typedef struct _virDomainDeviceInfo virDomainDeviceInfo;
 typedef virDomainDeviceInfo *virDomainDeviceInfoPtr;
 struct _virDomainDeviceInfo {
@@ -111,6 +119,7 @@ struct _virDomainDeviceInfo {
         virDomainDevicePCIAddress pci;
         virDomainDeviceDriveAddress drive;
         virDomainDeviceVirtioSerialAddress vioserial;
+        virDomainDeviceCcidAddress ccid;
     } addr;
 };

@@ -220,6 +229,7 @@ enum virDomainControllerType {
     VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
     VIR_DOMAIN_CONTROLLER_TYPE_SATA,
     VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
+    VIR_DOMAIN_CONTROLLER_TYPE_CCID,

     VIR_DOMAIN_CONTROLLER_TYPE_LAST
 };
@@ -461,6 +471,34 @@ struct _virDomainChrDef {
     virDomainDeviceInfo info;
 };

+enum virDomainSmartcardType {
+    VIR_DOMAIN_SMARTCARD_TYPE_HOST,
+    VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES,
+    VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH,
+
+    VIR_DOMAIN_SMARTCARD_TYPE_LAST,
+};
+
+# define VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES 3
+
+typedef struct _virDomainSmartcardDef virDomainSmartcardDef;
+typedef virDomainSmartcardDef *virDomainSmartcardDefPtr;
+struct _virDomainSmartcardDef {
+    int type; /* virDomainSmartcardType */
+    union {
+        struct {
+            char *dev;
+        } host; /* host */
+        struct {
+            char *file[VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES];
+            char *database;
+        } cert; /* host-certificates */
+        virDomainChrSourceDef passthru; /* passthrough */
+    } data;
+
+    virDomainDeviceInfo info;
+};
+
 enum virDomainInputType {
     VIR_DOMAIN_INPUT_TYPE_MOUSE,
     VIR_DOMAIN_INPUT_TYPE_TABLET,
@@ -1031,6 +1069,9 @@ struct _virDomainDef {
     int nhostdevs;
     virDomainHostdevDefPtr *hostdevs;

+    int nsmartcards;
+    virDomainSmartcardDefPtr *smartcards;
+
     int nserials;
     virDomainChrDefPtr *serials;

@@ -1109,6 +1150,7 @@ void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def);
 void virDomainControllerDefFree(virDomainControllerDefPtr def);
 void virDomainFSDefFree(virDomainFSDefPtr def);
 void virDomainNetDefFree(virDomainNetDefPtr def);
+void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def);
 void virDomainChrDefFree(virDomainChrDefPtr def);
 void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def);
 void virDomainSoundDefFree(virDomainSoundDefPtr def);
@@ -1257,6 +1299,15 @@ int virDomainObjListGetInactiveNames(virDomainObjListPtr doms,
                                      char **const names,
                                      int maxnames);

+typedef int (*virDomainSmartcardDefIterator)(virDomainDefPtr def,
+                                             virDomainSmartcardDefPtr dev,
+                                             void *opaque);
+
+int virDomainSmartcardDefForeach(virDomainDefPtr def,
+                                 bool abortOnError,
+                                 virDomainSmartcardDefIterator iter,
+                                 void *opaque);
+
 typedef int (*virDomainChrDefIterator)(virDomainDefPtr def,
                                        virDomainChrDefPtr dev,
                                        void *opaque);
@@ -1266,7 +1317,6 @@ int virDomainChrDefForeach(virDomainDefPtr def,
                            virDomainChrDefIterator iter,
                            void *opaque);

-
 typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk,
                                             const char *path,
                                             size_t depth,
@@ -1305,6 +1355,7 @@ VIR_ENUM_DECL(virDomainNetBackend)
 VIR_ENUM_DECL(virDomainChrDevice)
 VIR_ENUM_DECL(virDomainChrChannelTarget)
 VIR_ENUM_DECL(virDomainChrConsoleTarget)
+VIR_ENUM_DECL(virDomainSmartcard)
 VIR_ENUM_DECL(virDomainChr)
 VIR_ENUM_DECL(virDomainChrTcpProtocol)
 VIR_ENUM_DECL(virDomainSoundModel)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1f4bbeb..e6dbef0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -283,6 +283,10 @@ virDomainRemoveInactive;
 virDomainSaveConfig;
 virDomainSaveStatus;
 virDomainSaveXML;
+virDomainSmartcardDefForeach;
+virDomainSmartcardDefFree;
+virDomainSmartcardTypeFromString;
+virDomainSmartcardTypeToString;
 virDomainSnapshotAssignDef;
 virDomainSnapshotDefFormat;
 virDomainSnapshotDefFree;
-- 
1.7.3.5




More information about the libvir-list mailing list