From 59152902b0e9c1d48b3fd4dff01b73a776348f30 Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Sat, 15 Nov 2014 23:14:11 -0500 Subject: [PATCH] VBOX: Convert cleanup_snapshots() and various bug fixes --- samples/vboxwrapper/vbox.cpp | 167 ++++- samples/vboxwrapper/vbox.h | 107 +-- samples/vboxwrapper/vbox_unix.cpp | 16 +- samples/vboxwrapper/vbox_unix.h | 211 +----- samples/vboxwrapper/vbox_win.cpp | 1019 +++++++++++++++------------ samples/vboxwrapper/vbox_win.h | 54 +- samples/vboxwrapper/vboxwrapper.cpp | 91 ++- win_build/vboxwrapper.vcxproj | 22 +- 8 files changed, 839 insertions(+), 848 deletions(-) diff --git a/samples/vboxwrapper/vbox.cpp b/samples/vboxwrapper/vbox.cpp index 53ad7e58bc..51830e975b 100644 --- a/samples/vboxwrapper/vbox.cpp +++ b/samples/vboxwrapper/vbox.cpp @@ -118,6 +118,60 @@ VBOX_BASE::~VBOX_BASE() { } } +int VBOX_BASE::initialize() { + return ERR_EXEC; +} + +int VBOX_BASE::create_vm() { + return ERR_EXEC; +} + +int VBOX_BASE::register_vm() { + return ERR_EXEC; +} + +int VBOX_BASE::deregister_vm(bool delete_media) { + return ERR_EXEC; +} + +int VBOX_BASE::deregister_stale_vm() { + return ERR_EXEC; +} + +void VBOX_BASE::poll(bool /*log_state*/) { +} + +int VBOX_BASE::start() { + return ERR_EXEC; +} + +int VBOX_BASE::stop() { + return ERR_EXEC; +} +int VBOX_BASE::poweroff() { + return ERR_EXEC; +} + +int VBOX_BASE::pause() { + return ERR_EXEC; +} + +int VBOX_BASE::resume() { + return ERR_EXEC; +} + +int VBOX_BASE::create_snapshot(double elapsed_time) { + return ERR_EXEC; +} + +int VBOX_BASE::cleanup_snapshots(bool delete_active) { + return ERR_EXEC; +} + +int VBOX_BASE::restore_snapshot() { + return ERR_EXEC; +} + int VBOX_BASE::run(bool do_restore_snapshot) { int retval; @@ -230,6 +284,9 @@ void VBOX_BASE::dump_hypervisor_logs(bool include_error_logs) { } } +void VBOX_BASE::dump_hypervisor_status_reports() { +} + // t1 > t2 static bool is_timestamp_newer(VBOX_TIMESTAMP& t1, VBOX_TIMESTAMP& t2) { if (t1.hours > t2.hours) return true; @@ -288,6 +345,14 @@ void VBOX_BASE::dump_vmguestlog_entries() { } } +int VBOX_BASE::is_registered() { + return ERR_NOT_FOUND; +} + +bool VBOX_BASE::is_system_ready(std::string& message) { + return false; +} + bool VBOX_BASE::is_vm_machine_configuration_available() { string virtual_machine_slot_directory; string vm_machine_configuration_file; @@ -303,6 +368,14 @@ bool VBOX_BASE::is_vm_machine_configuration_available() { return false; } +bool VBOX_BASE::is_hdd_registered() { + return false; +} + +bool VBOX_BASE::is_extpack_installed() { + return false; +} + bool VBOX_BASE::is_logged_failure_vm_extensions_disabled() { if (vm_log.find("VERR_VMX_MSR_LOCKED_OR_DISABLED") != string::npos) return true; if (vm_log.find("VERR_SVM_DISABLED") != string::npos) return true; @@ -337,20 +410,6 @@ bool VBOX_BASE::is_logged_failure_guest_job_out_of_memory() { return false; } -bool VBOX_BASE::is_logged_completion_file_exists() { - char path[MAXPATHLEN]; - sprintf(path, "shared/%s", completion_trigger_file.c_str()); - if (boinc_file_exists(path)) return true; - return false; -} - -bool VBOX_BASE::is_logged_temporary_exit_file_exists() { - char path[MAXPATHLEN]; - sprintf(path, "shared/%s", temporary_exit_trigger_file.c_str()); - if (boinc_file_exists(path)) return true; - return false; -} - bool VBOX_BASE::is_virtualbox_version_newer(int maj, int min, int rel) { int vbox_major = 0, vbox_minor = 0, vbox_release = 0; if (3 == sscanf(virtualbox_version.c_str(), "%d.%d.%d", &vbox_major, &vbox_minor, &vbox_release)) { @@ -363,10 +422,16 @@ bool VBOX_BASE::is_virtualbox_version_newer(int maj, int min, int rel) { return false; } -bool VBOX_BASE::is_virtualbox_error_recoverable(int retval) { - // See comments for VBOX_BASE::vbm_popen about session lock issues. - if (VBOX_E_INVALID_OBJECT_STATE == (unsigned int)retval) return true; - return false; +int VBOX_BASE::get_install_directory(std::string& dir) { + return ERR_EXEC; +} + +int VBOX_BASE::get_version_information(std::string& version) { + return ERR_EXEC; +} + +int VBOX_BASE::get_guest_additions(std::string& dir) { + return ERR_EXEC; } // Returns the current directory in which the executable resides. @@ -383,18 +448,28 @@ int VBOX_BASE::get_slot_directory(string& dir) { return 0; } -void VBOX_BASE::sanitize_output(std::string& output) { -#ifdef _WIN32 - // Remove \r from the log spew - string::iterator iter = output.begin(); - while (iter != output.end()) { - if (*iter == '\r') { - iter = output.erase(iter); - } else { - ++iter; - } - } -#endif +int VBOX_BASE::get_default_network_interface(std::string& iface) { + return ERR_EXEC; +} + +int VBOX_BASE::get_vm_network_bytes_sent(double& sent) { + return ERR_EXEC; +} + +int VBOX_BASE::get_vm_network_bytes_received(double& received) { + return ERR_EXEC; +} + +int VBOX_BASE::get_vm_process_id() { + return 0; +} + +int VBOX_BASE::get_vm_exit_code(unsigned long& exit_code) { + return ERR_EXEC; +} + +double VBOX_BASE::get_vm_cpu_time() { + return 0.0; } int VBOX_BASE::get_system_log(string& log, bool tail_only, unsigned int buffer_size) { @@ -565,6 +640,18 @@ int VBOX_BASE::get_trace_log(string& log, bool tail_only, unsigned int buffer_si return retval; } +int VBOX_BASE::set_network_access(bool enabled) { + return ERR_EXEC; +} + +int VBOX_BASE::set_cpu_usage(int percentage) { + return ERR_EXEC; +} + +int VBOX_BASE::set_network_usage(int kilobytes) { + return ERR_EXEC; +} + int VBOX_BASE::read_floppy(std::string& data) { if (enable_floppyio && pFloppy) { data = pFloppy->receive(); @@ -580,3 +667,23 @@ int VBOX_BASE::write_floppy(std::string& data) { } return 1; } + +void VBOX_BASE::lower_vm_process_priority() { +} + +void VBOX_BASE::reset_vm_process_priority() { +} + +void VBOX_BASE::sanitize_output(std::string& output) { +#ifdef _WIN32 + // Remove \r from the log spew + string::iterator iter = output.begin(); + while (iter != output.end()) { + if (*iter == '\r') { + iter = output.erase(iter); + } else { + ++iter; + } + } +#endif +} diff --git a/samples/vboxwrapper/vbox.h b/samples/vboxwrapper/vbox.h index f40c2cb7eb..aa0326be08 100644 --- a/samples/vboxwrapper/vbox.h +++ b/samples/vboxwrapper/vbox.h @@ -21,18 +21,6 @@ #ifndef _VBOX_H_ #define _VBOX_H_ -// Known VirtualBox/COM error codes -// -#ifndef CO_E_SERVER_EXEC_FAILURE -#define CO_E_SERVER_EXEC_FAILURE 0x80080005 -#endif -#ifndef RPC_S_SERVER_UNAVAILABLE -#define RPC_S_SERVER_UNAVAILABLE 0x800706ba -#endif -#ifndef VBOX_E_INVALID_OBJECT_STATE -#define VBOX_E_INVALID_OBJECT_STATE 0x80bb0007 -#endif - // Vboxwrapper errors // #define VBOXWRAPPER_ERR_RECOVERABLE -1000 @@ -213,72 +201,53 @@ public: virtual int cleanup_snapshots(bool delete_active); virtual int restore_snapshot(); - int run(bool do_restore_snapshot); - void cleanup(); + virtual int run(bool do_restore_snapshot); + virtual void cleanup(); - void dump_hypervisor_logs(bool include_error_logs); - void dump_hypervisor_status_reports(); - void dump_vmguestlog_entries(); - void check_trickle_triggers(); - void check_intermediate_uploads(); - void delete_temporary_exit_trigger_file(); + virtual void dump_hypervisor_logs(bool include_error_logs); + virtual void dump_hypervisor_status_reports(); + virtual void dump_vmguestlog_entries(); - int is_registered(); - bool is_system_ready(std::string& message); - bool is_vm_machine_configuration_available(); - bool is_hdd_registered(); - bool is_extpack_installed(); - bool is_logged_failure_vm_extensions_disabled(); - bool is_logged_failure_vm_extensions_in_use(); - bool is_logged_failure_vm_extensions_not_supported(); - bool is_logged_failure_host_out_of_memory(); - bool is_logged_failure_guest_job_out_of_memory(); - bool is_logged_completion_file_exists(); - bool is_logged_temporary_exit_file_exists(); - bool is_virtualbox_version_newer(int maj, int min, int rel); - bool is_virtualbox_error_recoverable(int retval); + virtual int is_registered(); + virtual bool is_system_ready(std::string& message); + virtual bool is_vm_machine_configuration_available(); + virtual bool is_hdd_registered(); + virtual bool is_extpack_installed(); + virtual bool is_logged_failure_vm_extensions_disabled(); + virtual bool is_logged_failure_vm_extensions_in_use(); + virtual bool is_logged_failure_vm_extensions_not_supported(); + virtual bool is_logged_failure_host_out_of_memory(); + virtual bool is_logged_failure_guest_job_out_of_memory(); + virtual bool is_virtualbox_version_newer(int maj, int min, int rel); - int get_install_directory(std::string& dir); - int get_version_information(std::string& version); - int get_guest_additions(std::string& dir); - int get_slot_directory(std::string& dir); - int get_default_network_interface(std::string& iface); - int get_vm_network_bytes_sent(double& sent); - int get_vm_network_bytes_received(double& received); - int get_vm_process_id(); - int get_vm_exit_code(unsigned long& exit_code); - double get_vm_cpu_time(); + virtual int get_install_directory(std::string& dir); + virtual int get_version_information(std::string& version); + virtual int get_guest_additions(std::string& dir); + virtual int get_slot_directory(std::string& dir); + virtual int get_default_network_interface(std::string& iface); + virtual int get_vm_network_bytes_sent(double& sent); + virtual int get_vm_network_bytes_received(double& received); + virtual int get_vm_process_id(); + virtual int get_vm_exit_code(unsigned long& exit_code); + virtual double get_vm_cpu_time(); - int get_system_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int get_vm_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int get_trace_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); + virtual int get_system_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); + virtual int get_vm_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); + virtual int get_trace_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int set_network_access(bool enabled); - int set_cpu_usage(int percentage); - int set_network_usage(int kilobytes); + virtual int set_network_access(bool enabled); + virtual int set_cpu_usage(int percentage); + virtual int set_network_usage(int kilobytes); - int read_floppy(std::string& data); - int write_floppy(std::string& data); + virtual int read_floppy(std::string& data); + virtual int write_floppy(std::string& data); - void lower_vm_process_priority(); - void reset_vm_process_priority(); + virtual void lower_vm_process_priority(); + virtual void reset_vm_process_priority(); + + virtual void sanitize_output(std::string& output); - void sanitize_output(std::string& output); -#ifndef _WIN32 - int vbm_popen( - std::string& command, std::string& output, const char* item, bool log_error = true, bool retry_failures = true, unsigned int timeout = 45, bool log_trace = true - ); - int vbm_popen_raw( - std::string& command, std::string& output, unsigned int timeout - ); - void vbm_replay( - std::string& command - ); - void vbm_trace( - std::string& command, std::string& ouput, int retval - ); -#endif }; #endif diff --git a/samples/vboxwrapper/vbox_unix.cpp b/samples/vboxwrapper/vbox_unix.cpp index 310d43046e..579703224e 100644 --- a/samples/vboxwrapper/vbox_unix.cpp +++ b/samples/vboxwrapper/vbox_unix.cpp @@ -34,11 +34,6 @@ using std::string; -#if defined(_MSC_VER) -#define getcwd _getcwd -#define stricmp _stricmp -#endif - #include "diagnostics.h" #include "filesys.h" #include "parse.h" @@ -109,8 +104,7 @@ int VBOX_VM::initialize() { rc = get_version_information(virtualbox_version); if (rc) return rc; - rc = get_guest_additions(virtualbox_guest_additions); - if (rc) return rc; + get_guest_additions(virtualbox_guest_additions); return 0; } @@ -1805,6 +1799,14 @@ int VBOX_VM::get_vm_exit_code(unsigned long& exit_code) { return 0; } +double VBOX_VM::get_vm_cpu_time() { + double x = process_tree_cpu_time(vm_pid); + if (x > current_cpu_time) { + current_cpu_time = x; + } + return current_cpu_time; +} + // Enable the network adapter if a network connection is required. // NOTE: Network access should never be allowed if the code running in a // shared directory or the VM image itself is NOT signed. Doing so diff --git a/samples/vboxwrapper/vbox_unix.h b/samples/vboxwrapper/vbox_unix.h index a1391c21b3..f149a88356 100644 --- a/samples/vboxwrapper/vbox_unix.h +++ b/samples/vboxwrapper/vbox_unix.h @@ -18,8 +18,8 @@ // Provide cross-platform interfaces for making changes to VirtualBox -#ifndef _VBOX_H_ -#define _VBOX_H_ +#ifndef _VBOX_UNIX_H_ +#define _VBOX_UNIX_H_ // Known VirtualBox/COM error codes // @@ -33,224 +33,40 @@ #define VBOX_E_INVALID_OBJECT_STATE 0x80bb0007 #endif -// Vboxwrapper errors -// -#define VBOXWRAPPER_ERR_RECOVERABLE -1000 - -// Vboxwrapper diagnostics -// -#define REPLAYLOG_FILENAME "vbox_replay.txt" -#define TRACELOG_FILENAME "vbox_trace.txt" - - -// raw floppy drive device -class FloppyIO; - -// represents a VirtualBox Guest Log Timestamp -struct VBOX_TIMESTAMP { - int hours; - int minutes; - int seconds; - int milliseconds; -}; - -// represents the state of a intermediate upload -struct INTERMEDIATE_UPLOAD { - std::string file; - bool reported; - bool ignore; - - INTERMEDIATE_UPLOAD() { - clear(); - } - void clear() { - file = ""; - reported = false; - ignore = false; - } -}; - -struct PORT_FORWARD { - int host_port; // 0 means assign dynamically - int guest_port; - bool is_remote; - - PORT_FORWARD() { - host_port = 0; - guest_port = 0; - is_remote = false; - } - int get_host_port(); // assign host port -}; - -// represents a VirtualBox VM -class VBOX_VM { +class VBOX_VM : public VBOX_BASE { public: VBOX_VM(); ~VBOX_VM(); - std::string virtualbox_home_directory; - std::string virtualbox_install_directory; - std::string virtualbox_guest_additions; - std::string virtualbox_version; - - FloppyIO* pFloppy; - - std::string vm_log; - // last polled copy of the log file - VBOX_TIMESTAMP vm_log_timestamp; - // last VM guest log entry detected - std::string vm_master_name; - // unique name for the VM - std::string vm_master_description; - // unique description for the VM - std::string vm_name; - // unique name for the VM or UUID of a stale VM if deregistering it - std::string vm_cpu_count; - // required CPU core count - std::string vm_memory_size_mb; - // required size of the memory allocation for the VM, in megabytes - std::string image_filename; - // name of the virtual machine disk image file - std::string iso_image_filename; - // name of the virtual machine iso9660 disk image file - std::string cache_disk_filename; - // name of the virtual machine cache disk image file - std::string floppy_image_filename; - // name of the virtual machine floppy disk image file - double current_cpu_time; - // amount of CPU time consumed by the VM (note: use get_vm_cpu_time()) - bool suspended; - // is the VM suspended? - bool network_suspended; - // is network access temporarily suspended? - bool online; - // is VM even online? - bool saving; - // Is VM saving from checkpoint? - bool restoring; - // Is VM restoring from checkpoint? - bool crashed; - // Has the VM crashed? - bool register_only; - // whether we were instructed to only register the VM. - // useful for debugging VMs. - int rd_host_port; - // for optional remote desktop; dynamically assigned - bool headless; - - /////////// THE FOLLOWING SPECIFIED IN VBOX_JOB.XML ////////////// - // some of these don't really belong in this class - - std::string os_name; - // name of the OS the VM runs - std::string vm_disk_controller_type; - // the type of disk controller to emulate - std::string vm_disk_controller_model; - // the disk controller model to emulate - double memory_size_mb; - // size of the memory allocation for the VM, in megabytes - bool enable_cern_dataformat; - // whether to use CERN specific data structures - bool enable_isocontextualization; - // whether to use an iso9660 image to implement VM contextualization (e.g. uCernVM) - bool enable_cache_disk; - // whether to add an extra cache disk for systems like uCernVM - bool enable_network; - // whether to allow network access - bool network_bridged_mode; - // use bridged mode for network - bool enable_shared_directory; - // whether to use shared directory infrastructure - bool enable_floppyio; - // whether to use floppy io infrastructure - bool enable_remotedesktop; - // whether to enable remote desktop functionality - double job_duration; - // maximum amount of wall-clock time this VM is allowed to run before - // considering itself done. - std::string fraction_done_filename; - // name of file where app will write its fraction done - int pf_guest_port; // if nonzero, do port forwarding for Web GUI - int pf_host_port; // AFAIK this isn't needed - std::vector port_forwards; - double minimum_checkpoint_interval; - // minimum time between checkpoints - std::vector copy_to_shared; - // list of files to copy from slot dir to shared/ - std::vector trickle_trigger_files; - // if find file of this name in shared/, send trickle-up message - // with variety = filename, contents = file contents - std::vector intermediate_upload_files; - // if find file of this name in shared/, send specified file - std::string completion_trigger_file; - // if find this file in shared/, task is over. - // File can optionally contain exit code (first line) - // and stderr text (subsequent lines). - // Addresses a problem where VM doesn't shut down properly - - /////////// END VBOX_JOB.XML ITEMS ////////////// - + // the pid to the process for the VM/VboxSvc int vm_pid; int vboxsvc_pid; -#ifdef _WIN32 - // the handle to the process for the VM - // NOTE: we get a handle to the pid right after we parse it from the - // log files so we can adjust the process priority and retrieve the process - // exit code in case it crashed or was terminated. Without an outstanding - // handle to the process, the OS is free to reuse the pid for some other - // executable. - HANDLE vm_pid_handle; - - // the handle to the vboxsvc process created by us in the sandbox'ed environment - HANDLE vboxsvc_pid_handle; -#endif int initialize(); - int parse_port_forward(XML_PARSER&); - void set_web_graphics_url(); - void poll(bool log_state = true); - int create_vm(); int register_vm(); int deregister_vm(bool delete_media); int deregister_stale_vm(); - - int run(bool do_restore_snapshot); - void cleanup(); - + void poll(bool log_state = true); int start(); int stop(); int poweroff(); int pause(); int resume(); - void check_trickle_triggers(); - void check_intermediate_uploads(); int create_snapshot(double elapsed_time); int cleanup_snapshots(bool delete_active); int restore_snapshot(); - void dump_hypervisor_logs(bool include_error_logs); + void dump_hypervisor_status_reports(); - void dump_vmguestlog_entries(); int is_registered(); bool is_system_ready(std::string& message); - bool is_vm_machine_configuration_available(); bool is_hdd_registered(); bool is_extpack_installed(); - bool is_logged_failure_vm_extensions_disabled(); - bool is_logged_failure_vm_extensions_in_use(); - bool is_logged_failure_vm_extensions_not_supported(); - bool is_logged_failure_host_out_of_memory(); - bool is_logged_failure_guest_job_out_of_memory(); - bool is_logged_completion_file_exists(); - bool is_virtualbox_version_newer(int maj, int min, int rel); - bool is_virtualbox_error_recoverable(int retval); int get_install_directory(std::string& dir); int get_version_information(std::string& version); int get_guest_additions(std::string& dir); - int get_slot_directory(std::string& dir); int get_default_network_interface(std::string& iface); int get_vm_network_bytes_sent(double& sent); int get_vm_network_bytes_received(double& received); @@ -258,26 +74,13 @@ public: int get_vm_exit_code(unsigned long& exit_code); double get_vm_cpu_time(); - int get_system_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int get_vm_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int get_trace_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int set_network_access(bool enabled); int set_cpu_usage(int percentage); int set_network_usage(int kilobytes); - int read_floppy(std::string& data); - int write_floppy(std::string& data); - void lower_vm_process_priority(); void reset_vm_process_priority(); - int launch_vboxsvc(); - int launch_vboxvm(); - - void sanitize_output(std::string& output); - -#ifndef _WIN32 int vbm_popen( std::string& command, std::string& output, const char* item, bool log_error = true, bool retry_failures = true, unsigned int timeout = 45, bool log_trace = true ); @@ -290,7 +93,7 @@ public: void vbm_trace( std::string& command, std::string& ouput, int retval ); -#endif + }; #endif diff --git a/samples/vboxwrapper/vbox_win.cpp b/samples/vboxwrapper/vbox_win.cpp index a0f0e5d10f..28c57aede2 100644 --- a/samples/vboxwrapper/vbox_win.cpp +++ b/samples/vboxwrapper/vbox_win.cpp @@ -26,7 +26,6 @@ #include "atlsafe.h" #include "atlcoll.h" #include "atlstr.h" -#include "mscom/VirtualBox.h" #include "diagnostics.h" #include "filesys.h" #include "parse.h" @@ -38,6 +37,7 @@ #include "network.h" #include "boinc_api.h" #include "floppyio.h" +#include "mscom/VirtualBox_i.c" #include "vboxwrapper.h" #include "vbox.h" #include "vbox_win.h" @@ -114,7 +114,7 @@ void virtualbox_dump_error() { fprintf( stderr, "%s Error: getting error info! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); } else { @@ -123,14 +123,14 @@ void virtualbox_dump_error() { fprintf( stderr, "%s Error: getting error description! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); } else { fprintf( stderr, "%s Error description: %S\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), strDescription ); SysFreeString(strDescription); @@ -144,10 +144,6 @@ VBOX_VM::VBOX_VM() { VBOX_BASE::VBOX_BASE(); - m_pVirtualBox; - m_pSession; - m_pMachine; - vm_pid = 0; vm_pid_handle = 0; vboxsvc_pid = 0; @@ -236,12 +232,12 @@ int VBOX_VM::initialize() { // Instantiate the VirtualBox root object. rc = m_pVirtualBox.CoCreateInstance(CLSID_VirtualBox); - if (!SUCCEEDED(rc)) + if (FAILED(rc)) { fprintf( stderr, "%s Error creating VirtualBox instance! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); return rc; @@ -249,12 +245,12 @@ int VBOX_VM::initialize() { // Create the session object. rc = m_pSession.CoCreateInstance(CLSID_Session); - if (!SUCCEEDED(rc)) + if (FAILED(rc)) { fprintf( stderr, "%s Error creating Session instance! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); return rc; @@ -274,13 +270,16 @@ int VBOX_VM::create_vm() { char buf[256]; APP_INIT_DATA aid; CComBSTR vm_machine_uuid; + CComPtr pMachineRO; CComPtr pMachine; CComPtr pSession; CComPtr pBIOSSettings; CComPtr pNetworkAdapter; CComPtr pNATEngine; - CComPtr pSerialPort; - CComPtr pParallelPort; + CComPtr pSerialPort1; + CComPtr pSerialPort2; + CComPtr pParallelPort1; + CComPtr pParallelPort2; CComPtr pAudioAdapter; CComPtr pDiskController; CComPtr pFloppyController; @@ -295,10 +294,31 @@ int VBOX_VM::create_vm() { get_slot_directory(virtual_machine_slot_directory); + rc = pSession.CoCreateInstance(CLSID_Session); + if (!SUCCEEDED(rc)) + { + fprintf( + stderr, + "%s Error creating Session instance! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + return rc; + } + + // Reset VM name in case it was changed while deregistering a stale VM // vm_name = vm_master_name; + fprintf( + stderr, + "%s Create VM. (%s, slot#%d) \n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + vm_name.c_str(), + aid.slot + ); + // Fixup chipset and drive controller information for known configurations // if (enable_isocontextualization) { @@ -315,27 +335,19 @@ int VBOX_VM::create_vm() { // Start the VM creation process // - fprintf( - stderr, - "%s Create VM. (%s, slot#%d) \n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - vm_name.c_str(), - aid.slot - ); - rc = m_pVirtualBox->CreateMachine( - CComBSTR(string(virtual_machine_slot_directory + string("/") + vm_name + string(".vbox")).c_str()), + CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()), CComBSTR(vm_name.c_str()), NULL, CComBSTR(os_name.c_str()), CComBSTR(""), - &pMachine + &pMachineRO ); if (FAILED(rc)) { fprintf( stderr, "%s Error creating virtual machine instance! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -350,12 +362,12 @@ int VBOX_VM::create_vm() { // Also note that due to current VirtualBox limitations, the machine // must be registered *before* we can attach hard disks to it. // - rc = m_pVirtualBox->RegisterMachine(pMachine); + rc = m_pVirtualBox->RegisterMachine(pMachineRO); if (FAILED(rc)) { fprintf( stderr, "%s Error registering virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -363,12 +375,12 @@ int VBOX_VM::create_vm() { goto CLEANUP; } - rc = pMachine->LockMachine(pSession, LockType_Write); + rc = pMachineRO->LockMachine(pSession, LockType_Write); if (FAILED(rc)) { fprintf( stderr, "%s Error locking virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -381,7 +393,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error retrieving mutable virtual machine object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -395,7 +407,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error retrieving the BIOS settings for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -408,7 +420,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error retrieving the Bandwidth Control settings for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -421,7 +433,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error retrieving the Remote Desktop settings for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -434,7 +446,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error retrieving the Network Adapter for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -447,7 +459,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error retrieving the NAT Engine for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -460,7 +472,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error retrieving the Audio Adapter for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -479,12 +491,12 @@ int VBOX_VM::create_vm() { vboxwrapper_msg_prefix(buf, sizeof(buf)), (int)memory_size_mb ); - rc = pMachine->put_MemorySize((int)(memory_size_mb*1024)); + rc = pMachine->put_MemorySize((int)(memory_size_mb)); if (FAILED(rc)) { fprintf( stderr, "%s Error memory size for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -505,7 +517,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error CPU count for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -525,7 +537,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting ACPI enabled for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -538,7 +550,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting IOAPIC enabled for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -558,7 +570,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting hard disk boot order for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -571,7 +583,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting DVD boot order for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -584,22 +596,46 @@ int VBOX_VM::create_vm() { // Tweak the VM's Network Configuration // - fprintf( - stderr, - "%s Disconnecting VM Network Access.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - rc = pNetworkAdapter->put_Enabled(FALSE); - if (FAILED(rc)) { + if (enable_network) { + fprintf( stderr, - "%s Error disabling network access for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), - rc + "%s Enabling VM Network Access.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) ); - virtualbox_dump_error(); - retval = rc; - goto CLEANUP; + rc = pNetworkAdapter->put_Enabled(TRUE); + if (FAILED(rc)) { + fprintf( + stderr, + "%s Error enabling network access for the virtual machine! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + retval = rc; + goto CLEANUP; + } + + } else { + + fprintf( + stderr, + "%s Disabling VM Network Access.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) + ); + rc = pNetworkAdapter->put_Enabled(FALSE); + if (FAILED(rc)) { + fprintf( + stderr, + "%s Error disabling network access for the virtual machine! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + retval = rc; + goto CLEANUP; + } + } if (network_bridged_mode) { @@ -614,7 +650,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting network configuration for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -634,7 +670,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting network configuration (brigded interface) for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -654,7 +690,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting network configuration for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -667,7 +703,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error setting network configuration (DNS Proxy) for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -695,13 +731,13 @@ int VBOX_VM::create_vm() { "%s Disabling COM Port Support for VM.\n", vboxwrapper_msg_prefix(buf, sizeof(buf)) ); - rc = pMachine->GetSerialPort(0, &pSerialPort); + rc = pMachine->GetSerialPort(0, &pSerialPort1); if (SUCCEEDED(rc)) { - pSerialPort->put_Enabled(FALSE); + pSerialPort1->put_Enabled(FALSE); } - rc = pMachine->GetSerialPort(1, &pSerialPort); + rc = pMachine->GetSerialPort(1, &pSerialPort2); if (SUCCEEDED(rc)) { - pSerialPort->put_Enabled(FALSE); + pSerialPort2->put_Enabled(FALSE); } // Tweak the VM's LPT Port Support @@ -711,13 +747,13 @@ int VBOX_VM::create_vm() { "%s Disabling LPT Port Support for VM.\n", vboxwrapper_msg_prefix(buf, sizeof(buf)) ); - rc = pMachine->GetParallelPort(0, &pParallelPort); + rc = pMachine->GetParallelPort(0, &pParallelPort1); if (SUCCEEDED(rc)) { - pParallelPort->put_Enabled(FALSE); + pParallelPort1->put_Enabled(FALSE); } - rc = pMachine->GetParallelPort(1, &pParallelPort); + rc = pMachine->GetParallelPort(1, &pParallelPort2); if (SUCCEEDED(rc)) { - pParallelPort->put_Enabled(FALSE); + pParallelPort2->put_Enabled(FALSE); } // Tweak the VM's Audio Support @@ -806,7 +842,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error disabling hardware acceleration support for the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -840,7 +876,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding storage controller (IDE) to the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -854,7 +890,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding storage controller (SATA) to the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -870,7 +906,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding storage controller (SAS) to the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -885,7 +921,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding storage controller (SCSI) to the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -921,7 +957,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding storage controller (Floppy) to the virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -942,7 +978,7 @@ int VBOX_VM::create_vm() { ); CComPtr pISOImage; rc = m_pVirtualBox->OpenMedium( - CComBSTR(string(virtual_machine_slot_directory + "/" + iso_image_filename).c_str()), + CComBSTR(string(virtual_machine_slot_directory + "\\" + iso_image_filename).c_str()), DeviceType_DVD, AccessMode_ReadOnly, FALSE, @@ -952,7 +988,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual ISO 9660 disk drive to VirtualBox! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -971,7 +1007,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual ISO 9660 disk drive to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -998,7 +1034,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding VirtualBox Guest Additions to VirtualBox! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1017,7 +1053,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding VirtualBox Guest Additions to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1036,7 +1072,7 @@ int VBOX_VM::create_vm() { ); CComPtr pCacheImage; rc = m_pVirtualBox->OpenMedium( - CComBSTR(string(virtual_machine_slot_directory + "/" + cache_disk_filename).c_str()), + CComBSTR(string(virtual_machine_slot_directory + "\\" + cache_disk_filename).c_str()), DeviceType_HardDisk, AccessMode_ReadWrite, TRUE, @@ -1046,7 +1082,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual cache disk drive to VirtualBox! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1065,7 +1101,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual cache disk drive to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1086,7 +1122,7 @@ int VBOX_VM::create_vm() { ); CComPtr pDiskImage; rc = m_pVirtualBox->OpenMedium( - CComBSTR(string(virtual_machine_slot_directory + "/" + cache_disk_filename).c_str()), + CComBSTR(string(virtual_machine_slot_directory + "\\" + cache_disk_filename).c_str()), DeviceType_HardDisk, AccessMode_ReadWrite, TRUE, @@ -1096,7 +1132,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual disk drive to VirtualBox! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1115,7 +1151,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual disk drive to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1142,7 +1178,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding VirtualBox Guest Additions to VirtualBox! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1161,7 +1197,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding VirtualBox Guest Additions to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1201,7 +1237,7 @@ int VBOX_VM::create_vm() { ); CComPtr pFloppyImage; rc = m_pVirtualBox->OpenMedium( - CComBSTR(string(virtual_machine_slot_directory + "/" + floppy_image_filename).c_str()), + CComBSTR(string(virtual_machine_slot_directory + "\\" + floppy_image_filename).c_str()), DeviceType_Floppy, AccessMode_ReadWrite, TRUE, @@ -1211,7 +1247,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual floppy disk image to VirtualBox! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1230,7 +1266,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding virtual floppy disk image to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1256,7 +1292,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding network bandwidth group to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1264,13 +1300,9 @@ int VBOX_VM::create_vm() { goto CLEANUP; } - // Enable the network adapter if a network connection is required. + // Configure port forwarding // if (enable_network) { - set_network_access(true); - - // set up port forwarding - // if (pf_guest_port) { PORT_FORWARD pf; pf.guest_port = pf_guest_port; @@ -1305,7 +1337,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error adding port forward to virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1353,7 +1385,7 @@ int VBOX_VM::create_vm() { ); rc = pMachine->CreateSharedFolder( CComBSTR("shared"), - CComBSTR(string(virtual_machine_slot_directory + "/shared").c_str()), + CComBSTR(string(virtual_machine_slot_directory + "\\shared").c_str()), TRUE, TRUE ); @@ -1361,7 +1393,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error could not create shared folder for virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1375,7 +1407,7 @@ int VBOX_VM::create_vm() { fprintf( stderr, "%s Error could not save settings for virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1383,6 +1415,20 @@ int VBOX_VM::create_vm() { goto CLEANUP; } + rc = pSession->UnlockMachine(); + if (FAILED(rc)) { + fprintf( + stderr, + "%s Error could not unlock virtual machine! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + retval = rc; + goto CLEANUP; + } + + CLEANUP: return retval; } @@ -1413,14 +1459,14 @@ int VBOX_VM::register_vm() { ); rc = m_pVirtualBox->OpenMachine( - CComBSTR(string(virtual_machine_slot_directory + "/" + vm_name + "/" + vm_name + ".vbox").c_str()), + CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()), &pMachine ); if (FAILED(rc)) { fprintf( stderr, "%s Error opening virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1433,7 +1479,7 @@ int VBOX_VM::register_vm() { fprintf( stderr, "%s Error registering virtual machine! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1449,9 +1495,10 @@ int VBOX_VM::deregister_vm(bool delete_media) { int retval = ERR_EXEC; HRESULT rc; char buf[256]; - CComPtr pBandwidthControl; + CComPtr pMachine; CComPtr pProgress; - SAFEARRAY* pHardDisks; + CComPtr pBandwidthControl; + SAFEARRAY* pHardDisks = NULL; string virtual_machine_slot_directory; get_slot_directory(virtual_machine_slot_directory); @@ -1462,72 +1509,103 @@ int VBOX_VM::deregister_vm(bool delete_media) { vboxwrapper_msg_prefix(buf, sizeof(buf)) ); - - // Cleanup any left-over snapshots - // - cleanup_snapshots(true); - - // Delete network bandwidth throttle group - // - fprintf( - stderr, - "%s Removing network bandwidth throttle group from VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - rc = m_pMachine->get_BandwidthControl(&pBandwidthControl); + rc = m_pVirtualBox->FindMachine(CComBSTR(vm_name.c_str()), &pMachine); if (SUCCEEDED(rc)) { - pBandwidthControl->DeleteBandwidthGroup(CComBSTR(string(vm_name + "_net").c_str())); - } - - // Delete its storage controller(s) - // - fprintf( - stderr, - "%s Removing storage controller(s) from VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - m_pMachine->RemoveStorageController(CComBSTR("Hard Disk Controller")); - - if (enable_floppyio) { - m_pMachine->RemoveStorageController(CComBSTR("Floppy Controller")); - } - - // Next, delete VM - // - fprintf( - stderr, - "%s Removing VM from VirtualBox.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - if (!delete_media) { - rc = m_pMachine->Unregister(CleanupMode_UnregisterOnly, &pHardDisks); + // Delete network bandwidth throttle group + // + fprintf( + stderr, + "%s Removing network bandwidth throttle group from VM.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) + ); + rc = pMachine->get_BandwidthControl(&pBandwidthControl); if (SUCCEEDED(rc)) { - m_pMachine->DeleteConfig(pHardDisks, &pProgress); - if (SUCCEEDED(rc)) { - pProgress->WaitForCompletion(-1); - } + pBandwidthControl->DeleteBandwidthGroup(CComBSTR(string(vm_name + "_net").c_str())); } - } else { - rc = m_pMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, &pHardDisks); - if (SUCCEEDED(rc)) { - fprintf( - stderr, - "%s Removing virtual disk drive(s) from VirtualBox.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - m_pMachine->DeleteConfig(pHardDisks, &pProgress); + + // Delete its storage controller(s) + // + fprintf( + stderr, + "%s Removing storage controller(s) from VM.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) + ); + pMachine->RemoveStorageController(CComBSTR("Hard Disk Controller")); + + if (enable_floppyio) { + pMachine->RemoveStorageController(CComBSTR("Floppy Controller")); + } + + // Next, delete VM + // + fprintf( + stderr, + "%s Removing VM from VirtualBox.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) + ); + if (!delete_media) { + rc = pMachine->Unregister(CleanupMode_UnregisterOnly, &pHardDisks); if (SUCCEEDED(rc)) { - pProgress->WaitForCompletion(-1); + pMachine->DeleteConfig(pHardDisks, &pProgress); + if (SUCCEEDED(rc)) { + pProgress->WaitForCompletion(-1); + } else { + fprintf( + stderr, + "%s Error deleting configuration files for virtual machine instance! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + } + } else { + fprintf( + stderr, + "%s Error unregistering virtual machine instance! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + } + } else { + rc = pMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, &pHardDisks); + if (SUCCEEDED(rc)) { + fprintf( + stderr, + "%s Removing virtual disk drive(s) from VirtualBox.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) + ); + pMachine->DeleteConfig(pHardDisks, &pProgress); + if (SUCCEEDED(rc)) { + pProgress->WaitForCompletion(-1); + } else { + fprintf( + stderr, + "%s Error deleting configuration files for virtual machine instance! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + } + } else { + fprintf( + stderr, + "%s Error unregistering virtual machine instance! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); } } } + return 0; } int VBOX_VM::deregister_stale_vm() { HRESULT rc; - SAFEARRAY* pHardDisks; - SAFEARRAY* pMachines; + SAFEARRAY* pHardDisks = NULL; + SAFEARRAY* pMachines = NULL; CComSafeArray aHardDisks; CComSafeArray aMachines; CComPtr pHardDisk; @@ -1537,7 +1615,7 @@ int VBOX_VM::deregister_stale_vm() { string hdd_image_location; get_slot_directory(virtual_machine_root_dir); - hdd_image_location = string(virtual_machine_root_dir + "/" + image_filename); + hdd_image_location = string(virtual_machine_root_dir + "\\" + image_filename); rc = m_pVirtualBox->get_HardDisks(&pHardDisks); if (SUCCEEDED(rc)) { @@ -1577,6 +1655,7 @@ void VBOX_VM::poll(bool log_state) { char buf[256]; APP_INIT_DATA aid; HRESULT rc; + CComPtr pMachine; MachineState vmstate; static MachineState vmstate_old = MachineState_PoweredOff; @@ -1603,123 +1682,125 @@ void VBOX_VM::poll(bool log_state) { // // What state is the VM in? // - rc = m_pMachine->get_State(&vmstate); - if (SUCCEEDED(rc)) { + rc = m_pVirtualBox->FindMachine(CComBSTR(vm_master_name.c_str()), &pMachine); + if (SUCCEEDED(rc) && pMachine) { + rc = pMachine->get_State(&vmstate); + if (SUCCEEDED(rc)) { - // VirtualBox Documentation suggests that that a VM is running when its - // machine state is between MachineState_FirstOnline and MachineState_LastOnline - // which as of this writing is 5 and 17. - // - // VboxManage's source shows more than that though: - // see: http://www.virtualbox.org/browser/trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp - // - // So for now, go with what VboxManage is reporting. - // - switch(vmstate) - { - case MachineState_Running: - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - break; - case MachineState_Paused: - online = true; - saving = false; - restoring = false; - suspended = true; - crashed = false; - break; - case MachineState_Starting: - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - break; - case MachineState_Stopping: - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - break; - case MachineState_Saving: - online = true; - saving = true; - restoring = false; - suspended = false; - crashed = false; - break; - case MachineState_Restoring: - online = true; - saving = false; - restoring = true; - suspended = false; - crashed = false; - break; - case MachineState_LiveSnapshotting: - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - break; - case MachineState_DeletingSnapshotOnline: - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - break; - case MachineState_DeletingSnapshotPaused: - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - break; - case MachineState_Aborted: - online = false; - saving = false; - restoring = false; - suspended = false; - crashed = true; - break; - case MachineState_Stuck: - online = false; - saving = false; - restoring = false; - suspended = false; - crashed = true; - break; - default: - online = false; - saving = false; - restoring = false; - suspended = false; - crashed = false; - break; - } - - if (log_state) { - fprintf( - stderr, - "%s VM is no longer is a running state. It is in '%s'.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - MachineStateToName(vmstate) - ); - } - if (log_state && (vmstate_old != vmstate)) { - fprintf( - stderr, - "%s VM state change detected. (old = '%s', new = '%s')\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - MachineStateToName(vmstate_old), - MachineStateToName(vmstate) - ); - vmstate_old = vmstate; + // VirtualBox Documentation suggests that that a VM is running when its + // machine state is between MachineState_FirstOnline and MachineState_LastOnline + // which as of this writing is 5 and 17. + // + // VboxManage's source shows more than that though: + // see: http://www.virtualbox.org/browser/trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp + // + // So for now, go with what VboxManage is reporting. + // + switch(vmstate) + { + case MachineState_Running: + online = true; + saving = false; + restoring = false; + suspended = false; + crashed = false; + break; + case MachineState_Paused: + online = true; + saving = false; + restoring = false; + suspended = true; + crashed = false; + break; + case MachineState_Starting: + online = true; + saving = false; + restoring = false; + suspended = false; + crashed = false; + break; + case MachineState_Stopping: + online = true; + saving = false; + restoring = false; + suspended = false; + crashed = false; + break; + case MachineState_Saving: + online = true; + saving = true; + restoring = false; + suspended = false; + crashed = false; + break; + case MachineState_Restoring: + online = true; + saving = false; + restoring = true; + suspended = false; + crashed = false; + break; + case MachineState_LiveSnapshotting: + online = true; + saving = false; + restoring = false; + suspended = false; + crashed = false; + break; + case MachineState_DeletingSnapshotOnline: + online = true; + saving = false; + restoring = false; + suspended = false; + crashed = false; + break; + case MachineState_DeletingSnapshotPaused: + online = true; + saving = false; + restoring = false; + suspended = false; + crashed = false; + break; + case MachineState_Aborted: + online = false; + saving = false; + restoring = false; + suspended = false; + crashed = true; + break; + case MachineState_Stuck: + online = false; + saving = false; + restoring = false; + suspended = false; + crashed = true; + break; + default: + online = false; + saving = false; + restoring = false; + suspended = false; + crashed = false; + if (log_state) { + fprintf( + stderr, + "%s VM is no longer is a running state. It is in '%s'.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + MachineStateToName(vmstate) + ); + } + break; + } + if (log_state && (vmstate_old != vmstate)) { + fprintf( + stderr, + "%s VM state change detected. (old = '%s', new = '%s')\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + MachineStateToName(vmstate_old), + MachineStateToName(vmstate) + ); + vmstate_old = vmstate; + } } } @@ -1739,8 +1820,8 @@ int VBOX_VM::start() { int retval = ERR_EXEC; char buf[256]; HRESULT rc; - CComBSTR vm_name(vm_master_name.c_str()); CComBSTR session_type; + CComPtr pMachineRO; CComPtr pProgress; BOOL bCompleted; double timeout; @@ -1754,21 +1835,21 @@ int VBOX_VM::start() { if (!headless) { - session_type = _T("vrdp"); + session_type = _T("gui"); } else { session_type = _T("headless"); } - rc = m_pVirtualBox->FindMachine(vm_name, &m_pMachine); + rc = m_pVirtualBox->FindMachine(CComBSTR(vm_master_name.c_str()), &pMachineRO); if (SUCCEEDED(rc)) { // Start a VM session - rc = m_pMachine->LaunchVMProcess(m_pSession, session_type, NULL, &pProgress); + rc = pMachineRO->LaunchVMProcess(m_pSession, session_type, NULL, &pProgress); if (FAILED(rc)) { fprintf( stderr, "%s Error could not launch VM process! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1782,7 +1863,7 @@ int VBOX_VM::start() { fprintf( stderr, "%s Error could not wait for VM start completion! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -1795,14 +1876,15 @@ int VBOX_VM::start() { // We should now own what goes on with the VM. // - m_pMachine->LockMachine(m_pSession, LockType_Write); + pMachineRO->LockMachine(m_pSession, LockType_Write); + m_pSession->get_Machine(&m_pMachine); rc = m_pMachine->get_SessionPID((ULONG*)&vm_pid); if (FAILED(rc)) { fprintf( stderr, "%s Error could not get VM PID! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); } @@ -1858,89 +1940,86 @@ int VBOX_VM::stop() { ); - // Get console object. - rc = m_pSession->get_Console(&pConsole); - if (FAILED(rc)) { - fprintf( - stderr, - "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), - rc - ); - virtualbox_dump_error(); - retval = rc; - goto CLEANUP; - } - - // Save the state of the machine. - rc = pConsole->SaveState(&pProgress); - if (FAILED(rc)) { - fprintf( - stderr, - "%s Error could not save the state of the VM! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), - rc - ); - virtualbox_dump_error(); - retval = rc; - goto CLEANUP; - } - - // Wait until VM is powered down. - rc = pProgress->WaitForCompletion(-1); - if (FAILED(rc)) { - fprintf( - stderr, - "%s Error could not wait for VM save state completion! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), - rc - ); - virtualbox_dump_error(); - retval = rc; - goto CLEANUP; - } - - if (!retval) { - timeout = dtime() + 300; - do { - poll(false); - if (!online && !saving) break; - boinc_sleep(1.0); - } while (timeout >= dtime()); - } - - if (!online) { - fprintf( - stderr, - "%s Successfully stopped VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - retval = BOINC_SUCCESS; - } else { - fprintf( - stderr, - "%s VM did not stop when requested.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - - // Attempt to terminate the VM - retval = kill_program(vm_pid); - if (retval) { + if (online) { + // Get console object. + rc = m_pSession->get_Console(&pConsole); + if (FAILED(rc)) { fprintf( stderr, - "%s VM was NOT successfully terminated.\n", + "%s Error retrieving console object! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + } + + // Save the state of the machine. + rc = pConsole->SaveState(&pProgress); + if (FAILED(rc)) { + fprintf( + stderr, + "%s Error could not save the state of the VM! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + } + + // Wait until VM is powered down. + rc = pProgress->WaitForCompletion(-1); + if (FAILED(rc)) { + fprintf( + stderr, + "%s Error could not wait for VM save state completion! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + } + + if (!retval) { + timeout = dtime() + 300; + do { + poll(false); + if (!online && !saving) break; + boinc_sleep(1.0); + } while (timeout >= dtime()); + } + + if (!online) { + fprintf( + stderr, + "%s Successfully stopped VM.\n", vboxwrapper_msg_prefix(buf, sizeof(buf)) ); + retval = BOINC_SUCCESS; } else { fprintf( stderr, - "%s VM was successfully terminated.\n", + "%s VM did not stop when requested.\n", vboxwrapper_msg_prefix(buf, sizeof(buf)) ); + + // Attempt to terminate the VM + retval = kill_program(vm_pid); + if (retval) { + fprintf( + stderr, + "%s VM was NOT successfully terminated.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) + ); + } else { + fprintf( + stderr, + "%s VM was successfully terminated.\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)) + ); + } } + + m_pSession->UnlockMachine(); } -CLEANUP: return retval; } @@ -1959,6 +2038,7 @@ int VBOX_VM::poweroff() { vboxwrapper_msg_prefix(buf, sizeof(buf)) ); + if (online) { // Get console object. rc = m_pSession->get_Console(&pConsole); @@ -1966,12 +2046,10 @@ int VBOX_VM::poweroff() { fprintf( stderr, "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); - retval = rc; - goto CLEANUP; } // Power down the VM as quickly as possible. @@ -1980,12 +2058,10 @@ int VBOX_VM::poweroff() { fprintf( stderr, "%s Error could not save the state of the VM! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); - retval = rc; - goto CLEANUP; } // Wait until VM is powered down. @@ -1994,12 +2070,10 @@ int VBOX_VM::poweroff() { fprintf( stderr, "%s Error could not wait for VM save state completion! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); - retval = rc; - goto CLEANUP; } // Wait for up to 5 minutes for the VM to switch states. A system @@ -2045,9 +2119,10 @@ int VBOX_VM::poweroff() { ); } } + + m_pSession->UnlockMachine(); } -CLEANUP: return retval; } @@ -2072,7 +2147,7 @@ int VBOX_VM::pause() { fprintf( stderr, "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2087,7 +2162,7 @@ int VBOX_VM::pause() { fprintf( stderr, "%s Error could not pause VM! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2122,7 +2197,7 @@ int VBOX_VM::resume() { fprintf( stderr, "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2136,7 +2211,7 @@ int VBOX_VM::resume() { fprintf( stderr, "%s Error could not resume VM! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2176,7 +2251,7 @@ int VBOX_VM::create_snapshot(double elapsed_time) { fprintf( stderr, "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2188,7 +2263,7 @@ int VBOX_VM::create_snapshot(double elapsed_time) { fprintf( stderr, "%s Error taking snapshot! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2199,7 +2274,7 @@ int VBOX_VM::create_snapshot(double elapsed_time) { fprintf( stderr, "%s Error could not wait for snapshot creation completion! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2219,9 +2294,7 @@ int VBOX_VM::create_snapshot(double elapsed_time) { // Delete stale snapshot(s), if one exists retval = cleanup_snapshots(false); - if (retval) { - return retval; - } + if (retval) return retval; fprintf( stderr, @@ -2233,64 +2306,92 @@ CLEANUP: return retval; } +// We want to recurisively walk the snapshot tree so that we can delete the most recent children first. +// We also want to skip whatever the most current snapshot is. +// +void TraverseSnapshots(std::string& current_snapshot_id, std::vector& snapshots, ISnapshot* pSnapshot) { + HRESULT rc; + SAFEARRAY* pSnapshots = NULL; + CComSafeArray aSnapshots; + CComBSTR tmp; + ULONG lCount; + std::string snapshot_id; + + // Check to see if we have any children + // + rc = pSnapshot->GetChildrenCount(&lCount); + if (SUCCEEDED(rc) && lCount) { + rc = pSnapshot->get_Children(&pSnapshots); + if (SUCCEEDED(rc)) { + aSnapshots.Attach(pSnapshots); + if (aSnapshots.GetCount() > 0) { + for (int i = 0; i < (int)aSnapshots.GetCount(); i++) { + TraverseSnapshots(current_snapshot_id, snapshots, (ISnapshot*)(LPDISPATCH)aSnapshots[i]); + } + } + } + } + + // Check to see if we are the most recent snapshot. + // if not, add the snapshot id to the list of snapshots to be deleted. + // + pSnapshot->get_Id(&tmp); + if (SUCCEEDED(rc)) { + snapshot_id = CW2A(tmp); + if (current_snapshot_id == snapshot_id) { + return; + } else { + snapshots.push_back(snapshot_id); + } + } +} + int VBOX_VM::cleanup_snapshots(bool delete_active) { - string command; - string output; - string snapshotlist; - string line; - string uuid; - size_t eol_pos; - size_t eol_prev_pos; - size_t uuid_start; - size_t uuid_end; + int retval = ERR_EXEC; char buf[256]; - int retval; + HRESULT rc; + CComPtr pConsole; + CComPtr pCurrentSnapshot; + CComPtr pRootSnapshot; + CComBSTR tmp; + std::string current_snapshot_id; + std::vector snapshots; + rc = m_pSession->get_Console(&pConsole); + if (FAILED(rc)) { + fprintf( + stderr, + "%s Error retrieving console object! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + virtualbox_dump_error(); + retval = rc; + goto CLEANUP; + } - // Enumerate snapshot(s) - command = "snapshot \"" + vm_name + "\" "; - command += "list "; - - // Only log the error if we are not attempting to deregister the VM. - // delete_active is only set to true when we are deregistering the VM. - retval = vbm_popen(command, snapshotlist, "enumerate snapshot(s)", !delete_active, false, 0); - if (retval) return retval; - - // Output should look a little like this: - // Name: Snapshot 2 (UUID: 1751e9a6-49e7-4dcc-ab23-08428b665ddf) - // Name: Snapshot 3 (UUID: 92fa8b35-873a-4197-9d54-7b6b746b2c58) - // Name: Snapshot 4 (UUID: c049023a-5132-45d5-987d-a9cfadb09664) * + // Get the current snapshot // - // Traverse the list from newest to oldest. Otherwise we end up with an error: - // VBoxManage.exe: error: Snapshot operation failed - // VBoxManage.exe: error: Hard disk 'C:\ProgramData\BOINC\slots\23\vm_image.vdi' has - // more than one child hard disk (2) + rc = m_pMachine->get_CurrentSnapshot(&pCurrentSnapshot); + if (SUCCEEDED(rc) && pCurrentSnapshot) { + rc = pCurrentSnapshot->get_Id(&tmp); + if (SUCCEEDED(rc)) { + current_snapshot_id = CW2A(tmp); + } + } + + // Get the root snapshot and traverse the tree // + rc = m_pMachine->FindSnapshot(CComBSTR(""), &pRootSnapshot); + if (SUCCEEDED(rc) && pRootSnapshot) { + TraverseSnapshots(current_snapshot_id, snapshots, pRootSnapshot); + } - // Prepend a space and line feed to the output since we are going to traverse it backwards - snapshotlist = " \n" + snapshotlist; - - eol_prev_pos = snapshotlist.rfind("\n"); - eol_pos = snapshotlist.rfind("\n", eol_prev_pos - 1); - while (eol_pos != string::npos) { - line = snapshotlist.substr(eol_pos, eol_prev_pos - eol_pos); - - // Find the previous line to use in the next iteration - eol_prev_pos = eol_pos; - eol_pos = snapshotlist.rfind("\n", eol_prev_pos - 1); - - // This VM does not yet have any snapshots - if (line.find("does not have any snapshots") != string::npos) break; - - // The * signifies that it is the active snapshot and one we do not want to delete - if (!delete_active && (line.rfind("*") != string::npos)) continue; - - uuid_start = line.find("(UUID: "); - if (uuid_start != string::npos) { - // We can parse the virtual machine ID from the line - uuid_start += 7; - uuid_end = line.find(")", uuid_start); - uuid = line.substr(uuid_start, uuid_end - uuid_start); + // Delete stale snapshots + // + if (snapshots.size()) { + for (size_t i = 0; i < snapshots.size(); i++) { + CComPtr pProgress; fprintf( stderr, @@ -2298,20 +2399,26 @@ int VBOX_VM::cleanup_snapshots(bool delete_active) { vboxwrapper_msg_prefix(buf, sizeof(buf)) ); - // Delete stale snapshot, if one exists - command = "snapshot \"" + vm_name + "\" "; - command += "delete \""; - command += uuid; - command += "\" "; - - // Only log the error if we are not attempting to deregister the VM. - // delete_active is only set to true when we are deregistering the VM. - retval = vbm_popen(command, output, "delete stale snapshot", !delete_active, false, 0); - if (retval) return retval; + rc = pConsole->DeleteSnapshot(CComBSTR(snapshots[i].c_str()), &pProgress); + if (SUCCEEDED(rc)) { + pProgress->WaitForCompletion(-1); + } } } - return 0; + // Delete the current snapshot, if requested. + if (delete_active && current_snapshot_id.size()) { + CComPtr pProgress; + rc = pConsole->DeleteSnapshot(CComBSTR(current_snapshot_id.c_str()), &pProgress); + if (SUCCEEDED(rc)) { + pProgress->WaitForCompletion(-1); + } + } + + retval = BOINC_SUCCESS; + +CLEANUP: + return retval; } int VBOX_VM::restore_snapshot() { @@ -2333,7 +2440,7 @@ int VBOX_VM::restore_snapshot() { fprintf( stderr, "%s Error retrieving current snapshot object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2346,7 +2453,7 @@ int VBOX_VM::restore_snapshot() { fprintf( stderr, "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2359,7 +2466,7 @@ int VBOX_VM::restore_snapshot() { fprintf( stderr, "%s Error restoring snapshot! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2372,7 +2479,7 @@ int VBOX_VM::restore_snapshot() { fprintf( stderr, "%s Error could not wait for restore completion! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2447,21 +2554,21 @@ bool VBOX_VM::is_system_ready(std::string& message) { bool VBOX_VM::is_hdd_registered() { HRESULT rc; - SAFEARRAY* pHardDisks; + SAFEARRAY* pHardDisks = NULL; CComSafeArray aHardDisks; - CComPtr pHardDisk; CComBSTR tmp; + IMedium* pHardDisk; string virtual_machine_root_dir; string hdd_image_location; get_slot_directory(virtual_machine_root_dir); - hdd_image_location = string(virtual_machine_root_dir + "/" + image_filename); + hdd_image_location = string(virtual_machine_root_dir + "\\" + image_filename); rc = m_pVirtualBox->get_HardDisks(&pHardDisks); if (SUCCEEDED(rc)) { aHardDisks.Attach(pHardDisks); for (int i = 0; i < (int)aHardDisks.GetCount(); i++) { - pHardDisk = aHardDisks[i]; + pHardDisk = (IMedium*)(LPDISPATCH)aHardDisks[i]; pHardDisk->get_Location(&tmp); if (0 == stricmp(hdd_image_location.c_str(), CW2A(tmp))) { return true; @@ -2575,11 +2682,11 @@ int VBOX_VM::get_guest_additions(string& guest_additions) { int VBOX_VM::get_default_network_interface(string& iface) { int retval = ERR_EXEC; HRESULT rc; - SAFEARRAY* pNICS; - CComPtr pHost; - CComPtr pNIC; - CComBSTR tmp; + SAFEARRAY* pNICS = NULL; CComSafeArray aNICS; + CComPtr pHost; + CComBSTR tmp; + IHostNetworkInterface* pNIC; rc = m_pVirtualBox->get_Host(&pHost); if (SUCCEEDED(rc)) { @@ -2589,7 +2696,7 @@ int VBOX_VM::get_default_network_interface(string& iface) { aNICS.Attach(pNICS); // We only need the 'default' nic, which is usally the first one. - pNIC = aNICS[0]; + pNIC = (IHostNetworkInterface*)((LPDISPATCH)aNICS[0]); // Get the name for future use rc = pNIC->get_Name(&tmp); @@ -2622,7 +2729,7 @@ int VBOX_VM::get_vm_network_bytes_sent(double& sent) { fprintf( stderr, "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2684,7 +2791,7 @@ int VBOX_VM::get_vm_network_bytes_received(double& received) { fprintf( stderr, "%s Error retrieving console object! rc = 0x%x\n", - boinc_msg_prefix(buf, sizeof(buf)), + vboxwrapper_msg_prefix(buf, sizeof(buf)), rc ); virtualbox_dump_error(); @@ -2738,6 +2845,14 @@ int VBOX_VM::get_vm_exit_code(unsigned long& exit_code) { return 0; } +double VBOX_VM::get_vm_cpu_time() { + double x = process_tree_cpu_time(vm_pid); + if (x > current_cpu_time) { + current_cpu_time = x; + } + return current_cpu_time; +} + // Enable the network adapter if a network connection is required. // NOTE: Network access should never be allowed if the code running in a // shared directory or the VM image itself is NOT signed. Doing so diff --git a/samples/vboxwrapper/vbox_win.h b/samples/vboxwrapper/vbox_win.h index c831a9547b..e782c6e26e 100644 --- a/samples/vboxwrapper/vbox_win.h +++ b/samples/vboxwrapper/vbox_win.h @@ -19,13 +19,13 @@ #ifndef _VBOX_WIN_H_ #define _VBOX_WIN_H_ +#include "mscom/VirtualBox.h" class VBOX_VM : public VBOX_BASE { public: VBOX_VM(); ~VBOX_VM(); - CComPtr m_pVirtualBox; CComPtr m_pSession; CComPtr m_pMachine; @@ -36,46 +36,31 @@ public: int vboxsvc_pid; HANDLE vboxsvc_pid_handle; + int initialize(); + int create_vm(); + int register_vm(); + int deregister_vm(bool delete_media); + int deregister_stale_vm(); + void poll(bool log_state = true); + int start(); + int stop(); + int poweroff(); + int pause(); + int resume(); + int create_snapshot(double elapsed_time); + int cleanup_snapshots(bool delete_active); + int restore_snapshot(); - virtual int initialize(); - virtual int create_vm(); - virtual int register_vm(); - virtual int deregister_vm(bool delete_media); - virtual int deregister_stale_vm(); - virtual void poll(bool log_state = true); - virtual int start(); - virtual int stop(); - virtual int poweroff(); - virtual int pause(); - virtual int resume(); - virtual int create_snapshot(double elapsed_time); - virtual int cleanup_snapshots(bool delete_active); - virtual int restore_snapshot(); - - void dump_hypervisor_logs(bool include_error_logs); void dump_hypervisor_status_reports(); - void dump_vmguestlog_entries(); - void check_trickle_triggers(); - void check_intermediate_uploads(); int is_registered(); bool is_system_ready(std::string& message); - bool is_vm_machine_configuration_available(); bool is_hdd_registered(); bool is_extpack_installed(); - bool is_logged_failure_vm_extensions_disabled(); - bool is_logged_failure_vm_extensions_in_use(); - bool is_logged_failure_vm_extensions_not_supported(); - bool is_logged_failure_host_out_of_memory(); - bool is_logged_failure_guest_job_out_of_memory(); - bool is_logged_completion_file_exists(); - bool is_virtualbox_version_newer(int maj, int min, int rel); - bool is_virtualbox_error_recoverable(int retval); int get_install_directory(std::string& dir); int get_version_information(std::string& version); int get_guest_additions(std::string& dir); - int get_slot_directory(std::string& dir); int get_default_network_interface(std::string& iface); int get_vm_network_bytes_sent(double& sent); int get_vm_network_bytes_received(double& received); @@ -83,25 +68,16 @@ public: int get_vm_exit_code(unsigned long& exit_code); double get_vm_cpu_time(); - int get_system_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int get_vm_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int get_trace_log(std::string& log, bool tail_only = true, unsigned int buffer_size = 8192); - int set_network_access(bool enabled); int set_cpu_usage(int percentage); int set_network_usage(int kilobytes); - int read_floppy(std::string& data); - int write_floppy(std::string& data); - void lower_vm_process_priority(); void reset_vm_process_priority(); int launch_vboxsvc(); int launch_vboxvm(); - void sanitize_output(std::string& output); - }; #endif diff --git a/samples/vboxwrapper/vboxwrapper.cpp b/samples/vboxwrapper/vboxwrapper.cpp index 5f4c740c21..5956c96481 100644 --- a/samples/vboxwrapper/vboxwrapper.cpp +++ b/samples/vboxwrapper/vboxwrapper.cpp @@ -24,7 +24,7 @@ // (use this for credit granting if your app does its // own job management, like CernVM). // --nthreads N create a VM with N threads. -// --vmimage file Use "file" as the VM image. +// --vmimage N Use "vm_image_N" as the VM image. // This lets you create an app version with several images, // and the app_plan function can decide which one to use // for the particular host. @@ -50,7 +50,6 @@ #include "win_util.h" #include "atlcomcli.h" #include "atlstr.h" -#include "mscom/VirtualBox.h" #else #include #include @@ -75,7 +74,6 @@ #include "procinfo.h" #include "vboxwrapper.h" #include "vbox.h" - #ifdef _WIN32 #include "vbox_win.h" #else @@ -319,6 +317,13 @@ void read_fraction_done(double& frac_done, VBOX_VM& vm) { frac_done = frac; } +bool completion_file_exists(VBOX_VM& vm) { + char path[MAXPATHLEN]; + sprintf(path, "shared/%s", vm.completion_trigger_file.c_str()); + if (boinc_file_exists(path)) return true; + return false; +} + void read_completion_file_info(unsigned long& exit_code, bool& is_notice, string& message, VBOX_VM& vm) { char path[MAXPATHLEN]; char buf[1024]; @@ -342,6 +347,13 @@ void read_completion_file_info(unsigned long& exit_code, bool& is_notice, string } } +bool temporary_exit_file_exists(VBOX_VM& vm) { + char path[MAXPATHLEN]; + sprintf(path, "shared/%s", vm.temporary_exit_trigger_file.c_str()); + if (boinc_file_exists(path)) return true; + return false; +} + void read_temporary_exit_file_info(int& temp_delay, bool& is_notice, string& message, VBOX_VM& vm) { char path[MAXPATHLEN]; char buf[1024]; @@ -365,6 +377,12 @@ void read_temporary_exit_file_info(int& temp_delay, bool& is_notice, string& mes } } +void delete_temporary_exit_trigger_file(VBOX_VM& vm) { + char path[MAXPATHLEN]; + sprintf(path, "shared/%s", vm.temporary_exit_trigger_file.c_str()); + boinc_delete_file(path); +} + // set CPU and network throttling if needed // void set_throttles(APP_INIT_DATA& aid, VBOX_VM& vm) { @@ -494,10 +512,10 @@ void set_remote_desktop_info(APP_INIT_DATA& /* aid */, VBOX_VM& vm) { // check for trickle trigger files, and send trickles if find them. // -void VBOX_VM::check_trickle_triggers() { +void check_trickle_triggers(VBOX_VM& vm) { char filename[256], path[MAXPATHLEN], buf[256]; - for (unsigned int i=0; iAllRules.ruleset + vboxwrapper_26108_windows_x86_64 + vboxwrapper_26108_windows_x86_64 + vboxwrapper_26108_windows_intelx86 + vboxwrapper_26108_windows_intelx86 @@ -133,12 +137,12 @@ libcmt.lib;libcpmt.lib;atls.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;wsock32.lib;psapi.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\vboxwrapper_26108_windows_intelx86.exe + $(TargetDir)\$(TargetFileName) true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\vboxwrapper_26108_windows_intelx86.pdb + $(TargetDir)\$(TargetName).pdb Windows MachineX86 @@ -183,12 +187,12 @@ libcmt.lib;libcpmt.lib;atls.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;wsock32.lib;psapi.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\vboxwrapper_26108_windows_x86_64.exe + $(TargetDir)\$(TargetFileName) true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\vboxwrapper_26108_windows_x86_64.pdb + $(TargetDir)\$(TargetName).pdb Windows MachineX64 @@ -229,12 +233,12 @@ libcmtd.lib;libcpmtd.lib;atlsd.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;psapi.lib;wsock32.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\vboxwrapper_6.1_windows_intelx86.exe + $(TargetDir)\$(TargetFileName) true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\vboxwrapper_6.1_windows_intelx86.pdb + $(TargetDir)\$(TargetName).pdb Windows MachineX86 @@ -275,26 +279,24 @@ libcmtd.lib;libcpmtd.lib;atlsd.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;wsock32.lib;psapi.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\vboxwrapper_26063_windows_x86_64.exe + $(TargetDir)\$(TargetFileName) true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\vboxwrapper_26063_windows_x86_64.pdb + $(TargetDir)\$(TargetName).pdb Windows MachineX64 - -