VirtualBox

Ignore:
Timestamp:
Apr 30, 2014 8:42:52 AM (11 years ago)
Author:
vboxsync
Message:

Installer/win/VBoxStub: Fixed singleton mutex leaks + specifying multiple MSI parameters, added verbose switch ("/v") and optional console output support.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp

    r51129 r51170  
    2121#include <Windows.h>
    2222#include <commctrl.h>
     23#include <fcntl.h>
     24#include <io.h>
    2325#include <lmerr.h>
    2426#include <msiquery.h>
     
    5658#endif
    5759
     60#ifdef DEBUG
     61/* Use an own console window if run in debug mode. */
     62# define VBOX_STUB_WITH_OWN_CONSOLE
     63#endif
    5864
    5965/*******************************************************************************
     
    9096/** List of temporary files. */
    9197static RTLISTANCHOR     g_TmpFiles;
     98/** Verbosity flag. */
     99static int              g_iVerbosity = 0;
    92100
    93101
     
    802810    int vrc = RTR3InitExe(argc, &argv, 0);
    803811    if (RT_FAILURE(vrc))
     812    {
     813        /* Close the mutex for this application instance. */
     814        CloseHandle(hMutexAppRunning);
     815        hMutexAppRunning = NULL;
    804816        return RTMsgInitFailure(vrc);
     817    }
     818
     819#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0501
     820# ifndef VBOX_STUB_WITH_OWN_CONSOLE /* Use an own console window if run in debug mode. */
     821    if (!AllocConsole())
     822    {
     823        DWORD dwErr = GetLastError();
     824        ShowError("Unable to allocate console, error = %ld\n",
     825                  dwErr);
     826
     827        /* Close the mutex for this application instance. */
     828        CloseHandle(hMutexAppRunning);
     829        hMutexAppRunning = NULL;
     830        return RTEXITCODE_FAILURE;
     831    }
     832# else
     833    if (!AttachConsole(ATTACH_PARENT_PROCESS))
     834    {
     835        DWORD dwErr = GetLastError();
     836        /* Does the program have a console to attach to? */
     837        if (dwErr != ERROR_INVALID_HANDLE)
     838        {
     839            ShowError("Unable to attach to console, error = %ld\n",
     840                      dwErr);
     841
     842            /* Close the mutex for this application instance. */
     843            CloseHandle(hMutexAppRunning);
     844            hMutexAppRunning = NULL;
     845            return RTEXITCODE_FAILURE;
     846        }
     847    }
     848# endif /* DEBUG */
     849
     850    long lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
     851    int iConHandleStdOut = _open_osfhandle(lStdHandle, _O_TEXT);
     852    FILE *hFileStdOut = _fdopen(iConHandleStdOut, "w");
     853    *stdout = *hFileStdOut;
     854
     855    lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
     856    int iConHandleStdErr = _open_osfhandle(lStdHandle, _O_TEXT);
     857    FILE *hFileStdErr = _fdopen(iConHandleStdErr, "w");
     858    *stderr = *hFileStdErr;
     859
     860setvbuf( stdout, NULL, _IONBF, 0 );
     861
     862#endif
    805863
    806864    /*
     
    815873#endif
    816874    char szExtractPath[RTPATH_MAX] = {0};
    817     char szMSIArgs[4096]           = {0};
     875    char szMSIArgs[_4K]            = {0};
    818876
    819877    /* Parameter definitions. */
     
    844902        { "-reinstall",         'f', RTGETOPT_REQ_NOTHING },
    845903        { "/reinstall",         'f', RTGETOPT_REQ_NOTHING },
     904        { "--verbose",          'v', RTGETOPT_REQ_NOTHING },
     905        { "-verbose",           'v', RTGETOPT_REQ_NOTHING },
     906        { "/verbose",           'v', RTGETOPT_REQ_NOTHING },
    846907        { "--version",          'V', RTGETOPT_REQ_NOTHING },
    847908        { "-version",           'V', RTGETOPT_REQ_NOTHING },
     
    854915    };
    855916
     917    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     918
    856919    /* Parse the parameters. */
    857920    int ch;
     921    bool fParsingDone = false;
    858922    RTGETOPTUNION ValueUnion;
    859923    RTGETOPTSTATE GetState;
    860924    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
    861     while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     925    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     926           && rcExit == RTEXITCODE_SUCCESS
     927           && !fParsingDone)
    862928    {
    863929        switch (ch)
     
    870936                                   "REINSTALLMODE=vomus REINSTALL=ALL");
    871937                if (RT_FAILURE(vrc))
    872                     return ShowError("MSI parameters are too long.");
     938                    rcExit = ShowError("MSI parameters are too long.");
    873939                break;
    874940
     
    886952                break;
    887953#endif
    888 
    889954            case 'l':
    890955                fEnableLogging = true;
     
    894959                vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz);
    895960                if (RT_FAILURE(vrc))
    896                     return ShowError("Extraction path is too long.");
     961                    rcExit = ShowError("Extraction path is too long.");
    897962                break;
    898963
     
    903968                    vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz);
    904969                if (RT_FAILURE(vrc))
    905                     return ShowError("MSI parameters are too long.");
     970                    rcExit = ShowError("MSI parameters are too long.");
    906971                break;
    907972
    908973            case 'V':
    909974                ShowInfo("Version: %d.%d.%d.%d",
    910                          VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
    911                 return VINF_SUCCESS;
     975                         VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD,
     976                         VBOX_SVN_REV);
     977                fParsingDone = true;
     978                break;
     979
     980            case 'v':
     981                g_iVerbosity++;
     982                break;
    912983
    913984            case 'h':
     
    9291000                         VBOX_STUB_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
    9301001                         argv[0], argv[0]);
    931                 return VINF_SUCCESS;
     1002                fParsingDone = true;
     1003                break;
     1004
     1005            case VINF_GETOPT_NOT_OPTION:
     1006                /* Are (optional) MSI parameters specified and this is the last
     1007                 * parameter? Append everything to the MSI parameter list then. */
     1008                if (szMSIArgs[0])
     1009                {
     1010                    vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), " ");
     1011                    if (RT_SUCCESS(vrc))
     1012                        vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz);
     1013                    if (RT_FAILURE(vrc))
     1014                        rcExit = ShowError("MSI parameters are too long.");
     1015                    continue;
     1016                }
     1017                /* Fall through is intentional. */
    9321018
    9331019            default:
    9341020                if (g_fSilent)
    935                     return RTGetOptPrintError(ch, &ValueUnion);
    936                 if (ch == VINF_GETOPT_NOT_OPTION || ch == VERR_GETOPT_UNKNOWN_OPTION)
    937                     ShowError("Unknown option \"%s\"!\n"
    938                               "Please refer to the command line help by specifying \"/?\"\n"
    939                               "to get more information.", ValueUnion.psz);
     1021                    rcExit = RTGetOptPrintError(ch, &ValueUnion);
     1022                if (ch == VERR_GETOPT_UNKNOWN_OPTION)
     1023                    rcExit = ShowError("Unknown option \"%s\"\n"
     1024                                       "Please refer to the command line help by specifying \"/?\"\n"
     1025                                       "to get more information.", ValueUnion.psz);
    9401026                else
    941                     ShowError("Parameter parsing error: %Rrc\n"
    942                               "Please refer to the command line help by specifying \"/?\"\n"
    943                               "to get more information.", ch);
    944                 return RTEXITCODE_SYNTAX;
    945 
    946         }
    947     }
    948 
    949     /*
    950      * Determine the extration path if not given by the user, and gather some
    951      * other bits we'll be needing later.
    952      */
    953     if (szExtractPath[0] == '\0')
    954     {
    955         vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
    956         if (RT_SUCCESS(vrc))
    957             vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox");
    958         if (RT_FAILURE(vrc))
    959             return ShowError("Failed to determin extraction path (%Rrc)", vrc);
    960 
    961     }
    962     else
    963     {
    964         /** @todo should check if there is a .custom subdirectory there or not. */
    965     }
    966     RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */
     1027                    rcExit = ShowError("Parameter parsing error: %Rrc\n"
     1028                                       "Please refer to the command line help by specifying \"/?\"\n"
     1029                                       "to get more information.", ch);
     1030                break;
     1031        }
     1032    }
     1033
     1034    if (rcExit != RTEXITCODE_SUCCESS)
     1035        vrc = VERR_PARSE_ERROR;
     1036
     1037    if (   RT_SUCCESS(vrc)
     1038        && g_iVerbosity)
     1039    {
     1040        RTPrintf("Silent installation      : %RTbool\n", g_fSilent);
     1041        RTPrintf("Logging enabled          : %RTbool\n", fEnableLogging);
     1042        RTPrintf("Certificate installation : %RTbool\n", fEnableSilentCert);
     1043        RTPrintf("Additional MSI parameters: %s\n",
     1044                 szMSIArgs[0] ? szMSIArgs : "<None>");
     1045    }
     1046
     1047    if (RT_SUCCESS(vrc))
     1048    {
     1049        /*
     1050         * Determine the extration path if not given by the user, and gather some
     1051         * other bits we'll be needing later.
     1052         */
     1053        if (szExtractPath[0] == '\0')
     1054        {
     1055            vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
     1056            if (RT_SUCCESS(vrc))
     1057                vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox");
     1058            if (RT_FAILURE(vrc))
     1059                ShowError("Failed to determine extraction path (%Rrc)", vrc);
     1060
     1061        }
     1062        else
     1063        {
     1064            /** @todo should check if there is a .custom subdirectory there or not. */
     1065        }
     1066        RTPathChangeToDosSlashes(szExtractPath,
     1067                                 true /* Force conversion. */); /* MSI requirement. */
     1068    }
    9671069
    9681070    /* Read our manifest. */
    9691071    PVBOXSTUBPKGHEADER pHeader;
    970     vrc = FindData("MANIFEST", (PVOID *)&pHeader, NULL);
    971     if (RT_FAILURE(vrc))
    972         return ShowError("Internal package error: Manifest not found (%Rrc)", vrc);
    973     /** @todo If we could, we should validate the header. Only the magic isn't
    974      *        commonly defined, nor the version number... */
    975 
    976     RTListInit(&g_TmpFiles);
    977 
    978     /*
    979      * Up to this point, we haven't done anything that requires any cleanup.
    980      * From here on, we do everything in function so we can counter clean up.
    981      */
    982     bool fCreatedExtractDir;
    983     RTEXITCODE rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly, &fCreatedExtractDir);
    984     if (rcExit == RTEXITCODE_SUCCESS)
    985     {
    986         if (fExtractOnly)
    987             ShowInfo("Files were extracted to: %s", szExtractPath);
    988         else
    989         {
    990             rcExit = CopyCustomDir(szExtractPath);
     1072    if (RT_SUCCESS(vrc))
     1073    {
     1074        vrc = FindData("MANIFEST", (PVOID *)&pHeader, NULL);
     1075        if (RT_FAILURE(vrc))
     1076            rcExit = ShowError("Internal package error: Manifest not found (%Rrc)", vrc);
     1077    }
     1078    if (RT_SUCCESS(vrc))
     1079    {
     1080        /** @todo If we could, we should validate the header. Only the magic isn't
     1081         *        commonly defined, nor the version number... */
     1082
     1083        RTListInit(&g_TmpFiles);
     1084
     1085        /*
     1086         * Up to this point, we haven't done anything that requires any cleanup.
     1087         * From here on, we do everything in function so we can counter clean up.
     1088         */
     1089        bool fCreatedExtractDir;
     1090        rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath,
     1091                              fExtractOnly, &fCreatedExtractDir);
     1092        if (rcExit == RTEXITCODE_SUCCESS)
     1093        {
     1094            if (fExtractOnly)
     1095                ShowInfo("Files were extracted to: %s", szExtractPath);
     1096            else
     1097            {
     1098                rcExit = CopyCustomDir(szExtractPath);
    9911099#ifdef VBOX_WITH_CODE_SIGNING
    992             if (rcExit == RTEXITCODE_SUCCESS && fEnableSilentCert && g_fSilent)
    993                 rcExit = InstallCertificate();
     1100                if (rcExit == RTEXITCODE_SUCCESS && fEnableSilentCert && g_fSilent)
     1101                    rcExit = InstallCertificate();
    9941102#endif
    995             unsigned iPackage = 0;
    996             while (iPackage < pHeader->byCntPkgs && rcExit == RTEXITCODE_SUCCESS)
    997             {
    998                 rcExit = ProcessPackage(iPackage, szExtractPath, szMSIArgs, fEnableLogging);
    999                 iPackage++;
     1103                unsigned iPackage = 0;
     1104                while (   iPackage < pHeader->byCntPkgs
     1105                       && rcExit == RTEXITCODE_SUCCESS)
     1106                {
     1107                    rcExit = ProcessPackage(iPackage, szExtractPath,
     1108                                            szMSIArgs, fEnableLogging);
     1109                    iPackage++;
     1110                }
     1111
     1112                /* Don't fail if cleanup fail. At least for now. */
     1113                CleanUp(pHeader->byCntPkgs,
     1114                           !fEnableLogging
     1115                        && fCreatedExtractDir ? szExtractPath : NULL);
    10001116            }
    1001 
    1002             /* Don't fail if cleanup fail. At least for now. */
    1003             CleanUp(pHeader->byCntPkgs, !fEnableLogging && fCreatedExtractDir ? szExtractPath : NULL);
    1004         }
    1005     }
    1006 
    1007     /* Free any left behind cleanup records (not strictly needed). */
    1008     PSTUBCLEANUPREC pCur, pNext;
    1009     RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry)
    1010     {
    1011         RTListNodeRemove(&pCur->ListEntry);
    1012         RTMemFree(pCur);
    1013     }
     1117        }
     1118
     1119        /* Free any left behind cleanup records (not strictly needed). */
     1120        PSTUBCLEANUPREC pCur, pNext;
     1121        RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry)
     1122        {
     1123            RTListNodeRemove(&pCur->ListEntry);
     1124            RTMemFree(pCur);
     1125        }
     1126    }
     1127
     1128#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0501
     1129# ifndef VBOX_STUB_WITH_OWN_CONSOLE
     1130    if (iConHandleStdErr)
     1131        _close(iConHandleStdErr);
     1132    if (hFileStdErr)
     1133        fclose(hFileStdErr);
     1134    if (iConHandleStdOut)
     1135        _close(iConHandleStdOut);
     1136    if (hFileStdOut)
     1137        fclose(hFileStdOut);
     1138# endif /* VBOX_STUB_WITH_OWN_CONSOLE */
     1139    FreeConsole();
     1140#endif
    10141141
    10151142    /*
Note: See TracChangeset for help on using the changeset viewer.

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