VirtualBox

source: vbox/trunk/src/VBox/GuestHost/installation/VBoxDrvInst.cpp@ 108445

最後變更 在這個檔案從108445是 108445,由 vboxsync 提交於 10 天 前

Windows driver installation/VBoxDrvInst: Implemented 'uninstall host' sub command to uninstall all VBox-related host drivers. bugref:10762

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 43.0 KB
 
1/* $Id: VBoxDrvInst.cpp 108445 2025-03-05 08:14:04Z vboxsync $ */
2/** @file
3 * Driver installation utility for Windows hosts and guests.
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.alldomusa.eu.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#include <iprt/buildconfig.h>
33#include <iprt/ctype.h>
34#include <iprt/cpp/ministring.h> /* For replacement fun. */
35#include <iprt/env.h>
36#include <iprt/getopt.h>
37#include <iprt/initterm.h>
38#include <iprt/message.h>
39#include <iprt/path.h>
40#include <iprt/types.h>
41#include <iprt/process.h> /* For RTProcShortName(). */
42#include <iprt/stream.h>
43#include <iprt/string.h>
44#include <iprt/system.h>
45#include <iprt/test.h>
46#include <iprt/utf16.h>
47#include <iprt/win/windows.h>
48
49#include <package-generated.h>
50#include "product-generated.h"
51
52#include <VBox/version.h>
53#include <VBox/log.h>
54
55#include <VBox/err.h>
56
57#include <VBox/GuestHost/VBoxWinDrvInst.h>
58#include <VBox/GuestHost/VBoxWinDrvStore.h>
59
60
61/*********************************************************************************************************************************
62* Prototypes *
63*********************************************************************************************************************************/
64static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdListMain(PRTGETOPTSTATE pGetState);
65static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdInstallMain(PRTGETOPTSTATE pGetState);
66static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdUninstallMain(PRTGETOPTSTATE pGetState);
67static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdServiceMain(PRTGETOPTSTATE pGetState);
68
69static DECLCALLBACK(const char *) vboxDrvInstCmdListHelp(PCRTGETOPTDEF pOpt);
70static DECLCALLBACK(const char *) vboxDrvInstCmdInstallHelp(PCRTGETOPTDEF pOpt);
71static DECLCALLBACK(const char *) vboxDrvInstCmdUninstallHelp(PCRTGETOPTDEF pOpt);
72static DECLCALLBACK(const char *) vboxDrvInstCmdServiceHelp(PCRTGETOPTDEF pOpt);
73
74struct VBOXDRVINSTCMD;
75static RTEXITCODE vboxDrvInstShowUsage(PRTSTREAM pStrm, VBOXDRVINSTCMD const *pOnlyCmd);
76
77
78/*********************************************************************************************************************************
79* Global Variables *
80*********************************************************************************************************************************/
81/** Verbosity level. */
82static unsigned g_uVerbosity = 0;
83static PRTLOGGER g_pLoggerRelease = NULL;
84static char g_szLogFile[RTPATH_MAX];
85static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */
86static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */
87static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */
88
89
90/*********************************************************************************************************************************
91* Definitions *
92*********************************************************************************************************************************/
93typedef enum VBOXDRVINSTEXITCODE
94{
95 /** A reboot is needed in order to complete the (un)installation. */
96 VBOXDRVINSTEXITCODE_REBOOT_NEEDED = RTEXITCODE_END
97} VBOXDRVINSTEXITCODE;
98
99/**
100 * Driver installation command table entry.
101 */
102typedef struct VBOXDRVINSTCMD
103{
104 /** The command name. */
105 const char *pszCommand;
106 /** The command handler. */
107 DECLCALLBACKMEMBER(RTEXITCODE, pfnHandler,(PRTGETOPTSTATE pGetState));
108
109 /** Command description. */
110 const char *pszDesc;
111 /** Options array. */
112 PCRTGETOPTDEF paOptions;
113 /** Number of options in the option array. */
114 size_t cOptions;
115 /** Gets help for an option. */
116 DECLCALLBACKMEMBER(const char *, pfnOptionHelp,(PCRTGETOPTDEF pOpt));
117} VBOXDRVINSTCMD;
118/** Pointer to a const VBOXDRVINSTCMD entry. */
119typedef VBOXDRVINSTCMD const *PCVBOXDRVINSTCMD;
120
121/**
122 * Command definition for the 'list' command.
123 */
124const VBOXDRVINSTCMD g_CmdList =
125{
126 "list",
127 vboxDrvInstCmdListMain,
128 "Lists installed drivers.",
129 NULL, /* paOptions */
130 0, /* cOptions */
131 vboxDrvInstCmdListHelp
132};
133
134/**
135 * Long option values for the 'install' command.
136 */
137enum
138{
139 VBOXDRVINST_INSTALL_OPT_INF_FILE = 900,
140 VBOXDRVINST_INSTALL_OPT_INF_SECTION,
141 VBOXDRVINST_INSTALL_OPT_MODEL,
142 VBOXDRVINST_INSTALL_OPT_PNPID,
143 VBOXDRVINST_INSTALL_OPT_NOT_FORCE,
144 VBOXDRVINST_INSTALL_OPT_NOT_SILENT,
145 VBOXDRVINST_INSTALL_OPT_IGNORE_REBOOT,
146 VBOXDRVINST_INSTALL_OPT_DEBUG_OS_VER
147};
148
149/**
150 * Command line parameters for the 'install' command.
151 */
152static const RTGETOPTDEF g_aCmdInstallOptions[] =
153{
154 { "--inf-file", VBOXDRVINST_INSTALL_OPT_INF_FILE, RTGETOPT_REQ_STRING },
155 { "--inf-section", VBOXDRVINST_INSTALL_OPT_INF_SECTION, RTGETOPT_REQ_STRING },
156 { "--model", VBOXDRVINST_INSTALL_OPT_MODEL, RTGETOPT_REQ_STRING },
157 { "--pnp", VBOXDRVINST_INSTALL_OPT_PNPID, RTGETOPT_REQ_STRING },
158 { "--pnpid" , VBOXDRVINST_INSTALL_OPT_PNPID, RTGETOPT_REQ_STRING },
159 { "--pnp-id", VBOXDRVINST_INSTALL_OPT_PNPID, RTGETOPT_REQ_STRING },
160 { "--not-force", VBOXDRVINST_INSTALL_OPT_NOT_FORCE, RTGETOPT_REQ_NOTHING },
161 { "--not-silent", VBOXDRVINST_INSTALL_OPT_NOT_SILENT, RTGETOPT_REQ_NOTHING },
162 { "--ignore-reboot", VBOXDRVINST_INSTALL_OPT_IGNORE_REBOOT, RTGETOPT_REQ_NOTHING },
163 { "--debug-os-ver", VBOXDRVINST_INSTALL_OPT_DEBUG_OS_VER, RTGETOPT_REQ_UINT32_PAIR }
164};
165
166/**
167 * Command definition for the 'install' command.
168 */
169const VBOXDRVINSTCMD g_CmdInstall =
170{
171 "install",
172 vboxDrvInstCmdInstallMain,
173 "Installs a driver.",
174 g_aCmdInstallOptions,
175 RT_ELEMENTS(g_aCmdInstallOptions),
176 vboxDrvInstCmdInstallHelp
177};
178
179/**
180 * Long option values for the 'uninstall' command.
181 */
182enum
183{
184 VBOXDRVINST_UNINSTALL_OPT_HOST = 900,
185 VBOXDRVINST_UNINSTALL_OPT_INF_FILE,
186 VBOXDRVINST_UNINSTALL_OPT_INF_SECTION,
187 VBOXDRVINST_UNINSTALL_OPT_MODEL,
188 VBOXDRVINST_UNINSTALL_OPT_PNPID,
189 VBOXDRVINST_UNINSTALL_OPT_FORCE,
190 VBOXDRVINST_UNINSTALL_OPT_NOT_SILENT,
191 VBOXDRVINST_UNINSTALL_OPT_IGNORE_REBOOT
192};
193
194/**
195 * Command line parameters for the 'uninstall' command.
196 */
197static const RTGETOPTDEF g_aCmdUninstallOptions[] =
198{
199 /* Sub commands. */
200 { "host", VBOXDRVINST_UNINSTALL_OPT_HOST, RTGETOPT_REQ_NOTHING },
201 /* Parameters. */
202 { "--inf-file", VBOXDRVINST_UNINSTALL_OPT_INF_FILE, RTGETOPT_REQ_STRING },
203 { "--inf-section", VBOXDRVINST_UNINSTALL_OPT_INF_SECTION, RTGETOPT_REQ_STRING },
204 { "--model", VBOXDRVINST_UNINSTALL_OPT_MODEL, RTGETOPT_REQ_STRING },
205 { "--pnp", VBOXDRVINST_UNINSTALL_OPT_PNPID, RTGETOPT_REQ_STRING },
206 { "--pnpid" , VBOXDRVINST_UNINSTALL_OPT_PNPID, RTGETOPT_REQ_STRING },
207 { "--pnp-id", VBOXDRVINST_UNINSTALL_OPT_PNPID, RTGETOPT_REQ_STRING },
208 { "--force", VBOXDRVINST_UNINSTALL_OPT_FORCE, RTGETOPT_REQ_NOTHING },
209 { "--not-silent", VBOXDRVINST_UNINSTALL_OPT_NOT_SILENT, RTGETOPT_REQ_NOTHING },
210 { "--ignore-reboot", VBOXDRVINST_UNINSTALL_OPT_IGNORE_REBOOT, RTGETOPT_REQ_NOTHING }
211};
212
213/**
214 * Command definition for the 'uninstall' command.
215 */
216const VBOXDRVINSTCMD g_CmdUninstall =
217{
218 "uninstall",
219 vboxDrvInstCmdUninstallMain,
220 "Uninstalls drivers.",
221 g_aCmdUninstallOptions,
222 RT_ELEMENTS(g_aCmdUninstallOptions),
223 vboxDrvInstCmdUninstallHelp
224};
225
226/**
227 * Long option values for the 'service' command.
228 */
229enum
230{
231 VBOXDRVINST_SERVICE_OPT_START = 900,
232 VBOXDRVINST_SERVICE_OPT_STOP,
233 VBOXDRVINST_SERVICE_OPT_RESTART,
234 VBOXDRVINST_SERVICE_OPT_WAIT,
235 VBOXDRVINST_SERVICE_OPT_NO_WAIT
236};
237
238/**
239 * Command line parameters for the 'service' command.
240 */
241static const RTGETOPTDEF g_aCmdServiceOptions[] =
242{
243 { "start", VBOXDRVINST_SERVICE_OPT_START, RTGETOPT_REQ_NOTHING },
244 { "stop", VBOXDRVINST_SERVICE_OPT_STOP, RTGETOPT_REQ_NOTHING },
245 { "restart", VBOXDRVINST_SERVICE_OPT_RESTART, RTGETOPT_REQ_NOTHING },
246 { "--wait", VBOXDRVINST_SERVICE_OPT_WAIT, RTGETOPT_REQ_INT32 },
247 { "--no-wait", VBOXDRVINST_SERVICE_OPT_NO_WAIT, RTGETOPT_REQ_NOTHING }
248};
249
250/**
251 * Command definition for the 'service' command.
252 */
253const VBOXDRVINSTCMD g_CmdService =
254{
255 "service",
256 vboxDrvInstCmdServiceMain,
257 "Controls services.",
258 g_aCmdServiceOptions,
259 RT_ELEMENTS(g_aCmdServiceOptions),
260 vboxDrvInstCmdServiceHelp
261};
262
263/**
264 * Commands.
265 */
266static const VBOXDRVINSTCMD * const g_apCommands[] =
267{
268 &g_CmdList,
269 &g_CmdInstall,
270 &g_CmdUninstall,
271 &g_CmdService
272};
273
274/**
275 * Common option definitions for all commands.
276 */
277static const RTGETOPTDEF g_aCmdCommonOptions[] =
278{
279 { "--logfile", 'l', RTGETOPT_REQ_STRING },
280 { "--help", 'h', RTGETOPT_REQ_NOTHING },
281 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
282 { "--version", 'V', RTGETOPT_REQ_NOTHING }
283};
284
285
286/*********************************************************************************************************************************
287* Implementation *
288*********************************************************************************************************************************/
289
290/**
291 * Logs message, va_list version.
292 *
293 * @returns VBox status code.
294 * @param pszPrefix Logging prefix to use. Can be NULL.
295 * @param pszFormat Format string to log.
296 * @param args va_list to use.
297 */
298DECLINLINE(void) vboxDrvInstLogExV(const char *pszPrefix, const char *pszFormat, va_list args)
299{
300 char *psz = NULL;
301 RTStrAPrintfV(&psz, pszFormat, args);
302 AssertPtrReturnVoid(psz);
303
304 if (pszPrefix)
305 LogRel(("%s: %s", pszPrefix, psz));
306 else
307 LogRel(("%s", psz));
308
309 RTStrFree(psz);
310}
311
312/**
313 * Logs a message.
314 *
315 * @returns VBox status code.
316 * @param pszFormat Format string to log.
317 */
318DECLINLINE(void) vboxDrvInstLogError(const char *pszFormat, ...)
319{
320 va_list args;
321 va_start(args, pszFormat);
322 vboxDrvInstLogExV("*** Error", pszFormat, args);
323 va_end(args);
324}
325
326/**
327 * Logs an error message.
328 *
329 * @returns VBox status code.
330 * @param pszFormat Format string to log.
331 */
332DECLINLINE(void) vboxDrvInstLog(const char *pszFormat, ...)
333{
334 va_list args;
335 va_start(args, pszFormat);
336 vboxDrvInstLogExV(NULL, pszFormat, args);
337 va_end(args);
338}
339
340/**
341 * Logging callback for the Windows driver (un)installation code.
342 */
343static DECLCALLBACK(void) vboxDrvInstLogCallback(VBOXWINDRIVERLOGTYPE enmType, const char *pszMsg, void *pvUser)
344{
345 RT_NOREF(pvUser);
346
347 /*
348 * Log to standard output:
349 */
350 switch (enmType)
351 {
352 case VBOXWINDRIVERLOGTYPE_ERROR:
353 vboxDrvInstLogError("%s\n", pszMsg);
354 break;
355
356 case VBOXWINDRIVERLOGTYPE_REBOOT_NEEDED:
357 vboxDrvInstLog("A reboot is needed in order to complete the (un)installation!\n");
358 break;
359
360 default:
361 vboxDrvInstLog("%s\n", pszMsg);
362 break;
363 }
364}
365
366/** Option help for the 'list' command. */
367static DECLCALLBACK(const char *) vboxDrvInstCmdListHelp(PCRTGETOPTDEF pOpt)
368{
369 switch (pOpt->iShort)
370 {
371 default:
372 break;
373 }
374 return NULL;
375}
376
377/**
378 * Main (entry) function for the 'list' command.
379 *
380 * @returns Program exit code.
381 * @param pGetState RTGetOpt state.
382 */
383static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdListMain(PRTGETOPTSTATE pGetState)
384{
385 const char *pszPattern = NULL;
386
387 int ch;
388 RTGETOPTUNION ValueUnion;
389 while ((ch = RTGetOpt(pGetState, &ValueUnion)))
390 {
391 switch (ch)
392 {
393 case 'h':
394 return vboxDrvInstShowUsage(g_pStdOut, &g_CmdList);
395
396 case VINF_GETOPT_NOT_OPTION:
397 {
398 /** @todo Use pattern to filter entries, e.g. "pnp:<PNP-ID>" or "model:VBoxSup*". */
399 pszPattern = ValueUnion.psz;
400 break;
401 }
402
403 default:
404 return RTGetOptPrintError(ch, &ValueUnion);
405 }
406 }
407
408 PVBOXWINDRVSTORE pStore;
409 int rc = VBoxWinDrvStoreCreate(&pStore);
410
411 PVBOXWINDRVSTORELIST pList = NULL;
412 if (pszPattern)
413 rc = VBoxWinDrvStoreQueryAny(pStore, pszPattern, &pList);
414 else
415 rc = VBoxWinDrvStoreQueryAll(pStore, &pList);
416 if (RT_SUCCESS(rc))
417 {
418 vboxDrvInstLog("Location: %s\n\n", VBoxWinDrvStoreBackendGetLocation(pStore));
419
420 vboxDrvInstLog("%-40s | %-40s\n", "OEM INF File", "Version");
421 vboxDrvInstLog("%-40s | %-40s\n", " Model (First)", "PnP ID (First)");
422 vboxDrvInstLog("--------------------------------------------------------------------------------\n");
423
424 size_t cEntries = 0;
425 PVBOXWINDRVSTOREENTRY pCur;
426 RTListForEach(&pList->List, pCur, VBOXWINDRVSTOREENTRY, Node)
427 {
428 vboxDrvInstLog("%-40ls | %-40ls\n",
429 pCur->wszInfFile, pCur->Ver.wszDriverVer);
430 vboxDrvInstLog(" %-36ls | %-40ls\n",
431 pCur->wszModel, pCur->wszPnpId);
432 cEntries++;
433 }
434
435 if (pszPattern)
436 vboxDrvInstLog("\nFound %zu entries (filtered).\n", cEntries);
437 else
438 vboxDrvInstLog("\nFound %zu entries.\n", cEntries);
439 }
440
441 VBoxWinDrvStoreListFree(pList);
442
443 VBoxWinDrvStoreDestroy(pStore);
444 pStore = NULL;
445
446 vboxDrvInstLog("\nUse DOS-style wildcards to adjust results.\n");
447 vboxDrvInstLog("Use \"--help\" to print syntax help.\n");
448
449 return RTEXITCODE_SUCCESS;
450}
451
452/** Option help for the 'install' command. */
453static DECLCALLBACK(const char *) vboxDrvInstCmdInstallHelp(PCRTGETOPTDEF pOpt)
454{
455 switch (pOpt->iShort)
456 {
457 case VBOXDRVINST_INSTALL_OPT_INF_FILE: return "Specifies the INF file to install";
458 case VBOXDRVINST_INSTALL_OPT_INF_SECTION: return "Specifies the INF section to install";
459 case VBOXDRVINST_INSTALL_OPT_MODEL: return "Specifies the driver model";
460 case VBOXDRVINST_INSTALL_OPT_PNPID: return "Specifies the PnP (device) ID";
461 case VBOXDRVINST_INSTALL_OPT_NOT_FORCE: return "Installation will not be forced";
462 case VBOXDRVINST_INSTALL_OPT_NOT_SILENT: return "Installation will not run in silent mode";
463 case VBOXDRVINST_INSTALL_OPT_IGNORE_REBOOT: return "Ignores reboot requirements";
464 case VBOXDRVINST_INSTALL_OPT_DEBUG_OS_VER: return "Overwrites the detected OS version";
465 default:
466 break;
467 }
468 return NULL;
469}
470
471/**
472 * Main (entry) function for the 'install' command.
473 *
474 * @returns Program exit code.
475 * @param pGetState RTGetOpt state.
476 */
477static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdInstallMain(PRTGETOPTSTATE pGetState)
478{
479 char *pszInfFile = NULL;
480 char *pszModel = NULL;
481 char *pszPnpId = NULL;
482 char *pszInfSection = NULL;
483 uint64_t uOsVer = 0;
484
485 /* By default we want to force an installation.
486 *
487 * However, we do *not* want the installation to be silent by default,
488 * as this this will result in an ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED error
489 * if drivers get installed with our mixed SHA1 / SH256 certificates on older
490 * Windows guest (7, Vista, ++).
491 *
492 * So if the VBOX_WIN_DRIVERINSTALL_F_SILENT is missing, this will result in a
493 * (desired) Windows driver installation dialog to confirm (or reject) the installation
494 * by the user.
495 *
496 * On the other hand, for unattended installs we need VBOX_WIN_DRIVERINSTALL_F_SILENT
497 * being set, as our certificates will get installed into the Windows certificate
498 * store *before* we perform any driver installation.
499 */
500 uint32_t fInstall = VBOX_WIN_DRIVERINSTALL_F_FORCE;
501
502 /* Whether to ignore reboot messages or not. This will also affect the returned exit code. */
503 bool fIgnoreReboot = false;
504
505 int rc = VINF_SUCCESS;
506
507#define DUP_ARG_TO_STR(a_Str) \
508 a_Str = RTStrDup(ValueUnion.psz); \
509 if (!a_Str) \
510 { \
511 RTMsgError("Can't handle argument '%s': Out of memory\n", ValueUnion.psz); \
512 rc = VERR_NO_MEMORY; \
513 break; \
514 }
515
516 int ch;
517 RTGETOPTUNION ValueUnion;
518 while ((ch = RTGetOpt(pGetState, &ValueUnion)))
519 {
520 switch (ch)
521 {
522 case 'h':
523 return vboxDrvInstShowUsage(g_pStdOut, &g_CmdInstall);
524
525 case VBOXDRVINST_INSTALL_OPT_INF_FILE:
526 DUP_ARG_TO_STR(pszInfFile);
527 break;
528
529 case VBOXDRVINST_INSTALL_OPT_INF_SECTION:
530 DUP_ARG_TO_STR(pszInfSection);
531 break;
532
533 case VBOXDRVINST_INSTALL_OPT_MODEL:
534 DUP_ARG_TO_STR(pszModel);
535 break;
536
537 case VBOXDRVINST_INSTALL_OPT_PNPID:
538 DUP_ARG_TO_STR(pszPnpId);
539 break;
540
541 case VBOXDRVINST_INSTALL_OPT_NOT_FORCE:
542 fInstall &= ~VBOX_WIN_DRIVERINSTALL_F_FORCE;
543 break;
544
545 case VBOXDRVINST_INSTALL_OPT_NOT_SILENT:
546 fInstall &= ~VBOX_WIN_DRIVERINSTALL_F_SILENT;
547 break;
548
549 case VBOXDRVINST_INSTALL_OPT_IGNORE_REBOOT:
550 fIgnoreReboot = true;
551 break;
552
553 case VBOXDRVINST_INSTALL_OPT_DEBUG_OS_VER:
554 uOsVer = RTSYSTEM_MAKE_NT_VERSION(ValueUnion.PairU32.uFirst, ValueUnion.PairU32.uSecond,
555 0 /* Build Version */);
556 break;
557
558 default:
559 return RTGetOptPrintError(ch, &ValueUnion);
560 }
561 }
562
563#undef DUP_ARG_TO_STR
564
565 if (RT_FAILURE(rc))
566 return RTEXITCODE_FAILURE;
567
568 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
569
570 VBOXWINDRVINST hWinDrvInst;
571 rc = VBoxWinDrvInstCreateEx(&hWinDrvInst, g_uVerbosity, &vboxDrvInstLogCallback, NULL /* pvUser */);
572 if (RT_SUCCESS(rc))
573 {
574 if (uOsVer)
575 VBoxWinDrvInstSetOsVersion(hWinDrvInst, uOsVer);
576
577 rc = VBoxWinDrvInstInstallEx(hWinDrvInst, pszInfFile, pszModel, pszPnpId, fInstall);
578 if (RT_SUCCESS(rc))
579 {
580 if ( rc == VINF_REBOOT_NEEDED
581 && !fIgnoreReboot)
582 rcExit = (RTEXITCODE)VBOXDRVINSTEXITCODE_REBOOT_NEEDED;
583 }
584 else
585 rcExit = RTEXITCODE_FAILURE;
586
587 VBoxWinDrvInstDestroy(hWinDrvInst);
588 }
589
590 RTStrFree(pszInfFile);
591 RTStrFree(pszInfSection);
592 RTStrFree(pszModel);
593 RTStrFree(pszPnpId);
594
595 return rcExit;
596}
597
598/** Option help for the 'uninstall' command. */
599static DECLCALLBACK(const char *) vboxDrvInstCmdUninstallHelp(PCRTGETOPTDEF pOpt)
600{
601 switch (pOpt->iShort)
602 {
603 case VBOXDRVINST_UNINSTALL_OPT_HOST: return "Uninstalls all VirtualBox host drivers";
604 case VBOXDRVINST_UNINSTALL_OPT_INF_FILE: return "Specifies the INF File to uninstall";
605 case VBOXDRVINST_UNINSTALL_OPT_INF_SECTION: return "Specifies the INF section to uninstall";
606 case VBOXDRVINST_UNINSTALL_OPT_MODEL: return "Specifies the driver model to uninstall";
607 case VBOXDRVINST_UNINSTALL_OPT_PNPID: return "Specifies the PnP (device) ID to uninstall";
608 case VBOXDRVINST_UNINSTALL_OPT_FORCE: return "Forces uninstallation";
609 case VBOXDRVINST_UNINSTALL_OPT_NOT_SILENT: return "Runs uninstallation in non-silent mode";
610 case VBOXDRVINST_UNINSTALL_OPT_IGNORE_REBOOT: return "Ignores reboot requirements";
611 default:
612 break;
613 }
614 return NULL;
615}
616
617/**
618 * Uninstalls all (see notes below) VirtualBox host-related drivers.
619 *
620 * @returns VBox status code.
621 * @param hDrvInst Windows driver installer handle to use.
622 * @param fInstallFlags [Un]Installation flags to use (of type VBOX_WIN_DRIVERINSTALL_F_XXX).
623 */
624static int vboxDrvInstCmdUninstallVBoxHost(VBOXWINDRVINST hDrvInst, uint32_t fInstallFlags)
625{
626 /** @todo Check for running VirtualBox processes first? */
627
628 int rc;
629
630#define UNINSTALL_DRIVER(a_Driver) \
631 rc = VBoxWinDrvInstUninstall(hDrvInst, NULL /* pszInfFile */, a_Driver, NULL /* pszPnPId */, fInstallFlags); \
632 if ( RT_FAILURE(rc) \
633 && !(fInstallFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)) \
634 return rc;
635
636#define CONTROL_SERVICE(a_Svc, a_Fn) \
637 rc = VBoxWinDrvInstControlServiceEx(hDrvInst, a_Svc, a_Fn, VBOXWINDRVSVCFN_F_WAIT, RT_MS_30SEC); \
638 if (RT_FAILURE(rc)) \
639 { \
640 if ( rc != VERR_NOT_FOUND /* Service is optional, thus not fatal if not found. */ \
641 && !(fInstallFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)) \
642 return rc; \
643 }
644
645#define STOP_SERVICE(a_Svc) CONTROL_SERVICE(a_Svc, VBOXWINDRVSVCFN_STOP)
646#define DELETE_SERVICE(a_Svc) CONTROL_SERVICE(a_Svc, VBOXWINDRVSVCFN_DELETE)
647
648 /* Stop VBoxSDS first. */
649 STOP_SERVICE("VBoxSDS");
650
651 /*
652 * Note! The order how to uninstall all drivers is important here,
653 * as drivers can (and will!) hold references to the VBoxSUP (VirtualBox support) driver.
654 * So do not change the order here unless you exactly know what you are doing.
655 */
656 static const char *s_aszDriverUninstallOrdered[] =
657 {
658 "VBoxNetAdp*", /* To catch also deprecated VBoxNetAdp5 drivers. */
659 "VBoxNetLwf*",
660 "VBoxUSB*"
661 };
662
663 for (size_t i = 0; i < RT_ELEMENTS(s_aszDriverUninstallOrdered); i++)
664 UNINSTALL_DRIVER(s_aszDriverUninstallOrdered[i]);
665
666 static const char *s_aszServicesToStopOrdered[] =
667 {
668 "VBoxNetAdp",
669 "VBoxNetLwf",
670 "VBoxUSBMon"
671 };
672
673 for (size_t i = 0; i < RT_ELEMENTS(s_aszServicesToStopOrdered); i++)
674 STOP_SERVICE(s_aszServicesToStopOrdered[i]);
675
676 /* Must come last. */
677 UNINSTALL_DRIVER("VBoxSup*");
678
679 /* Delete all services (if not already done via driver uninstallation). */
680 for (size_t i = 0; i < RT_ELEMENTS(s_aszServicesToStopOrdered); i++)
681 DELETE_SERVICE(s_aszServicesToStopOrdered[i]);
682
683 /* Ditto. */
684 DELETE_SERVICE("VBoxSup");
685
686#undef STOP_SERVICE
687#undef UNINSTALL_DRIVER
688
689 return VINF_SUCCESS;
690}
691
692/**
693 * Main (entry) function for the 'uninstall' command.
694 *
695 * @returns Program exit code.
696 * @param pGetState RTGetOpt state.
697 */
698static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdUninstallMain(PRTGETOPTSTATE pGetState)
699{
700 char *pszInfFile = NULL;
701 char *pszModel = NULL;
702 char *pszPnpId = NULL;
703 char *pszInfSection = NULL;
704
705 /* By default we want a silent uninstallation (but not forcing it). */
706 uint32_t fInstall = VBOX_WIN_DRIVERINSTALL_F_SILENT;
707
708 /* Whether to ignore reboot messages or not. This will also affect the returned exit code. */
709 bool fIgnoreReboot = false;
710 /* Whether to (automatically) uninstall all related VBox host drivers or not. */
711 bool fVBoxHost = false;
712
713 int rc = VINF_SUCCESS;
714
715#define DUP_ARG_TO_STR(a_Str) \
716 a_Str = RTStrDup(ValueUnion.psz); \
717 if (!a_Str) \
718 { \
719 RTMsgError("Can't handle argument '%s': Out of memory\n", ValueUnion.psz); \
720 rc = VERR_NO_MEMORY; \
721 break; \
722 }
723
724 int ch;
725 RTGETOPTUNION ValueUnion;
726 while ((ch = RTGetOpt(pGetState, &ValueUnion)))
727 {
728 switch (ch)
729 {
730 case 'h':
731 return vboxDrvInstShowUsage(g_pStdOut, &g_CmdUninstall);
732
733 case VBOXDRVINST_UNINSTALL_OPT_HOST:
734 fVBoxHost = true;
735 break;
736
737 case VBOXDRVINST_UNINSTALL_OPT_INF_FILE:
738 DUP_ARG_TO_STR(pszInfFile);
739 break;
740
741 case VBOXDRVINST_UNINSTALL_OPT_INF_SECTION:
742 DUP_ARG_TO_STR(pszInfSection);
743 break;
744
745 case VBOXDRVINST_UNINSTALL_OPT_MODEL:
746 DUP_ARG_TO_STR(pszModel);
747 break;
748
749 case VBOXDRVINST_UNINSTALL_OPT_PNPID:
750 DUP_ARG_TO_STR(pszPnpId);
751 break;
752
753 case VBOXDRVINST_UNINSTALL_OPT_FORCE:
754 fInstall |= VBOX_WIN_DRIVERINSTALL_F_FORCE;
755 break;
756
757 case VBOXDRVINST_UNINSTALL_OPT_NOT_SILENT:
758 fInstall &= ~VBOX_WIN_DRIVERINSTALL_F_SILENT;
759 break;
760
761 case VBOXDRVINST_UNINSTALL_OPT_IGNORE_REBOOT:
762 fIgnoreReboot = true;
763 break;
764
765 default:
766 return RTGetOptPrintError(ch, &ValueUnion);
767 }
768 }
769
770#undef DUP_ARG_TO_STR
771
772 if (RT_FAILURE(rc))
773 return RTEXITCODE_FAILURE;
774
775 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
776
777 VBOXWINDRVINST hWinDrvInst;
778 rc = VBoxWinDrvInstCreateEx(&hWinDrvInst, g_uVerbosity, &vboxDrvInstLogCallback, NULL /* pvUser */);
779 if (RT_SUCCESS(rc))
780 {
781 if (fVBoxHost)
782 rc = vboxDrvInstCmdUninstallVBoxHost(hWinDrvInst, fInstall);
783 else
784 rc = VBoxWinDrvInstUninstall(hWinDrvInst, pszInfFile, pszModel, pszPnpId, fInstall);
785 if (RT_SUCCESS(rc))
786 {
787 if ( rc == VINF_REBOOT_NEEDED
788 && !fIgnoreReboot)
789 rcExit = (RTEXITCODE)VBOXDRVINSTEXITCODE_REBOOT_NEEDED;
790 }
791 else
792 rcExit = RTEXITCODE_FAILURE;
793
794 VBoxWinDrvInstDestroy(hWinDrvInst);
795 }
796
797 RTStrFree(pszInfFile);
798 RTStrFree(pszInfSection);
799 RTStrFree(pszModel);
800 RTStrFree(pszPnpId);
801
802 return rcExit;
803}
804
805/** Option help for the 'service' command. */
806static DECLCALLBACK(const char *) vboxDrvInstCmdServiceHelp(PCRTGETOPTDEF pOpt)
807{
808 switch (pOpt->iShort)
809 {
810 case VBOXDRVINST_SERVICE_OPT_START: return "Starts the service";
811 case VBOXDRVINST_SERVICE_OPT_STOP: return "Stops the service";
812 case VBOXDRVINST_SERVICE_OPT_RESTART: return "Restarts the service";
813 case VBOXDRVINST_SERVICE_OPT_WAIT: return "Waits for the service to reach the desired state";
814 case VBOXDRVINST_SERVICE_OPT_NO_WAIT: return "Skips waiting for the service to reach the desired state";
815
816 default:
817 break;
818 }
819 return NULL;
820}
821
822static DECLCALLBACK(RTEXITCODE) vboxDrvInstCmdServiceMain(PRTGETOPTSTATE pGetState)
823{
824 const char *pszService = NULL;
825 VBOXWINDRVSVCFN enmFn = VBOXWINDRVSVCFN_INVALID;
826 /* We wait 30s by default, unless specified otherwise below. */
827 uint32_t fFlags = VBOXWINDRVSVCFN_F_WAIT;
828 RTMSINTERVAL msTimeout = RT_MS_30SEC;
829
830 int ch;
831 RTGETOPTUNION ValueUnion;
832 while ((ch = RTGetOpt(pGetState, &ValueUnion)))
833 {
834 switch (ch)
835 {
836 case 'h':
837 return vboxDrvInstShowUsage(g_pStdOut, &g_CmdService);
838
839 case VBOXDRVINST_SERVICE_OPT_START:
840 {
841 if (enmFn != VBOXWINDRVSVCFN_INVALID)
842 return RTMsgErrorExitFailure("Service control function already specified\n");
843 enmFn = VBOXWINDRVSVCFN_START;
844 break;
845 }
846
847 case VBOXDRVINST_SERVICE_OPT_STOP:
848 {
849 if (enmFn != VBOXWINDRVSVCFN_INVALID)
850 return RTMsgErrorExitFailure("Service control function already specified\n");
851 enmFn = VBOXWINDRVSVCFN_STOP;
852 break;
853 }
854
855 case VBOXDRVINST_SERVICE_OPT_RESTART:
856 {
857 if (enmFn != VBOXWINDRVSVCFN_INVALID)
858 return RTMsgErrorExitFailure("Service control function already specified\n");
859 enmFn = VBOXWINDRVSVCFN_RESTART;
860 break;
861 }
862
863 case VBOXDRVINST_SERVICE_OPT_WAIT:
864 /* Note: fFlags already set above. */
865 msTimeout = ValueUnion.u32 * RT_MS_1SEC; /* Seconds -> Milliseconds. */
866 if (!msTimeout)
867 return RTMsgErrorExitFailure("Timeout value is invalid\n");
868 break;
869
870 case VBOXDRVINST_SERVICE_OPT_NO_WAIT:
871 fFlags &= ~VBOXWINDRVSVCFN_F_WAIT;
872 break;
873
874 case VINF_GETOPT_NOT_OPTION:
875 {
876 if (pszService)
877 return RTMsgErrorExitFailure("Service name already specified\n");
878
879 pszService = ValueUnion.psz;
880 break;
881 }
882
883 default:
884 return RTGetOptPrintError(ch, &ValueUnion);
885 }
886 }
887
888 if (!pszService)
889 return RTMsgErrorExitFailure("No service to control specified\n");
890 if (enmFn == VBOXWINDRVSVCFN_INVALID)
891 return RTMsgErrorExitFailure("No or invalid service control function specified\n");
892
893 VBOXWINDRVINST hWinDrvInst;
894 int rc = VBoxWinDrvInstCreateEx(&hWinDrvInst, g_uVerbosity, &vboxDrvInstLogCallback, NULL /* pvUser */);
895 if (RT_SUCCESS(rc))
896 {
897 rc = VBoxWinDrvInstControlServiceEx(hWinDrvInst, pszService, enmFn, fFlags, msTimeout);
898 VBoxWinDrvInstDestroy(hWinDrvInst);
899 }
900
901 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
902}
903
904/**
905 * Shows the commands and their descriptions.
906 *
907 * @returns RTEXITCODE
908 * @param pStrm Stream to use.
909 */
910static RTEXITCODE vboxDrvInstShowCommands(PRTSTREAM pStrm)
911{
912 RTStrmPrintf(pStrm, "Commands:\n");
913 for (uintptr_t iCmd = 0; iCmd < RT_ELEMENTS(g_apCommands); iCmd++)
914 RTStrmPrintf(pStrm, "%12s - %s\n", g_apCommands[iCmd]->pszCommand, g_apCommands[iCmd]->pszDesc);
915 return RTEXITCODE_SUCCESS;
916}
917
918/**
919 * Shows the general usage.
920 *
921 * @returns RTEXITCODE
922 * @param pStrm Stream to use.
923 */
924static RTEXITCODE vboxDrvInstShowUsage(PRTSTREAM pStrm, PCVBOXDRVINSTCMD pOnlyCmd)
925{
926 const char *pszProcName = RTProcShortName();
927
928 RTStrmPrintf(pStrm, "usage: %s [global options] <command> [command-options]\n", pszProcName);
929 RTStrmPrintf(pStrm,
930 "\n"
931 "Global Options:\n"
932 " -h, -?, --help\n"
933 " Displays help\n"
934 " -l | --logfile <file>\n"
935 " Enables logging to a file\n"
936 " -v, --verbose\n"
937 " Increase verbosity\n"
938 " -V, --version\n"
939 " Displays version\n"
940 );
941
942 for (uintptr_t iCmd = 0; iCmd < RT_ELEMENTS(g_apCommands); iCmd++)
943 {
944 PCVBOXDRVINSTCMD const pCmd = g_apCommands[iCmd];
945 if (!pOnlyCmd || pCmd == pOnlyCmd)
946 {
947 RTStrmPrintf(pStrm,
948 "\n"
949 "Command '%s':\n"
950 " %s\n",
951 pCmd->pszCommand, pCmd->pszDesc);
952
953 if (!pCmd->paOptions)
954 continue;
955
956 RTStrmPrintf(pStrm, "Options for '%s':\n", pCmd->pszCommand);
957 PCRTGETOPTDEF const paOptions = pCmd->paOptions;
958 for (unsigned i = 0; i < pCmd->cOptions; i++)
959 {
960 if (RT_C_IS_PRINT(paOptions[i].iShort))
961 RTStrmPrintf(pStrm, " -%c, %s\n", paOptions[i].iShort, paOptions[i].pszLong);
962 else
963 RTStrmPrintf(pStrm, " %s\n", paOptions[i].pszLong);
964
965 const char *pszHelp = NULL;
966 if (pCmd->pfnOptionHelp)
967 pszHelp = pCmd->pfnOptionHelp(&paOptions[i]);
968 if (pszHelp)
969 RTStrmPrintf(pStrm, " %s\n", pszHelp);
970 }
971 }
972 }
973
974 RTStrmPrintf(pStrm, "\nExamples:\n");
975 RTStrmPrintf(pStrm, "\t%s install --inf-file C:\\Path\\To\\VBoxUSB.inf\n", pszProcName);
976 RTStrmPrintf(pStrm, "\t%s install --debug-os-ver 6:0 --inf-file C:\\Path\\To\\VBoxGuest.inf\n", pszProcName);
977 RTStrmPrintf(pStrm, "\t%s uninstall host\n", pszProcName);
978 RTStrmPrintf(pStrm, "\t%s uninstall --inf -file C:\\Path\\To\\VBoxUSB.inf --pnp-id \"USB\\VID_80EE&PID_CAFE\"\n", pszProcName);
979 RTStrmPrintf(pStrm, "\t%s uninstall --model \"VBoxUSB.AMD64\"\n", pszProcName);
980 RTStrmPrintf(pStrm, "\t%s uninstall --model \"VBoxUSB*\"\n", pszProcName);
981 RTStrmPrintf(pStrm, "\t%s service VBoxSDS stop\n", pszProcName);
982 RTStrmPrintf(pStrm, "\t%s service VBoxSDS start --no-wait\n", pszProcName);
983 RTStrmPrintf(pStrm, "\t%s service VBoxSDS restart --wait 180\n", pszProcName);
984 RTStrmPrintf(pStrm, "\t%s list \"VBox*\"\n\n", pszProcName);
985 RTStrmPrintf(pStrm, "Exit codes:\n");
986 RTStrmPrintf(pStrm, "\t1 - The requested command failed.\n");
987 RTStrmPrintf(pStrm, "\t2 - Syntax error.\n");
988 RTStrmPrintf(pStrm, "\t5 - A reboot is needed in order to complete the (un)installation.\n\n");
989
990 return RTEXITCODE_SUCCESS;
991}
992
993/**
994 * Shows tool version.
995 *
996 * @returns RTEXITCODE
997 * @param pStrm Stream to use.
998 */
999static RTEXITCODE vboxDrvInstShowVersion(PRTSTREAM pStrm)
1000{
1001 RTStrmPrintf(pStrm, "%s\n", RTBldCfgRevisionStr());
1002 return RTEXITCODE_SUCCESS;
1003}
1004
1005/**
1006 * Shows the logo.
1007 *
1008 * @param pStream Output stream to show logo on.
1009 */
1010static void vboxDrvInstShowLogo(PRTSTREAM pStream)
1011{
1012 RTStrmPrintf(pStream, VBOX_PRODUCT " VBoxDrvInst (Driver Installation Utility) Version " VBOX_VERSION_STRING " - r%s (%s)\n"
1013 "Copyright (C) " VBOX_C_YEAR " " VBOX_VENDOR "\n\n", RTBldCfgRevisionStr(), RTBldCfgTargetArch());
1014}
1015
1016/**
1017 * @callback_method_impl{FNRTLOGPHASE, Release logger callback}
1018 */
1019static DECLCALLBACK(void) vboxDrvInstLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
1020{
1021 /* Some introductory information. */
1022 static RTTIMESPEC s_TimeSpec;
1023 char szTmp[256];
1024 if (enmPhase == RTLOGPHASE_BEGIN)
1025 RTTimeNow(&s_TimeSpec);
1026 RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
1027
1028 switch (enmPhase)
1029 {
1030 case RTLOGPHASE_BEGIN:
1031 {
1032 pfnLog(pLoggerRelease,
1033 "VBoxDrvInst %s r%s (verbosity: %u) (%s %s) release log (%s)\n"
1034 "Log opened %s\n",
1035 RTBldCfgVersion(), RTBldCfgRevisionStr(), g_uVerbosity,
1036 __DATE__, __TIME__, RTBldCfgTargetArch(), szTmp);
1037
1038 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
1039 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
1040 pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
1041 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
1042 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
1043 pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
1044 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
1045 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
1046 pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
1047 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
1048 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
1049 pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
1050
1051 /* the package type is interesting for Linux distributions */
1052 char szExecName[RTPATH_MAX];
1053 char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
1054 pfnLog(pLoggerRelease,
1055 "Executable: %s\n"
1056 "Process ID: %u\n"
1057 "Package type: %s"
1058#ifdef VBOX_OSE
1059 " (OSE)"
1060#endif
1061 "\n",
1062 pszExecName ? pszExecName : "unknown",
1063 RTProcSelf(),
1064 VBOX_PACKAGE_STRING);
1065 break;
1066 }
1067
1068 case RTLOGPHASE_PREROTATE:
1069 pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
1070 break;
1071
1072 case RTLOGPHASE_POSTROTATE:
1073 pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
1074 break;
1075
1076 case RTLOGPHASE_END:
1077 pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
1078 break;
1079
1080 default:
1081 /* nothing */
1082 break;
1083 }
1084}
1085
1086
1087/**
1088 * Creates the default release logger outputting to the specified file.
1089 *
1090 * @return IPRT status code.
1091 * @param pszLogFile Filename for log output.
1092 */
1093static int vboxDrvInstLogCreate(const char *pszLogFile)
1094{
1095 /* Create release logger (stdout + file). */
1096 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
1097 RTUINT fFlags = RTLOGFLAGS_USECRLF | RTLOGFLAGS_APPEND;
1098 int rc = RTLogCreateEx(&g_pLoggerRelease, "VBOXDRVINST_RELEASE_LOG", fFlags, "all",
1099 RT_ELEMENTS(s_apszGroups), s_apszGroups, UINT32_MAX /*cMaxEntriesPerGroup*/,
1100 0 /*cBufDescs*/, NULL /*paBufDescs*/, RTLOGDEST_STDOUT | RTLOGDEST_USER,
1101 vboxDrvInstLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
1102 NULL /*pOutputIf*/, NULL /*pvOutputIfUser*/,
1103 NULL /*pErrInfo*/, "%s", pszLogFile ? pszLogFile : "");
1104 if (RT_SUCCESS(rc))
1105 {
1106 /* register this logger as the release logger */
1107 RTLogRelSetDefaultInstance(g_pLoggerRelease);
1108
1109 /* Explicitly flush the log in case of VBOXDRVINST_RELEASE_LOG=buffered. */
1110 RTLogFlush(g_pLoggerRelease);
1111 }
1112
1113 return rc;
1114}
1115
1116/**
1117 * Destroys the currently active logging instance.
1118 */
1119static void vboxDrvInstLogDestroy(void)
1120{
1121 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
1122}
1123
1124/**
1125 * Performs initialization tasks before a specific command is being run.
1126 *
1127 * @returns VBox status code.
1128 */
1129static int vboxDrvInstInit(void)
1130{
1131 int rc = vboxDrvInstLogCreate(g_szLogFile[0] ? g_szLogFile : NULL);
1132 if (RT_FAILURE(rc))
1133 {
1134 RTMsgError("Failed to create release log '%s', rc=%Rrc\n", g_szLogFile[0] ? g_szLogFile : "<None>", rc);
1135 return rc;
1136 }
1137
1138 /* Refuse to run on too old Windows versions (<= NT4). */
1139 uint64_t const uNtVer = RTSystemGetNtVersion();
1140 if (RTSYSTEM_NT_VERSION_GET_MAJOR(uNtVer) <= 4)
1141 {
1142 vboxDrvInstLogError("Windows version (%d.%d.%d) too old and not supported\n", RTSYSTEM_NT_VERSION_GET_MAJOR(uNtVer),
1143 RTSYSTEM_NT_VERSION_GET_MINOR(uNtVer),
1144 RTSYSTEM_NT_VERSION_GET_BUILD(uNtVer));
1145 return VERR_NOT_SUPPORTED;
1146 }
1147
1148 return VINF_SUCCESS;
1149}
1150
1151/**
1152 * Performs destruction tasks after a specific command has been run.
1153 */
1154static void vboxDrvInstDestroy(void)
1155{
1156 vboxDrvInstLogDestroy();
1157}
1158
1159int main(int argc, char **argv)
1160{
1161 /*
1162 * Init IPRT.
1163 */
1164 int rc = RTR3InitExe(argc, &argv, 0);
1165 if (RT_FAILURE(rc))
1166 return RTMsgInitFailure(rc);
1167
1168 vboxDrvInstShowLogo(g_pStdOut);
1169
1170 /*
1171 * Process common options.
1172 */
1173 RTGETOPTSTATE GetState;
1174 RT_ZERO(GetState);
1175 rc = RTGetOptInit(&GetState, argc, argv, g_aCmdCommonOptions, RT_ELEMENTS(g_aCmdCommonOptions),
1176 1 /*idxFirst*/, 0 /*fFlags - must not sort! */);
1177 AssertRCReturn(rc, RTEXITCODE_INIT);
1178
1179 int ch;
1180 RTGETOPTUNION ValueUnion;
1181 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
1182 {
1183 switch (ch)
1184 {
1185 case 'h':
1186 return vboxDrvInstShowUsage(g_pStdOut, NULL);
1187
1188 case 'l':
1189 rc = RTStrCopy(g_szLogFile, sizeof(g_szLogFile), ValueUnion.psz);
1190 if (RT_FAILURE(rc))
1191 return RTMsgErrorExitFailure("Error setting logfile, rc=%Rrc\n", rc);
1192 break;
1193
1194 case 'v':
1195 g_uVerbosity++;
1196 break;
1197
1198 case 'V':
1199 return vboxDrvInstShowVersion(g_pStdOut);
1200
1201 case VERR_GETOPT_UNKNOWN_OPTION:
1202 return vboxDrvInstShowUsage(g_pStdOut, NULL);
1203
1204 case VINF_GETOPT_NOT_OPTION:
1205 {
1206 for (uintptr_t iCmd = 0; iCmd < RT_ELEMENTS(g_apCommands); iCmd++)
1207 {
1208 PCVBOXDRVINSTCMD const pCmd = g_apCommands[iCmd];
1209 if (strcmp(ValueUnion.psz, pCmd->pszCommand) == 0)
1210 {
1211 rc = vboxDrvInstInit();
1212 if (RT_FAILURE(rc))
1213 return RTEXITCODE_FAILURE;
1214
1215 /* Count the combined option definitions: */
1216 size_t cCombinedOptions = pCmd->cOptions + RT_ELEMENTS(g_aCmdCommonOptions);
1217
1218 RTEXITCODE rcExit;
1219
1220 /* Combine the option definitions: */
1221 PRTGETOPTDEF paCombinedOptions = (PRTGETOPTDEF)RTMemAlloc(cCombinedOptions * sizeof(RTGETOPTDEF));
1222 if (paCombinedOptions)
1223 {
1224 uint32_t idxOpts = 0;
1225 memcpy(paCombinedOptions, g_aCmdCommonOptions, sizeof(g_aCmdCommonOptions));
1226 idxOpts += RT_ELEMENTS(g_aCmdCommonOptions);
1227
1228 memcpy(&paCombinedOptions[idxOpts], pCmd->paOptions, pCmd->cOptions * sizeof(RTGETOPTDEF));
1229 idxOpts += (uint32_t)pCmd->cOptions;
1230
1231 /* Re-initialize the option getter state and pass it to the command handler. */
1232 rc = RTGetOptInit(&GetState, argc, argv, paCombinedOptions, cCombinedOptions,
1233 GetState.iNext /*idxFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
1234
1235 if (RT_SUCCESS(rc))
1236 rcExit = pCmd->pfnHandler(&GetState);
1237 else
1238 rcExit = RTMsgErrorExitFailure("RTGetOptInit failed for '%s': %Rrc", ValueUnion.psz, rc);
1239 RTMemFree(paCombinedOptions);
1240 }
1241 else
1242 rcExit = RTMsgErrorExitFailure("Out of memory!");
1243
1244 vboxDrvInstDestroy();
1245 return rcExit;
1246 }
1247 }
1248 RTMsgError("Unknown command '%s'!\n", ValueUnion.psz);
1249 vboxDrvInstShowCommands(g_pStdErr);
1250 return RTEXITCODE_SYNTAX;
1251 }
1252
1253 default:
1254 break;
1255 }
1256 }
1257
1258 /* List all Windows driver store entries if no command is given. */
1259 rc = vboxDrvInstInit();
1260 if (RT_FAILURE(rc))
1261 return RTEXITCODE_FAILURE;
1262 RTEXITCODE rcExit = vboxDrvInstCmdListMain(&GetState);
1263 vboxDrvInstDestroy();
1264 return rcExit;
1265}
1266
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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