X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fvirt.c;h=a95b0290037a4b83f6ecf094ffdf4565323bed4e;hb=454a08380d9de78448927ab77480f833342d214c;hp=a23ac0a58237f7f27ed9ca0bdaab005705f92b64;hpb=2020eded8a3f381c722abe001be8000723ff2418;p=libguestfs.git
diff --git a/src/virt.c b/src/virt.c
index a23ac0a..a95b029 100644
--- a/src/virt.c
+++ b/src/virt.c
@@ -53,6 +53,12 @@ init_libxml2 (void)
LIBXML_TEST_VERSION;
}
+static void
+ignore_errors (void *ignore, virErrorPtr ignore2)
+{
+ /* empty */
+}
+
struct guestfs___add_libvirt_dom_argv {
uint64_t bitmask;
#define GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK (UINT64_C(1)<<0)
@@ -61,6 +67,8 @@ struct guestfs___add_libvirt_dom_argv {
const char *iface;
#define GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK (UINT64_C(1)<<2)
int live;
+#define GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK (UINT64_C(1)<<3)
+ const char *readonlydisk;
};
static int guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom, const struct guestfs___add_libvirt_dom_argv *optargs);
@@ -76,6 +84,8 @@ guestfs__add_domain (guestfs_h *g, const char *domain_name,
const char *libvirturi;
int readonly;
int live;
+ int allowuuid;
+ const char *readonlydisk;
const char *iface;
struct guestfs___add_libvirt_dom_argv optargs2 = { .bitmask = 0 };
@@ -87,6 +97,10 @@ guestfs__add_domain (guestfs_h *g, const char *domain_name,
? optargs->iface : NULL;
live = optargs->bitmask & GUESTFS_ADD_DOMAIN_LIVE_BITMASK
? optargs->live : 0;
+ allowuuid = optargs->bitmask & GUESTFS_ADD_DOMAIN_ALLOWUUID_BITMASK
+ ? optargs->allowuuid : 0;
+ readonlydisk = optargs->bitmask & GUESTFS_ADD_DOMAIN_READONLYDISK_BITMASK
+ ? optargs->readonlydisk : NULL;
if (live && readonly) {
error (g, _("you cannot set both live and readonly flags"));
@@ -102,7 +116,20 @@ guestfs__add_domain (guestfs_h *g, const char *domain_name,
goto cleanup;
}
- dom = virDomainLookupByName (conn, domain_name);
+ /* Suppress default behaviour of printing errors to stderr. Note
+ * you can't set this to NULL to ignore errors; setting it to NULL
+ * restores the default error handler ...
+ */
+ virConnSetErrorFunc (conn, NULL, ignore_errors);
+
+ /* Try UUID first. */
+ if (allowuuid)
+ dom = virDomainLookupByUUIDString (conn, domain_name);
+
+ /* Try ordinary domain name. */
+ if (!dom)
+ dom = virDomainLookupByName (conn, domain_name);
+
if (!dom) {
err = virGetLastError ();
error (g, _("no libvirt domain called '%s': %s"),
@@ -122,6 +149,10 @@ guestfs__add_domain (guestfs_h *g, const char *domain_name,
optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK;
optargs2.live = live;
}
+ if (readonlydisk) {
+ optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK;
+ optargs2.readonlydisk = readonlydisk;
+ }
r = guestfs___add_libvirt_dom (g, dom, &optargs2);
@@ -145,6 +176,7 @@ guestfs___for_each_disk (guestfs_h *g,
virDomainPtr dom,
int (*f) (guestfs_h *g,
const char *filename, const char *format,
+ int readonly,
void *data),
void *data)
{
@@ -262,9 +294,20 @@ guestfs___for_each_disk (guestfs_h *g,
format = (char *) xmlNodeListGetString (doc, attr->children, 1);
}
+ /* Get the flag. */
+ xmlXPathObjectPtr xpreadonly;
+
+ xpathCtx->node = nodes->nodeTab[i];
+ xpreadonly = xmlXPathEvalExpression (BAD_CAST "./readonly", xpathCtx);
+ int readonly = 0;
+ if (xpreadonly != NULL &&
+ xpreadonly->nodesetval &&
+ xpreadonly->nodesetval->nodeNr > 0)
+ readonly = 1;
+
int t;
if (f)
- t = f (g, filename, format, data);
+ t = f (g, filename, format, readonly, data);
else
t = 0;
@@ -272,6 +315,7 @@ guestfs___for_each_disk (guestfs_h *g,
xmlFree (format);
xmlXPathFreeObject (xpfilename);
xmlXPathFreeObject (xpformat);
+ xmlXPathFreeObject (xpreadonly);
if (t == -1)
goto cleanup;
@@ -298,18 +342,34 @@ guestfs___for_each_disk (guestfs_h *g,
/* This was proposed as an external API, but it's not quite baked yet. */
-static int add_disk (guestfs_h *g, const char *filename, const char *format, void *optargs_vp);
+static int add_disk (guestfs_h *g, const char *filename, const char *format, int readonly, void *data);
static int connect_live (guestfs_h *g, virDomainPtr dom);
+enum readonlydisk {
+ readonlydisk_error,
+ readonlydisk_read,
+ readonlydisk_write,
+ readonlydisk_ignore,
+};
+
+struct add_disk_data {
+ int readonly;
+ enum readonlydisk readonlydisk;
+ /* Other args to pass through to add_drive_opts. */
+ struct guestfs_add_drive_opts_argv optargs;
+};
+
static int
guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
const struct guestfs___add_libvirt_dom_argv *optargs)
{
- int cmdline_pos;
+ size_t cmdline_pos;
int r;
int readonly;
const char *iface;
int live;
+ /* Default for back-compat reasons: */
+ enum readonlydisk readonlydisk = readonlydisk_write;
readonly =
optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK
@@ -321,6 +381,21 @@ guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK
? optargs->live : 0;
+ if ((optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK)) {
+ if (STREQ (optargs->readonlydisk, "error"))
+ readonlydisk = readonlydisk_error;
+ else if (STREQ (optargs->readonlydisk, "read"))
+ readonlydisk = readonlydisk_read;
+ else if (STREQ (optargs->readonlydisk, "write"))
+ readonlydisk = readonlydisk_write;
+ else if (STREQ (optargs->readonlydisk, "ignore"))
+ readonlydisk = readonlydisk_ignore;
+ else {
+ error (g, _("unknown readonlydisk parameter"));
+ return -1;
+ }
+ }
+
if (live && readonly) {
error (g, _("you cannot set both live and readonly flags"));
return -1;
@@ -357,40 +432,75 @@ guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
}
/* Add the disks. */
- struct guestfs_add_drive_opts_argv optargs2 = { .bitmask = 0 };
- if (readonly) {
- optargs2.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
- optargs2.readonly = readonly;
- }
+ struct add_disk_data data;
+ data.optargs.bitmask = 0;
+ data.readonly = readonly;
+ data.readonlydisk = readonlydisk;
if (iface) {
- optargs2.bitmask |= GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK;
- optargs2.iface = iface;
+ data.optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK;
+ data.optargs.iface = iface;
}
/* Checkpoint the command line around the operation so that either
* all disks are added or none are added.
*/
- cmdline_pos = guestfs___checkpoint_cmdline (g);
- r = guestfs___for_each_disk (g, dom, add_disk, &optargs2);
+ struct drive **cp = guestfs___checkpoint_drives (g);
+ r = guestfs___for_each_disk (g, dom, add_disk, &data);
if (r == -1)
- guestfs___rollback_cmdline (g, cmdline_pos);
+ guestfs___rollback_drives (g, cp);
return r;
}
static int
-add_disk (guestfs_h *g, const char *filename, const char *format,
- void *optargs_vp)
+add_disk (guestfs_h *g,
+ const char *filename, const char *format, int readonly_in_xml,
+ void *datavp)
{
- struct guestfs_add_drive_opts_argv *optargs = optargs_vp;
+ struct add_disk_data *data = datavp;
+ /* Copy whole struct so we can make local changes: */
+ struct guestfs_add_drive_opts_argv optargs = data->optargs;
+ int readonly, error = 0, skip = 0;
+
+ if (readonly_in_xml) { /* appears in the XML */
+ if (data->readonly) { /* asked to add disk read-only */
+ switch (data->readonlydisk) {
+ case readonlydisk_error: readonly = 1; break;
+ case readonlydisk_read: readonly = 1; break;
+ case readonlydisk_write: readonly = 1; break;
+ case readonlydisk_ignore: skip = 1; break;
+ default: abort ();
+ }
+ } else { /* asked to add disk for read/write */
+ switch (data->readonlydisk) {
+ case readonlydisk_error: error = 1; break;
+ case readonlydisk_read: readonly = 1; break;
+ case readonlydisk_write: readonly = 0; break;
+ case readonlydisk_ignore: skip = 1; break;
+ default: abort ();
+ }
+ }
+ } else /* no in XML */
+ readonly = data->readonly;
+
+ if (skip)
+ return 0;
+
+ if (error) {
+ error (g, _("%s: disk is marked in libvirt XML, and readonlydisk was set to \"error\""),
+ filename);
+ return -1;
+ }
+
+ optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
+ optargs.readonly = readonly;
if (format) {
- optargs->bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
- optargs->format = format;
- } else
- optargs->bitmask &= ~GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
+ optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
+ optargs.format = format;
+ }
- return guestfs__add_drive_opts (g, filename, optargs);
+ return guestfs__add_drive_opts (g, filename, &optargs);
}
static int