|
16 | 16 | // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
17 | 17 |
|
18 | 18 | #ifdef _WIN32
|
19 |
| -#include <algorithm> |
20 | 19 | #include "boinc_win.h"
|
21 | 20 | #include "win_util.h"
|
22 | 21 | #else
|
| 22 | +#include <algorithm> |
23 | 23 | #include <sys/wait.h>
|
24 | 24 | #include <sys/types.h>
|
25 | 25 | #include <sys/stat.h>
|
@@ -543,53 +543,147 @@ namespace vboxmanage {
|
543 | 543 | // See: https://www.virtualbox.org/manual/ch05.html#hdimagewrites
|
544 | 544 | // https://www.virtualbox.org/manual/ch05.html#diffimages
|
545 | 545 | // the vdi file downloaded to the projects dir becomes the parent (read only)
|
546 |
| - // "--setuid" must not be used |
547 | 546 | // each task gets it's own differencing image (writable)
|
548 | 547 | // differencing images are written to the VM's snapshot folder
|
549 | 548 | //
|
550 | 549 | string medium_file = aid.project_dir;
|
551 | 550 | medium_file += "/" + multiattach_vdi_file;
|
552 | 551 |
|
553 |
| -#ifdef _WIN32 |
554 |
| - replace(medium_file.begin(), medium_file.end(), '\\', '/'); |
555 |
| -#endif |
556 |
| - |
557 | 552 | vboxlog_msg("Adding virtual disk drive to VM. (%s)", multiattach_vdi_file.c_str());
|
558 |
| - command = "list hdds"; |
559 | 553 |
|
560 |
| - retval = vbm_popen(command, output, "check if parent hdd is registered", false, false); |
561 |
| - if (retval) return retval; |
| 554 | + int retry_count = 0; |
| 555 | + bool log_error = false; |
| 556 | + bool vbox_bug_mitigation = false; |
562 | 557 |
|
563 |
| -#ifdef _WIN32 |
564 |
| - replace(output.begin(), output.end(), '\\', '/'); |
565 |
| -#endif |
| 558 | + do { |
| 559 | + string set_new_uuid = ""; |
| 560 | + string type_line = ""; |
| 561 | + size_t type_start; |
| 562 | + size_t type_end; |
| 563 | + |
| 564 | + command = "showhdinfo \"" + medium_file + "\" "; |
| 565 | + |
| 566 | + retval = vbm_popen(command, output, "check if parent hdd is registered", false); |
| 567 | + if (retval) { |
| 568 | + // showhdinfo implicitly registers unregistered hdds. |
| 569 | + // Hence, this has to be handled first. |
| 570 | + // |
| 571 | + if ((output.rfind("VBoxManage: error:", 0) != string::npos) && |
| 572 | + (output.find("Cannot register the hard disk") != string::npos) && |
| 573 | + (output.find("because a hard disk") != string::npos) && |
| 574 | + (output.find("with UUID") != string::npos) && |
| 575 | + (output.find("already exists") != string::npos)) { |
| 576 | + // May happen if the project admin didn't set a new UUID. |
| 577 | + set_new_uuid = "--setuuid \"\" "; |
| 578 | + |
| 579 | + 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 <inputfile> <outputfile>\n", |
| 580 | + multiattach_vdi_file.c_str() |
| 581 | + ); |
| 582 | + } else { |
| 583 | + // other errors |
| 584 | + vboxlog_msg("Error in check if parent hdd is registered.\nCommand:\n%s\nOutput:\n%s", |
| 585 | + command.c_str(), |
| 586 | + output.c_str() |
| 587 | + ); |
| 588 | + return retval; |
| 589 | + } |
| 590 | + } |
566 | 591 |
|
567 |
| - if (output.find(medium_file) == string::npos) { |
568 |
| - // parent hdd is not registered |
569 |
| - // vdi files can't be registered and set to multiattach mode within 1 step. |
570 |
| - // They must first be attached to a VM in normal mode, then detached from the VM |
| 592 | + // Output from showhdinfo should look a little like this: |
| 593 | + // UUID: c119bcaf-636c-41f6-86c9-384739a31339 |
| 594 | + // Parent UUID: base |
| 595 | + // State: created |
| 596 | + // Type: multiattach |
| 597 | + // Location: C:\Users\romw\VirtualBox VMs\test2\test2.vdi |
| 598 | + // Storage format: VDI |
| 599 | + // Format variant: dynamic default |
| 600 | + // Capacity: 2048 MBytes |
| 601 | + // Size on disk: 2 MBytes |
| 602 | + // Encryption: disabled |
| 603 | + // Property: AllocationBlockSize=1048576 |
| 604 | + // Child UUIDs: dcb0daa5-3bf9-47cb-bfff-c65e74484615 |
571 | 605 | //
|
572 |
| - command = command_fix_part; |
573 |
| - command += "--medium \"" + medium_file + "\" "; |
574 | 606 |
|
575 |
| - retval = vbm_popen(command, output, "register parent hdd", false, false); |
576 |
| - if (retval) return retval; |
| 607 | + type_line = output; |
| 608 | + transform(type_line.cbegin(), type_line.cend(), |
| 609 | + type_line.begin(), [](unsigned char c) { return tolower(c); }); |
| 610 | + type_start = type_line.find("\ntype: ") + 1; |
| 611 | + type_end = type_line.find("\n", type_start) - type_start; |
| 612 | + type_line = type_line.substr(type_start, type_end); |
577 | 613 |
|
578 |
| - command = command_fix_part; |
579 |
| - command += "--medium none "; |
| 614 | + if (type_line.find("multiattach") == string::npos) { |
| 615 | + // Parent hdd is not (yet) of type multiattach. |
| 616 | + // Vdi files can't be registered and set to multiattach mode within 1 step. |
| 617 | + // They must first be attached to a VM in normal mode, then detached from the VM |
580 | 618 |
|
581 |
| - retval = vbm_popen(command, output, "detach parent vdi", false, false); |
582 |
| - if (retval) return retval; |
583 |
| - // the vdi file is now registered and ready to be attached in multiattach mode |
584 |
| - // |
585 |
| - } |
| 619 | + command = command_fix_part; |
| 620 | + command += set_new_uuid + "--medium \"" + medium_file + "\" "; |
586 | 621 |
|
587 |
| - command = command_fix_part; |
588 |
| - command += "--mtype multiattach "; |
589 |
| - command += "--medium \"" + medium_file + "\" "; |
| 622 | + retval = vbm_popen(command, output, "register parent vdi"); |
| 623 | + if (retval) return retval; |
590 | 624 |
|
591 |
| - retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)"); |
592 |
| - if (retval) return retval; |
| 625 | + command = command_fix_part; |
| 626 | + command += "--medium none "; |
| 627 | + |
| 628 | + retval = vbm_popen(command, output, "detach parent vdi"); |
| 629 | + if (retval) return retval; |
| 630 | + // the vdi file is now registered and ready to be attached in multiattach mode |
| 631 | + // |
| 632 | + } |
| 633 | + |
| 634 | + do { |
| 635 | + command = command_fix_part; |
| 636 | + command += "--mtype multiattach "; |
| 637 | + command += "--medium \"" + medium_file + "\" "; |
| 638 | + |
| 639 | + retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)", log_error); |
| 640 | + if (retval) { |
| 641 | + // VirtualBox occasionally writes the 'MultiAttach' attribute to |
| 642 | + // the disk entry in VirtualBox.xml although this is not allowed there. |
| 643 | + // As a result all VMs trying to connect that disk fail. |
| 644 | + // The error needs to be cleaned here to allow vboxwrapper to |
| 645 | + // succeed even with uncorrected VirtualBox versions. |
| 646 | + // |
| 647 | + // After cleanup attaching the disk should be tried again. |
| 648 | + |
| 649 | + if ((retry_count < 1) && |
| 650 | + (output.find("Cannot attach medium") != string::npos) && |
| 651 | + (output.find("the media type") != string::npos) && |
| 652 | + (output.find("MultiAttach") != string::npos) && |
| 653 | + (output.find("can only be attached to machines that were created with VirtualBox 4.0 or later") != string::npos)) { |
| 654 | + // try to deregister the medium from the global media store |
| 655 | + command = "closemedium \"" + medium_file + "\" "; |
| 656 | + |
| 657 | + retval = vbm_popen(command, output, "deregister parent vdi"); |
| 658 | + if (retval) return retval; |
| 659 | + |
| 660 | + retry_count++; |
| 661 | + log_error = true; |
| 662 | + boinc_sleep(1.0); |
| 663 | + break; |
| 664 | + } |
| 665 | + |
| 666 | + if (retry_count >= 1) { |
| 667 | + // in case of other errors or if retry also failed |
| 668 | + vboxlog_msg("Error in storage attach (fixed disk - multiattach mode).\nCommand:\n%s\nOutput:\n%s", |
| 669 | + command.c_str(), |
| 670 | + output.c_str() |
| 671 | + ); |
| 672 | + return retval; |
| 673 | + } |
| 674 | + |
| 675 | + retry_count++; |
| 676 | + log_error = true; |
| 677 | + boinc_sleep(1.0); |
| 678 | + |
| 679 | + } else { |
| 680 | + vbox_bug_mitigation = true; |
| 681 | + break; |
| 682 | + } |
| 683 | + } |
| 684 | + while (true); |
| 685 | + } |
| 686 | + while (!vbox_bug_mitigation); |
593 | 687 | }
|
594 | 688 |
|
595 | 689 |
|
|
0 commit comments