VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModAPIMonitor.cpp@ 55362

Last change on this file since 55362 was 55214, checked in by vboxsync, 10 years ago

Main/Console+Machine+Session+Snapshot: move the save state and snapshot related methods from IConsole to IMachine, with lots of unavoidable code restructuring and cleanup. Also define two new machine states (so that the "Saving" one is specifically for saving state now) which requires more changes everywhere
Frontends: necessary adjustments
doc/SDK: document the changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.4 KB
Line 
1/* $Id: VBoxModAPIMonitor.cpp 55214 2015-04-13 15:53:01Z vboxsync $ */
2/** @file
3 * VBoxModAPIMonitor - API monitor module for detecting host isolation.
4 */
5
6/*
7 * Copyright (C) 2012-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#ifndef VBOX_ONLY_DOCS
23# include <iprt/message.h>
24# include <VBox/com/errorprint.h>
25#endif /* !VBOX_ONLY_DOCS */
26
27#include "VBoxWatchdogInternal.h"
28
29using namespace com;
30
31#define VBOX_MOD_APIMON_NAME "apimon"
32
33/**
34 * The module's RTGetOpt-IDs for the command line.
35 */
36enum GETOPTDEF_APIMON
37{
38 GETOPTDEF_APIMON_GROUPS = 3000,
39 GETOPTDEF_APIMON_ISLN_RESPONSE,
40 GETOPTDEF_APIMON_ISLN_TIMEOUT,
41 GETOPTDEF_APIMON_RESP_TIMEOUT
42};
43
44/**
45 * The module's command line arguments.
46 */
47static const RTGETOPTDEF g_aAPIMonitorOpts[] = {
48 { "--apimon-groups", GETOPTDEF_APIMON_GROUPS, RTGETOPT_REQ_STRING },
49 { "--apimon-isln-response", GETOPTDEF_APIMON_ISLN_RESPONSE, RTGETOPT_REQ_STRING },
50 { "--apimon-isln-timeout", GETOPTDEF_APIMON_ISLN_TIMEOUT, RTGETOPT_REQ_UINT32 },
51 { "--apimon-resp-timeout", GETOPTDEF_APIMON_RESP_TIMEOUT, RTGETOPT_REQ_UINT32 }
52};
53
54enum APIMON_RESPONSE
55{
56 /** Unknown / unhandled response. */
57 APIMON_RESPONSE_NONE = 0,
58 /** Pauses the VM execution. */
59 APIMON_RESPONSE_PAUSE = 10,
60 /** Does a hard power off. */
61 APIMON_RESPONSE_POWEROFF = 200,
62 /** Tries to save the current machine state. */
63 APIMON_RESPONSE_SAVE = 250,
64 /** Tries to shut down all running VMs in
65 * a gentle manner. */
66 APIMON_RESPONSE_SHUTDOWN = 300
67};
68
69/** The VM group(s) the API monitor handles. If none, all VMs get handled. */
70static mapGroups g_vecAPIMonGroups; /** @todo Move this into module payload! */
71static APIMON_RESPONSE g_enmAPIMonIslnResp = APIMON_RESPONSE_NONE;
72static unsigned long g_ulAPIMonIslnTimeoutMS = 0;
73static Bstr g_strAPIMonIslnLastBeat;
74static unsigned long g_ulAPIMonResponseTimeoutMS = 0;
75static uint64_t g_uAPIMonIslnLastBeatMS = 0;
76
77static int apimonResponseToEnum(const char *pszResponse, APIMON_RESPONSE *pResp)
78{
79 AssertPtrReturn(pszResponse, VERR_INVALID_POINTER);
80 AssertPtrReturn(pResp, VERR_INVALID_POINTER);
81
82 int rc = VINF_SUCCESS;
83 if (!RTStrICmp(pszResponse, "none"))
84 {
85 *pResp = APIMON_RESPONSE_NONE;
86 }
87 else if (!RTStrICmp(pszResponse, "pause"))
88 {
89 *pResp = APIMON_RESPONSE_PAUSE;
90 }
91 else if ( !RTStrICmp(pszResponse, "poweroff")
92 || !RTStrICmp(pszResponse, "powerdown"))
93 {
94 *pResp = APIMON_RESPONSE_POWEROFF;
95 }
96 else if (!RTStrICmp(pszResponse, "save"))
97 {
98 *pResp = APIMON_RESPONSE_SAVE;
99 }
100 else if ( !RTStrICmp(pszResponse, "shutdown")
101 || !RTStrICmp(pszResponse, "shutoff"))
102 {
103 *pResp = APIMON_RESPONSE_SHUTDOWN;
104 }
105 else
106 {
107 *pResp = APIMON_RESPONSE_NONE;
108 rc = VERR_INVALID_PARAMETER;
109 }
110
111 return rc;
112}
113
114static const char* apimonResponseToStr(APIMON_RESPONSE enmResp)
115{
116 if (APIMON_RESPONSE_NONE == enmResp)
117 return "none";
118 else if (APIMON_RESPONSE_PAUSE == enmResp)
119 return "pausing";
120 else if (APIMON_RESPONSE_POWEROFF == enmResp)
121 return "powering off";
122 else if (APIMON_RESPONSE_SAVE == enmResp)
123 return "saving state";
124 else if (APIMON_RESPONSE_SHUTDOWN == enmResp)
125 return "shutting down";
126
127 return "unknown";
128}
129
130/* Copied from VBoxManageInfo.cpp. */
131static const char *apimonMachineStateToName(MachineState_T machineState, bool fShort)
132{
133 switch (machineState)
134 {
135 case MachineState_PoweredOff:
136 return fShort ? "poweroff" : "powered off";
137 case MachineState_Saved:
138 return "saved";
139 case MachineState_Aborted:
140 return "aborted";
141 case MachineState_Teleported:
142 return "teleported";
143 case MachineState_Running:
144 return "running";
145 case MachineState_Paused:
146 return "paused";
147 case MachineState_Stuck:
148 return fShort ? "gurumeditation" : "guru meditation";
149 case MachineState_LiveSnapshotting:
150 return fShort ? "livesnapshotting" : "live snapshotting";
151 case MachineState_Teleporting:
152 return "teleporting";
153 case MachineState_Starting:
154 return "starting";
155 case MachineState_Stopping:
156 return "stopping";
157 case MachineState_Saving:
158 return "saving";
159 case MachineState_Restoring:
160 return "restoring";
161 case MachineState_TeleportingPausedVM:
162 return fShort ? "teleportingpausedvm" : "teleporting paused vm";
163 case MachineState_TeleportingIn:
164 return fShort ? "teleportingin" : "teleporting (incoming)";
165 case MachineState_RestoringSnapshot:
166 return fShort ? "restoringsnapshot" : "restoring snapshot";
167 case MachineState_DeletingSnapshot:
168 return fShort ? "deletingsnapshot" : "deleting snapshot";
169 case MachineState_DeletingSnapshotOnline:
170 return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
171 case MachineState_DeletingSnapshotPaused:
172 return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
173 case MachineState_SettingUp:
174 return fShort ? "settingup" : "setting up";
175 default:
176 break;
177 }
178 return "unknown";
179}
180
181static int apimonMachineControl(const Bstr &strUuid, PVBOXWATCHDOG_MACHINE pMachine,
182 APIMON_RESPONSE enmResp, unsigned long ulTimeout)
183{
184 /** @todo Add other commands (with enmResp) here. */
185 AssertPtrReturn(pMachine, VERR_INVALID_POINTER);
186
187 serviceLogVerbose(("apimon: Triggering \"%s\" (%RU32ms timeout) for machine \"%ls\"\n",
188 apimonResponseToStr(enmResp), ulTimeout, strUuid.raw()));
189
190 if ( enmResp == APIMON_RESPONSE_NONE
191 || g_fDryrun)
192 return VINF_SUCCESS; /* Nothing to do. */
193
194 HRESULT rc;
195 ComPtr <IMachine> machine;
196 CHECK_ERROR_RET(g_pVirtualBox, FindMachine(strUuid.raw(),
197 machine.asOutParam()), VERR_NOT_FOUND);
198 do
199 {
200 /* Query the machine's state to avoid unnecessary IPC. */
201 MachineState_T machineState;
202 CHECK_ERROR_BREAK(machine, COMGETTER(State)(&machineState));
203
204 if ( machineState == MachineState_Running
205 || machineState == MachineState_Paused)
206 {
207 /* Open a session for the VM. */
208 CHECK_ERROR_BREAK(machine, LockMachine(g_pSession, LockType_Shared));
209
210 do
211 {
212 /* Get the associated console. */
213 ComPtr<IConsole> console;
214 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
215 /* Get the associated session machine. */
216 ComPtr<IMachine> sessionMachine;
217 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Machine)(sessionMachine.asOutParam()));
218
219 ComPtr<IProgress> progress;
220
221 switch (enmResp)
222 {
223 case APIMON_RESPONSE_PAUSE:
224 if (machineState != MachineState_Paused)
225 {
226 serviceLogVerbose(("apimon: Pausing machine \"%ls\" ...\n",
227 strUuid.raw()));
228 CHECK_ERROR_BREAK(console, Pause());
229 }
230 break;
231
232 case APIMON_RESPONSE_POWEROFF:
233 serviceLogVerbose(("apimon: Powering off machine \"%ls\" ...\n",
234 strUuid.raw()));
235 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
236 progress->WaitForCompletion(ulTimeout);
237 CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine \"%ls\"",
238 strUuid.raw()));
239 break;
240
241 case APIMON_RESPONSE_SAVE:
242 {
243 serviceLogVerbose(("apimon: Saving state of machine \"%ls\" ...\n",
244 strUuid.raw()));
245
246 /* First pause so we don't trigger a live save which needs more time/resources. */
247 bool fPaused = false;
248 rc = console->Pause();
249 if (FAILED(rc))
250 {
251 bool fError = true;
252 if (rc == VBOX_E_INVALID_VM_STATE)
253 {
254 /* Check if we are already paused. */
255 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
256 /* The error code was lost by the previous instruction. */
257 rc = VBOX_E_INVALID_VM_STATE;
258 if (machineState != MachineState_Paused)
259 {
260 serviceLog("apimon: Machine \"%ls\" in invalid state %d -- %s\n",
261 strUuid.raw(), machineState, apimonMachineStateToName(machineState, false));
262 }
263 else
264 {
265 fError = false;
266 fPaused = true;
267 }
268 }
269 if (fError)
270 break;
271 }
272
273 CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
274 if (SUCCEEDED(rc))
275 {
276 progress->WaitForCompletion(ulTimeout);
277 CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state of machine \"%ls\"",
278 strUuid.raw()));
279 }
280
281 if (SUCCEEDED(rc))
282 {
283 serviceLogVerbose(("apimon: State of machine \"%ls\" saved, powering off ...\n", strUuid.raw()));
284 CHECK_ERROR_BREAK(console, PowerButton());
285 }
286 else
287 serviceLogVerbose(("apimon: Saving state of machine \"%ls\" failed\n", strUuid.raw()));
288
289 break;
290 }
291
292 case APIMON_RESPONSE_SHUTDOWN:
293 serviceLogVerbose(("apimon: Shutting down machine \"%ls\" ...\n", strUuid.raw()));
294 CHECK_ERROR_BREAK(console, PowerButton());
295 break;
296
297 default:
298 AssertMsgFailed(("Response %d not implemented", enmResp));
299 break;
300 }
301 } while (0);
302
303 /* Unlock the machine again. */
304 g_pSession->UnlockMachine();
305 }
306 else
307 serviceLogVerbose(("apimon: Warning: Could not trigger \"%s\" (%d) for machine \"%ls\"; in state \"%s\" (%d) currently\n",
308 apimonResponseToStr(enmResp), enmResp, strUuid.raw(),
309 apimonMachineStateToName(machineState, false), machineState));
310 } while (0);
311
312
313
314 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_COM_IPRT_ERROR;
315}
316
317static bool apimonHandleVM(const PVBOXWATCHDOG_MACHINE pMachine)
318{
319 bool fHandleVM = false;
320
321 try
322 {
323 mapGroupsIterConst itVMGroup = pMachine->groups.begin();
324 while ( itVMGroup != pMachine->groups.end()
325 && !fHandleVM)
326 {
327 mapGroupsIterConst itInGroup = g_vecAPIMonGroups.find(itVMGroup->first);
328 if (itInGroup != g_vecAPIMonGroups.end())
329 fHandleVM = true;
330
331 itVMGroup++;
332 }
333 }
334 catch (...)
335 {
336 AssertFailed();
337 }
338
339 return fHandleVM;
340}
341
342static int apimonTrigger(APIMON_RESPONSE enmResp)
343{
344 int rc = VINF_SUCCESS;
345
346 bool fAllGroups = g_vecAPIMonGroups.empty();
347 mapVMIter it = g_mapVM.begin();
348
349 if (it == g_mapVM.end())
350 {
351 serviceLog("apimon: No machines in list, skipping ...\n");
352 return rc;
353 }
354
355 while (it != g_mapVM.end())
356 {
357 bool fHandleVM = fAllGroups;
358 try
359 {
360 if (!fHandleVM)
361 fHandleVM = apimonHandleVM(&it->second);
362
363 if (fHandleVM)
364 {
365 int rc2 = apimonMachineControl(it->first /* Uuid */,
366 &it->second /* Machine */, enmResp, g_ulAPIMonResponseTimeoutMS);
367 if (RT_FAILURE(rc2))
368 serviceLog("apimon: Controlling machine \"%ls\" (response \"%s\") failed with rc=%Rrc",
369 it->first.raw(), apimonResponseToStr(enmResp), rc);
370
371 if (RT_SUCCESS(rc))
372 rc = rc2; /* Store original error. */
373 /* Keep going. */
374 }
375 }
376 catch (...)
377 {
378 AssertFailed();
379 }
380
381 it++;
382 }
383
384 return rc;
385}
386
387/* Callbacks. */
388static DECLCALLBACK(int) VBoxModAPIMonitorPreInit(void)
389{
390 return VINF_SUCCESS;
391}
392
393static DECLCALLBACK(int) VBoxModAPIMonitorOption(int argc, char *argv[], int *piConsumed)
394{
395 if (!argc) /* Take a shortcut. */
396 return -1;
397
398 AssertPtrReturn(argv, VERR_INVALID_POINTER);
399 AssertPtrReturn(piConsumed, VERR_INVALID_POINTER);
400
401 RTGETOPTSTATE GetState;
402 int rc = RTGetOptInit(&GetState, argc, argv,
403 g_aAPIMonitorOpts, RT_ELEMENTS(g_aAPIMonitorOpts),
404 0 /* First */, 0 /*fFlags*/);
405 if (RT_FAILURE(rc))
406 return rc;
407
408 rc = 0; /* Set default parsing result to valid. */
409
410 int c;
411 RTGETOPTUNION ValueUnion;
412 while ((c = RTGetOpt(&GetState, &ValueUnion)))
413 {
414 switch (c)
415 {
416 case GETOPTDEF_APIMON_GROUPS:
417 {
418 rc = groupAdd(g_vecAPIMonGroups, ValueUnion.psz, 0 /* Flags */);
419 if (RT_FAILURE(rc))
420 rc = -1; /* Option unknown. */
421 break;
422 }
423
424 case GETOPTDEF_APIMON_ISLN_RESPONSE:
425 rc = apimonResponseToEnum(ValueUnion.psz, &g_enmAPIMonIslnResp);
426 if (RT_FAILURE(rc))
427 rc = -1; /* Option unknown. */
428 break;
429
430 case GETOPTDEF_APIMON_ISLN_TIMEOUT:
431 g_ulAPIMonIslnTimeoutMS = ValueUnion.u32;
432 if (g_ulAPIMonIslnTimeoutMS < 1000) /* Don't allow timeouts < 1s. */
433 g_ulAPIMonIslnTimeoutMS = 1000;
434 break;
435
436 case GETOPTDEF_APIMON_RESP_TIMEOUT:
437 g_ulAPIMonResponseTimeoutMS = ValueUnion.u32;
438 if (g_ulAPIMonResponseTimeoutMS < 5000) /* Don't allow timeouts < 5s. */
439 g_ulAPIMonResponseTimeoutMS = 5000;
440 break;
441
442 default:
443 rc = -1; /* We don't handle this option, skip. */
444 break;
445 }
446
447 /* At the moment we only process one option at a time. */
448 break;
449 }
450
451 *piConsumed += GetState.iNext - 1;
452
453 return rc;
454}
455
456static DECLCALLBACK(int) VBoxModAPIMonitorInit(void)
457{
458 HRESULT rc = S_OK;
459
460 do
461 {
462 Bstr strValue;
463
464 /* VM groups to watch for. */
465 if (g_vecAPIMonGroups.empty()) /* Not set by command line? */
466 {
467 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("VBoxInternal2/Watchdog/APIMonitor/Groups").raw(),
468 strValue.asOutParam()));
469 if (!strValue.isEmpty())
470 {
471 int rc2 = groupAdd(g_vecAPIMonGroups, Utf8Str(strValue).c_str(), 0 /* Flags */);
472 if (RT_FAILURE(rc2))
473 serviceLog("apimon: Warning: API monitor groups string invalid (%ls)\n", strValue.raw());
474 }
475 }
476
477 if (!g_ulAPIMonIslnTimeoutMS)
478 cfgGetValueULong(g_pVirtualBox, NULL /* Machine */,
479 "VBoxInternal2/Watchdog/APIMonitor/IsolationTimeoutMS", NULL /* Per-machine */,
480 &g_ulAPIMonIslnTimeoutMS, 30 * 1000 /* Default is 30 seconds timeout. */);
481 g_ulAPIMonIslnTimeoutMS = RT_MIN(1000, g_ulAPIMonIslnTimeoutMS);
482
483 if (g_enmAPIMonIslnResp == APIMON_RESPONSE_NONE) /* Not set by command line? */
484 {
485 Utf8Str strResp;
486 int rc2 = cfgGetValueStr(g_pVirtualBox, NULL /* Machine */,
487 "VBoxInternal2/Watchdog/APIMonitor/IsolationResponse", NULL /* Per-machine */,
488 strResp, "" /* Default value. */);
489 if (RT_SUCCESS(rc2))
490 {
491 rc2 = apimonResponseToEnum(strResp.c_str(), &g_enmAPIMonIslnResp);
492 if (RT_FAILURE(rc2))
493 serviceLog("apimon: Warning: API monitor response string invalid (%ls), defaulting to no action\n",
494 strValue.raw());
495 }
496 }
497
498 if (!g_ulAPIMonResponseTimeoutMS)
499 cfgGetValueULong(g_pVirtualBox, NULL /* Machine */,
500 "VBoxInternal2/Watchdog/APIMonitor/ResponseTimeoutMS", NULL /* Per-machine */,
501 &g_ulAPIMonResponseTimeoutMS, 30 * 1000 /* Default is 30 seconds timeout. */);
502 g_ulAPIMonResponseTimeoutMS = RT_MIN(5000, g_ulAPIMonResponseTimeoutMS);
503
504#ifdef DEBUG
505 /* Groups. */
506 serviceLogVerbose(("apimon: Handling %u groups:", g_vecAPIMonGroups.size()));
507 mapGroupsIterConst itGroups = g_vecAPIMonGroups.begin();
508 while (itGroups != g_vecAPIMonGroups.end())
509 {
510 serviceLogVerbose((" %s", itGroups->first.c_str()));
511 itGroups++;
512 }
513 serviceLogVerbose(("\n"));
514#endif
515
516 } while (0);
517
518 if (SUCCEEDED(rc))
519 {
520 g_uAPIMonIslnLastBeatMS = 0;
521 }
522
523 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_COM_IPRT_ERROR; /* @todo Find a better rc! */
524}
525
526static DECLCALLBACK(int) VBoxModAPIMonitorMain(void)
527{
528 static uint64_t uLastRun = 0;
529 uint64_t uNow = RTTimeProgramMilliTS();
530 uint64_t uDelta = uNow - uLastRun;
531 if (uDelta < 1000) /* Only check every second (or later). */
532 return VINF_SUCCESS;
533 uLastRun = uNow;
534
535 int vrc = VINF_SUCCESS;
536 HRESULT rc;
537
538#ifdef DEBUG
539 serviceLogVerbose(("apimon: Checking for API heartbeat (%RU64ms) ...\n",
540 g_ulAPIMonIslnTimeoutMS));
541#endif
542
543 do
544 {
545 Bstr strHeartbeat;
546 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/Heartbeat").raw(),
547 strHeartbeat.asOutParam()));
548 if ( SUCCEEDED(rc)
549 && !strHeartbeat.isEmpty()
550 && g_strAPIMonIslnLastBeat.compare(strHeartbeat, Bstr::CaseSensitive))
551 {
552 serviceLogVerbose(("apimon: API heartbeat received, resetting timeout\n"));
553
554 g_uAPIMonIslnLastBeatMS = 0;
555 g_strAPIMonIslnLastBeat = strHeartbeat;
556 }
557 else
558 {
559 g_uAPIMonIslnLastBeatMS += uDelta;
560 if (g_uAPIMonIslnLastBeatMS > g_ulAPIMonIslnTimeoutMS)
561 {
562 serviceLogVerbose(("apimon: No API heartbeat within time received (%RU64ms)\n",
563 g_ulAPIMonIslnTimeoutMS));
564
565 vrc = apimonTrigger(g_enmAPIMonIslnResp);
566 g_uAPIMonIslnLastBeatMS = 0;
567 }
568 }
569 } while (0);
570
571 if (FAILED(rc))
572 vrc = VERR_COM_IPRT_ERROR;
573
574 return vrc;
575}
576
577static DECLCALLBACK(int) VBoxModAPIMonitorStop(void)
578{
579 return VINF_SUCCESS;
580}
581
582static DECLCALLBACK(void) VBoxModAPIMonitorTerm(void)
583{
584}
585
586static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineRegistered(const Bstr &strUuid)
587{
588 return VINF_SUCCESS;
589}
590
591static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineUnregistered(const Bstr &strUuid)
592{
593 return VINF_SUCCESS;
594}
595
596static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineStateChanged(const Bstr &strUuid,
597 MachineState_T enmState)
598{
599 return VINF_SUCCESS;
600}
601
602static DECLCALLBACK(int) VBoxModAPIMonitorOnServiceStateChanged(bool fAvailable)
603{
604 if (!fAvailable)
605 {
606 serviceLog(("apimon: VBoxSVC became unavailable, triggering action\n"));
607 return apimonTrigger(g_enmAPIMonIslnResp);
608 }
609 return VINF_SUCCESS;
610}
611
612/**
613 * The 'apimonitor' module description.
614 */
615VBOXMODULE g_ModAPIMonitor =
616{
617 /* pszName. */
618 VBOX_MOD_APIMON_NAME,
619 /* pszDescription. */
620 "API monitor for host isolation detection",
621 /* pszDepends. */
622 NULL,
623 /* uPriority. */
624 0 /* Not used */,
625 /* pszUsage. */
626 " [--apimon-groups=<string[,stringN]>]\n"
627 " [--apimon-isln-response=<cmd>] [--apimon-isln-timeout=<ms>]\n"
628 " [--apimon-resp-timeout=<ms>]",
629 /* pszOptions. */
630 "--apimon-groups Sets the VM groups for monitoring (all),\n"
631 " comma-separated list.\n"
632 "--apimon-isln-response Sets the isolation response to one of:\n"
633 " none, pause, poweroff, save, shutdown\n"
634 " (none).\n"
635 "--apimon-isln-timeout Sets the isolation timeout in ms (30s).\n"
636 "--apimon-resp-timeout Sets the response timeout in ms (30s).\n",
637 /* methods. */
638 VBoxModAPIMonitorPreInit,
639 VBoxModAPIMonitorOption,
640 VBoxModAPIMonitorInit,
641 VBoxModAPIMonitorMain,
642 VBoxModAPIMonitorStop,
643 VBoxModAPIMonitorTerm,
644 /* callbacks. */
645 VBoxModAPIMonitorOnMachineRegistered,
646 VBoxModAPIMonitorOnMachineUnregistered,
647 VBoxModAPIMonitorOnMachineStateChanged,
648 VBoxModAPIMonitorOnServiceStateChanged
649};
650
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette