diff --git a/samples/vboxwrapper/vbox_common.cpp b/samples/vboxwrapper/vbox_common.cpp
index f8da6411ea..d847ea0cfb 100644
--- a/samples/vboxwrapper/vbox_common.cpp
+++ b/samples/vboxwrapper/vbox_common.cpp
@@ -1186,13 +1186,25 @@ int VBOX_BASE::vbm_popen(string& command, string& output, const char* item, bool
// Error Code: VBOX_E_INVALID_OBJECT_STATE (0x80bb0007)
//
if (VBOX_E_INVALID_OBJECT_STATE == (unsigned int)retval) {
- if (retry_notes.find("Another VirtualBox management") == string::npos) {
- retry_notes += "Another VirtualBox management application has locked the session for\n";
- retry_notes += "this VM. BOINC cannot properly monitor this VM\n";
- retry_notes += "and so this job will be aborted.\n\n";
- }
- if (retry_count) {
- sleep_interval *= 2;
+ if ((output.find("Cannot attach medium") != string::npos) &&
+ (output.find("the media type") != string::npos) &&
+ (output.find("MultiAttach") != string::npos) &&
+ (output.find("can only be attached to machines that were created with VirtualBox 4.0 or later") != string::npos)) {
+ // VirtualBox occasionally writes the 'MultiAttach' attribute to
+ // the disk entry in VirtualBox.xml although this is not allowed there.
+ // As a result all VMs trying to connect that disk fail.
+ // Report the error back immediately without a retry.
+ //
+ break;
+ } else {
+ if (retry_notes.find("Another VirtualBox management") == string::npos) {
+ retry_notes += "Another VirtualBox management application has locked the session for\n";
+ retry_notes += "this VM. BOINC cannot properly monitor this VM\n";
+ retry_notes += "and so this job will be aborted.\n\n";
+ }
+ if (retry_count) {
+ sleep_interval *= 2;
+ }
}
}
@@ -1482,4 +1494,3 @@ VBOX_VM::VBOX_VM() {
VBOX_VM::~VBOX_VM() {
}
-
diff --git a/samples/vboxwrapper/vbox_vboxmanage.cpp b/samples/vboxwrapper/vbox_vboxmanage.cpp
index 1d2f04e1c4..6aef5daae3 100644
--- a/samples/vboxwrapper/vbox_vboxmanage.cpp
+++ b/samples/vboxwrapper/vbox_vboxmanage.cpp
@@ -16,10 +16,10 @@
// along with BOINC. If not, see .
#ifdef _WIN32
-#include
#include "boinc_win.h"
#include "win_util.h"
#else
+#include
#include
#include
#include
@@ -543,53 +543,147 @@ namespace vboxmanage {
// See: https://www.virtualbox.org/manual/ch05.html#hdimagewrites
// https://www.virtualbox.org/manual/ch05.html#diffimages
// the vdi file downloaded to the projects dir becomes the parent (read only)
- // "--setuid" must not be used
// each task gets it's own differencing image (writable)
// differencing images are written to the VM's snapshot folder
//
string medium_file = aid.project_dir;
medium_file += "/" + multiattach_vdi_file;
-#ifdef _WIN32
- replace(medium_file.begin(), medium_file.end(), '\\', '/');
-#endif
-
vboxlog_msg("Adding virtual disk drive to VM. (%s)", multiattach_vdi_file.c_str());
- command = "list hdds";
- retval = vbm_popen(command, output, "check if parent hdd is registered", false, false);
- if (retval) return retval;
+ int retry_count = 0;
+ bool log_error = false;
+ bool vbox_bug_mitigation = false;
-#ifdef _WIN32
- replace(output.begin(), output.end(), '\\', '/');
-#endif
+ do {
+ string set_new_uuid = "";
+ string type_line = "";
+ size_t type_start;
+ size_t type_end;
- if (output.find(medium_file) == string::npos) {
- // parent hdd is not registered
- // vdi files can't be registered and set to multiattach mode within 1 step.
- // They must first be attached to a VM in normal mode, then detached from the VM
+ command = "showhdinfo \"" + medium_file + "\" ";
+
+ retval = vbm_popen(command, output, "check if parent hdd is registered", false);
+ if (retval) {
+ // showhdinfo implicitly registers unregistered hdds.
+ // Hence, this has to be handled first.
+ //
+ if ((output.rfind("VBoxManage: error:", 0) != string::npos) &&
+ (output.find("Cannot register the hard disk") != string::npos) &&
+ (output.find("because a hard disk") != string::npos) &&
+ (output.find("with UUID") != string::npos) &&
+ (output.find("already exists") != string::npos)) {
+ // May happen if the project admin didn't set a new UUID.
+ set_new_uuid = "--setuuid \"\" ";
+
+ vboxlog_msg("Disk UUID conflicts with an already existing disk.\nWill set a new UUID for '%s'.\nThe project admin should be informed to do this server side running:\nvboxmanage clonemedium \n",
+ multiattach_vdi_file.c_str()
+ );
+ } else {
+ // other errors
+ vboxlog_msg("Error in check if parent hdd is registered.\nCommand:\n%s\nOutput:\n%s",
+ command.c_str(),
+ output.c_str()
+ );
+ return retval;
+ }
+ }
+
+ // Output from showhdinfo should look a little like this:
+ // UUID: c119bcaf-636c-41f6-86c9-384739a31339
+ // Parent UUID: base
+ // State: created
+ // Type: multiattach
+ // Location: C:\Users\romw\VirtualBox VMs\test2\test2.vdi
+ // Storage format: VDI
+ // Format variant: dynamic default
+ // Capacity: 2048 MBytes
+ // Size on disk: 2 MBytes
+ // Encryption: disabled
+ // Property: AllocationBlockSize=1048576
+ // Child UUIDs: dcb0daa5-3bf9-47cb-bfff-c65e74484615
//
- command = command_fix_part;
- command += "--medium \"" + medium_file + "\" ";
- retval = vbm_popen(command, output, "register parent hdd", false, false);
- if (retval) return retval;
+ type_line = output;
+ transform(type_line.cbegin(), type_line.cend(),
+ type_line.begin(), [](unsigned char c) { return tolower(c); });
+ type_start = type_line.find("\ntype: ") + 1;
+ type_end = type_line.find("\n", type_start) - type_start;
+ type_line = type_line.substr(type_start, type_end);
- command = command_fix_part;
- command += "--medium none ";
+ if (type_line.find("multiattach") == string::npos) {
+ // Parent hdd is not (yet) of type multiattach.
+ // Vdi files can't be registered and set to multiattach mode within 1 step.
+ // They must first be attached to a VM in normal mode, then detached from the VM
- retval = vbm_popen(command, output, "detach parent vdi", false, false);
- if (retval) return retval;
- // the vdi file is now registered and ready to be attached in multiattach mode
- //
+ command = command_fix_part;
+ command += set_new_uuid + "--medium \"" + medium_file + "\" ";
+
+ retval = vbm_popen(command, output, "register parent vdi");
+ if (retval) return retval;
+
+ command = command_fix_part;
+ command += "--medium none ";
+
+ retval = vbm_popen(command, output, "detach parent vdi");
+ if (retval) return retval;
+ // the vdi file is now registered and ready to be attached in multiattach mode
+ //
+ }
+
+ do {
+ command = command_fix_part;
+ command += "--mtype multiattach ";
+ command += "--medium \"" + medium_file + "\" ";
+
+ retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)", log_error);
+ if (retval) {
+ // VirtualBox occasionally writes the 'MultiAttach' attribute to
+ // the disk entry in VirtualBox.xml although this is not allowed there.
+ // As a result all VMs trying to connect that disk fail.
+ // The error needs to be cleaned here to allow vboxwrapper to
+ // succeed even with uncorrected VirtualBox versions.
+ //
+ // After cleanup attaching the disk should be tried again.
+
+ if ((retry_count < 1) &&
+ (output.find("Cannot attach medium") != string::npos) &&
+ (output.find("the media type") != string::npos) &&
+ (output.find("MultiAttach") != string::npos) &&
+ (output.find("can only be attached to machines that were created with VirtualBox 4.0 or later") != string::npos)) {
+ // try to deregister the medium from the global media store
+ command = "closemedium \"" + medium_file + "\" ";
+
+ retval = vbm_popen(command, output, "deregister parent vdi");
+ if (retval) return retval;
+
+ retry_count++;
+ log_error = true;
+ boinc_sleep(1.0);
+ break;
+ }
+
+ if (retry_count >= 1) {
+ // in case of other errors or if retry also failed
+ vboxlog_msg("Error in storage attach (fixed disk - multiattach mode).\nCommand:\n%s\nOutput:\n%s",
+ command.c_str(),
+ output.c_str()
+ );
+ return retval;
+ }
+
+ retry_count++;
+ log_error = true;
+ boinc_sleep(1.0);
+
+ } else {
+ vbox_bug_mitigation = true;
+ break;
+ }
+ }
+ while (true);
}
-
- command = command_fix_part;
- command += "--mtype multiattach ";
- command += "--medium \"" + medium_file + "\" ";
-
- retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)");
- if (retval) return retval;
+ while (!vbox_bug_mitigation);
}