VirtualBox

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

Last change on this file since 109023 was 107710, checked in by vboxsync, 4 months ago

Frontends/VBoxBalloonCtrl/VBoxModAPIMonitor.cpp: Remove unused variable, bugref:3409

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

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