X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fvirt.c;h=a95b0290037a4b83f6ecf094ffdf4565323bed4e;hb=34c0542189a443e57f2b09886f31b5bdad404bbf;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