diff --git a/samples/vboxwrapper/vbox.cpp b/samples/vboxwrapper/vbox.cpp index e2ae0f6200..9a9972b415 100644 --- a/samples/vboxwrapper/vbox.cpp +++ b/samples/vboxwrapper/vbox.cpp @@ -18,6 +18,11 @@ #ifdef _WIN32 #include "boinc_win.h" #include "win_util.h" + +#if defined(_MSC_VER) +#define getcwd _getcwd +#endif + #else #include #include @@ -39,11 +44,6 @@ using std::string; -#if defined(_MSC_VER) -#define getcwd _getcwd -#define stricmp _stricmp -#endif - #include "diagnostics.h" #include "filesys.h" #include "parse.h" @@ -58,9 +58,8 @@ using std::string; #include "vboxwrapper.h" #include "vbox.h" -//#define NEW_EXECUTION_PATH 1 -VBOX_VM::VBOX_VM() { +VBOX_BASE::VBOX_BASE() { virtualbox_home_directory.clear(); virtualbox_install_directory.clear(); virtualbox_guest_additions.clear(); @@ -100,1134 +99,26 @@ VBOX_VM::VBOX_VM() { enable_cache_disk = false; enable_isocontextualization = false; enable_remotedesktop = false; - enable_gbac = false; register_only = false; enable_network = false; network_bridged_mode = false; pf_guest_port = 0; pf_host_port = 0; headless = true; - vm_pid = 0; - vboxsvc_pid = 0; -#ifdef _WIN32 - vm_pid_handle = 0; - vboxsvc_pid_handle = 0; -#endif // Initialize default values vm_disk_controller_type = "ide"; vm_disk_controller_model = "PIIX4"; } -VBOX_VM::~VBOX_VM() { +VBOX_BASE::~VBOX_BASE() { if (pFloppy) { delete pFloppy; pFloppy = NULL; } -#ifdef _WIN32 - if (vm_pid_handle) { - CloseHandle(vm_pid_handle); - vm_pid_handle = NULL; - } - if (vboxsvc_pid_handle) { - CloseHandle(vboxsvc_pid_handle); - vboxsvc_pid_handle = NULL; - } -#endif } -int VBOX_VM::initialize() { - int rc = 0; - string old_path; - string new_path; - string command; - string output; - APP_INIT_DATA aid; - bool force_sandbox = false; - char buf[256]; - - boinc_get_init_data_p(&aid); - get_install_directory(virtualbox_install_directory); - - // Prep the environment so we can execute the vboxmanage application - // - // TODO: Fix for non-Windows environments if we ever find another platform - // where vboxmanage is not already in the search path -#ifdef _WIN32 - if (!virtualbox_install_directory.empty()) - { - old_path = getenv("PATH"); - new_path = virtualbox_install_directory + ";" + old_path; - - if (!SetEnvironmentVariable("PATH", const_cast(new_path.c_str()))) { - fprintf( - stderr, - "%s Failed to modify the search path.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } - } -#endif - - // Determine the VirtualBox home directory. Overwrite as needed. - // - if (getenv("VBOX_USER_HOME")) { - virtualbox_home_directory = getenv("VBOX_USER_HOME"); - } else { - // If the override environment variable isn't specified then - // it is based of the current users HOME directory. -#ifdef _WIN32 - virtualbox_home_directory = getenv("USERPROFILE"); -#else - virtualbox_home_directory = getenv("HOME"); -#endif - virtualbox_home_directory += "/.VirtualBox"; - } - - // On *nix style systems, VirtualBox expects that there is a home directory specified - // by environment variable. When it doesn't exist it attempts to store logging information - // in root's home directory. Bad things happen if the process isn't owned by root. - // - // if the HOME environment variable is missing force VirtualBox to use a directory it - // has a reasonable chance of writing log files too. -#ifndef _WIN32 - if (NULL == getenv("HOME")) { - force_sandbox = true; - } -#endif - - // Set the location in which the VirtualBox Configuration files can be - // stored for this instance. - if (aid.using_sandbox || force_sandbox) { - virtualbox_home_directory = aid.project_dir; - virtualbox_home_directory += "/../virtualbox"; - - if (!boinc_file_exists(virtualbox_home_directory.c_str())) boinc_mkdir(virtualbox_home_directory.c_str()); - -#ifdef _WIN32 - if (!SetEnvironmentVariable("VBOX_USER_HOME", const_cast(virtualbox_home_directory.c_str()))) { - fprintf( - stderr, - "%s Failed to modify the search path.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#else - // putenv does not copy its input buffer, so we must use setenv - if (setenv("VBOX_USER_HOME", const_cast(virtualbox_home_directory.c_str()), 1)) { - fprintf( - stderr, - "%s Failed to modify the VBOX_USER_HOME path.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#endif - } - - rc = get_version_information(virtualbox_version); - if (rc) return rc; - - get_guest_additions(virtualbox_guest_additions); - - return 0; -} - -void VBOX_VM::poll(bool log_state) { - char buf[256]; - APP_INIT_DATA aid; - string command; - string output; - string::iterator iter; - string vmstate; - static string vmstate_old = "poweroff"; - size_t vmstate_start; - size_t vmstate_end; - - boinc_get_init_data_p(&aid); - - // - // Is our environment still sane? - // -#ifdef _WIN32 - if (aid.using_sandbox && vboxsvc_pid_handle && !process_exists(vboxsvc_pid_handle)) { - fprintf( - stderr, - "%s Status Report: vboxsvc.exe is no longer running.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } - if (vm_pid_handle && !process_exists(vm_pid_handle)) { - fprintf( - stderr, - "%s Status Report: virtualbox.exe/vboxheadless.exe is no longer running.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#else - if (vm_pid && !process_exists(vm_pid)) { - fprintf( - stderr, - "%s Status Report: virtualbox/vboxheadless is no longer running.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#endif - - // - // What state is the VM in? - // - - command = "showvminfo \"" + vm_name + "\" "; - command += "--machinereadable "; - - if (vbm_popen(command, output, "VM state", false, false, 45, false) == 0) { - vmstate_start = output.find("VMState=\""); - if (vmstate_start != string::npos) { - vmstate_start += 9; - vmstate_end = output.find("\"", vmstate_start); - vmstate = output.substr(vmstate_start, vmstate_end - vmstate_start); - - // 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. - // - if (vmstate == "running") { - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - } else if (vmstate == "paused") { - online = true; - saving = false; - restoring = false; - suspended = true; - crashed = false; - } else if (vmstate == "starting") { - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - } else if (vmstate == "stopping") { - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - } else if (vmstate == "saving") { - online = true; - saving = true; - restoring = false; - suspended = false; - crashed = false; - } else if (vmstate == "restoring") { - online = true; - saving = false; - restoring = true; - suspended = false; - crashed = false; - } else if (vmstate == "livesnapshotting") { - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - } else if (vmstate == "deletingsnapshotlive") { - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - } else if (vmstate == "deletingsnapshotlivepaused") { - online = true; - saving = false; - restoring = false; - suspended = false; - crashed = false; - } else if (vmstate == "aborted") { - online = false; - saving = false; - restoring = false; - suspended = false; - crashed = true; - } else if (vmstate == "gurumeditation") { - online = false; - saving = false; - restoring = false; - suspended = false; - crashed = true; - } else { - 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)), - vmstate.c_str() - ); - } - } - if (log_state && (vmstate_old != vmstate)) { - fprintf( - stderr, - "%s VM state change detected. (old = '%s', new = '%s')\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - vmstate_old.c_str(), - vmstate.c_str() - ); - vmstate_old = vmstate; - } - } - } - - // - // Grab a snapshot of the latest log file. Avoids multiple queries across several - // functions. - // - get_vm_log(vm_log); - - // - // Dump any new VM Guest Log entries - // - dump_vmguestlog_entries(); -} - -int VBOX_VM::create_vm() { - string command; - string output; - string virtual_machine_slot_directory; - string default_interface; - APP_INIT_DATA aid; - bool disable_acceleration = false; - char buf[256]; - int retval; - - boinc_get_init_data_p(&aid); - get_slot_directory(virtual_machine_slot_directory); - - - // 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) { - if ("PIIX4" == vm_disk_controller_model) { - fprintf( - stderr, - "%s Updating drive controller type and model for desired configuration.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - vm_disk_controller_type = "sata"; - vm_disk_controller_model = "IntelAHCI"; - } - } - - // Create and register the VM - // - command = "createvm "; - command += "--name \"" + vm_name + "\" "; - command += "--basefolder \"" + virtual_machine_slot_directory + "\" "; - command += "--ostype \"" + os_name + "\" "; - command += "--register"; - - retval = vbm_popen(command, output, "create"); - if (retval) return retval; - - // Tweak the VM's Description - // - command = "modifyvm \"" + vm_name + "\" "; - command += "--description \"" + vm_master_description + "\" "; - - vbm_popen(command, output, "modifydescription", false, false); - - // Tweak the VM's CPU Count - // - fprintf( - stderr, - "%s Setting CPU Count for VM. (%s)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - vm_cpu_count.c_str() - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--cpus " + vm_cpu_count + " "; - - retval = vbm_popen(command, output, "modifycpu"); - if (retval) return retval; - - // Tweak the VM's Memory Size - // - fprintf( - stderr, - "%s Setting Memory Size for VM. (%sMB)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - vm_memory_size_mb.c_str() - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--memory " + vm_memory_size_mb + " "; - - retval = vbm_popen(command, output, "modifymem"); - if (retval) return retval; - - // Tweak the VM's Chipset Options - // - fprintf( - stderr, - "%s Setting Chipset Options for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--acpi on "; - command += "--ioapic on "; - - retval = vbm_popen(command, output, "modifychipset"); - if (retval) return retval; - - // Tweak the VM's Boot Options - // - fprintf( - stderr, - "%s Setting Boot Options for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--boot1 disk "; - command += "--boot2 dvd "; - command += "--boot3 none "; - command += "--boot4 none "; - - retval = vbm_popen(command, output, "modifyboot"); - if (retval) return retval; - - // Tweak the VM's Network Configuration - // - if (network_bridged_mode) { - fprintf( - stderr, - "%s Setting Network Configuration for Bridged Mode.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--nic1 bridged "; - command += "--cableconnected1 off "; - - retval = vbm_popen(command, output, "set bridged mode"); - if (retval) return retval; - - get_default_network_interface(default_interface); - fprintf( - stderr, - "%s Setting Bridged Interface. (%s)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - default_interface.c_str() - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--bridgeadapter1 \""; - command += default_interface; - command += "\" "; - - retval = vbm_popen(command, output, "set bridged interface"); - if (retval) return retval; - } else { - fprintf( - stderr, - "%s Setting Network Configuration for NAT.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--nic1 nat "; - command += "--natdnsproxy1 on "; - command += "--cableconnected1 off "; - - retval = vbm_popen(command, output, "modifynetwork"); - if (retval) return retval; - } - - // Tweak the VM's USB Configuration - // - fprintf( - stderr, - "%s Disabling USB Support for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--usb off "; - - vbm_popen(command, output, "modifyusb", false, false); - - // Tweak the VM's COM Port Support - // - fprintf( - stderr, - "%s Disabling COM Port Support for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--uart1 off "; - command += "--uart2 off "; - - vbm_popen(command, output, "modifycom", false, false); - - // Tweak the VM's LPT Port Support - // - fprintf( - stderr, - "%s Disabling LPT Port Support for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--lpt1 off "; - command += "--lpt2 off "; - - vbm_popen(command, output, "modifylpt", false, false); - - // Tweak the VM's Audio Support - // - fprintf( - stderr, - "%s Disabling Audio Support for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--audio none "; - - vbm_popen(command, output, "modifyaudio", false, false); - - // Tweak the VM's Clipboard Support - // - fprintf( - stderr, - "%s Disabling Clipboard Support for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--clipboard disabled "; - - vbm_popen(command, output, "modifyclipboard", false, false); - - // Tweak the VM's Drag & Drop Support - // - fprintf( - stderr, - "%s Disabling Drag and Drop Support for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--draganddrop disabled "; - - vbm_popen(command, output, "modifydragdrop", false, false); - - // Check to see if the processor supports hardware acceleration for virtualization - // If it doesn't, disable the use of it in VirtualBox. Multi-core jobs require hardware - // acceleration and actually override this setting. - // - if (!strstr(aid.host_info.p_features, "vmx") && !strstr(aid.host_info.p_features, "svm")) { - fprintf( - stderr, - "%s Hardware acceleration CPU extensions not detected. Disabling VirtualBox hardware acceleration support.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - disable_acceleration = true; - } - if (strstr(aid.host_info.p_features, "hypervisor")) { - fprintf( - stderr, - "%s Running under Hypervisor. Disabling VirtualBox hardware acceleration support.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - disable_acceleration = true; - } - if (is_boinc_client_version_newer(aid, 7, 2, 16)) { - if (aid.vm_extensions_disabled) { - fprintf( - stderr, - "%s Hardware acceleration failed with previous execution. Disabling VirtualBox hardware acceleration support.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - disable_acceleration = true; - } - } else { - if (vm_cpu_count == "1") { - // Keep this around for older clients. Removing this for older clients might - // lead to a machine that will only return crashed VM reports. - vboxwrapper_msg_prefix(buf, sizeof(buf)); - fprintf( - stderr, - "%s Legacy fallback configuration detected. Disabling VirtualBox hardware acceleration support.\n" - "%s NOTE: Upgrading to BOINC 7.2.16 or better may re-enable hardware acceleration.\n", - buf, - buf - ); - disable_acceleration = true; - } - } - - // Only allow disabling of hardware acceleration on 32-bit VM types, 64-bit VM types require it. - // - if (os_name.find("_64") == std::string::npos) { - if (disable_acceleration) { - fprintf( - stderr, - "%s Disabling hardware acceleration support for virtualization.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--hwvirtex off "; - - retval = vbm_popen(command, output, "VT-x/AMD-V support"); - if (retval) return retval; - } - } else if (os_name.find("_64") != std::string::npos) { - if (disable_acceleration) { - fprintf( - stderr, - "%s ERROR: Invalid configuration. VM type requires acceleration but the current configuration cannot support it.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - return ERR_INVALID_PARAM; - } - } - - // Add storage controller to VM - // See: http://www.virtualbox.org/manual/ch08.html#vboxmanage-storagectl - // See: http://www.virtualbox.org/manual/ch05.html#iocaching - // - fprintf( - stderr, - "%s Adding storage controller to VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "storagectl \"" + vm_name + "\" "; - command += "--name \"Hard Disk Controller\" "; - command += "--add \"" + vm_disk_controller_type + "\" "; - command += "--controller \"" + vm_disk_controller_model + "\" "; - if ( - (vm_disk_controller_type == "sata") || (vm_disk_controller_type == "SATA") || - (vm_disk_controller_type == "scsi") || (vm_disk_controller_type == "SCSI") || - (vm_disk_controller_type == "sas") || (vm_disk_controller_type == "SAS") - ) { - command += "--hostiocache off "; - } - if ((vm_disk_controller_type == "sata") || (vm_disk_controller_type == "SATA")) { - if (is_virtualbox_version_newer(4, 3, 0)) { - command += "--portcount 3"; - } else { - command += "--sataportcount 3"; - } - } - - retval = vbm_popen(command, output, "add storage controller (fixed disk)"); - if (retval) return retval; - - // Add storage controller for a floppy device if desired - // - if (enable_floppyio) { - command = "storagectl \"" + vm_name + "\" "; - command += "--name \"Floppy Controller\" "; - command += "--add floppy "; - - retval = vbm_popen(command, output, "add storage controller (floppy)"); - if (retval) return retval; - } - - if (enable_isocontextualization) { - - // Add virtual ISO 9660 disk drive to VM - // - fprintf( - stderr, - "%s Adding virtual ISO 9660 disk drive to VM. (%s)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - iso_image_filename.c_str() - ); - command = "storageattach \"" + vm_name + "\" "; - command += "--storagectl \"Hard Disk Controller\" "; - command += "--port 0 "; - command += "--device 0 "; - command += "--type dvddrive "; - command += "--medium \"" + virtual_machine_slot_directory + "/" + iso_image_filename + "\" "; - - retval = vbm_popen(command, output, "storage attach (ISO 9660 image)"); - if (retval) return retval; - - if (!virtualbox_guest_additions.empty()) { - - // Add guest additions to the VM - // - fprintf( - stderr, - "%s Adding VirtualBox Guest Additions to VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "storageattach \"" + vm_name + "\" "; - command += "--storagectl \"Hard Disk Controller\" "; - command += "--port 2 "; - command += "--device 0 "; - command += "--type dvddrive "; - command += "--medium \"" + virtualbox_guest_additions + "\" "; - - retval = vbm_popen(command, output, "storage attach (guest additions image)"); - if (retval) return retval; - - } - - // Add a virtual cache disk drive to VM - // - if (enable_cache_disk){ - fprintf( - stderr, - "%s Adding virtual cache disk drive to VM. (%s)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - cache_disk_filename.c_str() - ); - command = "storageattach \"" + vm_name + "\" "; - command += "--storagectl \"Hard Disk Controller\" "; - command += "--port 1 "; - command += "--device 0 "; - command += "--type hdd "; - command += "--setuuid \"\" "; - command += "--medium \"" + virtual_machine_slot_directory + "/" + cache_disk_filename + "\" "; - - retval = vbm_popen(command, output, "storage attach (cached disk)"); - if (retval) return retval; - } - - } else { - - // Adding virtual hard drive to VM - // - fprintf( - stderr, - "%s Adding virtual disk drive to VM. (%s)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - image_filename.c_str() - ); - command = "storageattach \"" + vm_name + "\" "; - command += "--storagectl \"Hard Disk Controller\" "; - command += "--port 0 "; - command += "--device 0 "; - command += "--type hdd "; - command += "--setuuid \"\" "; - command += "--medium \"" + virtual_machine_slot_directory + "/" + image_filename + "\" "; - - retval = vbm_popen(command, output, "storage attach (fixed disk)"); - if (retval) return retval; - - if (!virtualbox_guest_additions.empty()) { - - // Add guest additions to the VM - // - fprintf( - stderr, - "%s Adding VirtualBox Guest Additions to VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "storageattach \"" + vm_name + "\" "; - command += "--storagectl \"Hard Disk Controller\" "; - command += "--port 1 "; - command += "--device 0 "; - command += "--type dvddrive "; - command += "--medium \"" + virtualbox_guest_additions + "\" "; - - retval = vbm_popen(command, output, "storage attach (guest additions image)"); - if (retval) return retval; - - } - - } - - - // Add network bandwidth throttle group - // - if (is_virtualbox_version_newer(4, 2, 0)) { - fprintf( - stderr, - "%s Adding network bandwidth throttle group to VM. (Defaulting to 1024GB)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "bandwidthctl \"" + vm_name + "\" "; - command += "add \"" + vm_name + "_net\" "; - command += "--type network "; - command += "--limit 1024G"; - command += " "; - - retval = vbm_popen(command, output, "network throttle group (add)"); - if (retval) return retval; - } - - // Adding virtual floppy disk drive to VM - // - if (enable_floppyio) { - - // Put in place the FloppyIO abstraction - // - // NOTE: This creates the floppy.img file at runtime for use by the VM. - // - pFloppy = new FloppyIO(floppy_image_filename.c_str()); - if (!pFloppy->ready()) { - vboxwrapper_msg_prefix(buf, sizeof(buf)); - fprintf( - stderr, - "%s Creating virtual floppy image failed.\n" - "%s Error Code '%d' Error Message '%s'\n", - buf, - buf, - pFloppy->error, - pFloppy->errorStr.c_str() - ); - return ERR_FWRITE; - } - - fprintf( - stderr, - "%s Adding virtual floppy disk drive to VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "storageattach \"" + vm_name + "\" "; - command += "--storagectl \"Floppy Controller\" "; - command += "--port 0 "; - command += "--device 0 "; - command += "--medium \"" + virtual_machine_slot_directory + "/" + floppy_image_filename + "\" "; - - retval = vbm_popen(command, output, "storage attach (floppy disk)"); - if (retval) return retval; - - } - - // Enable the network adapter if a network connection is required. - // - if (enable_network) { - set_network_access(true); - - // set up port forwarding - // - for (unsigned int i=0; i 45) { - retval = ERR_TIMEOUT; - break; - } - } -#endif - - if (BOINC_SUCCESS == retval) { - fprintf( - stderr, - "%s Successfully started VM. (PID = '%d')\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - vm_pid - ); - } else { - fprintf( - stderr, - "%s VM failed to start.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } - - return retval; -} - -int VBOX_VM::stop() { - string command; - string output; - double timeout; - char buf[256]; - int retval = 0; - - fprintf( - stderr, - "%s Stopping VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - if (online) { - command = "controlvm \"" + vm_name + "\" savestate"; - retval = vbm_popen(command, output, "stop VM", true, false); - - // Wait for up to 5 minutes for the VM to switch states. A system - // under load can take a while. Since the poll function can wait for up - // to 45 seconds to execute a command we need to make this time based instead - // of iteration based. - 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) { - 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)) - ); - } - } - } - - return retval; -} - -int VBOX_VM::poweroff() { - string command; - string output; - double timeout; - char buf[256]; - int retval = 0; - - fprintf( - stderr, - "%s Powering off VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - if (online) { - command = "controlvm \"" + vm_name + "\" poweroff"; - retval = vbm_popen(command, output, "poweroff VM", true, false); - - // Wait for up to 5 minutes for the VM to switch states. A system - // under load can take a while. Since the poll function can wait for up - // to 45 seconds to execute a command we need to make this time based instead - // of iteration based. - 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 powered off VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - retval = BOINC_SUCCESS; - } else { - fprintf( - stderr, - "%s VM did not power off 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)) - ); - } - } - } - - return retval; -} - -int VBOX_VM::pause() { - string command; - string output; - int retval; - - // Restore the process priority back to the default process priority - // to speed up the last minute maintenance tasks before the VirtualBox - // VM goes to sleep - // - reset_vm_process_priority(); - - command = "controlvm \"" + vm_name + "\" pause"; - retval = vbm_popen(command, output, "pause VM"); - if (retval) return retval; - suspended = true; - return 0; -} - -int VBOX_VM::resume() { - string command; - string output; - int retval; - - // Set the process priority back to the lowest level before resuming - // execution - // - lower_vm_process_priority(); - - command = "controlvm \"" + vm_name + "\" resume"; - retval = vbm_popen(command, output, "resume VM"); - if (retval) return retval; - suspended = false; - return 0; -} - -int VBOX_VM::create_snapshot(double elapsed_time) { - string command; - string output; - char buf[256]; - int retval; - - fprintf( - stderr, - "%s Creating new snapshot for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - - // Pause VM - Try and avoid the live snapshot and trigger an online - // snapshot instead. - pause(); - - // Create new snapshot - sprintf(buf, "%d", (int)elapsed_time); - command = "snapshot \"" + vm_name + "\" "; - command += "take boinc_"; - command += buf; - retval = vbm_popen(command, output, "create new snapshot", true, true, 0); - if (retval) return retval; - - // Resume VM - resume(); - - // Set the suspended flag back to false before deleting the stale - // snapshot - poll(false); - - // Delete stale snapshot(s), if one exists - retval = cleanup_snapshots(false); - if (retval) return retval; - - fprintf( - stderr, - "%s Checkpoint completed.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - - return 0; -} - -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; - char buf[256]; - int retval; - - - // 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) * - // - // 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) - // - - // 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); - - fprintf( - stderr, - "%s Deleting stale snapshot.\n", - 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; - } - } - - return 0; -} - -int VBOX_VM::restore_snapshot() { - string command; - string output; - char buf[256]; - int retval = BOINC_SUCCESS; - - fprintf( - stderr, - "%s Restore from previously saved snapshot.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - - command = "snapshot \"" + vm_name + "\" "; - command += "restorecurrent "; - retval = vbm_popen(command, output, "restore current snapshot", true, false, 0); - if (retval) return retval; - - fprintf( - stderr, - "%s Restore completed.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - - return retval; -} - -void VBOX_VM::dump_hypervisor_logs(bool include_error_logs) { +void VBOX_BASE::dump_hypervisor_logs(bool include_error_logs) { string local_system_log; string local_vm_log; string local_trace_log; @@ -1710,45 +230,6 @@ void VBOX_VM::dump_hypervisor_logs(bool include_error_logs) { } } -void VBOX_VM::dump_hypervisor_status_reports() { - -#ifdef _WIN32 - char buf[256]; - SIZE_T ulMinimumWorkingSetSize; - SIZE_T ulMaximumWorkingSetSize; - - if ( - GetProcessWorkingSetSize( - vboxsvc_pid_handle, - &ulMinimumWorkingSetSize, - &ulMaximumWorkingSetSize) - ) { - fprintf( - stderr, - "%s Status Report (VirtualBox VboxSvc.exe): Minimum WSS: '%dKB', Maximum WSS: '%dKB'\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - ulMinimumWorkingSetSize/1024, - ulMaximumWorkingSetSize/1024 - ); - } - - if ( - GetProcessWorkingSetSize( - vm_pid_handle, - &ulMinimumWorkingSetSize, - &ulMaximumWorkingSetSize) - ) { - fprintf( - stderr, - "%s Status Report (VirtualBox Vboxheadless.exe/VirtualBox.exe): Minimum WSS: '%dKB', Maximum WSS: '%dKB'\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - ulMinimumWorkingSetSize/1024, - ulMaximumWorkingSetSize/1024 - ); - } -#endif -} - // t1 > t2 static bool is_timestamp_newer(VBOX_TIMESTAMP& t1, VBOX_TIMESTAMP& t2) { if (t1.hours > t2.hours) return true; @@ -1763,7 +244,7 @@ static bool is_timestamp_newer(VBOX_TIMESTAMP& t1, VBOX_TIMESTAMP& t2) { // Dump any new guest log messages which are generated by applications running within // the guest VM. -void VBOX_VM::dump_vmguestlog_entries() { +void VBOX_BASE::dump_vmguestlog_entries() { string local_vm_log; string line; size_t eol_pos; @@ -1807,110 +288,7 @@ void VBOX_VM::dump_vmguestlog_entries() { } } -void VBOX_VM::delete_temporary_exit_trigger_file() { - char path[MAXPATHLEN]; - sprintf(path, "shared/%s", temporary_exit_trigger_file.c_str()); - boinc_delete_file(path); -} - -int VBOX_VM::is_registered() { - string command; - string output; - string needle; - char buf[256]; - int retval; - - command = "showvminfo \"" + vm_master_name + "\" "; - command += "--machinereadable "; - - // Look for this string in the output - // - needle = "name=\"" + vm_master_name + "\""; - - retval = vbm_popen(command, output, "registration detection", false, false); - - // Handle explicit cases first - if (ERR_TIMEOUT == retval) { - return ERR_TIMEOUT; - } - if (output.find("VBOX_E_OBJECT_NOT_FOUND") != string::npos) { - return ERR_NOT_FOUND; - } - if (!retval && output.find(needle.c_str()) != string::npos) { - return BOINC_SUCCESS; - } - - // Something unexpected has happened. Dump diagnostic output. - fprintf( - stderr, - "%s Error in registration for VM: %d\nArguments:\n%s\nOutput:\n%s\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - retval, - command.c_str(), - output.c_str() - ); - - return retval; -} - -// Attempt to detect any condition that would prevent VirtualBox from running a VM properly, like: -// 1. The DCOM service not being started on Windows -// 2. Vboxmanage not being able to communicate with vboxsvc for some reason -// 3. VirtualBox driver not loaded for the current Linux kernel. -// -// Luckly both of the above conditions can be detected by attempting to detect the host information -// via vboxmanage and it is cross platform. -// -bool VBOX_VM::is_system_ready(std::string& message) { - string command; - string output; - char buf[256]; - int retval; - bool rc = false; - - command = "list hostinfo "; - retval = vbm_popen(command, output, "host info"); - if (BOINC_SUCCESS == retval) { - rc = true; - } - - if (output.size() == 0) { - fprintf( - stderr, - "%s WARNING: Communication with VM Hypervisor failed. (Possibly Out of Memory).\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - message = "Communication with VM Hypervisor failed. (Possibly Out of Memory)."; - rc = false; - } - - if (output.find("Processor count:") == string::npos) { - fprintf( - stderr, - "%s WARNING: Communication with VM Hypervisor failed.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - message = "Communication with VM Hypervisor failed."; - rc = false; - } - - if (output.find("WARNING: The vboxdrv kernel module is not loaded.") != string::npos) { - vboxwrapper_msg_prefix(buf, sizeof(buf)); - fprintf( - stderr, - "%s WARNING: The vboxdrv kernel module is not loaded.\n" - "%s WARNING: Please update/recompile VirtualBox kernel drivers.\n", - buf, - buf - ); - message = "Please update/recompile VirtualBox kernel drivers."; - rc = false; - } - - return rc; -} - -bool VBOX_VM::is_vm_machine_configuration_available() { +bool VBOX_BASE::is_vm_machine_configuration_available() { string virtual_machine_slot_directory; string vm_machine_configuration_file; APP_INIT_DATA aid; @@ -1925,42 +303,7 @@ bool VBOX_VM::is_vm_machine_configuration_available() { return false; } -bool VBOX_VM::is_hdd_registered() { - string command; - string output; - string virtual_machine_root_dir; - - get_slot_directory(virtual_machine_root_dir); - - command = "showhdinfo \"" + virtual_machine_root_dir + "/" + image_filename + "\" "; - - if (vbm_popen(command, output, "hdd registration", false, false) == 0) { - if ((output.find("VBOX_E_FILE_ERROR") == string::npos) && - (output.find("VBOX_E_OBJECT_NOT_FOUND") == string::npos) && - (output.find("does not match the value") == string::npos) - ) { - // Error message not found in text - return true; - } - } - return false; -} - -bool VBOX_VM::is_extpack_installed() { - string command; - string output; - - command = "list extpacks"; - - if (vbm_popen(command, output, "extpack detection", false, false) == 0) { - if ((output.find("Oracle VM VirtualBox Extension Pack") != string::npos) && (output.find("VBoxVRDP") != string::npos)) { - return true; - } - } - return false; -} - -bool VBOX_VM::is_logged_failure_vm_extensions_disabled() { +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; @@ -1971,44 +314,37 @@ bool VBOX_VM::is_logged_failure_vm_extensions_disabled() { return false; } -bool VBOX_VM::is_logged_failure_vm_extensions_in_use() { +bool VBOX_BASE::is_logged_failure_vm_extensions_in_use() { if (vm_log.find("VERR_VMX_IN_VMX_ROOT_MODE") != string::npos) return true; if (vm_log.find("VERR_SVM_IN_USE") != string::npos) return true; return false; } -bool VBOX_VM::is_logged_failure_vm_extensions_not_supported() { +bool VBOX_BASE::is_logged_failure_vm_extensions_not_supported() { if (vm_log.find("VERR_VMX_NO_VMX") != string::npos) return true; if (vm_log.find("VERR_SVM_NO_SVM") != string::npos) return true; return false; } -bool VBOX_VM::is_logged_failure_host_out_of_memory() { +bool VBOX_BASE::is_logged_failure_host_out_of_memory() { if (vm_log.find("VERR_EM_NO_MEMORY") != string::npos) return true; if (vm_log.find("VERR_NO_MEMORY") != string::npos) return true; return false; } -bool VBOX_VM::is_logged_failure_guest_job_out_of_memory() { +bool VBOX_BASE::is_logged_failure_guest_job_out_of_memory() { if (vm_log.find("EXIT_OUT_OF_MEMORY") != string::npos) return true; return false; } -bool VBOX_VM::is_logged_completion_file_exists() { +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_VM::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_VM::is_virtualbox_version_newer(int maj, int min, int rel) { +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)) { if (maj < vbox_major) return true; @@ -2020,132 +356,15 @@ bool VBOX_VM::is_virtualbox_version_newer(int maj, int min, int rel) { return false; } -bool VBOX_VM::is_virtualbox_error_recoverable(int retval) { - // See comments for VBOX_VM::vbm_popen about session lock issues. +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_VM::get_install_directory(string& install_directory ) { -#ifdef _WIN32 - LONG lReturnValue; - HKEY hkSetupHive; - LPTSTR lpszRegistryValue = NULL; - DWORD dwSize = 0; - - // change the current directory to the boinc data directory if it exists - lReturnValue = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Oracle\\VirtualBox"), - 0, - KEY_READ, - &hkSetupHive - ); - if (lReturnValue == ERROR_SUCCESS) { - // How large does our buffer need to be? - lReturnValue = RegQueryValueEx( - hkSetupHive, - _T("InstallDir"), - NULL, - NULL, - NULL, - &dwSize - ); - if (lReturnValue != ERROR_FILE_NOT_FOUND) { - // Allocate the buffer space. - lpszRegistryValue = (LPTSTR) malloc(dwSize); - (*lpszRegistryValue) = NULL; - - // Now get the data - lReturnValue = RegQueryValueEx( - hkSetupHive, - _T("InstallDir"), - NULL, - NULL, - (LPBYTE)lpszRegistryValue, - &dwSize - ); - - install_directory = lpszRegistryValue; - } - } - - if (hkSetupHive) RegCloseKey(hkSetupHive); - if (lpszRegistryValue) free(lpszRegistryValue); - if (install_directory.empty()) { - return 1; - } - return 0; -#else - install_directory = ""; - return 0; -#endif -} - -int VBOX_VM::get_version_information(string& version) { - string command; - string output; - int retval; - - // Record the VirtualBox version information for later use. - command = "--version "; - retval = vbm_popen(command, output, "version check"); - - if (!retval) { - // Remove \r or \n from the output spew - string::iterator iter = output.begin(); - while (iter != output.end()) { - if (*iter == '\r' || *iter == '\n') { - iter = output.erase(iter); - } else { - ++iter; - } - } - version = output; - } - - return retval; -} - -int VBOX_VM::get_guest_additions(string& guest_additions) { - string command; - string output; - size_t ga_start; - size_t ga_end; - int retval; - - // Get the location of where the guest additions are - command = "list systemproperties"; - retval = vbm_popen(command, output, "guest additions"); - - // Output should look like this: - // API version: 4_3 - // Minimum guest RAM size: 4 Megabytes - // Maximum guest RAM size: 2097152 Megabytes - // Minimum video RAM size: 1 Megabytes - // Maximum video RAM size: 256 Megabytes - // ... - // Default Guest Additions ISO: C:\Program Files\Oracle\VirtualBox/VBoxGuestAdditions.iso - // - - ga_start = output.find("Default Guest Additions ISO:"); - if (ga_start == string::npos) { - return ERR_NOT_FOUND; - } - ga_start += strlen("Default Guest Additions ISO:"); - ga_end = output.find("\n", ga_start); - guest_additions = output.substr(ga_start, ga_end - ga_start); - strip_whitespace(guest_additions); - if (guest_additions.size() <= 0) { - return ERR_NOT_FOUND; - } - - return retval; -} - // Returns the current directory in which the executable resides. // -int VBOX_VM::get_slot_directory(string& dir) { +int VBOX_BASE::get_slot_directory(string& dir) { char slot_dir[256]; getcwd(slot_dir, sizeof(slot_dir)); @@ -2157,184 +376,21 @@ int VBOX_VM::get_slot_directory(string& dir) { return 0; } -int VBOX_VM::get_default_network_interface(string& iface) { - string command; - string output; - size_t if_start; - size_t if_end; - int retval; - - // Get the location of where the guest additions are - command = "list bridgedifs"; - retval = vbm_popen(command, output, "default interface"); - - // Output should look like this: - // Name: Intel(R) Ethernet Connection I217-V - // GUID: 4b8796d6-a4ed-4752-8e8e-bf23984fd93c - // DHCP: Enabled - // IPAddress: 192.168.1.19 - // NetworkMask: 255.255.255.0 - // IPV6Address: fe80:0000:0000:0000:31c2:0053:4f50:4e64 - // IPV6NetworkMaskPrefixLength: 64 - // HardwareAddress: bc:5f:f4:ba:cc:16 - // MediumType: Ethernet - // Status: Up - // VBoxNetworkName: HostInterfaceNetworking-Intel(R) Ethernet Connection I217-V - - if_start = output.find("Name:"); - if (if_start == string::npos) { - return ERR_NOT_FOUND; - } - if_start += strlen("Name:"); - if_end = output.find("\n", if_start); - iface = output.substr(if_start, if_end - if_start); - strip_whitespace(iface); - if (iface.size() <= 0) { - return ERR_NOT_FOUND; - } - - return retval; -} - -int VBOX_VM::get_vm_network_bytes_sent(double& sent) { - string command; - string output; - string counter_value; - size_t counter_start; - size_t counter_end; - int retval; - - command = "debugvm \"" + vm_name + "\" "; - command += "statistics --pattern \"/Devices/*/TransmitBytes\" "; - - retval = vbm_popen(command, output, "get bytes sent"); - if (retval) return retval; - - // Output should look like this: - // - // - // - // - // - - // add up the counter(s) - // - sent = 0; - counter_start = output.find("c=\""); - while (counter_start != string::npos) { - counter_start += 3; - counter_end = output.find("\"", counter_start); - counter_value = output.substr(counter_start, counter_end - counter_start); - sent += atof(counter_value.c_str()); - counter_start = output.find("c=\"", counter_start); - } - return 0; -} - -int VBOX_VM::get_vm_network_bytes_received(double& received) { - string command; - string output; - string counter_value; - size_t counter_start; - size_t counter_end; - int retval; - - command = "debugvm \"" + vm_name + "\" "; - command += "statistics --pattern \"/Devices/*/ReceiveBytes\" "; - - retval = vbm_popen(command, output, "get bytes received"); - if (retval) return retval; - - // Output should look like this: - // - // - // - // - // - - // add up the counter(s) - // - received = 0; - counter_start = output.find("c=\""); - while (counter_start != string::npos) { - counter_start += 3; - counter_end = output.find("\"", counter_start); - counter_value = output.substr(counter_start, counter_end - counter_start); - received += atof(counter_value.c_str()); - counter_start = output.find("c=\"", counter_start); - } - - return 0; -} - -int VBOX_VM::get_vm_process_id() { - string output; - string pid; - size_t pid_start; - size_t pid_end; - - get_vm_log(output, false); - - // Output should look like this: - // VirtualBox 4.1.0 r73009 win.amd64 (Jul 19 2011 13:05:53) release log - // 00:00:06.008 Log opened 2011-09-01T23:00:59.829170900Z - // 00:00:06.008 OS Product: Windows 7 - // 00:00:06.009 OS Release: 6.1.7601 - // 00:00:06.009 OS Service Pack: 1 - // 00:00:06.015 Host RAM: 4094MB RAM, available: 876MB - // 00:00:06.015 Executable: C:\Program Files\Oracle\VirtualBox\VirtualBox.exe - // 00:00:06.015 Process ID: 6128 - // 00:00:06.015 Package type: WINDOWS_64BITS_GENERIC - // 00:00:06.015 Installed Extension Packs: - // 00:00:06.015 None installed! - // - pid_start = output.find("Process ID: "); - if (pid_start == string::npos) { - return ERR_NOT_FOUND; - } - pid_start += strlen("Process ID: "); - pid_end = output.find("\n", pid_start); - pid = output.substr(pid_start, pid_end - pid_start); - strip_whitespace(pid); - if (pid.size() <= 0) { - return ERR_NOT_FOUND; - } - - vm_pid = atol(pid.c_str()); - +void VBOX_BASE::sanitize_output(std::string& output) { #ifdef _WIN32 - vm_pid_handle = OpenProcess( - PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION, - FALSE, - vm_pid - ); -#endif - - return 0; -} - -int VBOX_VM::get_vm_exit_code(unsigned long& exit_code) { -#ifdef _WIN32 - if (vm_pid_handle) { - GetExitCodeProcess(vm_pid_handle, &exit_code); + // Remove \r from the log spew + string::iterator iter = output.begin(); + while (iter != output.end()) { + if (*iter == '\r') { + iter = output.erase(iter); + } else { + ++iter; + } } -#else - int ec = 0; - waitpid(vm_pid, &ec, WNOHANG); - exit_code = ec; #endif - 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; -} - -int VBOX_VM::get_system_log(string& log, bool tail_only, unsigned int buffer_size) { +int VBOX_BASE::get_system_log(string& log, bool tail_only, unsigned int buffer_size) { string slot_directory; string virtualbox_system_log_src; string virtualbox_system_log_dst; @@ -2396,7 +452,7 @@ int VBOX_VM::get_system_log(string& log, bool tail_only, unsigned int buffer_siz return retval; } -int VBOX_VM::get_vm_log(string& log, bool tail_only, unsigned int buffer_size) { +int VBOX_BASE::get_vm_log(string& log, bool tail_only, unsigned int buffer_size) { string slot_directory; string virtualbox_vm_log_src; string virtualbox_vm_log_dst; @@ -2459,7 +515,7 @@ int VBOX_VM::get_vm_log(string& log, bool tail_only, unsigned int buffer_size) { return retval; } -int VBOX_VM::get_trace_log(string& log, bool tail_only, unsigned int buffer_size) { +int VBOX_BASE::get_trace_log(string& log, bool tail_only, unsigned int buffer_size) { string slot_directory; string vm_trace_log; string::iterator iter; @@ -2502,140 +558,7 @@ int VBOX_VM::get_trace_log(string& log, bool tail_only, unsigned int buffer_size return retval; } -// 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 -// opens up the network behind the company firewall to attack. -// -// Imagine a doomsday scenario where a project has been compromised and -// an unsigned executable/VM image has been tampered with. Volunteer -// downloads compromised code and executes it on a company machine. -// Now the compromised VM starts attacking other machines on the company -// network. The company firewall cannot help because the attacking -// machine is already behind the company firewall. -// -int VBOX_VM::set_network_access(bool enabled) { - string command; - string output; - char buf[256]; - int retval; - - network_suspended = !enabled; - - if (enabled) { - fprintf( - stderr, - "%s Enabling network access for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--cableconnected1 on "; - - retval = vbm_popen(command, output, "enable network"); - if (retval) return retval; - } else { - fprintf( - stderr, - "%s Disabling network access for VM.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - command = "modifyvm \"" + vm_name + "\" "; - command += "--cableconnected1 off "; - - retval = vbm_popen(command, output, "disable network"); - if (retval) return retval; - } - return 0; -} - -int VBOX_VM::set_cpu_usage(int percentage) { - string command; - string output; - char buf[256]; - int retval; - - // the arg to controlvm is percentage - // - fprintf( - stderr, - "%s Setting CPU throttle for VM. (%d%%)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - percentage - ); - sprintf(buf, "%d", percentage); - command = "controlvm \"" + vm_name + "\" "; - command += "cpuexecutioncap "; - command += buf; - command += " "; - - retval = vbm_popen(command, output, "CPU throttle"); - if (retval) return retval; - return 0; -} - -int VBOX_VM::set_network_usage(int kilobytes) { - string command; - string output; - char buf[256]; - int retval; - - // the argument to modifyvm is in KB - // - if (kilobytes == 0) { - fprintf( - stderr, - "%s Setting network throttle for VM. (1024GB)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } else { - fprintf( - stderr, - "%s Setting network throttle for VM. (%dKB)\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - kilobytes - ); - } - - if (is_virtualbox_version_newer(4, 2, 0)) { - - // Update bandwidth group limits - // - if (kilobytes == 0) { - command = "bandwidthctl \"" + vm_name + "\" "; - command += "set \"" + vm_name + "_net\" "; - command += "--limit 1024G "; - - retval = vbm_popen(command, output, "network throttle (set default value)"); - if (retval) return retval; - } else { - sprintf(buf, "%d", kilobytes); - command = "bandwidthctl \"" + vm_name + "\" "; - command += "set \"" + vm_name + "_net\" "; - command += "--limit "; - command += buf; - command += "K "; - - retval = vbm_popen(command, output, "network throttle (set)"); - if (retval) return retval; - } - - } else { - - sprintf(buf, "%d", kilobytes); - command = "modifyvm \"" + vm_name + "\" "; - command += "--nicspeed1 "; - command += buf; - command += " "; - - retval = vbm_popen(command, output, "network throttle"); - if (retval) return retval; - - } - - return 0; -} - -int VBOX_VM::read_floppy(std::string& data) { +int VBOX_BASE::read_floppy(std::string& data) { if (enable_floppyio && pFloppy) { data = pFloppy->receive(); return 0; @@ -2643,684 +566,10 @@ int VBOX_VM::read_floppy(std::string& data) { return 1; } -int VBOX_VM::write_floppy(std::string& data) { +int VBOX_BASE::write_floppy(std::string& data) { if (enable_floppyio && pFloppy) { pFloppy->send(data); return 0; } return 1; } - -void VBOX_VM::lower_vm_process_priority() { - char buf[256]; -#ifdef _WIN32 - if (vm_pid_handle) { - SetPriorityClass(vm_pid_handle, BELOW_NORMAL_PRIORITY_CLASS); - fprintf( - stderr, - "%s Lowering VM Process priority.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#else - if (vm_pid) { - setpriority(PRIO_PROCESS, vm_pid, PROCESS_MEDIUM_PRIORITY); - fprintf( - stderr, - "%s Lowering VM Process priority.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#endif -} - -void VBOX_VM::reset_vm_process_priority() { - char buf[256]; -#ifdef _WIN32 - if (vm_pid_handle) { - SetPriorityClass(vm_pid_handle, NORMAL_PRIORITY_CLASS); - fprintf( - stderr, - "%s Restoring VM Process priority.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#else - if (vm_pid) { - setpriority(PRIO_PROCESS, vm_pid, PROCESS_NORMAL_PRIORITY); - fprintf( - stderr, - "%s Restoring VM Process priority.\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) - ); - } -#endif -} - -// Launch VboxSVC.exe before going any further. if we don't, it'll be launched by -// svchost.exe with its environment block which will not contain the reference -// to VBOX_USER_HOME which is required for running in the BOINC account-based -// sandbox on Windows. -int VBOX_VM::launch_vboxsvc() { - APP_INIT_DATA aid; - PROC_MAP pm; - PROCINFO p; - string command; - int retval = ERR_EXEC; - -#ifdef _WIN32 - char buf[256]; - STARTUPINFO si; - PROCESS_INFORMATION pi; - int pidVboxSvc = 0; - HANDLE hVboxSvc = NULL; - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - - boinc_get_init_data_p(&aid); - - if (aid.using_sandbox) { - - if (!vboxsvc_pid_handle || !process_exists(vboxsvc_pid_handle)) { - - if (vboxsvc_pid_handle) CloseHandle(vboxsvc_pid_handle); - - procinfo_setup(pm); - for (PROC_MAP::iterator i = pm.begin(); i != pm.end(); ++i) { - p = i->second; - - // We are only looking for vboxsvc - if (0 != stricmp(p.command, "vboxsvc.exe")) continue; - - // Store process id for later use - pidVboxSvc = p.id; - - // Is this the vboxsvc for the current user? - // Non-service install it would be the current username - // Service install it would be boinc_project - hVboxSvc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, p.id); - if (hVboxSvc) break; - } - - if (pidVboxSvc && hVboxSvc) { - - fprintf( - stderr, - "%s Status Report: Detected vboxsvc.exe. (PID = '%d')\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - pidVboxSvc - ); - vboxsvc_pid = pidVboxSvc; - vboxsvc_pid_handle = hVboxSvc; - retval = BOINC_SUCCESS; - - } else { - - si.cb = sizeof(STARTUPINFO); - si.dwFlags |= STARTF_FORCEOFFFEEDBACK | STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - - command = "\"VBoxSVC.exe\" --logrotate 1"; - - CreateProcess(NULL, (LPTSTR)command.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi); - - if (pi.hThread) CloseHandle(pi.hThread); - if (pi.hProcess) { - fprintf( - stderr, - "%s Status Report: Launching vboxsvc.exe. (PID = '%d')\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - pi.dwProcessId - ); - vboxsvc_pid = pi.dwProcessId; - vboxsvc_pid_handle = pi.hProcess; - retval = BOINC_SUCCESS; - } else { - fprintf( - stderr, - "%s Status Report: Launching vboxsvc.exe failed!.\n" - " Error: %s", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - windows_format_error_string(GetLastError(), buf, sizeof(buf)) - ); - } - - vbm_trace(command, std::string(""), retval); - } - } - } -#endif - - return retval; -} - -// Launch the VM. -int VBOX_VM::launch_vboxvm() { - char buf[256]; - char cmdline[1024]; - char* argv[5]; - int argc; - std::string output; - int retval = ERR_EXEC; - - // Construct the command line parameters - // - if (headless) { - argv[0] = const_cast("VboxHeadless.exe"); - } else { - argv[0] = const_cast("VirtualBox.exe"); - } - argv[1] = const_cast("--startvm"); - argv[2] = const_cast(vm_name.c_str()); - if (headless) { - argv[3] = const_cast("--vrde config"); - } else { - argv[3] = const_cast("--no-startvm-errormsgbox"); - } - argv[4] = NULL; - argc = 4; - - strcpy(cmdline, ""); - for (int i=0; i= 1000)) break; - - Sleep(250); - ulExitTimeout += 250; - } - - if (ulExitCode != STILL_ACTIVE) { - sanitize_output(output); - vboxwrapper_msg_prefix(buf, sizeof(buf)); - fprintf( - stderr, - "%s Status Report: Virtualbox.exe/Vboxheadless.exe exited prematurely!.\n" - "%s Exit Code: %d\n" - "%s Output:\n" - "%s\n", - buf, - buf, - ulExitCode, - buf, - output.c_str() - ); - } - - if (pi.hProcess && (ulExitCode == STILL_ACTIVE)) { - vm_pid = pi.dwProcessId; - vm_pid_handle = pi.hProcess; - retval = BOINC_SUCCESS; - } - -CLEANUP: - if (pi.hThread) CloseHandle(pi.hThread); - if (hReadPipe) CloseHandle(hReadPipe); - if (hWritePipe) CloseHandle(hWritePipe); - -#else - int pid = fork(); - if (-1 == pid) { - output = strerror(errno); - fprintf( - stderr, - "%s Status Report: Launching virtualbox.exe/vboxheadless.exe failed!.\n" - " Error: %s", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - output.c_str() - ); - retval = ERR_FORK; - } else if (0 == pid) { - if (-1 == execv(argv[0], argv)) { - _exit(errno); - } - } else { - vm_pid = pid; - retval = BOINC_SUCCESS; - } -#endif - - string cmd_line = cmdline; - vbm_trace(cmd_line, output, retval); - - return retval; -} - -void VBOX_VM::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 -} - -// If there are errors we can recover from, process them here. -// -int VBOX_VM::vbm_popen(string& command, string& output, const char* item, bool log_error, bool retry_failures, unsigned int timeout, bool log_trace) { - int retval = 0; - int retry_count = 0; - double sleep_interval = 1.0; - char buf[256]; - string retry_notes; - - // Initialize command line - command = "VBoxManage -q " + command; - - do { - retval = vbm_popen_raw(command, output, timeout); - sanitize_output(command); - sanitize_output(output); - - if (log_trace) { - vbm_trace(command, output, retval); - } - - if (retval) { - - // VirtualBox designed the concept of sessions to prevent multiple applications using - // the VirtualBox COM API (virtualbox.exe, vboxmanage.exe) from modifying the same VM - // at the same time. - // - // The problem here is that vboxwrapper uses vboxmanage.exe to modify and control the - // VM. Vboxmanage.exe can only maintain the session lock for as long as it takes it - // to run. So that means 99% of the time that a VM is running under BOINC technology - // it is running without a session lock. - // - // If a volunteer opens another VirtualBox management application and goes poking around - // that application can aquire the session lock and not give it up for some time. - // - // If we detect that condition retry the desired command. - // - // Experiments performed by jujube suggest changing the sleep interval to an exponential - // style backoff would increase our chances of success in situations where the previous - // lock is held by a previous instance of vboxmanage whos instance data hasn't been - // cleaned up within vboxsvc yet. - // - // 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; - } - } - - // VboxManage has to be able to communicate with vboxsvc in order to actually issue a - // command. In cases where we detect CO_E_SERVER_EXEC_FAILURE, we should just automatically - // try the command again. Vboxmanage wasn't even able to issue the desired command - // anyway. - // - // Experiments performed by jujube suggest changing the sleep interval to an exponential - // style backoff would increase our chances of success. - // - // Error Code: CO_E_SERVER_EXEC_FAILURE (0x80080005) - // - if (CO_E_SERVER_EXEC_FAILURE == (unsigned int)retval) { - if (retry_notes.find("Unable to communicate with VirtualBox") == string::npos) { - retry_notes += "Unable to communicate with VirtualBox. VirtualBox may need to\n"; - retry_notes += "be reinstalled.\n\n"; - } - if (retry_count) { - sleep_interval *= 2; - } - } - - // Retry? - if (!retry_failures && - (VBOX_E_INVALID_OBJECT_STATE != (unsigned int)retval) && - (CO_E_SERVER_EXEC_FAILURE != (unsigned int)retval) - ) { - break; - } - - // Timeout? - if (retry_count >= 5) break; - - retry_count++; - boinc_sleep(sleep_interval); - } - } - while (retval); - - // Add all relivent notes to the output string and log errors - // - if (retval && log_error) { - if (!retry_notes.empty()) { - output += "\nNotes:\n\n" + retry_notes; - } - - fprintf( - stderr, - "%s Error in %s for VM: %d\nCommand:\n%s\nOutput:\n%s\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - item, - retval, - command.c_str(), - output.c_str() - ); - } - - return retval; -} - -// Execute the vbox manage application and copy the output to the buffer. -// -int VBOX_VM::vbm_popen_raw(string& command, string& output, unsigned int timeout) { - char buf[256]; - size_t errcode_start; - size_t errcode_end; - string errcode; - int retval = BOINC_SUCCESS; - - // Launch vboxsvc in case it was shutdown for being idle - launch_vboxsvc(); - - // Reset output buffer - output.clear(); - -#ifdef _WIN32 - - STARTUPINFO si; - PROCESS_INFORMATION pi; - SECURITY_ATTRIBUTES sa; - SECURITY_DESCRIPTOR sd; - HANDLE hReadPipe = NULL, hWritePipe = NULL; - void* pBuf = NULL; - DWORD dwCount = 0; - unsigned long ulExitCode = 0; - unsigned long ulExitTimeout = 0; - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - memset(&sa, 0, sizeof(sa)); - memset(&sd, 0, sizeof(sd)); - - InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); - SetSecurityDescriptorDacl(&sd, true, NULL, false); - - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = &sd; - - if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, NULL)) { - fprintf( - stderr, - "%s CreatePipe failed! (%d).\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - GetLastError() - ); - goto CLEANUP; - } - SetHandleInformation(hReadPipe, HANDLE_FLAG_INHERIT, 0); - - si.cb = sizeof(STARTUPINFO); - si.dwFlags |= STARTF_FORCEOFFFEEDBACK | STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - si.wShowWindow = SW_HIDE; - si.hStdOutput = hWritePipe; - si.hStdError = hWritePipe; - si.hStdInput = NULL; - - // Execute command - if (!CreateProcess( - NULL, - (LPTSTR)command.c_str(), - NULL, - NULL, - TRUE, - CREATE_NO_WINDOW, - NULL, - NULL, - &si, - &pi - )) { - fprintf( - stderr, - "%s CreateProcess failed! (%d).\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - GetLastError() - ); - goto CLEANUP; - } - - // Wait until process has completed - while(1) { - if (timeout == 0) { - WaitForSingleObject(pi.hProcess, INFINITE); - } - - GetExitCodeProcess(pi.hProcess, &ulExitCode); - - // Copy stdout/stderr to output buffer, handle in the loop so that we can - // copy the pipe as it is populated and prevent the child process from blocking - // in case the output is bigger than pipe buffer. - PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &dwCount, NULL); - if (dwCount) { - pBuf = malloc(dwCount+1); - memset(pBuf, 0, dwCount+1); - - if (ReadFile(hReadPipe, pBuf, dwCount, &dwCount, NULL)) { - output += (char*)pBuf; - } - - free(pBuf); - } - - if (ulExitCode != STILL_ACTIVE) break; - - // Timeout? - if (ulExitTimeout >= (timeout * 1000)) { - if (!TerminateProcess(pi.hProcess, EXIT_FAILURE)) { - fprintf( - stderr, - "%s TerminateProcess failed! (%d).\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - GetLastError() - ); - } - ulExitCode = 0; - retval = ERR_TIMEOUT; - Sleep(1000); - } - - Sleep(250); - ulExitTimeout += 250; - } - -CLEANUP: - if (pi.hThread) CloseHandle(pi.hThread); - if (pi.hProcess) CloseHandle(pi.hProcess); - if (hReadPipe) CloseHandle(hReadPipe); - if (hWritePipe) CloseHandle(hWritePipe); - - if ((ulExitCode != 0) || (!pi.hProcess)) { - - // Determine the real error code by parsing the output - errcode_start = output.find("(0x"); - if (errcode_start != string::npos) { - errcode_start += 1; - errcode_end = output.find(")", errcode_start); - errcode = output.substr(errcode_start, errcode_end - errcode_start); - - sscanf(errcode.c_str(), "%x", &retval); - } - - // If something couldn't be found, just return ERR_FOPEN - if (!retval) retval = ERR_FOPEN; - - } - -#else - - FILE* fp; - - // redirect stderr to stdout for the child process so we can trap it with popen. - string modified_command = command + " 2>&1"; - - // Execute command - fp = popen(modified_command.c_str(), "r"); - if (fp == NULL){ - fprintf( - stderr, - "%s vbm_popen popen failed! errno = %d\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - errno - ); - retval = ERR_FOPEN; - } else { - // Copy output to buffer - while (fgets(buf, 256, fp)) { - output += buf; - } - - // Close stream - pclose(fp); - - // Determine the real error code by parsing the output - errcode_start = output.find("(0x"); - if (errcode_start != string::npos) { - errcode_start += 1; - errcode_end = output.find(")", errcode_start); - errcode = output.substr(errcode_start, errcode_end - errcode_start); - - sscanf(errcode.c_str(), "%x", &retval); - } - } - -#endif - - // Is this a RPC_S_SERVER_UNAVAILABLE returned by vboxmanage? - if (output.find("RPC_S_SERVER_UNAVAILABLE") != string::npos) { - retval = RPC_S_SERVER_UNAVAILABLE; - } - - return retval; -} - -void VBOX_VM::vbm_replay(std::string& command) { - FILE* f = fopen(REPLAYLOG_FILENAME, "a"); - if (f) { - fprintf(f, "%s\n", command.c_str()); - fclose(f); - } -} - -void VBOX_VM::vbm_trace(std::string& command, std::string& output, int retval) { - vbm_replay(command); - - char buf[256]; - FILE* f = fopen(TRACELOG_FILENAME, "a"); - if (f) { - fprintf( - f, - "%s\nCommand: %s\nExit Code: %d\nOutput:\n%s\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - command.c_str(), - retval, - output.c_str() - ); - fclose(f); - } -} - diff --git a/samples/vboxwrapper/vbox.h b/samples/vboxwrapper/vbox.h index 407ca534dc..365cadd352 100644 --- a/samples/vboxwrapper/vbox.h +++ b/samples/vboxwrapper/vbox.h @@ -74,21 +74,19 @@ struct PORT_FORWARD { int host_port; // 0 means assign dynamically int guest_port; bool is_remote; - bool web_application; PORT_FORWARD() { host_port = 0; guest_port = 0; is_remote = false; - web_application = false; } + int get_host_port(); // assign host port }; -// represents a VirtualBox VM -class VBOX_VM { +class VBOX_BASE { public: - VBOX_VM(); - ~VBOX_VM(); + VBOX_BASE(); + ~VBOX_BASE(); std::string virtualbox_home_directory; std::string virtualbox_install_directory; @@ -167,8 +165,6 @@ public: // whether to use floppy io infrastructure bool enable_remotedesktop; // whether to enable remote desktop functionality - bool enable_gbac; - // whether to enable GBAC functionality double job_duration; // maximum amount of wall-clock time this VM is allowed to run before // considering itself done. @@ -189,58 +185,35 @@ public: std::string completion_trigger_file; // if find this file in shared/, task is over. // File can optionally contain exit code (first line) - // File can optionally contain is_notice bool (second line) - // and stderr text (subsequent lines). - // Addresses a problem where VM doesn't shut down properly - std::string temporary_exit_trigger_file; - // if find this file in shared/, task is restarted at a later date. - // File can optionally contain restart delay (first line) - // File can optionally contain is_notice bool (second line) // and stderr text (subsequent lines). // Addresses a problem where VM doesn't shut down properly /////////// END VBOX_JOB.XML ITEMS ////////////// - 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(); - void poll(bool log_state = true); - - int create_vm(); - int register_vm(); - int deregister_vm(bool delete_media); - int deregister_stale_vm(); + 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(); int run(bool do_restore_snapshot); void cleanup(); - 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(); - void delete_temporary_exit_trigger_file(); + void check_trickle_triggers(); + void check_intermediate_uploads(); int is_registered(); bool is_system_ready(std::string& message); @@ -253,7 +226,6 @@ public: 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); @@ -282,9 +254,6 @@ public: void lower_vm_process_priority(); void reset_vm_process_priority(); - int launch_vboxsvc(); - int launch_vboxvm(); - void sanitize_output(std::string& output); #ifndef _WIN32 diff --git a/samples/vboxwrapper/vboxwrapper.cpp b/samples/vboxwrapper/vboxwrapper.cpp index 90418cd78c..a47ac18277 100644 --- a/samples/vboxwrapper/vboxwrapper.cpp +++ b/samples/vboxwrapper/vboxwrapper.cpp @@ -48,6 +48,9 @@ #ifdef _WIN32 #include "boinc_win.h" #include "win_util.h" +#include "atlcomcli.h" +#include "atlstr.h" +#include "mscom/VirtualBox.h" #else #include #include @@ -73,6 +76,12 @@ #include "vboxwrapper.h" #include "vbox.h" +#ifdef _WIN32 +#include "vbox_win.h" +#else +#include "vbox_unix.h" +#endif + using std::vector; using std::string; @@ -126,38 +135,46 @@ char* vboxwrapper_msg_prefix(char* sbuf, int len) { return sbuf; } -int parse_port_forward(XML_PARSER& xp, VBOX_VM& vm) { +int parse_port_forward(VBOX_VM& vm, XML_PARSER& xp) { + char buf2[256]; int host_port=0, guest_port=0, nports=1; - bool is_remote = false, web_application = false; - char buf[256]; + bool is_remote; while (!xp.get_tag()) { if (xp.match_tag("/port_forward")) { - if (!guest_port) { - fprintf(stderr, "%s parse_port_forward(): unspecified guest port\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)) + if (!host_port) { + fprintf(stderr, + "%s parse_port_forward(): unspecified host port\n", + vboxwrapper_msg_prefix(buf2, sizeof(buf2)) ); + return ERR_XML_PARSE; + } + if (!guest_port) { + fprintf(stderr, + "%s parse_port_forward(): unspecified guest port\n", + vboxwrapper_msg_prefix(buf2, sizeof(buf2)) + ); + return ERR_XML_PARSE; } PORT_FORWARD pf; pf.host_port = host_port; pf.guest_port = guest_port; pf.is_remote = is_remote; - pf.web_application = web_application; for (int i=0; iApplication false MultiByte + Static Application false MultiByte + Static Application false MultiByte + Static Application false MultiByte + Static @@ -89,10 +93,6 @@ AllRules.ruleset - vboxwrapper_26108_windows_intelx86 - vboxwrapper_26110_windows_intelx86 - vboxwrapper_26108_windows_x86_64 - vboxwrapper_26110_windows_x86_64 @@ -132,13 +132,13 @@ ..\..\boinc_depends_win_vs2010\wxwidgets\include;..;%(AdditionalIncludeDirectories) - libcmt.lib;libcpmt.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;wsock32.lib;psapi.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\$(TargetFileName) + 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 true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\$(TargetName).pdb + .\Build\$(Platform)\$(Configuration)\vboxwrapper_26108_windows_intelx86.pdb Windows MachineX86 @@ -182,13 +182,13 @@ ..\..\boinc_depends_win_vs2010\wxwidgets\include;..;%(AdditionalIncludeDirectories) - libcmt.lib;libcpmt.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;wsock32.lib;psapi.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\$(TargetFileName) + 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 true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\$(TargetName).pdb + .\Build\$(Platform)\$(Configuration)\vboxwrapper_26108_windows_x86_64.pdb Windows MachineX64 @@ -228,13 +228,13 @@ ..\..\boinc_depends_win_vs2010\wxwidgets\include;..;%(AdditionalIncludeDirectories) - libcmtd.lib;libcpmtd.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;psapi.lib;wsock32.lib;psapi.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\$(TargetFileName) + 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 true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\$(TargetName).pdb + .\Build\$(Platform)\$(Configuration)\vboxwrapper_6.1_windows_intelx86.pdb Windows MachineX86 @@ -274,13 +274,13 @@ ..\..\boinc_depends_win_vs2010\wxwidgets\include;..;%(AdditionalIncludeDirectories) - libcmtd.lib;libcpmtd.lib;kernel32.lib;user32.lib;gdi32.lib;ole32.lib;wsock32.lib;psapi.lib;%(AdditionalDependencies) - .\Build\$(Platform)\$(Configuration)\$(TargetFileName) + 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 true true %(DelayLoadDLLs) true - .\Build\$(Platform)\$(Configuration)\$(TargetName).pdb + .\Build\$(Platform)\$(Configuration)\vboxwrapper_26063_windows_x86_64.pdb Windows MachineX64 @@ -298,6 +298,7 @@ +