mirror of https://github.com/BOINC/boinc.git
805 lines
22 KiB
C++
805 lines
22 KiB
C++
// This file is part of BOINC.
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2010 University of California
|
|
//
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// BOINC is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#ifdef _WIN32
|
|
#include "boinc_win.h"
|
|
#include "win_util.h"
|
|
#else
|
|
#include <sys/wait.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
using std::string;
|
|
|
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
|
#define popen _popen
|
|
#define pclose _pclose
|
|
#define getcwd _getcwd
|
|
#define putenv _putenv
|
|
#endif
|
|
|
|
#include "diagnostics.h"
|
|
#include "filesys.h"
|
|
#include "parse.h"
|
|
#include "str_util.h"
|
|
#include "str_replace.h"
|
|
#include "util.h"
|
|
#include "error_numbers.h"
|
|
#include "procinfo.h"
|
|
#include "boinc_api.h"
|
|
#include "vbox.h"
|
|
#include "vm.h"
|
|
|
|
|
|
// Execute the vbox manage application and copy the output to the
|
|
// designated buffer.
|
|
//
|
|
int virtualbox_vbm_popen(string& arguments, string& output) {
|
|
char buf[256];
|
|
string command;
|
|
|
|
// Initialize command line
|
|
command = "VBoxManage -q " + arguments;
|
|
|
|
#ifdef _WIN32
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
SECURITY_ATTRIBUTES sa;
|
|
SECURITY_DESCRIPTOR sd;
|
|
HANDLE hReadPipe, hWritePipe;
|
|
void* pBuf;
|
|
DWORD dwCount;
|
|
unsigned long ulExitCode = 0;
|
|
int retval = VBOX_POPEN_ERROR;
|
|
|
|
|
|
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, 0)) {
|
|
fprintf(
|
|
stderr,
|
|
"%s CreatePipe failed! (%d).\n",
|
|
boinc_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",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
GetLastError()
|
|
);
|
|
goto CLEANUP;
|
|
}
|
|
|
|
|
|
// Wait until process has completed
|
|
while(1) {
|
|
GetExitCodeProcess(pi.hProcess, &ulExitCode);
|
|
if (ulExitCode != STILL_ACTIVE) break;
|
|
}
|
|
|
|
|
|
// Copy stdout/stderr to output buffer
|
|
if (!PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &dwCount, NULL)) {
|
|
fprintf(
|
|
stderr,
|
|
"%s PeekNamedPipe failed! (%d).\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
if (dwCount) {
|
|
pBuf = malloc(dwCount+1);
|
|
memset(pBuf, 0, dwCount+1);
|
|
|
|
if (ReadFile(hReadPipe, pBuf, dwCount, &dwCount, NULL)) {
|
|
output += (char*)pBuf;
|
|
}
|
|
|
|
free(pBuf);
|
|
}
|
|
|
|
|
|
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)) {
|
|
retval = VBOX_SUCCESS;
|
|
}
|
|
|
|
return retval;
|
|
|
|
#else
|
|
FILE* fp;
|
|
|
|
// Execute command
|
|
fp = popen(command.c_str(), "r");
|
|
if (fp == NULL){
|
|
fprintf(
|
|
stderr,
|
|
"%s vbm_popen popen failed! errno = %d\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
errno
|
|
);
|
|
return VBOX_POPEN_ERROR;
|
|
}
|
|
|
|
// Copy output to buffer
|
|
while (fgets(buf, 256, fp)) {
|
|
output += buf;
|
|
}
|
|
|
|
// Close stream
|
|
pclose(fp);
|
|
|
|
#endif
|
|
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
// Returns the current directory in which the executable resides.
|
|
//
|
|
int virtualbox_generate_vm_root_dir( string& dir ) {
|
|
char root_dir[256];
|
|
|
|
getcwd(root_dir, (sizeof(root_dir)*sizeof(char)));
|
|
dir = root_dir;
|
|
|
|
if (!dir.empty()) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Generate a unique virtual machine name for a given task instance
|
|
// Rules:
|
|
// 1. Must be unique
|
|
// 2. Must identifity itself as being part of BOINC
|
|
// 3. Must be file system compatible
|
|
//
|
|
int virtualbox_generate_vm_name( string& name ) {
|
|
APP_INIT_DATA aid;
|
|
boinc_get_init_data_p( &aid );
|
|
|
|
name.empty();
|
|
name = "boinc_";
|
|
|
|
if (boinc_is_standalone()) {
|
|
name += "standalone";
|
|
} else {
|
|
name += aid.wu_name;
|
|
}
|
|
|
|
if (!name.empty()) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool virtualbox_vm_is_registered() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_name;
|
|
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
command = "showvminfo " + virtual_machine_name;
|
|
|
|
if (VBOX_SUCCESS == virtualbox_vbm_popen(command, output)) {
|
|
if (output.find("VBOX_E_OBJECT_NOT_FOUND") != string::npos) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool virtualbox_vm_is_hdd_registered() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_root_dir;
|
|
|
|
virtualbox_generate_vm_root_dir(virtual_machine_root_dir);
|
|
|
|
command = "showhdinfo \"" + virtual_machine_root_dir + "/" + vm.image_filename + "\" ";
|
|
|
|
if (VBOX_SUCCESS == virtualbox_vbm_popen(command, output)) {
|
|
if (output.find("VBOX_E_FILE_ERROR") != string::npos) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool virtualbox_vm_is_running() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_name;
|
|
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
command = "list runningvms";
|
|
|
|
if (VBOX_SUCCESS == virtualbox_vbm_popen(command, output)) {
|
|
if (output.find(virtual_machine_name) != string::npos) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int virtualbox_get_install_directory( string& virtualbox_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
|
|
);
|
|
|
|
virtualbox_install_directory = lpszRegistryValue;
|
|
}
|
|
}
|
|
|
|
if (hkSetupHive) RegCloseKey(hkSetupHive);
|
|
if (lpszRegistryValue) free(lpszRegistryValue);
|
|
#endif
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_initialize() {
|
|
string virtualbox_install_directory;
|
|
string old_path;
|
|
string new_path;
|
|
char buf[256];
|
|
|
|
virtualbox_get_install_directory(virtualbox_install_directory);
|
|
|
|
// Prep the environment so we can execute the vboxmanage application
|
|
if (!virtualbox_install_directory.empty()) {
|
|
old_path = getenv("path");
|
|
|
|
new_path = "path=";
|
|
|
|
new_path += virtualbox_install_directory;
|
|
|
|
// Path environment variable seperator
|
|
#ifdef _WIN32
|
|
new_path += ";";
|
|
#else
|
|
new_path += ":";
|
|
#endif
|
|
|
|
new_path += old_path;
|
|
|
|
if (putenv((char*)new_path.c_str())) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Failed to modify the search path.\n",
|
|
boinc_msg_prefix(buf, sizeof(buf))
|
|
);
|
|
}
|
|
}
|
|
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_register_vm() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_name;
|
|
string virtual_machine_root_dir;
|
|
char buf[256];
|
|
int retval;
|
|
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
virtualbox_generate_vm_root_dir(virtual_machine_root_dir);
|
|
|
|
fprintf(
|
|
stderr,
|
|
"%s Registering virtual machine. (%s) \n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
virtual_machine_name.c_str()
|
|
);
|
|
|
|
|
|
// Create and register the VM
|
|
//
|
|
command = "createvm ";
|
|
command += "--name \"" + virtual_machine_name + "\" ";
|
|
command += "--basefolder \"" + virtual_machine_root_dir + "\" ";
|
|
command += "--ostype \"" + vm.os_name + "\" ";
|
|
command += "--register";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error registering virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
|
|
// Tweak the VM from it's default configuration
|
|
//
|
|
command = "modifyvm \"" + virtual_machine_name + "\" ";
|
|
command += "--memory " + vm.memory_size_mb + " ";
|
|
command += "--acpi on ";
|
|
command += "--ioapic on ";
|
|
command += "--boot1 disk ";
|
|
command += "--boot2 none ";
|
|
command += "--boot3 none ";
|
|
command += "--boot4 none ";
|
|
command += "--nic1 nat ";
|
|
command += "--natdnsproxy1 on ";
|
|
command += "--cableconnected1 off ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error modifing virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
|
|
// Add storage controller to VM
|
|
//
|
|
command = "storagectl \"" + virtual_machine_name + "\" ";
|
|
command += "--name \"IDE Controller\" ";
|
|
command += "--add ide ";
|
|
command += "--controller PIIX4 ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error adding storage controller to virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
|
|
// Adding virtual hard drive to VM
|
|
//
|
|
command = "storageattach \"" + virtual_machine_name + "\" ";
|
|
command += "--storagectl \"IDE Controller\" ";
|
|
command += "--port 0 ";
|
|
command += "--device 0 ";
|
|
command += "--type hdd ";
|
|
command += "--medium \"" + virtual_machine_root_dir + "/" + vm.image_filename + "\" ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error adding virtual disk drive to virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
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 itself is NOT signed. Doing so opens up
|
|
// the network behind the firewall to attack.
|
|
//
|
|
if (vm.enable_network) {
|
|
command = "modifyvm \"" + virtual_machine_name + "\" ";
|
|
command += "--cableconnected1 on ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error enabling network access for virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
// Enable the shared folder if a shared folder is specified.
|
|
//
|
|
if (vm.enable_shared_directory) {
|
|
command = "sharedfolder add \"" + virtual_machine_name + "\" ";
|
|
command += "--name \"shared\" ";
|
|
command += "--hostpath \"" + virtual_machine_root_dir + "/shared\"";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error enabling shared directory for virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_deregister_vm_by_name( string& virtual_machine_name ) {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_root_dir;
|
|
char buf[256];
|
|
int retval;
|
|
|
|
virtualbox_generate_vm_root_dir(virtual_machine_root_dir);
|
|
|
|
fprintf(
|
|
stderr,
|
|
"%s Deregistering virtual machine. (%s)\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
virtual_machine_name.c_str()
|
|
);
|
|
|
|
|
|
// First step in deregistering a VM is to delete its storage controller
|
|
//
|
|
command = "storagectl \"" + virtual_machine_name + "\" ";
|
|
command += "--name \"IDE Controller\" ";
|
|
command += "--remove ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error removing storage controller from virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
|
|
// Next delete VM
|
|
//
|
|
command = "unregistervm \"" + virtual_machine_name + "\" ";
|
|
command += "--delete ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error removing virtual machine from virtual box! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
|
|
// Lastly delete medium from Virtual Box Media Registry
|
|
//
|
|
command = "closemedium disk \"" + virtual_machine_root_dir + "/" + vm.image_filename + "\" ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error removing virtual hdd from virtual box! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_deregister_stale_vm() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_root_dir;
|
|
string virtual_machine_name;
|
|
size_t uuid_location;
|
|
size_t uuid_length;
|
|
char buf[256];
|
|
int retval;
|
|
|
|
virtualbox_generate_vm_root_dir(virtual_machine_root_dir);
|
|
|
|
// We need to determine what the name or uuid is of the previous VM which owns
|
|
// this virtual disk
|
|
//
|
|
command = "showhdinfo \"" + virtual_machine_root_dir + "/" + vm.image_filename + "\" ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error retrieving virtual hard disk information from virtual box! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
|
|
// Output should look a little like this:
|
|
// UUID: c119acaf-636c-41f6-86c9-38e639a31339
|
|
// Accessible: yes
|
|
// Logical size: 10240 MBytes
|
|
// Current size on disk: 0 MBytes
|
|
// Type: normal (base)
|
|
// Storage format: VDI
|
|
// Format variant: dynamic default
|
|
// In use by VMs: test2 (UUID: 000ab2be-1254-4c6a-9fdc-1536a478f601)
|
|
// Location: C:\Users\romw\VirtualBox VMs\test2\test2.vdi
|
|
//
|
|
uuid_location = output.find("(UUID: ");
|
|
if (uuid_location != string::npos) {
|
|
// We can parse the virtual machine ID from the output
|
|
|
|
uuid_location += 7;
|
|
uuid_length = output.find(")", uuid_location);
|
|
|
|
virtual_machine_name = output.substr(uuid_location, uuid_length);
|
|
|
|
// Deregister stale VM by UUID
|
|
return virtualbox_deregister_vm_by_name(virtual_machine_name);
|
|
} else {
|
|
// Did the user delete the VM in VirtualBox and not the medium? If so,
|
|
// just remove the medium.
|
|
command = "closemedium \"" + virtual_machine_root_dir + "/" + vm.image_filename + "\" ";
|
|
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error removing virtual hdd from virtual box! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_deregister_vm() {
|
|
string virtual_machine_name;
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
return virtualbox_deregister_vm_by_name(virtual_machine_name);
|
|
}
|
|
|
|
|
|
int virtualbox_cleanup() {
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_startvm() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_name;
|
|
char buf[256];
|
|
int retval;
|
|
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
command = "startvm \"" + virtual_machine_name + "\" --type headless";
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error starting virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_stopvm() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_name;
|
|
char buf[256];
|
|
int retval;
|
|
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
command = "controlvm \"" + virtual_machine_name + "\" savestate";
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error stopping virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_pausevm() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_name;
|
|
char buf[256];
|
|
int retval;
|
|
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
command = "controlvm \"" + virtual_machine_name + "\" pause";
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error pausing virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_resumevm() {
|
|
string command;
|
|
string output;
|
|
string virtual_machine_name;
|
|
char buf[256];
|
|
int retval;
|
|
|
|
virtualbox_generate_vm_name(virtual_machine_name);
|
|
command = "controlvm \"" + virtual_machine_name + "\" resume";
|
|
retval = virtualbox_vbm_popen(command, output);
|
|
if (retval) {
|
|
fprintf(
|
|
stderr,
|
|
"%s Error resuming virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n",
|
|
boinc_msg_prefix(buf, sizeof(buf)),
|
|
retval,
|
|
command.c_str(),
|
|
output.c_str()
|
|
);
|
|
return retval;
|
|
}
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|
|
|
|
int virtualbox_monitor() {
|
|
return VBOX_SUCCESS;
|
|
}
|
|
|