VirtualBox

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

Last change on this file since 92401 was 91363, checked in by vboxsync, 3 years ago

FE/VBoxSDL+VirtualBox,Main/Console+Machine+VirtualBox.xidl: VMs which
crash while restoring from the 'Saved' state shouldn't lose their saved
state file. bugref:1484

A new machine state named 'AbortedSaved' has been added which a VM will
enter if it crashes when restoring from the 'Saved' state before the
'Running' state has been reached. A VM in the 'AbortedSaved' machine
state will have its saved state file preserved so that the VM can still be
restored once the cause of the failure to powerUp() and reach the
'Running' state has been resolved.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.6 KB
Line 
1/* $Id: VBoxModAPIMonitor.cpp 91363 2021-09-24 13:08:32Z vboxsync $ */
2/** @file
3 * VBoxModAPIMonitor - API monitor module for detecting host isolation.
4 */
5
6/*
7 * Copyright (C) 2012-2020 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 uint32_t g_cMsAPIMonIslnTimeout = 0;
73static Bstr g_strAPIMonIslnLastBeat;
74static uint32_t g_cMsAPIMonResponseTimeout = 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_Teleported:
140 return "teleported";
141 case MachineState_Aborted:
142 return "aborted";
143 case MachineState_AbortedSaved:
144 return "aborted-saved";
145 case MachineState_Running:
146 return "running";
147 case MachineState_Paused:
148 return "paused";
149 case MachineState_Stuck:
150 return fShort ? "gurumeditation" : "guru meditation";
151 case MachineState_LiveSnapshotting:
152 return fShort ? "livesnapshotting" : "live snapshotting";
153 case MachineState_Teleporting:
154 return "teleporting";
155 case MachineState_Starting:
156 return "starting";
157 case MachineState_Stopping:
158 return "stopping";
159 case MachineState_Saving:
160 return "saving";
161 case MachineState_Restoring:
162 return "restoring";
163 case MachineState_TeleportingPausedVM:
164 return fShort ? "teleportingpausedvm" : "teleporting paused vm";
165 case MachineState_TeleportingIn:
166 return fShort ? "teleportingin" : "teleporting (incoming)";
167 case MachineState_RestoringSnapshot:
168 return fShort ? "restoringsnapshot" : "restoring snapshot";
169 case MachineState_DeletingSnapshot:
170 return fShort ? "deletingsnapshot" : "deleting snapshot";
171 case MachineState_DeletingSnapshotOnline:
172 return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
173 case MachineState_DeletingSnapshotPaused:
174 return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
175 case MachineState_SettingUp:
176 return fShort ? "settingup" : "setting up";
177 default:
178 break;
179 }
180 return "unknown";
181}
182
183static int apimonMachineControl(const Bstr &strUuid, PVBOXWATCHDOG_MACHINE pMachine,
184 APIMON_RESPONSE enmResp, uint32_t cMsTimeout)
185{
186 /** @todo Add other commands (with enmResp) here. */
187 AssertPtrReturn(pMachine, VERR_INVALID_POINTER);
188
189 serviceLogVerbose(("apimon: Triggering \"%s\" (%RU32ms timeout) for machine \"%ls\"\n",
190 apimonResponseToStr(enmResp), cMsTimeout, strUuid.raw()));
191
192 if ( enmResp == APIMON_RESPONSE_NONE
193 || g_fDryrun)
194 return VINF_SUCCESS; /* Nothing to do. */
195
196 HRESULT rc;
197 ComPtr <IMachine> machine;
198 CHECK_ERROR_RET(g_pVirtualBox, FindMachine(strUuid.raw(),
199 machine.asOutParam()), VERR_NOT_FOUND);
200 do
201 {
202 /* Query the machine's state to avoid unnecessary IPC. */
203 MachineState_T machineState;
204 CHECK_ERROR_BREAK(machine, COMGETTER(State)(&machineState));
205
206 if ( machineState == MachineState_Running
207 || machineState == MachineState_Paused)
208 {
209 /* Open a session for the VM. */
210 CHECK_ERROR_BREAK(machine, LockMachine(g_pSession, LockType_Shared));
211
212 do
213 {
214 /* Get the associated console. */
215 ComPtr<IConsole> console;
216 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
217 /* Get the associated session machine. */
218 ComPtr<IMachine> sessionMachine;
219 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Machine)(sessionMachine.asOutParam()));
220
221 ComPtr<IProgress> progress;
222
223 switch (enmResp)
224 {
225 case APIMON_RESPONSE_PAUSE:
226 if (machineState != MachineState_Paused)
227 {
228 serviceLogVerbose(("apimon: Pausing machine \"%ls\" ...\n",
229 strUuid.raw()));
230 CHECK_ERROR_BREAK(console, Pause());
231 }
232 break;
233
234 case APIMON_RESPONSE_POWEROFF:
235 serviceLogVerbose(("apimon: Powering off machine \"%ls\" ...\n",
236 strUuid.raw()));
237 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
238 progress->WaitForCompletion(cMsTimeout);
239 CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine \"%ls\"",
240 strUuid.raw()));
241 break;
242
243 case APIMON_RESPONSE_SAVE:
244 {
245 serviceLogVerbose(("apimon: Saving state of machine \"%ls\" ...\n",
246 strUuid.raw()));
247
248 /* First pause so we don't trigger a live save which needs more time/resources. */
249 bool fPaused = false;
250 rc = console->Pause();
251 if (FAILED(rc))
252 {
253 bool fError = true;
254 if (rc == VBOX_E_INVALID_VM_STATE)
255 {
256 /* Check if we are already paused. */
257 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
258 /* The error code was lost by the previous instruction. */
259 rc = VBOX_E_INVALID_VM_STATE;
260 if (machineState != MachineState_Paused)
261 {
262 serviceLog("apimon: Machine \"%ls\" in invalid state %d -- %s\n",
263 strUuid.raw(), machineState, apimonMachineStateToName(machineState, false));
264 }
265 else
266 {
267 fError = false;
268 fPaused = true;
269 }
270 }
271 if (fError)
272 break;
273 }
274
275 CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
276 if (SUCCEEDED(rc))
277 {
278 progress->WaitForCompletion(cMsTimeout);
279 CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state of machine \"%ls\"",
280 strUuid.raw()));
281 }
282
283 if (SUCCEEDED(rc))
284 {
285 serviceLogVerbose(("apimon: State of machine \"%ls\" saved, powering off ...\n", strUuid.raw()));
286 CHECK_ERROR_BREAK(console, PowerButton());
287 }
288 else
289 serviceLogVerbose(("apimon: Saving state of machine \"%ls\" failed\n", strUuid.raw()));
290
291 break;
292 }
293
294 case APIMON_RESPONSE_SHUTDOWN:
295 serviceLogVerbose(("apimon: Shutting down machine \"%ls\" ...\n", strUuid.raw()));
296 CHECK_ERROR_BREAK(console, PowerButton());
297 break;
298
299 default:
300 AssertMsgFailed(("Response %d not implemented", enmResp));
301 break;
302 }
303 } while (0);
304
305 /* Unlock the machine again. */
306 g_pSession->UnlockMachine();
307 }
308 else
309 serviceLogVerbose(("apimon: Warning: Could not trigger \"%s\" (%d) for machine \"%ls\"; in state \"%s\" (%d) currently\n",
310 apimonResponseToStr(enmResp), enmResp, strUuid.raw(),
311 apimonMachineStateToName(machineState, false), machineState));
312 } while (0);
313
314
315
316 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_COM_IPRT_ERROR;
317}
318
319static bool apimonHandleVM(const PVBOXWATCHDOG_MACHINE pMachine)
320{
321 bool fHandleVM = false;
322
323 try
324 {
325 mapGroupsIterConst itVMGroup = pMachine->groups.begin();
326 while ( itVMGroup != pMachine->groups.end()
327 && !fHandleVM)
328 {
329 mapGroupsIterConst itInGroup = g_vecAPIMonGroups.find(itVMGroup->first);
330 if (itInGroup != g_vecAPIMonGroups.end())
331 fHandleVM = true;
332
333 ++itVMGroup;
334 }
335 }
336 catch (...)
337 {
338 AssertFailed();
339 }
340
341 return fHandleVM;
342}
343
344static int apimonTrigger(APIMON_RESPONSE enmResp)
345{
346 int rc = VINF_SUCCESS;
347
348 bool fAllGroups = g_vecAPIMonGroups.empty();
349 mapVMIter it = g_mapVM.begin();
350
351 if (it == g_mapVM.end())
352 {
353 serviceLog("apimon: No machines in list, skipping ...\n");
354 return rc;
355 }
356
357 while (it != g_mapVM.end())
358 {
359 bool fHandleVM = fAllGroups;
360 try
361 {
362 if (!fHandleVM)
363 fHandleVM = apimonHandleVM(&it->second);
364
365 if (fHandleVM)
366 {
367 int rc2 = apimonMachineControl(it->first /* Uuid */,
368 &it->second /* Machine */, enmResp, g_cMsAPIMonResponseTimeout);
369 if (RT_FAILURE(rc2))
370 serviceLog("apimon: Controlling machine \"%ls\" (response \"%s\") failed with rc=%Rrc",
371 it->first.raw(), apimonResponseToStr(enmResp), rc);
372
373 if (RT_SUCCESS(rc))
374 rc = rc2; /* Store original error. */
375 /* Keep going. */
376 }
377 }
378 catch (...)
379 {
380 AssertFailed();
381 }
382
383 ++it;
384 }
385
386 return rc;
387}
388
389/* Callbacks. */
390static DECLCALLBACK(int) VBoxModAPIMonitorPreInit(void)
391{
392 return VINF_SUCCESS;
393}
394
395static DECLCALLBACK(int) VBoxModAPIMonitorOption(int argc, char *argv[], int *piConsumed)
396{
397 if (!argc) /* Take a shortcut. */
398 return -1;
399
400 AssertPtrReturn(argv, VERR_INVALID_POINTER);
401 AssertPtrReturn(piConsumed, VERR_INVALID_POINTER);
402
403 RTGETOPTSTATE GetState;
404 int rc = RTGetOptInit(&GetState, argc, argv,
405 g_aAPIMonitorOpts, RT_ELEMENTS(g_aAPIMonitorOpts),
406 0 /* First */, 0 /*fFlags*/);
407 if (RT_FAILURE(rc))
408 return rc;
409
410 rc = 0; /* Set default parsing result to valid. */
411
412 int c;
413 RTGETOPTUNION ValueUnion;
414 while ((c = RTGetOpt(&GetState, &ValueUnion)))
415 {
416 switch (c)
417 {
418 case GETOPTDEF_APIMON_GROUPS:
419 {
420 rc = groupAdd(g_vecAPIMonGroups, ValueUnion.psz, 0 /* Flags */);
421 if (RT_FAILURE(rc))
422 rc = -1; /* Option unknown. */
423 break;
424 }
425
426 case GETOPTDEF_APIMON_ISLN_RESPONSE:
427 rc = apimonResponseToEnum(ValueUnion.psz, &g_enmAPIMonIslnResp);
428 if (RT_FAILURE(rc))
429 rc = -1; /* Option unknown. */
430 break;
431
432 case GETOPTDEF_APIMON_ISLN_TIMEOUT:
433 g_cMsAPIMonIslnTimeout = ValueUnion.u32;
434 if (g_cMsAPIMonIslnTimeout < 1000) /* Don't allow timeouts < 1s. */
435 g_cMsAPIMonIslnTimeout = 1000;
436 break;
437
438 case GETOPTDEF_APIMON_RESP_TIMEOUT:
439 g_cMsAPIMonResponseTimeout = ValueUnion.u32;
440 if (g_cMsAPIMonResponseTimeout < 5000) /* Don't allow timeouts < 5s. */
441 g_cMsAPIMonResponseTimeout = 5000;
442 break;
443
444 default:
445 rc = -1; /* We don't handle this option, skip. */
446 break;
447 }
448
449 /* At the moment we only process one option at a time. */
450 break;
451 }
452
453 *piConsumed += GetState.iNext - 1;
454
455 return rc;
456}
457
458static DECLCALLBACK(int) VBoxModAPIMonitorInit(void)
459{
460 HRESULT rc = S_OK;
461
462 do
463 {
464 Bstr strValue;
465
466 /* VM groups to watch for. */
467 if (g_vecAPIMonGroups.empty()) /* Not set by command line? */
468 {
469 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("VBoxInternal2/Watchdog/APIMonitor/Groups").raw(),
470 strValue.asOutParam()));
471 if (!strValue.isEmpty())
472 {
473 int rc2 = groupAdd(g_vecAPIMonGroups, Utf8Str(strValue).c_str(), 0 /* Flags */);
474 if (RT_FAILURE(rc2))
475 serviceLog("apimon: Warning: API monitor groups string invalid (%ls)\n", strValue.raw());
476 }
477 }
478
479 if (!g_cMsAPIMonIslnTimeout)
480 cfgGetValueU32(g_pVirtualBox, NULL /* Machine */,
481 "VBoxInternal2/Watchdog/APIMonitor/IsolationTimeoutMS", NULL /* Per-machine */,
482 &g_cMsAPIMonIslnTimeout, 30 * 1000 /* Default is 30 seconds timeout. */);
483 g_cMsAPIMonIslnTimeout = RT_MIN(1000, g_cMsAPIMonIslnTimeout);
484
485 if (g_enmAPIMonIslnResp == APIMON_RESPONSE_NONE) /* Not set by command line? */
486 {
487 Utf8Str strResp;
488 int rc2 = cfgGetValueStr(g_pVirtualBox, NULL /* Machine */,
489 "VBoxInternal2/Watchdog/APIMonitor/IsolationResponse", NULL /* Per-machine */,
490 strResp, "" /* Default value. */);
491 if (RT_SUCCESS(rc2))
492 {
493 rc2 = apimonResponseToEnum(strResp.c_str(), &g_enmAPIMonIslnResp);
494 if (RT_FAILURE(rc2))
495 serviceLog("apimon: Warning: API monitor response string invalid (%ls), defaulting to no action\n",
496 strValue.raw());
497 }
498 }
499
500 if (!g_cMsAPIMonResponseTimeout)
501 cfgGetValueU32(g_pVirtualBox, NULL /* Machine */,
502 "VBoxInternal2/Watchdog/APIMonitor/ResponseTimeoutMS", NULL /* Per-machine */,
503 &g_cMsAPIMonResponseTimeout, 30 * 1000 /* Default is 30 seconds timeout. */);
504 g_cMsAPIMonResponseTimeout = RT_MIN(5000, g_cMsAPIMonResponseTimeout);
505
506#ifdef DEBUG
507 /* Groups. */
508 serviceLogVerbose(("apimon: Handling %u groups:", g_vecAPIMonGroups.size()));
509 mapGroupsIterConst itGroups = g_vecAPIMonGroups.begin();
510 while (itGroups != g_vecAPIMonGroups.end())
511 {
512 serviceLogVerbose((" %s", itGroups->first.c_str()));
513 ++itGroups;
514 }
515 serviceLogVerbose(("\n"));
516#endif
517
518 } while (0);
519
520 if (SUCCEEDED(rc))
521 {
522 g_uAPIMonIslnLastBeatMS = 0;
523 }
524
525 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_COM_IPRT_ERROR; /** @todo Find a better rc! */
526}
527
528static DECLCALLBACK(int) VBoxModAPIMonitorMain(void)
529{
530 static uint64_t uLastRun = 0;
531 uint64_t uNow = RTTimeProgramMilliTS();
532 uint64_t uDelta = uNow - uLastRun;
533 if (uDelta < 1000) /* Only check every second (or later). */
534 return VINF_SUCCESS;
535 uLastRun = uNow;
536
537 int vrc = VINF_SUCCESS;
538 HRESULT rc;
539
540#ifdef DEBUG
541 serviceLogVerbose(("apimon: Checking for API heartbeat (%RU64ms) ...\n",
542 g_cMsAPIMonIslnTimeout));
543#endif
544
545 do
546 {
547 Bstr strHeartbeat;
548 CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/Heartbeat").raw(),
549 strHeartbeat.asOutParam()));
550 if ( SUCCEEDED(rc)
551 && !strHeartbeat.isEmpty()
552 && g_strAPIMonIslnLastBeat.compare(strHeartbeat, Bstr::CaseSensitive))
553 {
554 serviceLogVerbose(("apimon: API heartbeat received, resetting timeout\n"));
555
556 g_uAPIMonIslnLastBeatMS = 0;
557 g_strAPIMonIslnLastBeat = strHeartbeat;
558 }
559 else
560 {
561 g_uAPIMonIslnLastBeatMS += uDelta;
562 if (g_uAPIMonIslnLastBeatMS > g_cMsAPIMonIslnTimeout)
563 {
564 serviceLogVerbose(("apimon: No API heartbeat within time received (%RU64ms)\n",
565 g_cMsAPIMonIslnTimeout));
566
567 vrc = apimonTrigger(g_enmAPIMonIslnResp);
568 g_uAPIMonIslnLastBeatMS = 0;
569 }
570 }
571 } while (0);
572
573 if (FAILED(rc))
574 vrc = VERR_COM_IPRT_ERROR;
575
576 return vrc;
577}
578
579static DECLCALLBACK(int) VBoxModAPIMonitorStop(void)
580{
581 return VINF_SUCCESS;
582}
583
584static DECLCALLBACK(void) VBoxModAPIMonitorTerm(void)
585{
586}
587
588static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineRegistered(const Bstr &strUuid)
589{
590 RT_NOREF(strUuid);
591 return VINF_SUCCESS;
592}
593
594static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineUnregistered(const Bstr &strUuid)
595{
596 RT_NOREF(strUuid);
597 return VINF_SUCCESS;
598}
599
600static DECLCALLBACK(int) VBoxModAPIMonitorOnMachineStateChanged(const Bstr &strUuid, MachineState_T enmState)
601{
602 RT_NOREF(strUuid, enmState);
603 return VINF_SUCCESS;
604}
605
606static DECLCALLBACK(int) VBoxModAPIMonitorOnServiceStateChanged(bool fAvailable)
607{
608 if (!fAvailable)
609 {
610 serviceLog(("apimon: VBoxSVC became unavailable, triggering action\n"));
611 return apimonTrigger(g_enmAPIMonIslnResp);
612 }
613 return VINF_SUCCESS;
614}
615
616/**
617 * The 'apimonitor' module description.
618 */
619VBOXMODULE g_ModAPIMonitor =
620{
621 /* pszName. */
622 VBOX_MOD_APIMON_NAME,
623 /* pszDescription. */
624 "API monitor for host isolation detection",
625 /* pszDepends. */
626 NULL,
627 /* uPriority. */
628 0 /* Not used */,
629 /* pszUsage. */
630 " [--apimon-groups=<string[,stringN]>]\n"
631 " [--apimon-isln-response=<cmd>] [--apimon-isln-timeout=<ms>]\n"
632 " [--apimon-resp-timeout=<ms>]",
633 /* pszOptions. */
634 " --apimon-groups=<string[,...]>\n"
635 " Sets the VM groups for monitoring (all), comma-separated list.\n"
636 " --apimon-isln-response=<cmd>\n"
637 " Sets the isolation response to one of: none, pause, poweroff,\n"
638 " save, or shutdown. Default: none\n"
639 " --apimon-isln-timeout=<ms>\n"
640 " Sets the isolation timeout in ms (30s).\n"
641 " --apimon-resp-timeout=<ms>\n"
642 " Sets the response timeout in ms (30s).\n",
643 /* methods. */
644 VBoxModAPIMonitorPreInit,
645 VBoxModAPIMonitorOption,
646 VBoxModAPIMonitorInit,
647 VBoxModAPIMonitorMain,
648 VBoxModAPIMonitorStop,
649 VBoxModAPIMonitorTerm,
650 /* callbacks. */
651 VBoxModAPIMonitorOnMachineRegistered,
652 VBoxModAPIMonitorOnMachineUnregistered,
653 VBoxModAPIMonitorOnMachineStateChanged,
654 VBoxModAPIMonitorOnServiceStateChanged
655};
656
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