This returns the internal list of drives. 'debug' commands are
not part of the formal API and can be removed or changed at any time.");
- ("add_domain", (RInt "nrdisks", [String "dom"], [String "libvirturi"; Bool "readonly"; String "iface"; Bool "live"; Bool "allowuuid"]), -1, [FishAlias "domain"],
+ ("add_domain", (RInt "nrdisks", [String "dom"], [String "libvirturi"; Bool "readonly"; String "iface"; Bool "live"; Bool "allowuuid"; String "readonlydisk"]), -1, [FishAlias "domain"],
[],
"add the disk(s) from a named libvirt domain",
"\
treated as a UUID first and looked up, and if that lookup fails
then we treat C<dom> as a name as usual.
+The optional C<readonlydisk> parameter controls what we do for
+disks which are marked E<lt>readonly/E<gt> in the libvirt XML.
+Possible values are:
+
+=over 4
+
+=item readonlydisk = \"error\"
+
+If C<readonly> is false:
+
+The whole call is aborted with an error if any disk with
+the E<lt>readonly/E<gt> flag is found.
+
+If C<readonly> is true:
+
+Disks with the E<lt>readonly/E<gt> flag are added read-only.
+
+=item readonlydisk = \"read\"
+
+If C<readonly> is false:
+
+Disks with the E<lt>readonly/E<gt> flag are added read-only.
+Other disks are added read/write.
+
+If C<readonly> is true:
+
+Disks with the E<lt>readonly/E<gt> flag are added read-only.
+
+=item readonlydisk = \"write\" (default)
+
+If C<readonly> is false:
+
+Disks with the E<lt>readonly/E<gt> flag are added read/write.
+
+If C<readonly> is true:
+
+Disks with the E<lt>readonly/E<gt> flag are added read-only.
+
+=item readonlydisk = \"ignore\"
+
+If C<readonly> is true or false:
+
+Disks with the E<lt>readonly/E<gt> flag are skipped.
+
+=back
+
The other optional parameters are passed directly through to
C<guestfs_add_drive_opts>.");
(*
This interface is not quite baked yet. -- RWMJ 2010-11-11
- ("add_libvirt_dom", (RInt "nrdisks", [Pointer ("virDomainPtr", "dom")], [Bool "readonly"; String "iface"; Bool "live"]), -1, [NotInFish],
+ ("add_libvirt_dom", (RInt "nrdisks", [Pointer ("virDomainPtr", "dom")], [Bool "readonly"; String "iface"; Bool "live"; String "readonlydisk"]), -1, [NotInFish],
[],
"add the disk(s) from a libvirt domain",
"\
to try. See L<guestfs(3)/ATTACHING TO RUNNING DAEMONS> for more
information.
+The optional C<readonlydisk> parameter controls what we do for
+disks which are marked E<lt>readonly/E<gt> in the libvirt XML.
+See C<guestfs_add_domain> for possible values.
+
The other optional parameters are passed directly through to
C<guestfs_add_drive_opts>.");
*)
set -e
-rm -f test1.img test2.img test3.img test.xml test.out
+rm -f test1.img test2.img test3.img test4.img test.xml test.out
cwd="$(pwd)"
-truncate -s 1M test1.img test2.img test3.img
+truncate -s 1M test1.img test2.img test3.img test4.img
# Libvirt test XML, see libvirt.git/examples/xml/test/testnode.xml
cat > test.xml <<EOF
<source file="$cwd/test3.img"/>
<target dev="hdc"/>
</disk>
+ <disk type="file">
+ <driver name="qemu" type="raw"/>
+ <source file="$cwd/test4.img"/>
+ <target dev="hdd"/>
+ <readonly/>
+ </disk>
</devices>
</domain>
</node>
grep -sq "test2.img.*snapshot=on.*format=raw" test.out
grep -sq "test3.img.*snapshot=on.*format=qcow2" test.out
+# Test readonlydisk = "ignore".
+../fish/guestfish >test.out <<EOF
+ -domain guest libvirturi:test://$cwd/test.xml readonly:true readonlydisk:ignore
+ debug-drives
+EOF
+grep -sq "test1.img" test.out
+grep -sq "test2.img" test.out
+grep -sq "test3.img" test.out
+! grep -sq "test4.img" test.out
+
# Test atomicity.
rm test3.img
! grep -sq "test1.img" test.out
! grep -sq "test2.img" test.out
! grep -sq "test3.img" test.out
+! grep -sq "test4.img" test.out
-rm -f test1.img test2.img test3.img test.xml test.out
+rm -f test1.img test2.img test3.img test4.img test.xml test.out
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);
int readonly;
int live;
int allowuuid;
+ const char *readonlydisk;
const char *iface;
struct guestfs___add_libvirt_dom_argv optargs2 = { .bitmask = 0 };
? 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"));
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);
/* 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, int readonly, 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 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
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;
}
/* 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.
*/
struct drive **cp = guestfs___checkpoint_drives (g);
- r = guestfs___for_each_disk (g, dom, add_disk, &optargs2);
+ r = guestfs___for_each_disk (g, dom, add_disk, &data);
if (r == -1)
guestfs___rollback_drives (g, cp);
static int
add_disk (guestfs_h *g,
- const char *filename, const char *format, int readonly,
- void *optargs_vp)
+ 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) { /* <readonly/> 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 <readonly/> in XML */
+ readonly = data->readonly;
+
+ if (skip)
+ return 0;
+
+ if (error) {
+ error (g, _("%s: disk is marked <readonly/> 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