VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/guestcontrol/VBoxGuestControlHelper.cpp@ 104620

Last change on this file since 104620 was 104375, checked in by vboxsync, 7 months ago

Validation Kit/VBoxGuestControlHelper: export to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1/* $Id: VBoxGuestControlHelper.cpp 104375 2024-04-19 12:47:54Z vboxsync $ */
2/** @file
3 * Helper binary for Guest Control tests.
4 */
5
6/*
7 * Copyright (C) 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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/buildconfig.h>
42#include <iprt/ctype.h>
43#include <iprt/errcore.h>
44#include <iprt/initterm.h>
45#include <iprt/getopt.h>
46#include <iprt/ldr.h>
47#include <iprt/mem.h>
48#include <iprt/message.h>
49#include <iprt/process.h>
50#include <iprt/stream.h>
51#include <iprt/string.h>
52#include <iprt/test.h>
53#ifdef RT_OS_WINDOWS
54# include <iprt/win/windows.h>
55#endif
56
57#include <package-generated.h>
58#include "product-generated.h"
59
60#include <VBox/version.h>
61#include <VBox/log.h>
62
63
64
65/*********************************************************************************************************************************
66* Structures and Typedefs *
67*********************************************************************************************************************************/
68#ifdef RT_OS_WINDOWS
69 /* kernel32.dll: */
70 typedef BOOL (WINAPI *PFNPROCESSIDTOSESSIONID)(DWORD, DWORD *);
71
72 /* kernel32.dll: */
73 static PFNPROCESSIDTOSESSIONID g_pfnProcessIdToSessionId = NULL;
74#endif
75
76
77/*********************************************************************************************************************************
78* Global Variables *
79*********************************************************************************************************************************/
80
81/**
82 * Guest Control test helper command table entry.
83 */
84typedef struct GSTCTLHLPCMD
85{
86 /** The command name. */
87 const char *pszCommand;
88 /** The command handler. */
89 DECLCALLBACKMEMBER(RTEXITCODE, pfnHandler,(PRTGETOPTSTATE pGetState));
90
91 /** Command description. */
92 const char *pszDesc;
93 /** Options array. */
94 PCRTGETOPTDEF paOptions;
95 /** Number of options in the option array. */
96 size_t cOptions;
97 /** Gets help for an option. */
98 DECLCALLBACKMEMBER(const char *, pfnOptionHelp,(PCRTGETOPTDEF pOpt));
99} GSTCTLHLPCMD;
100/** Pointer to a const GSTCTLHLPCMD command entry. */
101typedef GSTCTLHLPCMD const *PCGSTCTLHLPCMD;
102
103/**
104 * Long option values for the 'show' command.
105 */
106enum
107{
108 GSTCTLHLP_SHOW_OPT_VERSION = 900,
109 GSTCTLHLP_SHOW_OPT_WIN_SESSION_ID
110};
111
112/**
113 * Command line parameters for test mode.
114 */
115static const RTGETOPTDEF g_aCmdShowOptions[] =
116{
117 { "version", GSTCTLHLP_SHOW_OPT_VERSION, RTGETOPT_REQ_NOTHING },
118#ifdef RT_OS_WINDOWS
119 { "win-session-id", GSTCTLHLP_SHOW_OPT_WIN_SESSION_ID, RTGETOPT_REQ_NOTHING },
120#endif
121};
122
123/**
124 * Shows tool version.
125 */
126static RTEXITCODE gstCtlHlpVersion(void)
127{
128 RTPrintf("%s\n", RTBldCfgRevisionStr());
129 return RTEXITCODE_SUCCESS;
130}
131
132#ifdef RT_OS_WINDOWS
133/**
134 * Resolves impports for Windows platforms.
135 */
136static void gstCtlHlpWinResolveImports(void)
137{
138 RTLDRMOD hLdrMod;
139
140 /* kernel32: */
141 int rc = RTLdrLoadSystem("kernel32.dll", true /*fNoUnload*/, &hLdrMod);
142 if (RT_SUCCESS(rc))
143 RTLdrGetSymbol(hLdrMod, "ProcessIdToSessionId", (void **)&g_pfnProcessIdToSessionId);
144}
145
146/**
147 * Shows the Windows session ID.
148 *
149 * @returns 1000 + "session ID" on success as exit code.
150 * @returns RTEXITCODE on failure.
151 */
152static DECLCALLBACK(RTEXITCODE) gstCtlHlpCmdShowWinSessionId(void)
153{
154 DWORD dwSessionId = 0;
155 if (g_pfnProcessIdToSessionId)
156 {
157 if (g_pfnProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId))
158 {
159 RTPrintf("Session ID: %ld\n", dwSessionId);
160 return RTEXITCODE(1000 + dwSessionId);
161 }
162 else
163 {
164 DWORD const dwErr = GetLastError();
165 RTMsgError("Getting session ID failed: %Rrc (%#x)\n", RTErrConvertFromWin32(dwErr), dwErr);
166 }
167 }
168 else
169 RTMsgError("Getting session ID not available on this OS\n");
170
171 return RTEXITCODE_FAILURE;
172}
173#endif /* RT_OS_WINDOWS */
174
175/**
176 * Handles the "show" command.
177 *
178 * @returns RTEXITCODE
179 * @param pGetState GetOpt state to use.
180 */
181static DECLCALLBACK(RTEXITCODE) gstCtlHlpCmdShow(PRTGETOPTSTATE pGetState)
182{
183 int ch;
184 RTGETOPTUNION ValueUnion;
185 while ((ch = RTGetOpt(pGetState, &ValueUnion)))
186 {
187 switch (ch)
188 {
189 case GSTCTLHLP_SHOW_OPT_VERSION:
190 return gstCtlHlpVersion();
191#ifdef RT_OS_WINDOWS
192 case GSTCTLHLP_SHOW_OPT_WIN_SESSION_ID:
193 return gstCtlHlpCmdShowWinSessionId();
194#endif /* RT_OS_WINDOWS */
195
196 default:
197 return RTGetOptPrintError(ch, &ValueUnion);
198 }
199 }
200
201 return RTEXITCODE_SUCCESS;
202}
203
204/**
205 * Option help for the 'show' command.
206 *
207 * @returns Help text if found, or NULL if not found.
208 * @param pOpt GetOpt definition to return help text for.
209 */
210static DECLCALLBACK(const char *) gstCtlHlpCmdShowHelp(PCRTGETOPTDEF pOpt)
211{
212 switch (pOpt->iShort)
213 {
214 case GSTCTLHLP_SHOW_OPT_VERSION: return "Shows the program version.\n";
215#ifdef RT_OS_WINDOWS
216 case GSTCTLHLP_SHOW_OPT_WIN_SESSION_ID: return "Shows this process Windows session ID.\n"
217 " Exit code is 1000 + <session ID>.";
218#endif
219 default:
220 break;
221 }
222 return NULL;
223}
224
225/**
226 * Option defintions for the 'show' command.
227 */
228const GSTCTLHLPCMD g_CmdShow =
229{
230 "show",
231 gstCtlHlpCmdShow,
232 "Shows various information and exits.",
233 g_aCmdShowOptions,
234 RT_ELEMENTS(g_aCmdShowOptions),
235 gstCtlHlpCmdShowHelp
236};
237
238/**
239 * Commands.
240 */
241static const GSTCTLHLPCMD * const g_apCommands[] =
242{
243 &g_CmdShow
244};
245
246/**
247 * Shows tool usage text.
248 */
249static RTEXITCODE gstCtlHlpUsage(PRTSTREAM pStrm, PCGSTCTLHLPCMD pOnlyCmd)
250{
251 RTStrmPrintf(pStrm, "usage: %s [global options] <command> [command-options]\n", RTProcShortName());
252 RTStrmPrintf(pStrm,
253 "\n"
254 "Global Options:\n"
255 " -V, --version\n"
256 " Displays version\n"
257 " -h, -?, --help\n"
258 " Displays help\n"
259 );
260
261 for (uintptr_t iCmd = 0; iCmd < RT_ELEMENTS(g_apCommands); iCmd++)
262 {
263 PCGSTCTLHLPCMD const pCmd = g_apCommands[iCmd];
264 if (!pOnlyCmd || pCmd == pOnlyCmd)
265 {
266 RTStrmPrintf(pStrm,
267 "\n"
268 "Command '%s':\n"
269 " %s\n"
270 "Options for '%s':\n",
271 pCmd->pszCommand, pCmd->pszDesc, pCmd->pszCommand);
272 PCRTGETOPTDEF const paOptions = pCmd->paOptions;
273 for (unsigned i = 0; i < pCmd->cOptions; i++)
274 {
275 if (RT_C_IS_PRINT(paOptions[i].iShort))
276 RTStrmPrintf(pStrm, " -%c, %s\n", paOptions[i].iShort, paOptions[i].pszLong);
277 else
278 RTStrmPrintf(pStrm, " %s\n", paOptions[i].pszLong);
279
280 const char *pszHelp = NULL;
281 if (pCmd->pfnOptionHelp)
282 pszHelp = pCmd->pfnOptionHelp(&paOptions[i]);
283 if (pszHelp)
284 RTStrmPrintf(pStrm, " %s\n", pszHelp);
285 }
286 }
287 }
288
289 return RTEXITCODE_SUCCESS;
290}
291
292/**
293 * Lists the commands and their descriptions.
294 */
295static RTEXITCODE gstCtlHlplLstCommands(PRTSTREAM pStrm)
296{
297 RTStrmPrintf(pStrm, "Commands:\n");
298 for (uintptr_t iCmd = 0; iCmd < RT_ELEMENTS(g_apCommands); iCmd++)
299 RTStrmPrintf(pStrm, "%8s - %s\n", g_apCommands[iCmd]->pszCommand, g_apCommands[iCmd]->pszDesc);
300 return RTEXITCODE_SUCCESS;
301}
302
303/**
304 * Common command line parameters.
305 */
306static const RTGETOPTDEF g_aCmdCommonOptions[] =
307{
308 { "--help", 'h', RTGETOPT_REQ_NOTHING },
309 { "--version", 'V', RTGETOPT_REQ_NOTHING }
310};
311
312int main(int argc, char **argv)
313{
314 /*
315 * Init IPRT.
316 */
317 int rc = RTR3InitExe(argc, &argv, 0);
318 if (RT_FAILURE(rc))
319 return RTMsgInitFailure(rc);
320
321 RTGETOPTSTATE GetState;
322 rc = RTGetOptInit(&GetState, argc, argv, g_aCmdCommonOptions,
323 RT_ELEMENTS(g_aCmdCommonOptions), 1 /*idxFirst*/, 0 /*fFlags - must not sort! */);
324 AssertRCReturn(rc, RTEXITCODE_INIT);
325
326#ifdef RT_OS_WINDOWS
327 gstCtlHlpWinResolveImports();
328#endif
329
330 int ch;
331 RTGETOPTUNION ValueUnion;
332 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
333 {
334 switch (ch)
335 {
336 case 'V':
337 return gstCtlHlpVersion();
338
339 case 'h':
340 return gstCtlHlpUsage(g_pStdOut, NULL);
341
342 case VINF_GETOPT_NOT_OPTION:
343 {
344 for (uintptr_t iCmd = 0; iCmd < RT_ELEMENTS(g_apCommands); iCmd++)
345 {
346 PCGSTCTLHLPCMD const pCmd = g_apCommands[iCmd];
347 if (strcmp(ValueUnion.psz, pCmd->pszCommand) == 0)
348 {
349 /* Count the combined option definitions: */
350 size_t cCombinedOptions = pCmd->cOptions;
351
352 /* Combine the option definitions: */
353 PRTGETOPTDEF paCombinedOptions = (PRTGETOPTDEF)RTMemAlloc(cCombinedOptions * sizeof(RTGETOPTDEF));
354 if (paCombinedOptions)
355 {
356 uint32_t idxOpts = 0;
357
358 memcpy(&paCombinedOptions[idxOpts], pCmd->paOptions, pCmd->cOptions * sizeof(RTGETOPTDEF));
359 idxOpts += (uint32_t)pCmd->cOptions;
360
361 /* Re-initialize the option getter state and pass it to the command handler. */
362 rc = RTGetOptInit(&GetState, argc, argv, paCombinedOptions, cCombinedOptions,
363 GetState.iNext /*idxFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
364 if (RT_SUCCESS(rc))
365 {
366 RTEXITCODE rcExit = pCmd->pfnHandler(&GetState);
367 RTMemFree(paCombinedOptions);
368 return rcExit;
369 }
370 RTMemFree(paCombinedOptions);
371 return RTMsgErrorExitFailure("RTGetOptInit failed for '%s': %Rrc", ValueUnion.psz, rc);
372 }
373 return RTMsgErrorExitFailure("Out of memory!");
374 }
375 }
376 RTMsgError("Unknown command '%s'!\n", ValueUnion.psz);
377 gstCtlHlplLstCommands(g_pStdErr);
378 break;
379 }
380
381 default:
382 return RTGetOptPrintError(ch, &ValueUnion);
383 }
384 }
385
386 RTMsgInfo("No command given. Try '%s --help'.\n", RTProcShortName());
387 return RTEXITCODE_SUCCESS;
388}
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