| 1 |
// This file is part of BOINC. |
|---|
| 2 |
// http://boinc.berkeley.edu |
|---|
| 3 |
// Copyright (C) 2008 University of California |
|---|
| 4 |
// |
|---|
| 5 |
// BOINC is free software; you can redistribute it and/or modify it |
|---|
| 6 |
// under the terms of the GNU Lesser General Public License |
|---|
| 7 |
// as published by the Free Software Foundation, |
|---|
| 8 |
// either version 3 of the License, or (at your option) any later version. |
|---|
| 9 |
// |
|---|
| 10 |
// BOINC is distributed in the hope that it will be useful, |
|---|
| 11 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|---|
| 13 |
// See the GNU Lesser General Public License for more details. |
|---|
| 14 |
// |
|---|
| 15 |
// You should have received a copy of the GNU Lesser General Public |
|---|
| 16 |
// License |
|---|
| 17 |
// along with BOINC. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 18 |
|
|---|
| 19 |
// vmwrapper.C |
|---|
| 20 |
// VMWare wrapper program - lets you use BOINC to drive a VMWare Server |
|---|
| 21 |
// guest OS |
|---|
| 22 |
|
|---|
| 23 |
#include <stdio.h> |
|---|
| 24 |
#include <vector> |
|---|
| 25 |
#include <string> |
|---|
| 26 |
#ifdef _WIN32 |
|---|
| 27 |
#include "boinc_win.h" |
|---|
| 28 |
#include "win_util.h" |
|---|
| 29 |
#else |
|---|
| 30 |
#include <sys/wait.h> |
|---|
| 31 |
#include <sys/types.h> |
|---|
| 32 |
#include <sys/stat.h> |
|---|
| 33 |
#include <unistd.h> |
|---|
| 34 |
#include "procinfo.h" |
|---|
| 35 |
#endif |
|---|
| 36 |
|
|---|
| 37 |
#include "boinc_api.h" |
|---|
| 38 |
#include "diagnostics.h" |
|---|
| 39 |
#include "filesys.h" |
|---|
| 40 |
#include "parse.h" |
|---|
| 41 |
#include "str_util.h" |
|---|
| 42 |
#include "util.h" |
|---|
| 43 |
#include "error_numbers.h" |
|---|
| 44 |
|
|---|
| 45 |
#include "vmware-vix/vix.h" |
|---|
| 46 |
|
|---|
| 47 |
#define JOB_FILENAME "job.xml" |
|---|
| 48 |
#define CHECKPOINT_FILENAME "checkpoint.txt" |
|---|
| 49 |
|
|---|
| 50 |
#define POLL_PERIOD 1.0 |
|---|
| 51 |
|
|---|
| 52 |
using std::vector; |
|---|
| 53 |
using std::string; |
|---|
| 54 |
|
|---|
| 55 |
struct TASK |
|---|
| 56 |
{ |
|---|
| 57 |
string application; |
|---|
| 58 |
string stdin_filename; |
|---|
| 59 |
string stdout_filename; |
|---|
| 60 |
string stderr_filename; |
|---|
| 61 |
|
|---|
| 62 |
string vm; |
|---|
| 63 |
string innerjob; |
|---|
| 64 |
string datadir; |
|---|
| 65 |
string partial_credit; |
|---|
| 66 |
string snapshots; |
|---|
| 67 |
string user; |
|---|
| 68 |
string password; |
|---|
| 69 |
|
|---|
| 70 |
vector < string > data; |
|---|
| 71 |
vector < string > output; |
|---|
| 72 |
|
|---|
| 73 |
string checkpoint_filename; |
|---|
| 74 |
// name of task's checkpoint file, if any |
|---|
| 75 |
double checkpoint_cpu_time; |
|---|
| 76 |
// CPU time at last checkpoint |
|---|
| 77 |
string command_line; |
|---|
| 78 |
double weight; |
|---|
| 79 |
// contribution of this task to overall fraction done |
|---|
| 80 |
double final_cpu_time; |
|---|
| 81 |
double starting_cpu; |
|---|
| 82 |
// how much CPU time was used by tasks before this in the job file |
|---|
| 83 |
bool suspended; |
|---|
| 84 |
double wall_cpu_time; |
|---|
| 85 |
// for estimating CPU time on Win98/ME and Mac |
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 |
#ifdef _WIN32 |
|---|
| 89 |
|
|---|
| 90 |
HANDLE pid_handle; |
|---|
| 91 |
DWORD pid; |
|---|
| 92 |
HANDLE thread_handle; |
|---|
| 93 |
struct _stat last_stat; // mod time of checkpoint file |
|---|
| 94 |
|
|---|
| 95 |
#else |
|---|
| 96 |
|
|---|
| 97 |
int pid; |
|---|
| 98 |
struct stat last_stat; |
|---|
| 99 |
|
|---|
| 100 |
#endif |
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 |
bool stat_first; |
|---|
| 104 |
int parse (XML_PARSER &); |
|---|
| 105 |
bool poll (int &status); |
|---|
| 106 |
int run (int argc, char **argv); |
|---|
| 107 |
void kill (); |
|---|
| 108 |
void stop (); |
|---|
| 109 |
void resume (); |
|---|
| 110 |
double cpu_time (); |
|---|
| 111 |
|
|---|
| 112 |
inline bool has_checkpointed () |
|---|
| 113 |
{ |
|---|
| 114 |
bool changed = false; |
|---|
| 115 |
|
|---|
| 116 |
if (checkpoint_filename.size () == 0) |
|---|
| 117 |
return false; |
|---|
| 118 |
|
|---|
| 119 |
struct stat new_stat; |
|---|
| 120 |
|
|---|
| 121 |
int retval = stat (checkpoint_filename.c_str (), &new_stat); |
|---|
| 122 |
|
|---|
| 123 |
if (retval) |
|---|
| 124 |
return false; |
|---|
| 125 |
|
|---|
| 126 |
if (!stat_first && new_stat.st_mtime != last_stat.st_mtime) |
|---|
| 127 |
{ |
|---|
| 128 |
changed = true; |
|---|
| 129 |
} |
|---|
| 130 |
|
|---|
| 131 |
stat_first = false; |
|---|
| 132 |
|
|---|
| 133 |
last_stat.st_mtime = new_stat.st_mtime; |
|---|
| 134 |
return changed; |
|---|
| 135 |
} |
|---|
| 136 |
}; |
|---|
| 137 |
|
|---|
| 138 |
vector < TASK > tasks; |
|---|
| 139 |
APP_INIT_DATA aid; |
|---|
| 140 |
bool graphics = false; |
|---|
| 141 |
|
|---|
| 142 |
int TASK::parse (XML_PARSER & xp) |
|---|
| 143 |
{ |
|---|
| 144 |
|
|---|
| 145 |
string this_data, this_output; |
|---|
| 146 |
char tag[1024], buf[8192], buf2[8192]; |
|---|
| 147 |
|
|---|
| 148 |
bool is_tag; |
|---|
| 149 |
|
|---|
| 150 |
weight = 1; |
|---|
| 151 |
final_cpu_time = 0; |
|---|
| 152 |
stat_first = true; |
|---|
| 153 |
while (!xp.get (tag, sizeof (tag), is_tag)) |
|---|
| 154 |
{ |
|---|
| 155 |
if (!is_tag) |
|---|
| 156 |
{ |
|---|
| 157 |
fprintf (stderr, "SCHED_CONFIG::parse(): unexpected text %s\n", |
|---|
| 158 |
tag); |
|---|
| 159 |
continue; |
|---|
| 160 |
} |
|---|
| 161 |
if (!strcmp (tag, "/task")) |
|---|
| 162 |
{ |
|---|
| 163 |
return 0; |
|---|
| 164 |
} |
|---|
| 165 |
else if (xp.parse_string (tag, "application", application)) |
|---|
| 166 |
continue; |
|---|
| 167 |
|
|---|
| 168 |
else if (xp.parse_string (tag, "innerjob", innerjob)) |
|---|
| 169 |
continue; |
|---|
| 170 |
else if (xp.parse_string (tag, "vm", vm)) |
|---|
| 171 |
continue; |
|---|
| 172 |
else if (xp.parse_string (tag, "datadir", datadir)) |
|---|
| 173 |
continue; |
|---|
| 174 |
else if (xp.parse_string (tag, "partial_credit", partial_credit)) |
|---|
| 175 |
continue; |
|---|
| 176 |
else if (xp.parse_string (tag, "snapshots", snapshots)) |
|---|
| 177 |
continue; |
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 |
else if (xp.parse_string (tag, "data", this_data)) { |
|---|
| 181 |
data.push_back(this_data); |
|---|
| 182 |
continue; |
|---|
| 183 |
} |
|---|
| 184 |
|
|---|
| 185 |
else if (xp.parse_string (tag, "output", this_output)) { |
|---|
| 186 |
output.push_back(this_output); |
|---|
| 187 |
continue; |
|---|
| 188 |
} |
|---|
| 189 |
|
|---|
| 190 |
else if (xp.parse_string (tag, "user", user)) |
|---|
| 191 |
continue; |
|---|
| 192 |
else if (xp.parse_string (tag, "password", password)) |
|---|
| 193 |
continue; |
|---|
| 194 |
|
|---|
| 195 |
else if (xp.parse_string (tag, "stdin_filename", stdin_filename)) |
|---|
| 196 |
continue; |
|---|
| 197 |
else if (xp.parse_string (tag, "stdout_filename", stdout_filename)) |
|---|
| 198 |
continue; |
|---|
| 199 |
else if (xp.parse_string (tag, "stderr_filename", stderr_filename)) |
|---|
| 200 |
continue; |
|---|
| 201 |
else if (xp.parse_str (tag, "command_line", buf, sizeof (buf))) |
|---|
| 202 |
{ |
|---|
| 203 |
while (1) |
|---|
| 204 |
{ |
|---|
| 205 |
char *p = strstr (buf, "$PROJECT_DIR"); |
|---|
| 206 |
|
|---|
| 207 |
if (!p) |
|---|
| 208 |
break; |
|---|
| 209 |
strcpy (buf2, p + strlen ("$PROJECT_DIR")); |
|---|
| 210 |
strcpy (p, aid.project_dir); |
|---|
| 211 |
strcat (p, buf2); |
|---|
| 212 |
} |
|---|
| 213 |
command_line = buf; |
|---|
| 214 |
continue; |
|---|
| 215 |
} |
|---|
| 216 |
else if (xp. |
|---|
| 217 |
parse_string (tag, "checkpoint_filename", |
|---|
| 218 |
checkpoint_filename)) |
|---|
| 219 |
continue; |
|---|
| 220 |
else if (xp.parse_double (tag, "weight", weight)) |
|---|
| 221 |
continue; |
|---|
| 222 |
} |
|---|
| 223 |
return ERR_XML_PARSE; |
|---|
| 224 |
} |
|---|
| 225 |
|
|---|
| 226 |
|
|---|
| 227 |
int parse_job_file () |
|---|
| 228 |
{ |
|---|
| 229 |
MIOFILE mf; |
|---|
| 230 |
char tag[1024], buf[256]; |
|---|
| 231 |
|
|---|
| 232 |
bool is_tag; |
|---|
| 233 |
|
|---|
| 234 |
boinc_resolve_filename (JOB_FILENAME, buf, 1024); |
|---|
| 235 |
FILE *f = boinc_fopen (buf, "r"); |
|---|
| 236 |
|
|---|
| 237 |
if (!f) |
|---|
| 238 |
{ |
|---|
| 239 |
fprintf (stderr, "can't open job file %s\n", buf); |
|---|
| 240 |
return ERR_FOPEN; |
|---|
| 241 |
} |
|---|
| 242 |
mf.init_file (f); |
|---|
| 243 |
XML_PARSER xp (&mf); |
|---|
| 244 |
|
|---|
| 245 |
if (!xp.parse_start ("job_desc")) |
|---|
| 246 |
return ERR_XML_PARSE; |
|---|
| 247 |
while (!xp.get (tag, sizeof (tag), is_tag)) |
|---|
| 248 |
{ |
|---|
| 249 |
if (!is_tag) |
|---|
| 250 |
{ |
|---|
| 251 |
fprintf (stderr, "SCHED_CONFIG::parse(): unexpected text %s\n", |
|---|
| 252 |
tag); |
|---|
| 253 |
continue; |
|---|
| 254 |
} |
|---|
| 255 |
if (!strcmp (tag, "/job_desc")) |
|---|
| 256 |
{ |
|---|
| 257 |
fclose (f); |
|---|
| 258 |
return 0; |
|---|
| 259 |
} |
|---|
| 260 |
if (!strcmp (tag, "task")) |
|---|
| 261 |
{ |
|---|
| 262 |
TASK task; |
|---|
| 263 |
int retval = task.parse (xp); |
|---|
| 264 |
|
|---|
| 265 |
if (!retval) |
|---|
| 266 |
{ |
|---|
| 267 |
tasks.push_back (task); |
|---|
| 268 |
} |
|---|
| 269 |
} |
|---|
| 270 |
} |
|---|
| 271 |
fclose (f); |
|---|
| 272 |
return ERR_XML_PARSE; |
|---|
| 273 |
} |
|---|
| 274 |
|
|---|
| 275 |
|
|---|
| 276 |
#ifdef _WIN32 |
|---|
| 277 |
// CreateProcess() takes HANDLEs for the stdin/stdout. |
|---|
| 278 |
// We need to use CreateFile() to get them. Ugh. |
|---|
| 279 |
// |
|---|
| 280 |
HANDLE |
|---|
| 281 |
win_fopen (const char *path, const char *mode) |
|---|
| 282 |
{ |
|---|
| 283 |
SECURITY_ATTRIBUTES sa; |
|---|
| 284 |
memset (&sa, 0, sizeof (sa)); |
|---|
| 285 |
sa.nLength = sizeof (sa); |
|---|
| 286 |
sa.bInheritHandle = TRUE; |
|---|
| 287 |
|
|---|
| 288 |
if (!strcmp (mode, "r")) |
|---|
| 289 |
{ |
|---|
| 290 |
return CreateFile (path, |
|---|
| 291 |
GENERIC_READ, |
|---|
| 292 |
FILE_SHARE_READ, &sa, OPEN_EXISTING, 0, 0); |
|---|
| 293 |
} |
|---|
| 294 |
else if (!strcmp (mode, "w")) |
|---|
| 295 |
{ |
|---|
| 296 |
return CreateFile (path, |
|---|
| 297 |
GENERIC_WRITE, |
|---|
| 298 |
FILE_SHARE_WRITE, &sa, OPEN_ALWAYS, 0, 0); |
|---|
| 299 |
} |
|---|
| 300 |
else if (!strcmp (mode, "a")) |
|---|
| 301 |
{ |
|---|
| 302 |
HANDLE |
|---|
| 303 |
hAppend = CreateFile (path, |
|---|
| 304 |
GENERIC_WRITE, |
|---|
| 305 |
FILE_SHARE_WRITE, &sa, OPEN_ALWAYS, 0, 0); |
|---|
| 306 |
SetFilePointer (hAppend, 0, NULL, FILE_END); |
|---|
| 307 |
return hAppend; |
|---|
| 308 |
} |
|---|
| 309 |
else |
|---|
| 310 |
{ |
|---|
| 311 |
return 0; |
|---|
| 312 |
} |
|---|
| 313 |
} |
|---|
| 314 |
#endif |
|---|
| 315 |
|
|---|
| 316 |
void slash_to_backslash (char *p) |
|---|
| 317 |
{ |
|---|
| 318 |
while (1) |
|---|
| 319 |
{ |
|---|
| 320 |
char *q = strchr (p, '/'); |
|---|
| 321 |
|
|---|
| 322 |
if (!q) |
|---|
| 323 |
break; |
|---|
| 324 |
*q = '\\'; |
|---|
| 325 |
} |
|---|
| 326 |
} |
|---|
| 327 |
|
|---|
| 328 |
|
|---|
| 329 |
int TASK::run (int argct, char **argvt) |
|---|
| 330 |
{ |
|---|
| 331 |
string stdout_path, stdin_path, stderr_path; |
|---|
| 332 |
char app_path[1024], buf[256]; |
|---|
| 333 |
|
|---|
| 334 |
strcpy (buf, application.c_str ()); |
|---|
| 335 |
char *p = strstr (buf, "$PROJECT_DIR"); |
|---|
| 336 |
|
|---|
| 337 |
if (p) |
|---|
| 338 |
{ |
|---|
| 339 |
p += strlen ("$PROJECT_DIR"); |
|---|
| 340 |
sprintf (app_path, "%s%s", aid.project_dir, p); |
|---|
| 341 |
} |
|---|
| 342 |
else |
|---|
| 343 |
{ |
|---|
| 344 |
boinc_resolve_filename (buf, app_path, sizeof (app_path)); |
|---|
| 345 |
} |
|---|
| 346 |
|
|---|
| 347 |
// Append wrapper's command-line arguments to those in the job file. |
|---|
| 348 |
// |
|---|
| 349 |
for (int i = 1; i < argct; i++) |
|---|
| 350 |
{ |
|---|
| 351 |
command_line += argvt[i]; |
|---|
| 352 |
if ((i + 1) < argct) |
|---|
| 353 |
{ |
|---|
| 354 |
command_line += string (" "); |
|---|
| 355 |
} |
|---|
| 356 |
} |
|---|
| 357 |
|
|---|
| 358 |
fprintf (stderr, "wrapper: running %s (%s)\n", |
|---|
| 359 |
app_path, command_line.c_str ()); |
|---|
| 360 |
|
|---|
| 361 |
#ifdef _WIN32 |
|---|
| 362 |
PROCESS_INFORMATION process_info; |
|---|
| 363 |
STARTUPINFO startup_info; |
|---|
| 364 |
string command; |
|---|
| 365 |
|
|---|
| 366 |
slash_to_backslash (app_path); |
|---|
| 367 |
memset (&process_info, 0, sizeof (process_info)); |
|---|
| 368 |
memset (&startup_info, 0, sizeof (startup_info)); |
|---|
| 369 |
command = string ("\"") + app_path + string ("\" ") + command_line; |
|---|
| 370 |
|
|---|
| 371 |
// pass std handles to app |
|---|
| 372 |
// |
|---|
| 373 |
startup_info.dwFlags = STARTF_USESTDHANDLES; |
|---|
| 374 |
if (stdout_filename != "") |
|---|
| 375 |
{ |
|---|
| 376 |
boinc_resolve_filename_s (stdout_filename.c_str (), stdout_path); |
|---|
| 377 |
startup_info.hStdOutput = win_fopen (stdout_path.c_str (), "a"); |
|---|
| 378 |
} |
|---|
| 379 |
if (stdin_filename != "") |
|---|
| 380 |
{ |
|---|
| 381 |
boinc_resolve_filename_s (stdin_filename.c_str (), stdin_path); |
|---|
| 382 |
startup_info.hStdInput = win_fopen (stdin_path.c_str (), "r"); |
|---|
| 383 |
} |
|---|
| 384 |
if (stderr_filename != "") |
|---|
| 385 |
{ |
|---|
| 386 |
boinc_resolve_filename_s (stderr_filename.c_str (), stderr_path); |
|---|
| 387 |
startup_info.hStdError = win_fopen (stderr_path.c_str (), "a"); |
|---|
| 388 |
} |
|---|
| 389 |
else |
|---|
| 390 |
{ |
|---|
| 391 |
startup_info.hStdError = win_fopen (STDERR_FILE, "a"); |
|---|
| 392 |
} |
|---|
| 393 |
|
|---|
| 394 |
// bInheritHandles |
|---|
| 395 |
if (!CreateProcess (app_path, (LPSTR) command.c_str (), NULL, NULL, TRUE, |
|---|
| 396 |
CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS, |
|---|
| 397 |
NULL, NULL, &startup_info, &process_info)) |
|---|
| 398 |
{ |
|---|
| 399 |
return ERR_EXEC; |
|---|
| 400 |
} |
|---|
| 401 |
pid_handle = process_info.hProcess; |
|---|
| 402 |
pid = process_info.dwProcessId; |
|---|
| 403 |
thread_handle = process_info.hThread; |
|---|
| 404 |
SetThreadPriority (thread_handle, THREAD_PRIORITY_IDLE); |
|---|
| 405 |
#else |
|---|
| 406 |
int retval, argc; |
|---|
| 407 |
char progname[256]; |
|---|
| 408 |
char *argv[256]; |
|---|
| 409 |
char arglist[4096]; |
|---|
| 410 |
FILE *stdout_file; |
|---|
| 411 |
FILE *stdin_file; |
|---|
| 412 |
FILE *stderr_file; |
|---|
| 413 |
|
|---|
| 414 |
pid = fork (); |
|---|
| 415 |
if (pid == -1) |
|---|
| 416 |
{ |
|---|
| 417 |
boinc_finish (ERR_FORK); |
|---|
| 418 |
} |
|---|
| 419 |
if (pid == 0) |
|---|
| 420 |
{ |
|---|
| 421 |
// we're in the child process here |
|---|
| 422 |
// |
|---|
| 423 |
// open stdout, stdin if file names are given |
|---|
| 424 |
// NOTE: if the application is restartable, |
|---|
| 425 |
// we should deal with atomicity somehow |
|---|
| 426 |
// |
|---|
| 427 |
if (stdout_filename != "") |
|---|
| 428 |
{ |
|---|
| 429 |
boinc_resolve_filename_s (stdout_filename.c_str (), stdout_path); |
|---|
| 430 |
stdout_file = freopen (stdout_path.c_str (), "a", stdout); |
|---|
| 431 |
if (!stdout_file) |
|---|
| 432 |
return ERR_FOPEN; |
|---|
| 433 |
} |
|---|
| 434 |
if (stdin_filename != "") |
|---|
| 435 |
{ |
|---|
| 436 |
boinc_resolve_filename_s (stdin_filename.c_str (), stdin_path); |
|---|
| 437 |
stdin_file = freopen (stdin_path.c_str (), "r", stdin); |
|---|
| 438 |
if (!stdin_file) |
|---|
| 439 |
return ERR_FOPEN; |
|---|
| 440 |
} |
|---|
| 441 |
if (stderr_filename != "") |
|---|
| 442 |
{ |
|---|
| 443 |
boinc_resolve_filename_s (stderr_filename.c_str (), stderr_path); |
|---|
| 444 |
stderr_file = freopen (stderr_path.c_str (), "a", stderr); |
|---|
| 445 |
if (!stderr_file) |
|---|
| 446 |
return ERR_FOPEN; |
|---|
| 447 |
} |
|---|
| 448 |
// construct argv |
|---|
| 449 |
// TODO: use malloc instead of stack var |
|---|
| 450 |
// |
|---|
| 451 |
argv[0] = app_path; |
|---|
| 452 |
strlcpy (arglist, command_line.c_str (), sizeof (arglist)); |
|---|
| 453 |
argc = parse_command_line (arglist, argv + 1); |
|---|
| 454 |
setpriority (PRIO_PROCESS, 0, PROCESS_IDLE_PRIORITY); |
|---|
| 455 |
retval = execv (app_path, argv); |
|---|
| 456 |
exit (ERR_EXEC); |
|---|
| 457 |
} |
|---|
| 458 |
#endif |
|---|
| 459 |
wall_cpu_time = 0; |
|---|
| 460 |
suspended = false; |
|---|
| 461 |
return 0; |
|---|
| 462 |
} |
|---|
| 463 |
|
|---|
| 464 |
|
|---|
| 465 |
bool TASK::poll (int &status) |
|---|
| 466 |
{ |
|---|
| 467 |
if (!suspended) |
|---|
| 468 |
wall_cpu_time += POLL_PERIOD; |
|---|
| 469 |
#ifdef _WIN32 |
|---|
| 470 |
unsigned long |
|---|
| 471 |
exit_code; |
|---|
| 472 |
|
|---|
| 473 |
if (GetExitCodeProcess (pid_handle, &exit_code)) |
|---|
| 474 |
{ |
|---|
| 475 |
if (exit_code != STILL_ACTIVE) |
|---|
| 476 |
{ |
|---|
| 477 |
status = exit_code; |
|---|
| 478 |
final_cpu_time = cpu_time (); |
|---|
| 479 |
return true; |
|---|
| 480 |
} |
|---|
| 481 |
} |
|---|
| 482 |
#else |
|---|
| 483 |
int |
|---|
| 484 |
wpid, |
|---|
| 485 |
stat; |
|---|
| 486 |
struct rusage |
|---|
| 487 |
ru; |
|---|
| 488 |
|
|---|
| 489 |
wpid = wait4 (pid, &status, WNOHANG, &ru); |
|---|
| 490 |
if (wpid) |
|---|
| 491 |
{ |
|---|
| 492 |
final_cpu_time = |
|---|
| 493 |
(float) ru.ru_utime.tv_sec + ((float) ru.ru_utime.tv_usec) / 1e+6; |
|---|
| 494 |
return true; |
|---|
| 495 |
} |
|---|
| 496 |
#endif |
|---|
| 497 |
return false; |
|---|
| 498 |
} |
|---|
| 499 |
|
|---|
| 500 |
|
|---|
| 501 |
void TASK::kill () |
|---|
| 502 |
{ |
|---|
| 503 |
#ifdef _WIN32 |
|---|
| 504 |
TerminateProcess (pid_handle, -1); |
|---|
| 505 |
#else |
|---|
| 506 |
::kill (pid, SIGKILL); |
|---|
| 507 |
#endif |
|---|
| 508 |
} |
|---|
| 509 |
|
|---|
| 510 |
|
|---|
| 511 |
void TASK::stop () |
|---|
| 512 |
{ |
|---|
| 513 |
suspended = true; |
|---|
| 514 |
} |
|---|
| 515 |
|
|---|
| 516 |
|
|---|
| 517 |
void TASK::resume () |
|---|
| 518 |
{ |
|---|
| 519 |
suspended = false; |
|---|
| 520 |
} |
|---|
| 521 |
|
|---|
| 522 |
|
|---|
| 523 |
|
|---|
| 524 |
|
|---|
| 525 |
double TASK::cpu_time () |
|---|
| 526 |
{ |
|---|
| 527 |
#ifdef _WIN32 |
|---|
| 528 |
FILETIME creation_time, exit_time, kernel_time, user_time; |
|---|
| 529 |
ULARGE_INTEGER tKernel, tUser; |
|---|
| 530 |
LONGLONG totTime; |
|---|
| 531 |
|
|---|
| 532 |
int retval = GetProcessTimes (pid_handle, &creation_time, &exit_time, |
|---|
| 533 |
&kernel_time, |
|---|
| 534 |
&user_time); |
|---|
| 535 |
|
|---|
| 536 |
if (retval == 0) |
|---|
| 537 |
{ |
|---|
| 538 |
return wall_cpu_time; |
|---|
| 539 |
} |
|---|
| 540 |
|
|---|
| 541 |
tKernel.LowPart = kernel_time.dwLowDateTime; |
|---|
| 542 |
tKernel.HighPart = kernel_time.dwHighDateTime; |
|---|
| 543 |
tUser.LowPart = user_time.dwLowDateTime; |
|---|
| 544 |
tUser.HighPart = user_time.dwHighDateTime; |
|---|
| 545 |
totTime = tKernel.QuadPart + tUser.QuadPart; |
|---|
| 546 |
|
|---|
| 547 |
return totTime / 1.e7; |
|---|
| 548 |
#elif defined(__APPLE__) |
|---|
| 549 |
// There's no easy way to get another process's CPU time in Mac OS X |
|---|
| 550 |
// |
|---|
| 551 |
return wall_cpu_time; |
|---|
| 552 |
#else |
|---|
| 553 |
return linux_cpu_time (pid); |
|---|
| 554 |
#endif |
|---|
| 555 |
} |
|---|
| 556 |
|
|---|
| 557 |
|
|---|
| 558 |
|
|---|
| 559 |
|
|---|
| 560 |
// Support for multiple tasks. |
|---|
| 561 |
// We keep a checkpoint file that says how many tasks we've completed |
|---|
| 562 |
// and how much CPU time has been used so far |
|---|
| 563 |
// |
|---|
| 564 |
void write_checkpoint (int ntasks, double cpu) |
|---|
| 565 |
{ |
|---|
| 566 |
FILE *f = fopen (CHECKPOINT_FILENAME, "w"); |
|---|
| 567 |
|
|---|
| 568 |
if (!f) |
|---|
| 569 |
return; |
|---|
| 570 |
fprintf (f, "%d %f\n", ntasks, cpu); |
|---|
| 571 |
fclose (f); |
|---|
| 572 |
} |
|---|
| 573 |
|
|---|
| 574 |
|
|---|
| 575 |
void read_checkpoint (int &ntasks, double &cpu) |
|---|
| 576 |
{ |
|---|
| 577 |
int nt; |
|---|
| 578 |
double c; |
|---|
| 579 |
|
|---|
| 580 |
ntasks = 0; |
|---|
| 581 |
cpu = 0; |
|---|
| 582 |
FILE *f = fopen (CHECKPOINT_FILENAME, "r"); |
|---|
| 583 |
|
|---|
| 584 |
if (!f) |
|---|
| 585 |
return; |
|---|
| 586 |
int n = fscanf (f, "%d %lf", &nt, &c); |
|---|
| 587 |
|
|---|
| 588 |
fclose (f); |
|---|
| 589 |
if (n != 2) |
|---|
| 590 |
return; |
|---|
| 591 |
ntasks = nt; |
|---|
| 592 |
cpu = c; |
|---|
| 593 |
} |
|---|
| 594 |
|
|---|
| 595 |
|
|---|
| 596 |
|
|---|
| 597 |
void check_vm_result(VixError err, VixHandle hostHandle, string errorString) |
|---|
| 598 |
{ |
|---|
| 599 |
if (VIX_OK != err) |
|---|
| 600 |
{ |
|---|
| 601 |
fprintf (stderr, "\n\n Error: %s\n",errorString.c_str()); |
|---|
| 602 |
fprintf (stderr, "Error message: \"%s\"\n", Vix_GetErrorText (err, NULL)); |
|---|
| 603 |
VixHost_Disconnect (hostHandle); |
|---|
| 604 |
boinc_finish(100); |
|---|
| 605 |
} |
|---|
| 606 |
} |
|---|
| 607 |
|
|---|
| 608 |
int main (int argc, char **argv) |
|---|
| 609 |
{ |
|---|
| 610 |
|
|---|
| 611 |
BOINC_OPTIONS options; |
|---|
| 612 |
int retval, ntasks; |
|---|
| 613 |
unsigned int i; |
|---|
| 614 |
double cpu, total_weight = 0, w = 0; |
|---|
| 615 |
|
|---|
| 616 |
for (i = 1; i < (unsigned int) argc; i++) |
|---|
| 617 |
{ |
|---|
| 618 |
if (!strcmp (argv[i], "--graphics")) |
|---|
| 619 |
{ |
|---|
| 620 |
graphics = true; |
|---|
| 621 |
} |
|---|
| 622 |
} |
|---|
| 623 |
|
|---|
| 624 |
memset (&options, 0, sizeof (options)); |
|---|
| 625 |
options.main_program = true; |
|---|
| 626 |
options.check_heartbeat = true; |
|---|
| 627 |
options.handle_process_control = true; |
|---|
| 628 |
if (graphics) |
|---|
| 629 |
{ |
|---|
| 630 |
options.backwards_compatible_graphics = true; |
|---|
| 631 |
} |
|---|
| 632 |
|
|---|
| 633 |
// boinc_init_options(&options); |
|---|
| 634 |
|
|---|
| 635 |
fprintf (stderr, "vmwrapper: starting\n"); |
|---|
| 636 |
|
|---|
| 637 |
boinc_get_init_data (aid); |
|---|
| 638 |
|
|---|
| 639 |
retval = parse_job_file (); |
|---|
| 640 |
if (retval) |
|---|
| 641 |
{ |
|---|
| 642 |
fprintf (stderr, "can't parse job file: %d\n", retval); |
|---|
| 643 |
boinc_finish (retval); |
|---|
| 644 |
} |
|---|
| 645 |
|
|---|
| 646 |
read_checkpoint (ntasks, cpu); |
|---|
| 647 |
if (ntasks > (int) tasks.size ()) |
|---|
| 648 |
{ |
|---|
| 649 |
fprintf (stderr, "Checkpoint file: ntasks %d too large\n", ntasks); |
|---|
| 650 |
boinc_finish (1); |
|---|
| 651 |
} |
|---|
| 652 |
|
|---|
| 653 |
for (i = 0; i < tasks.size (); i++) |
|---|
| 654 |
{ |
|---|
| 655 |
total_weight += tasks[i].weight; |
|---|
| 656 |
} |
|---|
| 657 |
|
|---|
| 658 |
|
|---|
| 659 |
|
|---|
| 660 |
|
|---|
| 661 |
VixHandle hostHandle = VIX_INVALID_HANDLE; |
|---|
| 662 |
VixHandle jobHandle = VIX_INVALID_HANDLE; |
|---|
| 663 |
VixError err; |
|---|
| 664 |
string vmxFilename; |
|---|
| 665 |
|
|---|
| 666 |
jobHandle = VixHost_Connect (VIX_API_VERSION, VIX_SERVICEPROVIDER_VMWARE_SERVER, NULL, 0, NULL, NULL, 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 667 |
|
|---|
| 668 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &hostHandle, VIX_PROPERTY_NONE); |
|---|
| 669 |
|
|---|
| 670 |
if (VIX_OK != err) |
|---|
| 671 |
{ |
|---|
| 672 |
fprintf (stderr, "Unable to connect to server!\n"); |
|---|
| 673 |
fprintf (stderr, "Error message: \"%s\"\n", Vix_GetErrorText (err, NULL)); |
|---|
| 674 |
VixHost_Disconnect (hostHandle); |
|---|
| 675 |
boinc_finish(1); |
|---|
| 676 |
} |
|---|
| 677 |
|
|---|
| 678 |
fprintf (stderr, "Connected to server.\n"); |
|---|
| 679 |
|
|---|
| 680 |
|
|---|
| 681 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 682 |
jobHandle = VIX_INVALID_HANDLE; |
|---|
| 683 |
|
|---|
| 684 |
|
|---|
| 685 |
for (i = 0; i < tasks.size (); i++) |
|---|
| 686 |
{ |
|---|
| 687 |
|
|---|
| 688 |
fprintf(stderr,"Processing task %d.\n", i); |
|---|
| 689 |
|
|---|
| 690 |
TASK & task = tasks[i]; |
|---|
| 691 |
|
|---|
| 692 |
// w += task.weight; |
|---|
| 693 |
|
|---|
| 694 |
// this line is to do with cpu time storage |
|---|
| 695 |
// if ((int) i < ntasks) |
|---|
| 696 |
// continue; |
|---|
| 697 |
|
|---|
| 698 |
double frac_done = w / total_weight; |
|---|
| 699 |
|
|---|
| 700 |
|
|---|
| 701 |
fprintf(stderr, "Task %d.\n========\n\n", i+1); |
|---|
| 702 |
|
|---|
| 703 |
|
|---|
| 704 |
fprintf(stderr, "VM file root is %s\n", task.vm.c_str ()); |
|---|
| 705 |
|
|---|
| 706 |
string vm_file_in_1, vm_file_in_2; |
|---|
| 707 |
char vm_file_1[1024], vm_file_2[1024]; |
|---|
| 708 |
|
|---|
| 709 |
string pwd = get_current_dir_name (); |
|---|
| 710 |
|
|---|
| 711 |
|
|---|
| 712 |
// VMWare Server 1 requires full path |
|---|
| 713 |
vm_file_in_1 = pwd + "/" + task.vm + ".vmx"; |
|---|
| 714 |
vm_file_in_2 = pwd + "/" + task.vm + ".vmdk"; |
|---|
| 715 |
|
|---|
| 716 |
// fprintf (stderr, "Input filenames are %s, %s\n", |
|---|
| 717 |
// vm_file_in_1.c_str (), vm_file_in_2.c_str ()); |
|---|
| 718 |
|
|---|
| 719 |
boinc_resolve_filename (vm_file_in_1.c_str (), vm_file_1, 1024); |
|---|
| 720 |
boinc_resolve_filename (vm_file_in_2.c_str (), vm_file_2, 1024); |
|---|
| 721 |
|
|---|
| 722 |
// fprintf (stderr, "Resolved to %s, %s\n", vm_file_1, vm_file_2); |
|---|
| 723 |
|
|---|
| 724 |
if (access (vm_file_1, R_OK)) |
|---|
| 725 |
{ |
|---|
| 726 |
fprintf (stderr, "Unable to access VM file %s!\n",vm_file_1); |
|---|
| 727 |
boinc_finish (1); |
|---|
| 728 |
} |
|---|
| 729 |
|
|---|
| 730 |
if (access (vm_file_2, R_OK)) |
|---|
| 731 |
{ |
|---|
| 732 |
fprintf (stderr, "Unable to access VM file %s!\n",vm_file_2); |
|---|
| 733 |
boinc_finish (1); |
|---|
| 734 |
} |
|---|
| 735 |
|
|---|
| 736 |
|
|---|
| 737 |
// Register VM |
|---|
| 738 |
jobHandle = VixHost_RegisterVM (hostHandle, vm_file_1, NULL, NULL); |
|---|
| 739 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 740 |
check_vm_result(err, hostHandle, "Unable to register VM."); |
|---|
| 741 |
fprintf (stderr, "Registered virtual machine with the server.\n"); |
|---|
| 742 |
|
|---|
| 743 |
VixHandle vmHandle = VIX_INVALID_HANDLE; |
|---|
| 744 |
|
|---|
| 745 |
// Open VM |
|---|
| 746 |
jobHandle = VixVM_Open (hostHandle, vm_file_1, NULL, NULL); |
|---|
| 747 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &vmHandle, VIX_PROPERTY_NONE); |
|---|
| 748 |
check_vm_result(err, hostHandle, "Unable to open VM."); |
|---|
| 749 |
fprintf (stderr, "Got handle.\n"); |
|---|
| 750 |
|
|---|
| 751 |
// Power on VM |
|---|
| 752 |
jobHandle = VixVM_PowerOn (vmHandle, 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 753 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 754 |
check_vm_result(err, hostHandle, "Unable to power on VM."); |
|---|
| 755 |
fprintf (stderr, "VM is now on (if it wasn't already).\n"); |
|---|
| 756 |
|
|---|
| 757 |
// Wait for guest OS to start |
|---|
| 758 |
jobHandle = VixVM_WaitForToolsInGuest (vmHandle, 0, NULL, NULL); |
|---|
| 759 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 760 |
check_vm_result(err, hostHandle, "Did not get confirmation of VMWare Tools."); |
|---|
| 761 |
|
|---|
| 762 |
// Log in |
|---|
| 763 |
jobHandle = VixVM_LoginInGuest (vmHandle, task.user.c_str(), task.password.c_str(), 0, NULL, NULL); |
|---|
| 764 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 765 |
check_vm_result(err, hostHandle, "Unable to log in."); |
|---|
| 766 |
fprintf (stderr, "Logged in. Preparing job...\n"); |
|---|
| 767 |
|
|---|
| 768 |
|
|---|
| 769 |
string guestfile = task.datadir + "/" + task.innerjob; |
|---|
| 770 |
string st_hostfile = pwd + "/" + task.innerjob; |
|---|
| 771 |
char hostfile[1024]; |
|---|
| 772 |
|
|---|
| 773 |
boinc_resolve_filename (st_hostfile.c_str (), hostfile, 1024); |
|---|
| 774 |
|
|---|
| 775 |
jobHandle = VixVM_CopyFileFromHostToGuest (vmHandle, hostfile, guestfile.c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 776 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 777 |
check_vm_result(err, hostHandle, "Unable to copy executable."); |
|---|
| 778 |
|
|---|
| 779 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 780 |
|
|---|
| 781 |
// Changing permissions, do we really need to do this? |
|---|
| 782 |
jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/chmod", ("+x " + guestfile).c_str (), 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 783 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 784 |
check_vm_result(err, hostHandle, "Unable to change permissions."); |
|---|
| 785 |
|
|---|
| 786 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 787 |
|
|---|
| 788 |
|
|---|
| 789 |
fprintf (stderr, "Copying in input...\n"); |
|---|
| 790 |
|
|---|
| 791 |
for(int files=0;files<task.data.size();files++) |
|---|
| 792 |
{ |
|---|
| 793 |
fprintf(stderr,"Processing: %s\n",task.data[files].c_str()); |
|---|
| 794 |
|
|---|
| 795 |
// should use boinc_resolve_filename here |
|---|
| 796 |
jobHandle = VixVM_CopyFileFromHostToGuest (vmHandle, (pwd + "/" + task.data[files]).c_str(), (task.datadir + "/" + task.data[files]).c_str(), |
|---|
| 797 |
0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 798 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 799 |
check_vm_result(err, hostHandle, "Error copying in file."); |
|---|
| 800 |
|
|---|
| 801 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 802 |
|
|---|
| 803 |
} |
|---|
| 804 |
|
|---|
| 805 |
|
|---|
| 806 |
|
|---|
| 807 |
|
|---|
| 808 |
|
|---|
| 809 |
|
|---|
| 810 |
// Run the target program. |
|---|
| 811 |
fprintf (stderr, "Running main program: "); |
|---|
| 812 |
jobHandle = VixVM_RunProgramInGuest (vmHandle, guestfile.c_str (), "", 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 813 |
|
|---|
| 814 |
Bool complete=false; |
|---|
| 815 |
|
|---|
| 816 |
task.starting_cpu = cpu; |
|---|
| 817 |
task.checkpoint_cpu_time = cpu; |
|---|
| 818 |
|
|---|
| 819 |
|
|---|
| 820 |
BOINC_STATUS status; |
|---|
| 821 |
VixHandle innerJobHandle; |
|---|
| 822 |
VixHandle snapshotHandle; |
|---|
| 823 |
|
|---|
| 824 |
while(!complete) |
|---|
| 825 |
{ |
|---|
| 826 |
if(boinc_time_to_checkpoint()) |
|---|
| 827 |
fprintf(stderr,"Time to checkpoint run here...\n"); |
|---|
| 828 |
|
|---|
| 829 |
|
|---|
| 830 |
|
|---|
| 831 |
boinc_get_status (&status); |
|---|
| 832 |
|
|---|
| 833 |
if (status.no_heartbeat || status.quit_request || status.abort_request) |
|---|
| 834 |
{ |
|---|
| 835 |
VixHost_Disconnect (hostHandle); |
|---|
| 836 |
boinc_finish(0); |
|---|
| 837 |
} |
|---|
| 838 |
|
|---|
| 839 |
|
|---|
| 840 |
// contents of this control structure needs fixing, since suspend doesn't work |
|---|
| 841 |
if (status.suspended) |
|---|
| 842 |
{ |
|---|
| 843 |
if (!task.suspended) |
|---|
| 844 |
{ |
|---|
| 845 |
// innerJobHandle = VixVM_Suspend(vmHandle,0,VIX_INVALID_HANDLE,NULL,NULL); |
|---|
| 846 |
// err = VixJob_Wait(innerJobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &snapshotHandle, VIX_PROPERTY_NONE); |
|---|
| 847 |
// check_vm_result(err, hostHandle, "Error pausing VM."); |
|---|
| 848 |
task.stop(); |
|---|
| 849 |
} |
|---|
| 850 |
} |
|---|
| 851 |
else |
|---|
| 852 |
{ |
|---|
| 853 |
if (task.suspended) |
|---|
| 854 |
{ |
|---|
| 855 |
// innerJobHandle = VixVM_Unpause(vmHandle,0,VIX_INVALID_HANDLE,NULL,NULL); |
|---|
| 856 |
// err = VixJob_Wait(innerJobHandle, VIX_PROPERTY_JOB_RESULT_HANDLE, &snapshotHandle, VIX_PROPERTY_NONE); |
|---|
| 857 |
// check_vm_result(err, hostHandle, "Error unpausing VM."); |
|---|
| 858 |
task.resume (); |
|---|
| 859 |
} |
|---|
| 860 |
} |
|---|
| 861 |
|
|---|
| 862 |
|
|---|
| 863 |
// send_status_message (task, frac_done); |
|---|
| 864 |
// fprintf(stderr,"Partial credit check here...\n"); |
|---|
| 865 |
|
|---|
| 866 |
// double current_cpu_time = task.starting_cpu + task.cpu_time (); |
|---|
| 867 |
|
|---|
| 868 |
// if (task.has_checkpointed ()) |
|---|
| 869 |
// { |
|---|
| 870 |
// task.checkpoint_cpu_time = current_cpu_time; |
|---|
| 871 |
// } |
|---|
| 872 |
|
|---|
| 873 |
// not sure how to do this yet |
|---|
| 874 |
// boinc_report_app_status (current_cpu_time, task.checkpoint_cpu_time, frac_done); |
|---|
| 875 |
|
|---|
| 876 |
|
|---|
| 877 |
boinc_sleep(POLL_PERIOD); |
|---|
| 878 |
|
|---|
| 879 |
|
|---|
| 880 |
if(!task.suspended) { |
|---|
| 881 |
err = VixJob_CheckCompletion(jobHandle, &complete); |
|---|
| 882 |
check_vm_result(err, hostHandle, "Error polling for job completion."); |
|---|
| 883 |
} |
|---|
| 884 |
} |
|---|
| 885 |
|
|---|
| 886 |
|
|---|
| 887 |
cpu += task.final_cpu_time; |
|---|
| 888 |
// write_checkpoint here is necessary to keep track of CPU time |
|---|
| 889 |
// we either use the time measured, or the time from within |
|---|
| 890 |
write_checkpoint (i + 1, cpu); |
|---|
| 891 |
|
|---|
| 892 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 893 |
check_vm_result(err, hostHandle, "Error running target program."); |
|---|
| 894 |
fprintf (stderr, "done.\n"); |
|---|
| 895 |
|
|---|
| 896 |
|
|---|
| 897 |
|
|---|
| 898 |
|
|---|
| 899 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 900 |
|
|---|
| 901 |
|
|---|
| 902 |
fprintf(stderr, "Copying out output...\n"); |
|---|
| 903 |
|
|---|
| 904 |
for(int files=0;files<task.output.size();files++) |
|---|
| 905 |
{ |
|---|
| 906 |
fprintf(stderr,"Processing: %s\n",task.output[files].c_str()); |
|---|
| 907 |
|
|---|
| 908 |
|
|---|
| 909 |
// FIXME: need to tell BOINC about these files |
|---|
| 910 |
jobHandle = VixVM_CopyFileFromGuestToHost (vmHandle, (task.datadir + "/" + task.output[0]).c_str(), |
|---|
| 911 |
(pwd + "/" + task.output[files]).c_str (), 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 912 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 913 |
check_vm_result(err, hostHandle, "Error copying out file."); |
|---|
| 914 |
|
|---|
| 915 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 916 |
|
|---|
| 917 |
jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/rm", (task.datadir + "/" + task.output[files]).c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 918 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 919 |
check_vm_result(err, hostHandle, "Error deleting file."); |
|---|
| 920 |
|
|---|
| 921 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 922 |
} |
|---|
| 923 |
|
|---|
| 924 |
|
|---|
| 925 |
// now delete the executable, the output and the data |
|---|
| 926 |
fprintf(stderr, "Sanitising virtual machine...\n"); |
|---|
| 927 |
|
|---|
| 928 |
for(int files=0;files<task.data.size();files++) |
|---|
| 929 |
{ |
|---|
| 930 |
fprintf(stderr,"Removing: %s\n",task.data[files].c_str()); |
|---|
| 931 |
|
|---|
| 932 |
jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/rm", (task.datadir + "/" + task.data[files]).c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 933 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 934 |
check_vm_result(err, hostHandle, "Error deleting file."); |
|---|
| 935 |
|
|---|
| 936 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 937 |
} |
|---|
| 938 |
|
|---|
| 939 |
|
|---|
| 940 |
fprintf(stderr,"Removing executable.\n"); |
|---|
| 941 |
jobHandle = VixVM_RunProgramInGuest (vmHandle, "/bin/rm", guestfile.c_str(), 0, VIX_INVALID_HANDLE, NULL, NULL); |
|---|
| 942 |
err = VixJob_Wait (jobHandle, VIX_PROPERTY_NONE); |
|---|
| 943 |
check_vm_result(err, hostHandle, "Error deleting file."); |
|---|
| 944 |
|
|---|
| 945 |
Vix_ReleaseHandle (jobHandle); |
|---|
| 946 |
|
|---|
| 947 |
|
|---|
| 948 |
|
|---|
| 949 |
} |
|---|
| 950 |
|
|---|
| 951 |
boinc_finish (0); |
|---|
| 952 |
} |
|---|
| 953 |
|
|---|
| 954 |
|
|---|
| 955 |
#ifdef _WIN32 |
|---|
| 956 |
|
|---|
| 957 |
int WINAPI |
|---|
| 958 |
WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode) |
|---|
| 959 |
{ |
|---|
| 960 |
LPSTR command_line; |
|---|
| 961 |
char *argv[100]; |
|---|
| 962 |
int argc; |
|---|
| 963 |
|
|---|
| 964 |
command_line = GetCommandLine (); |
|---|
| 965 |
argc = parse_command_line (command_line, argv); |
|---|
| 966 |
return main (argc, argv); |
|---|
| 967 |
} |
|---|
| 968 |
#endif |
|---|