+ if (r == -1)
+ guestfs___rollback_cmdline (g, cmdline_pos);
+
+ return r;
+}
+
+static int
+add_disk (guestfs_h *g, const char *filename, const char *format,
+ void *optargs_vp)
+{
+ struct guestfs_add_drive_opts_argv *optargs = optargs_vp;
+
+ if (format) {
+ optargs->bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
+ optargs->format = format;
+ } else
+ optargs->bitmask &= ~GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
+
+ return guestfs__add_drive_opts (g, filename, optargs);
+}
+
+static int
+connect_live (guestfs_h *g, virDomainPtr dom)
+{
+ int i, r = -1;
+ virErrorPtr err;
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr xpathCtx = NULL;
+ xmlXPathObjectPtr xpathObj = NULL;
+ char *xml = NULL;
+ char *path = NULL;
+ char *attach_method = NULL;
+
+ /* Domain XML. */
+ xml = virDomainGetXMLDesc (dom, 0);
+
+ if (!xml) {
+ err = virGetLastError ();
+ error (g, _("error reading libvirt XML information: %s"),
+ err->message);
+ goto cleanup;
+ }
+
+ /* Parse XML to document. */
+ doc = xmlParseMemory (xml, strlen (xml));
+ if (doc == NULL) {
+ error (g, _("unable to parse XML information returned by libvirt"));
+ goto cleanup;
+ }
+
+ xpathCtx = xmlXPathNewContext (doc);
+ if (xpathCtx == NULL) {
+ error (g, _("unable to create new XPath context"));
+ goto cleanup;
+ }
+
+ /* This gives us a set of all the <channel> nodes related to the
+ * guestfsd virtio-serial channel.
+ */
+ xpathObj = xmlXPathEvalExpression (BAD_CAST
+ "//devices/channel[@type=\"unix\" and "
+ "./source/@mode=\"bind\" and "
+ "./source/@path and "
+ "./target/@type=\"virtio\" and "
+ "./target/@name=\"org.libguestfs.channel.0\"]",
+ xpathCtx);
+ if (xpathObj == NULL) {
+ error (g, _("unable to evaluate XPath expression"));
+ goto cleanup;
+ }
+
+ xmlNodeSetPtr nodes = xpathObj->nodesetval;
+ for (i = 0; i < nodes->nodeNr; ++i) {
+ xmlXPathObjectPtr xppath;
+
+ /* See note in function above. */
+ xpathCtx->node = nodes->nodeTab[i];
+
+ /* The path is in <source path=..> attribute. */
+ xppath = xmlXPathEvalExpression (BAD_CAST "./source/@path", xpathCtx);
+ if (xppath == NULL ||
+ xppath->nodesetval == NULL ||
+ xppath->nodesetval->nodeNr == 0) {
+ xmlXPathFreeObject (xppath);
+ continue; /* no type attribute, skip it */
+ }
+ assert (xppath->nodesetval->nodeTab[0]);
+ assert (xppath->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
+ xmlAttrPtr attr = (xmlAttrPtr) xppath->nodesetval->nodeTab[0];
+ path = (char *) xmlNodeListGetString (doc, attr->children, 1);
+ xmlXPathFreeObject (xppath);
+ break;
+ }
+
+ if (path == NULL) {
+ error (g, _("this guest has no libvirt <channel> definition for guestfsd\n"
+ "See ATTACHING TO RUNNING DAEMONS in guestfs(3) for further information."));
+ goto cleanup;
+ }
+
+ /* Got a path. */
+ attach_method = safe_malloc (g, strlen (path) + 5 + 1);
+ strcpy (attach_method, "unix:");
+ strcat (attach_method, path);
+ r = guestfs_set_attach_method (g, attach_method);