VirtualBox

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

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

Windows driver installation/VBoxDrvInst: Implemented 'service delete' sub command to delete a Windows service. bugref:10762

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

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