VirtualBox

Changeset 93136 in vbox for trunk


Ignore:
Timestamp:
Jan 7, 2022 3:05:59 AM (3 years ago)
Author:
vboxsync
Message:

Add/os2: More installer code.

Location:
trunk/src/VBox/Additions/os2
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/os2/Makefile.kmk

    r93128 r93136  
    4747# A barebone installer.
    4848#
    49 if 0
     49if 1
    5050PROGRAMS += VBoxOs2AdditionsInstall
    5151endif
     
    8585 VBoxOs2AdditionsInstall_SOURCES        += \
    8686        VBoxOs2AdditionsInstallA.asm \
     87        $(VBOX_PATH_RUNTIME_SRC)/common/string/strcpy.cpp \
     88        $(VBOX_PATH_RUNTIME_SRC)/common/string/strchr.cpp \
    8789        $(VBOX_PATH_RUNTIME_SRC)/common/string/strlen.cpp \
    8890        $(VBOX_PATH_RUNTIME_SRC)/common/string/strncmp.cpp \
    89         $(VBOX_PATH_RUNTIME_SRC)/common/string/memcpy.cpp
     91        $(VBOX_PATH_RUNTIME_SRC)/common/string/memchr.cpp \
     92        $(VBOX_PATH_RUNTIME_SRC)/common/string/memcmp.cpp \
     93        $(VBOX_PATH_RUNTIME_SRC)/common/string/memcpy.cpp \
     94        $(VBOX_PATH_RUNTIME_SRC)/common/string/memrchr.cpp \
     95        $(VBOX_PATH_RUNTIME_SRC)/common/string/memset.cpp
    9096 VBoxOs2AdditionsInstall_LIBS             = \
    9197        $(PATH_TOOL_OPENWATCOM)/lib386/os2/os2386.lib
  • trunk/src/VBox/Additions/os2/VBoxOs2AdditionsInstall.cpp

    r93128 r93136  
    2727#include <iprt/ctype.h>
    2828#include <iprt/path.h>
     29
     30
     31/*********************************************************************************************************************************
     32*   Defined Constants And Macros                                                                                                 *
     33*********************************************************************************************************************************/
     34#define SKIP_CONFIG_SYS     0x01
     35#define SKIP_STARTUP_CMD    0x02
     36#define SKIP_SERVICE        0x04
     37#define SKIP_SHARED_FOLDERS 0x08
     38#define SKIP_GRAPHICS       0x10
     39#define SKIP_MOUSE          0x20
     40#define SKIP_LIBC_DLLS      0x40
     41
     42/** NIL HFILE value. */
     43#define MY_NIL_HFILE        (~(HFILE)0)
     44
     45
     46/*********************************************************************************************************************************
     47*   Structures and Typedefs                                                                                                      *
     48*********************************************************************************************************************************/
     49typedef struct FILEEDITOR
     50{
     51    size_t          cbOrg;
     52    char           *pszOrg;
     53    size_t          cbNew;
     54    size_t          cbNewAlloc;
     55    char           *pszNew;
     56    bool            fOverflowed;
     57} FILEEDITOR;
    2958
    3059
     
    4473/** The length of g_szDstPath, including a trailing slash. */
    4574static size_t       g_cchDstPath                    = sizeof("C:\\VBoxGA\\") - 1;
    46 /** Whether to install shared folders. */
    47 static bool         g_fSharedFolders                = true;
    48 /** Whether to install the mouse driver. */
    49 static bool         g_fMouse                        = true;
    50 /** Whether to install the graphics driver. */
    51 static bool         g_fGraphics                     = true;
    52 /** Whether to install the service. */
    53 static bool         g_fService                      = true;
    54 /** Whether to modify startup.cmd to start VBoxService. */
    55 static bool         g_fModifyStartupCmd             = true;
    56 /** Whether to install the kLibC DLLs. */
    57 static bool         g_fLibcDlls                     = true;
     75/** Mask of SKIP_XXX flags of components/tasks to skip. */
     76static uint8_t      g_fSkipMask                     = 0;
     77/** Verbose or quiet. */
     78static bool         g_fVerbose                      = true;
    5879
    5980/** The standard output handle. */
    60 static HFILE const g_hStdOut = (HFILE)1;
     81static HFILE const  g_hStdOut = (HFILE)1;
    6182/** The standard error handle. */
    62 static HFILE const g_hStdErr = (HFILE)2;
    63 
     83static HFILE const  g_hStdErr = (HFILE)2;
     84
     85
     86/** File editor for Config.sys. */
     87static FILEEDITOR   g_ConfigSys;
     88/** File editor for Startup.cmd. */
     89static FILEEDITOR   g_StartupCmd;
     90
     91
     92/*********************************************************************************************************************************
     93*   Messaging.                                                                                                                   *
     94*********************************************************************************************************************************/
    6495
    6596static void DoWriteNStr(HFILE hFile, const char *psz, size_t cch)
     
    74105{
    75106    DoWriteNStr(hFile, psz, strlen(psz));
     107}
     108
     109
     110/** Writes a variable number of strings to @a hFile, stopping at NULL. */
     111static void WriteStrings(HFILE hFile, ...)
     112{
     113    va_list va;
     114    va_start(va, hFile);
     115    for (;;)
     116    {
     117        const char *psz = va_arg(va, const char *);
     118        if (psz)
     119            DoWriteStr(hFile, psz);
     120        else
     121            break;
     122    }
     123    va_end(va);
    76124}
    77125
     
    103151}
    104152
    105 
    106 static RTEXITCODE ApiError(const char *pszMsg, APIRET rc)
     153static RTEXITCODE ApiErrorN(APIRET rc, unsigned cMsgs, ...)
    107154{
    108155    DoWriteNStr(g_hStdErr, RT_STR_TUPLE("VBoxOs2AdditionsInstall: error: "));
    109     DoWriteStr(g_hStdErr, pszMsg);
     156    va_list va;
     157    va_start(va, cMsgs);
     158    while (cMsgs-- > 0)
     159    {
     160        const char *pszMsg = va_arg(va, const char *);
     161        DoWriteStr(g_hStdErr, pszMsg);
     162    }
     163    va_end(va);
    110164    DoWriteNStr(g_hStdErr, RT_STR_TUPLE(": "));
    111165    DoWriteNumber(g_hStdErr, rc);
    112166    DoWriteNStr(g_hStdErr, RT_STR_TUPLE("\r\n"));
    113     return RTEXITCODE_SYNTAX;
    114 }
    115 
     167    return RTEXITCODE_FAILURE;
     168}
     169
     170
     171DECLINLINE(RTEXITCODE) ApiError(const char *pszMsg, APIRET rc)
     172{
     173    return ApiErrorN(rc, 1, pszMsg);
     174}
    116175
    117176
     
    125184
    126185
     186/*********************************************************************************************************************************
     187*   Editor.                                                                                                                      *
     188*********************************************************************************************************************************/
     189
     190/**
     191 * Reads a file into the editor.
     192 */
     193static RTEXITCODE EditorReadInFile(FILEEDITOR *pEditor, const char *pszFilename, size_t cbExtraEdit, bool fMustExist)
     194{
     195    if (g_fVerbose)
     196        WriteStrings(g_hStdOut, "info: Preparing \"", pszFilename, "\" modifications...\r\n", NULL);
     197
     198    /*
     199     * Open the file.
     200     */
     201    HFILE  hFile   = MY_NIL_HFILE;
     202    ULONG  uAction = ~0U;
     203    APIRET rc = DosOpen(pszFilename, &hFile, &uAction, 0, FILE_NORMAL,
     204                        OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
     205                        OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_SEQUENTIAL | OPEN_FLAGS_NOINHERIT,
     206                        NULL /*pEaOp2*/);
     207    if (rc == ERROR_FILE_NOT_FOUND)
     208        hFile = MY_NIL_HFILE;
     209    else if (rc != NO_ERROR)
     210        return ApiErrorN(rc, 3, "DosOpen(\"", pszFilename, "\",READONLY)");
     211
     212    /*
     213     * Get it's size and check that it's sane.
     214     */
     215    FILESTATUS3 FileSts;
     216    if (hFile != MY_NIL_HFILE)
     217    {
     218        rc = DosQueryFileInfo(hFile, FIL_STANDARD, &FileSts, sizeof(FileSts));
     219        if (rc != NO_ERROR)
     220            return ApiErrorN(rc, 3, "DosQueryFileInfo(\"", pszFilename, "\",FIL_STANDARD,,)");
     221
     222        if (FileSts.cbFile > _2M)
     223            return ApiErrorN(rc, FileSts.cbFile, "File \"", pszFilename, "\" is too large");
     224    }
     225    else
     226        FileSts.cbFile = 0;
     227
     228    /*
     229     * Allocate buffers.
     230     */
     231    PVOID  pvAlloc = NULL;
     232    size_t cbAlloc = FileSts.cbFile * 2 + cbExtraEdit + 16;
     233    rc = DosAllocMem(&pvAlloc, cbAlloc, PAG_COMMIT | PAG_WRITE | PAG_READ);
     234    if (rc == NO_ERROR)
     235        return ApiError("DosAllocMem", rc);
     236
     237    memset(pvAlloc, 0, cbAlloc);
     238    pEditor->cbOrg      = FileSts.cbFile;
     239    pEditor->pszOrg     = (char *)pvAlloc;
     240    pEditor->pszNew     = (char *)pvAlloc + FileSts.cbFile + 1;
     241    pEditor->cbNew      = 0;
     242    pEditor->cbNewAlloc = cbAlloc - FileSts.cbFile - 2;
     243
     244    /*
     245     * Read in the file content.
     246     */
     247    if (hFile != MY_NIL_HFILE)
     248    {
     249        ULONG cbRead = 0;
     250        rc = DosRead(hFile, pEditor->pszOrg, FileSts.cbFile, &cbRead);
     251        if (rc != NO_ERROR)
     252            return ApiErrorN(rc, 3, "DosRead(\"", pszFilename, "\")");
     253        if (cbRead != FileSts.cbFile)
     254            return ApiErrorN(cbRead < FileSts.cbFile ? ERROR_MORE_DATA : ERROR_BUFFER_OVERFLOW,
     255                             3, "DosRead(\"", pszFilename, "\")");
     256        DosClose(hFile);
     257    }
     258
     259    return RTEXITCODE_SUCCESS;
     260}
     261
     262
     263/**
     264 * Writes out a modified file, backing up the original.
     265 */
     266static RTEXITCODE EditorWriteOutFile(FILEEDITOR *pEditor, const char *pszFilename)
     267{
     268    if (g_fVerbose)
     269        WriteStrings(g_hStdOut, "info: Writing out \"", pszFilename, "\" modifications...\r\n", NULL);
     270
     271    /*
     272     * Skip if no change was made.
     273     */
     274    if (   pEditor->cbNew == 0
     275        || (   pEditor->cbNew == pEditor->cbOrg
     276            && memcmp(pEditor->pszNew, pEditor->pszOrg, pEditor->cbNew) == 0))
     277    {
     278        WriteStrings(g_hStdOut, "info: No changes to \"", pszFilename, "\".\r\n", NULL);
     279        return RTEXITCODE_SUCCESS;
     280    }
     281
     282    /*
     283     * Back up the original.
     284     * ASSUMES that the input is CCHMAXPATH or less.
     285     */
     286    if (pEditor->cbOrg != 0)
     287    {
     288        CHAR         szBackup[CCHMAXPATH + 16];
     289        size_t const cchFilename = strlen(pszFilename);
     290        memcpy(szBackup, pszFilename, cchFilename + 1);
     291        char *pszExt = (char *)memrchr(szBackup, '.', cchFilename);
     292        if (!pszExt || strchr(pszExt, '\\') || strchr(pszExt, '/'))
     293            pszExt = &szBackup[cchFilename];
     294        strcpy(pszExt, ".BAK");
     295        for (unsigned short i = 0; ; i++)
     296        {
     297            HFILE  hFile   = MY_NIL_HFILE;
     298            ULONG  uAction = ~0U;
     299            APIRET rc = DosOpen(szBackup, &hFile, &uAction, 0, FILE_NORMAL,
     300                                OPEN_ACTION_FAIL_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
     301                                OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_SEQUENTIAL | OPEN_FLAGS_NOINHERIT,
     302                                NULL /*pEaOp2*/);
     303            if (rc == NO_ERROR)
     304            {
     305                ULONG cbWritten = 0;
     306                do
     307                    rc = DosWrite(hFile, pEditor->pszOrg, pEditor->cbOrg, &cbWritten);
     308                while (rc == ERROR_INTERRUPT);
     309                DosClose(hFile);
     310                if (rc != NO_ERROR)
     311                    return ApiErrorN(rc, 5, "Failed backing up \"", pszFilename, "\" as \"", szBackup, "\"");
     312                break;
     313            }
     314
     315            /* try next extension variation */
     316            if (i >= 1000)
     317                return ApiErrorN(rc, 5, "Failed backing up \"", pszFilename, "\" as \"", szBackup, "\"");
     318            if (i >= 100)
     319                pszExt[1] = '0' + (i / 100);
     320            if (i >= 10)
     321                pszExt[2] = '0' + (i / 100 % 10);
     322            pszExt[3] = '0' + (i % 10);
     323        }
     324    }
     325
     326    /*
     327     * Write out the new copy.
     328     */
     329    HFILE  hFile   = MY_NIL_HFILE;
     330    ULONG  uAction = ~0U;
     331    APIRET rc = DosOpen(pszFilename, &hFile, &uAction, 0, FILE_NORMAL,
     332                        OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
     333                        OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_SEQUENTIAL | OPEN_FLAGS_NOINHERIT,
     334                        NULL /*pEaOp2*/);
     335    if (rc != NO_ERROR)
     336        return ApiErrorN(rc, 3, "Opening \"", pszFilename, "\" for writing");
     337
     338    ULONG cbWritten = 0;
     339    do
     340        rc = DosWrite(hFile, pEditor->pszNew, pEditor->cbNew, &cbWritten);
     341    while (rc == ERROR_INTERRUPT);
     342
     343    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     344    if (rc != NO_ERROR)
     345        rcExit = ApiErrorN(rc, 3, "Failed writing \"", pszFilename, "\"");
     346    else if (cbWritten != pEditor->cbNew)
     347        rcExit = ApiErrorN(ERROR_MORE_DATA, 3, "Failed writing \"", pszFilename, "\" - incomplete write");
     348
     349    rc = DosClose(hFile);
     350    if (rc != NO_ERROR)
     351        rcExit = ApiErrorN(rc, 3, "Failed closing \"", pszFilename, "\"");
     352
     353    return rcExit;
     354}
     355
     356
     357/**
     358 * Gets the next line.
     359 *
     360 * @returns The offset to pass to the next EditorGetLine call.
     361 * @retval  0 if no further lines in the input file.
     362 *
     363 * @param   pEditor     Pointer to the editor.
     364 * @param   offSrc      The current source offset. Initialize to zero before
     365 *                      first calls and pass return value for subsequent calls
     366 * @param   ppchLine    Where to return the pointer to the start of the line.
     367 * @param   pcchLine    Where to return the length of the line (sans EOL).
     368 */
     369static size_t EditorGetLine(FILEEDITOR *pEditor, size_t offSrc, const char **ppchLine, size_t *pcchLine)
     370{
     371    if (offSrc < pEditor->cbOrg)
     372    {
     373        const char *pchLine = &pEditor->pszOrg[offSrc];
     374        *ppchLine = pchLine;
     375
     376        size_t      cchMax  = pEditor->cbOrg - offSrc;
     377        const char *pchCr   = (const char *)memchr(pchLine, '\r', cchMax);
     378        const char *pchNl   = (const char *)memchr(pchLine, '\n', pchCr ? pchCr - pchLine : cchMax);
     379        size_t      cchLine;
     380        size_t      cchEol;
     381        if (pchCr && !pchNl)
     382        {
     383            cchLine = pchCr - pchLine;
     384            cchEol  = 1 + (pchCr[1] == '\n');
     385        }
     386        else if (pchNl)
     387        {
     388            cchLine = pchNl - pchLine;
     389            cchEol  = 1;
     390        }
     391        else
     392        {
     393            cchLine = cchMax;
     394            cchEol  = 0;
     395        }
     396        *pcchLine = cchLine;
     397        return offSrc + cchLine + cchEol;
     398    }
     399
     400    *ppchLine = "";
     401    *pcchLine = 0;
     402    return 0;
     403}
     404
     405
     406/**
     407 * Adds a line to the output buffer.
     408 *
     409 * A CRLF is appended automatically.
     410 *
     411 * @returns true on success, false on overflow (error displayed and sets
     412 *          fOverflowed on the editor).
     413 *
     414 * @param   pEditor     Pointer to the editor.
     415 * @param   pchLine     Pointer to the line string.
     416 * @param   cchLine     The length of the line (sans newline).
     417 */
     418static bool EditorPutLine(FILEEDITOR *pEditor, const char *pchLine, size_t cchLine)
     419{
     420    size_t offNew = pEditor->cbNew;
     421    if (offNew + cchLine + 2 < pEditor->cbNewAlloc)
     422    {
     423        char *pszNew = pEditor->pszNew;
     424        memcpy(&pszNew[offNew], pchLine, cchLine);
     425        offNew += cchLine;
     426        pszNew[offNew++] = '\r';
     427        pszNew[offNew++] = '\n';
     428        pszNew[offNew]   = '\0';
     429        pEditor->cbNew   = offNew;
     430        return true;
     431    }
     432    pEditor->fOverflowed = true;
     433    return false;
     434}
     435
     436
     437/**
     438 * Writes a string to the output buffer.
     439 *
     440 * @returns true on success, false on overflow (error displayed and sets
     441 *          fOverflowed on the editor).
     442 *
     443 * @param   pEditor     Pointer to the editor.
     444 * @param   pchString   Pointer to the string.
     445 * @param   cchString   The length of the string.
     446 */
     447static bool EditorPutStringN(FILEEDITOR *pEditor, const char *pchString, size_t cchString)
     448{
     449    size_t offNew = pEditor->cbNew;
     450    if (offNew + cchString < pEditor->cbNewAlloc)
     451    {
     452        char *pszNew = pEditor->pszNew;
     453        memcpy(&pszNew[offNew], pchString, cchString);
     454        offNew += cchString;
     455        pszNew[offNew]   = '\0';
     456        pEditor->cbNew   = offNew;
     457        return true;
     458    }
     459    pEditor->fOverflowed = true;
     460    return false;
     461}
     462
     463
     464/*********************************************************************************************************************************
     465*   Installation Steps.                                                                                                          *
     466*********************************************************************************************************************************/
    127467
    128468/**
     
    131471static RTEXITCODE CheckForGradd(void)
    132472{
     473    strcpy(&g_szBootDrivePath[g_cchBootDrivePath], "OS2\\DLL\\GENGRADD.DLL");
     474    FILESTATUS3 FileSts;
     475    APIRET rc = DosQueryPathInfo(g_szBootDrivePath, FIL_STANDARD, &FileSts, sizeof(FileSts));
     476    if (rc != NO_ERROR)
     477        return ApiErrorN(rc, 3, "DosQueryPathInfo(\"", g_szBootDrivePath, "\",,,) - installed gengradd?");
    133478    return RTEXITCODE_SUCCESS;
     479}
     480
     481
     482/**
     483 * Checks if the path @a pchString ends with @a pszFilename, ignoring case.
     484 *
     485 * @returns true if filename found, false if not.
     486 * @param   pchString           The image PATH of a DEVICE or IFS statement.
     487 * @param   cchString           The length of valid string.
     488 * @param   pszFilename         The filename (no path) to match with, all upper
     489 *                              cased.
     490 * @param   cchFilename         The length of the filename to match with.
     491 */
     492static bool MatchOnlyFilename(const char *pchString, size_t cchString, const char *pszFilename, size_t cchFilename)
     493{
     494    /*
     495     * Skip ahead in pchString till we get to the filename.
     496     */
     497    size_t offFilename = 0;
     498    size_t offCur      = 0;
     499    if (   cchString > 2
     500        && pchString[1] == ':'
     501        && RT_C_IS_ALPHA(pchString[0]))
     502        offCur += 2;
     503    while (offCur < cchString)
     504    {
     505        char ch = pchString[offCur];
     506        if (RTPATH_IS_SLASH(pchString[offCur]))
     507            offFilename = offCur + 1;
     508        else if (RT_C_IS_BLANK(ch))
     509            break;
     510        offCur++;
     511    }
     512    size_t const cchLeftFilename = offCur - offFilename;
     513
     514    /*
     515     * Check if the length matches.
     516     */
     517    if (cchLeftFilename != cchFilename)
     518        return false;
     519
     520    /*
     521     * Check if the filenames matches (ASSUMES right side is uppercased).
     522     */
     523    pchString += offFilename;
     524    while (cchFilename-- > 0)
     525    {
     526        if (RT_C_TO_UPPER(*pchString) != *pszFilename)
     527            return false;
     528        pchString++;
     529        pszFilename++;
     530    }
     531    return true;
     532}
     533
     534
     535/** Adds DEVICE=[path]\VBoxGuest.sys to the modified Config.sys. */
     536static bool ConfigSysAddVBoxGuest(void)
     537{
     538    EditorPutStringN(&g_ConfigSys, RT_STR_TUPLE("DEVICE="));
     539    EditorPutStringN(&g_ConfigSys, g_szDstPath, g_cchDstPath);
     540    EditorPutLine(&g_ConfigSys, RT_STR_TUPLE("VBoxGuest.sys"));
     541    return true;
     542}
     543
     544
     545/** Adds IFS=[path]\VBoxFS.IFS to the modified Config.sys. */
     546static bool ConfigSysAddVBoxSF(void)
     547{
     548    EditorPutStringN(&g_ConfigSys, RT_STR_TUPLE("IFS="));
     549    EditorPutStringN(&g_ConfigSys, g_szDstPath, g_cchDstPath);
     550    EditorPutLine(&g_ConfigSys, RT_STR_TUPLE("VBoxSF.ifs"));
     551    return true;
     552}
     553
     554
     555/** Adds DEVICE=[path]\VBoxMouse.sys to the modified Config.sys. */
     556static bool ConfigSysAddVBoxMouse(void)
     557{
     558    EditorPutStringN(&g_ConfigSys, RT_STR_TUPLE("DEVICE="));
     559    EditorPutStringN(&g_ConfigSys, g_szDstPath, g_cchDstPath);
     560    EditorPutLine(&g_ConfigSys, RT_STR_TUPLE("VBoxMouse.sys"));
     561    return true;
    134562}
    135563
     
    140568static RTEXITCODE PrepareConfigSys(void)
    141569{
     570    if (g_fSkipMask & SKIP_CONFIG_SYS)
     571        return RTEXITCODE_SUCCESS;
     572
     573    strcpy(&g_szBootDrivePath[g_cchBootDrivePath], "CONFIG.SYS");
     574    RTEXITCODE rcExit = EditorReadInFile(&g_ConfigSys, g_szBootDrivePath, 2048, true /*fMustExist*/);
     575    if (rcExit != RTEXITCODE_SUCCESS)
     576        return rcExit;
     577
     578    /*
     579     * Figure out which IFS we should place ourselves after by examining the
     580     * destination path's file system, assuming HPFS if we cannot figure it out.
     581     */
     582    const char *pszAfterIfs =        "HPFS.IFS";
     583    size_t      cchAfterIfs = sizeof("HPFS.IFS") - 1;
     584
     585    union
     586    {
     587        FSQBUFFER2 FsQBuf;
     588        uint8_t abPadding[1024];
     589    } u;
     590    memset(&u, 0, sizeof(u));
     591    ULONG cbBuf = sizeof(u) - 8 /* for adding .IFS */;
     592
     593    char szDrv[4];
     594    szDrv[0] = g_szDstPath[0];
     595    szDrv[1] = g_szDstPath[1];
     596    szDrv[2] = '\0';
     597
     598    APIRET rc = DosQueryFSAttach(szDrv, 0 /*iOrdinal*/, FSAIL_QUERYNAME, &u.FsQBuf, &cbBuf);
     599    if (   rc == NO_ERROR
     600        || (rc == ERROR_BUFFER_OVERFLOW && u.FsQBuf.cbFSDName > 2 && u.FsQBuf.cbFSDName <= 7))
     601    {
     602        char *pszFsdName = (char *)&u.FsQBuf.szName[u.FsQBuf.cbName + 1];
     603        if (   RT_C_IS_ALNUM(pszFsdName[0])
     604            && RT_C_IS_ALNUM(pszFsdName[1])
     605            && pszFsdName[u.FsQBuf.cbFSDName] == '\0')
     606        {
     607            /* MatchOnlyFilename requires it to be all uppercase (should be the case already). */
     608            size_t off = u.FsQBuf.cbFSDName;
     609            while (off-- > 0)
     610                pszFsdName[off] = RT_C_TO_UPPER(pszFsdName[off]);
     611
     612            /* Add the IFS suffix. */
     613            strcpy(&pszFsdName[u.FsQBuf.cbFSDName], ".IFS");
     614            pszAfterIfs = pszFsdName;
     615            cchAfterIfs = u.FsQBuf.cbFSDName + sizeof(".IFS") - 1;
     616
     617            if (g_fVerbose)
     618                WriteStrings(g_hStdOut, "info: Found \"IFS=", pszFsdName, "\" for ", pszFsdName, "\r\n", NULL);
     619        }
     620        else
     621        {
     622            pszFsdName[10] = '\0';
     623            ApiErrorN(ERROR_INVALID_NAME, 5, "Bogus FSD name \"", pszFsdName, "\" for ", szDrv, " - assuming HPFS");
     624        }
     625    }
     626    else
     627        ApiErrorN(rc, 3, "DosQueryFSAttach(", szDrv, ") - assuming HPFS");
     628
     629    /*
     630     * Do a scan to locate where to insert ourselves and such.
     631     */
     632    char        szLineNo[32];
     633    bool        fInsertedGuest = false;
     634    bool        fInsertedMouse = RT_BOOL(g_fSkipMask & SKIP_MOUSE);
     635    bool        fPendingMouse  = false;
     636    bool        fInsertedIfs   = RT_BOOL(g_fSkipMask & SKIP_SHARED_FOLDERS);
     637    unsigned    cPathsFound    = 0;
     638    unsigned    iLine  = 0;
     639    size_t      offSrc = 0;
     640    const char *pchLine;
     641    size_t      cchLine;
     642    while ((offSrc = EditorGetLine(&g_ConfigSys, offSrc, &pchLine, &cchLine)) != 0)
     643    {
     644        iLine++;
     645
     646        size_t off = 0;
     647#define SKIP_BLANKS() \
     648            while (off < cchLine && RT_C_IS_BLANK(pchLine[off])) \
     649                off++
     650
     651        bool fDone = false;
     652        SKIP_BLANKS();
     653
     654        /*
     655         * Add the destination directory to the PATH.
     656         * If there are multiple SET PATH statements, we add ourselves to all of them.
     657         */
     658        if (   cchLine - off >= sizeof("SET PATH=") - 1
     659            && (pchLine[off + 0] == 'S' || pchLine[off + 0] == 's')
     660            && (pchLine[off + 1] == 'E' || pchLine[off + 1] == 'e')
     661            && (pchLine[off + 2] == 'T' || pchLine[off + 2] == 't')
     662            && RT_C_IS_BLANK(pchLine[off + 3]))
     663        {
     664            off += 4;
     665            SKIP_BLANKS();
     666            if (   cchLine - off >= sizeof("PATH=") - 1
     667                && (pchLine[off + 0] == 'P' || pchLine[off + 0] == 'p')
     668                && (pchLine[off + 1] == 'A' || pchLine[off + 1] == 'a')
     669                && (pchLine[off + 2] == 'T' || pchLine[off + 2] == 't')
     670                && (pchLine[off + 3] == 'H' || pchLine[off + 3] == 'h'))
     671            {
     672                off += 4;
     673                SKIP_BLANKS();
     674                if (cchLine > off && pchLine[off] == '=')
     675                {
     676                    off++;
     677                    SKIP_BLANKS();
     678
     679                    if (g_fVerbose)
     680                        WriteStrings(g_hStdOut, "info: Config.sys line ", MyNumToString(szLineNo, iLine), ": SET PATH\r\n", NULL);
     681
     682                    /* check if already part of the string */
     683                    bool fNeeded = true;
     684                    /** @todo look for destination directory in PATH. */
     685
     686                    if (fNeeded)
     687                    {
     688                        while (cchLine > off && RT_C_IS_BLANK(pchLine[cchLine - 1]))
     689                            cchLine--;
     690                        EditorPutStringN(&g_ConfigSys, pchLine, cchLine);
     691                        if (pchLine[cchLine - 1] != ';')
     692                            EditorPutStringN(&g_ConfigSys, RT_STR_TUPLE(";"));
     693                        EditorPutStringN(&g_ConfigSys, g_szDstPath, g_cchDstPath - (g_cchDstPath > 3 ? 1 : 0));
     694                        EditorPutLine(&g_ConfigSys, RT_STR_TUPLE(";"));
     695                        fDone = true;
     696                    }
     697                    cPathsFound += 1;
     698                }
     699            }
     700        }
     701        /*
     702         * Look for that IFS that should be loaded before we can load our drivers.
     703         */
     704        else if (   cchLine - off >= sizeof("IFS=XX.IFS") - 1
     705                 && (pchLine[off + 0] == 'I' || pchLine[off + 0] == 'i')
     706                 && (pchLine[off + 1] == 'F' || pchLine[off + 1] == 'f')
     707                 && (pchLine[off + 2] == 'S' || pchLine[off + 2] == 's')
     708                 && (pchLine[off + 3] == '=' || RT_C_IS_BLANK(pchLine[off + 3])) )
     709        {
     710            off += 3;
     711            SKIP_BLANKS();
     712            if (cchLine > off && pchLine[off] == '=')
     713            {
     714                off++;
     715                SKIP_BLANKS();
     716                if (MatchOnlyFilename(&pchLine[off], cchLine - off, pszAfterIfs, cchAfterIfs))
     717                {
     718                    if (g_fVerbose)
     719                        WriteStrings(g_hStdOut, "info: Config.sys line ", MyNumToString(szLineNo, iLine),
     720                                     ": Found IFS=", pszAfterIfs, "\r\n", NULL);
     721                    EditorPutLine(&g_ConfigSys, pchLine, cchLine);
     722                    fDone = true;
     723
     724                    if (!fInsertedGuest)
     725                        fInsertedGuest = ConfigSysAddVBoxGuest();
     726                    if (!fInsertedIfs)
     727                        fInsertedIfs   = ConfigSysAddVBoxSF();
     728                    if (fPendingMouse && !fInsertedMouse)
     729                        fInsertedMouse = ConfigSysAddVBoxMouse();
     730                }
     731                /* Remove old VBoxSF.IFS lines */
     732                else if (   !(g_fSkipMask & SKIP_SHARED_FOLDERS)
     733                         && MatchOnlyFilename(&pchLine[off], cchLine, RT_STR_TUPLE("VBOXSF.IFS")))
     734                {
     735                    if (g_fVerbose)
     736                        WriteStrings(g_hStdOut, "info: Config.sys line ", MyNumToString(szLineNo, iLine),
     737                                     ": Removing old VBoxSF.ifs statement\r\n", NULL);
     738                    fDone = true;
     739                }
     740            }
     741        }
     742        /*
     743         * Look for the mouse driver we need to comment out / existing VBoxMouse.sys,
     744         * as well as older VBoxGuest.sys statements we should remove.
     745         */
     746        else if (   cchLine - off >= sizeof("DEVICE=XX.SYS") - 1
     747                 && (pchLine[off + 0] == 'D' || pchLine[off + 0] == 'd')
     748                 && (pchLine[off + 1] == 'E' || pchLine[off + 1] == 'e')
     749                 && (pchLine[off + 2] == 'V' || pchLine[off + 2] == 'v')
     750                 && (pchLine[off + 3] == 'I' || pchLine[off + 3] == 'i')
     751                 && (pchLine[off + 4] == 'C' || pchLine[off + 4] == 'c')
     752                 && (pchLine[off + 5] == 'E' || pchLine[off + 5] == 'e')
     753                 && (pchLine[off + 6] == '=' || RT_C_IS_BLANK(pchLine[off + 6])) )
     754        {
     755            off += 6;
     756            SKIP_BLANKS();
     757            if (cchLine > off && pchLine[off] == '=')
     758            {
     759                off++;
     760                SKIP_BLANKS();
     761                if (   !(g_fSkipMask & SKIP_MOUSE)
     762                    && MatchOnlyFilename(&pchLine[off], cchLine - off, RT_STR_TUPLE("MOUSE.SYS")))
     763                {
     764                    if (g_fVerbose)
     765                        WriteStrings(g_hStdOut, "info: Config.sys line ", MyNumToString(szLineNo, iLine),
     766                                     ": Found DEVICE=<path>\\MOUSE.SYS\r\n", NULL);
     767                    EditorPutStringN(&g_ConfigSys, RT_STR_TUPLE("REM "));
     768                    EditorPutLine(&g_ConfigSys, pchLine, cchLine);
     769                    fDone = true;
     770
     771                    if (!fInsertedMouse)
     772                    {
     773                        if (fInsertedGuest) /* means we've found the IFS and can access the destination dir */
     774                            fInsertedMouse = ConfigSysAddVBoxMouse();
     775                        else
     776                            fPendingMouse = true;
     777                    }
     778                }
     779                /* Remove or replace old VBoxMouse.IFS lines */
     780                else if (   !(g_fSkipMask & SKIP_MOUSE)
     781                         && MatchOnlyFilename(&pchLine[off], cchLine, RT_STR_TUPLE("VBOXMOUSE.SYS")))
     782                {
     783                    if (g_fVerbose)
     784                        WriteStrings(g_hStdOut, "info: Config.sys line ", MyNumToString(szLineNo, iLine), ": ",
     785                                     fInsertedMouse || !fInsertedGuest ? "Removing" : "Replacing",
     786                                     " old VBoxMouse.sys statement\r\n", NULL);
     787                    if (!fInsertedMouse)
     788                    {
     789                        if (fInsertedGuest) /* means we've found the IFS and can access the destination dir */
     790                            fInsertedMouse = ConfigSysAddVBoxMouse();
     791                        else
     792                            fPendingMouse = true;
     793                    }
     794                    fDone = true;
     795                }
     796                /* Remove old VBoxGuest.sys lines. */
     797                else if (MatchOnlyFilename(&pchLine[off], cchLine, RT_STR_TUPLE("VBOXGUEST.SYS")))
     798                {
     799                    if (g_fVerbose)
     800                        WriteStrings(g_hStdOut, "info: Config.sys line ", MyNumToString(szLineNo, iLine),
     801                                     ": Removing old VBoxGuest.sys statement\r\n", NULL);
     802                    fDone = true;
     803                }
     804            }
     805        }
     806#undef SKIP_BLANKS
     807
     808        /*
     809         * Output the current line if we didn't already do so above.
     810         */
     811        if (!fDone)
     812            EditorPutLine(&g_ConfigSys, pchLine, cchLine);
     813    }
     814
     815    /*
     816     * If we've still got pending stuff, add it now at the end.
     817     */
     818    if (!fInsertedGuest)
     819        fInsertedGuest = ConfigSysAddVBoxGuest();
     820    if (!fInsertedIfs)
     821        fInsertedIfs   = ConfigSysAddVBoxSF();
     822    if (!fInsertedMouse)
     823        fInsertedMouse = ConfigSysAddVBoxMouse();
     824
     825    if (!cPathsFound)
     826        WriteStrings(g_hStdErr, "warning: Found no SET PATH statement in Config.sys.\r\n", NULL);
     827
    142828    return RTEXITCODE_SUCCESS;
    143829}
     
    149835static RTEXITCODE PrepareStartupCmd(void)
    150836{
     837    if (g_fSkipMask & SKIP_STARTUP_CMD)
     838        return RTEXITCODE_SUCCESS;
     839
     840    strcpy(&g_szBootDrivePath[g_cchBootDrivePath], "STARTUP.CMD");
     841    RTEXITCODE rcExit = EditorReadInFile(&g_StartupCmd, g_szBootDrivePath, 1024, false /*fMustExist*/);
     842    if (rcExit != RTEXITCODE_SUCCESS)
     843        return rcExit;
     844
    151845    return RTEXITCODE_SUCCESS;
     846}
     847
     848
     849/**
     850 * Worker for CopyFiles that handles one copying operation.
     851 */
     852static RTEXITCODE CopyOneFile(const char *pszSrc, const char *pszDst)
     853{
     854    if (g_fVerbose)
     855        WriteStrings(g_hStdOut, "info: Copying \"", pszSrc, "\" to \"", pszDst, "\"...\r\n", NULL);
     856
     857    /* Make sure the destination file isn't read-only before attempting to copying it. */
     858    FILESTATUS3 FileSts;
     859    APIRET rc = DosQueryPathInfo(pszDst, FIL_STANDARD, &FileSts, sizeof(FileSts));
     860    if (rc != NO_ERROR && (FileSts.attrFile & FILE_READONLY))
     861    {
     862        rc = DosQueryPathInfo(pszDst, FIL_STANDARD, &FileSts, sizeof(FileSts));
     863
     864        FileSts.attrFile &= ~FILE_READONLY;
     865
     866        /* Don't update the timestamps: */
     867        *(USHORT *)&FileSts.fdateCreation   = 0;
     868        *(USHORT *)&FileSts.ftimeCreation   = 0;
     869        *(USHORT *)&FileSts.fdateLastAccess = 0;
     870        *(USHORT *)&FileSts.ftimeLastAccess = 0;
     871        *(USHORT *)&FileSts.fdateLastWrite  = 0;
     872        *(USHORT *)&FileSts.ftimeLastWrite  = 0;
     873
     874        rc = DosSetPathInfo(pszDst, FIL_STANDARD, &FileSts, sizeof(FileSts), 0 /*fOptions*/);
     875        if (rc != NO_ERROR)
     876            ApiErrorN(rc, 3, "DosSetPathInfo(\"", pszDst, "\",~READONLY,)");
     877    }
     878
     879    /* Do the copying. */
     880    rc = DosCopy(pszSrc, pszDst, DCPY_EXISTING);
     881    if (rc == NO_ERROR)
     882        return RTEXITCODE_SUCCESS;
     883    if (rc != ERROR_SHARING_VIOLATION)
     884        return ApiErrorN(rc, 3, "Failed copying to \"", pszDst, "\"");
     885
     886    if (g_fVerbose)
     887        DoWriteNStr(g_hStdOut, RT_STR_TUPLE("info: Sharing violation - applying DosReplaceModule...\r\n"));
     888    rc = DosReplaceModule(pszDst, NULL, NULL);
     889    if (rc != NO_ERROR)
     890        ApiErrorN(rc, 3, "DosReplaceModule(\"", pszDst, "\",,)");
     891
     892    rc = DosCopy(pszSrc, pszDst, DCPY_EXISTING);
     893    if (rc == NO_ERROR)
     894        return RTEXITCODE_SUCCESS;
     895    return ApiErrorN(rc, 3, "Failed copying to \"", pszDst, "\"");
    152896}
    153897
     
    158902static RTEXITCODE CopyFiles(void)
    159903{
    160     return RTEXITCODE_SUCCESS;
     904    /*
     905     * Create the install directory.  We do this from the root up as that is
     906     * a nice feature and saves us dealing with trailing slash troubles.
     907     */
     908    char *psz = g_szDstPath;
     909    if (psz[1] == ':' && RTPATH_IS_SLASH(psz[2]))
     910        psz += 3;
     911    else if (psz[1] == ':')
     912        psz += 2;
     913    else
     914        return ApiError("Unexpected condition", __LINE__);
     915
     916    for (;;)
     917    {
     918        char ch;
     919        while ((ch = *psz) != '\0' && !RTPATH_IS_SLASH(ch))
     920            psz++;
     921        if (ch != '\0')
     922            *psz = '\0';
     923        APIRET rc = DosMkDir(g_szDstPath, 0);
     924        if (rc != NO_ERROR && rc != ERROR_ALREADY_EXISTS)
     925            return ApiErrorN(rc, 3, "DosMkDir(\"", g_szDstPath, "\")");
     926        if (ch == '\0')
     927            break;
     928        *psz++ = ch;
     929        while ((ch = *psz) != '\0' && RTPATH_IS_SLASH(ch))
     930            psz++;
     931        if (ch == '\0')
     932            break;
     933    }
     934
     935    /*
     936     * Start copying files.  We copy all files into the directory regardless
     937     * of whether they will be referenced by config.sys, startup.cmd or whatever.
     938     */
     939    static struct
     940    {
     941        const char *pszFile;
     942        const char *pszAltDst;
     943        uint8_t     fSkipMask;
     944    } const s_aFiles[] =
     945    {
     946        { "VBoxService.exe",    NULL, 0 }, /* first as likely to be running */
     947        { "VBoxControl.exe",    NULL, 0 },
     948        { "VBoxReplaceDll.exe", NULL, 0 },
     949        { "gengradd.dll",       "\\OS2\\DLL\\gengradd.dll", SKIP_GRAPHICS },
     950        { "libc06.dll",         "\\OS2\\DLL\\libc06.dll",  SKIP_LIBC_DLLS },
     951        { "libc061.dll",        "\\OS2\\DLL\\libc061.dll", SKIP_LIBC_DLLS },
     952        { "libc062.dll",        "\\OS2\\DLL\\libc062.dll", SKIP_LIBC_DLLS },
     953        { "libc063.dll",        "\\OS2\\DLL\\libc063.dll", SKIP_LIBC_DLLS },
     954        { "libc064.dll",        "\\OS2\\DLL\\libc064.dll", SKIP_LIBC_DLLS },
     955        { "libc065.dll",        "\\OS2\\DLL\\libc065.dll", SKIP_LIBC_DLLS },
     956        { "libc066.dll",        "\\OS2\\DLL\\libc066.dll", SKIP_LIBC_DLLS },
     957        { "VBoxGuest.sys",      NULL, 0 },
     958        { "VBoxSF.ifs",         NULL, 0 },
     959        { "vboxmouse.sys",      NULL, 0 },
     960        { "readme.txt",         NULL, 0 },
     961    };
     962
     963    RTEXITCODE rcExit;
     964    for (size_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
     965    {
     966        /* Always copy files to the destination folder. */
     967        strcpy(&g_szSrcPath[g_cchSrcPath], s_aFiles[i].pszFile);
     968        strcpy(&g_szDstPath[g_cchDstPath], s_aFiles[i].pszFile);
     969        RTEXITCODE rcExit2 = CopyOneFile(g_szSrcPath, g_szDstPath);
     970        if (rcExit2 != RTEXITCODE_SUCCESS)
     971            rcExit = rcExit2;
     972
     973        /* Additional install location and this not being skipped? */
     974        if (   s_aFiles[i].pszAltDst
     975            && !(s_aFiles[i].fSkipMask & g_fSkipMask) /* ASSUMES one skip bit per file */)
     976        {
     977            strcpy(&g_szBootDrivePath[g_cchBootDrivePath], s_aFiles[i].pszFile);
     978
     979            rcExit2 = CopyOneFile(g_szSrcPath, g_szBootDrivePath);
     980            if (rcExit2 != RTEXITCODE_SUCCESS)
     981                rcExit = rcExit2;
     982        }
     983    }
     984
     985    return rcExit;
    161986}
    162987
     
    167992static RTEXITCODE WriteConfigSys(void)
    168993{
    169     return RTEXITCODE_SUCCESS;
     994    if (g_fSkipMask & SKIP_CONFIG_SYS)
     995        return RTEXITCODE_SUCCESS;
     996    strcpy(&g_szBootDrivePath[g_cchBootDrivePath], "CONFIG.SYS");
     997    return EditorWriteOutFile(&g_ConfigSys, g_szBootDrivePath);
    170998}
    171999
     
    1761004static RTEXITCODE WriteStartupCmd(void)
    1771005{
    178     return RTEXITCODE_SUCCESS;
    179 }
    180 
     1006    if (g_fSkipMask & SKIP_CONFIG_SYS)
     1007        return RTEXITCODE_SUCCESS;
     1008    strcpy(&g_szBootDrivePath[g_cchBootDrivePath], "STARTUP.CMD");
     1009    return EditorWriteOutFile(&g_ConfigSys, g_szBootDrivePath);
     1010}
     1011
     1012
     1013/*********************************************************************************************************************************
     1014*   Option parsing and such.                                                                                                     *
     1015*********************************************************************************************************************************/
    1811016
    1821017static RTEXITCODE ShowUsage(void)
    1831018{
    184     static const char g_szUsage[] = "Usage:\r\n";
     1019    static const char g_szUsage[] =
     1020        VBOX_PRODUCT " OS/2 Additions Installer " VBOX_VERSION_STRING "\r\n"
     1021        "(C) 2005-" VBOX_C_YEAR " " VBOX_VENDOR "\r\n"
     1022        "\r\n"
     1023        "This is a very barebone OS/2 guest additions installer which main purpose is\r\n"
     1024        "to help with unattended installation.  Do not expect it to handle complicated\r\n"
     1025        "situations like upgrades and similar.  It also does not understand arguments\r\n"
     1026        "that are placed in double quotes.\r\n"
     1027        "\r\n"
     1028        "Usage: VBoxIs2AdditionsInstall.exe [options]\r\n"
     1029        "   or  VBoxIs2AdditionsInstall.exe <-h|-?|--help>\r\n"
     1030        "   or  VBoxIs2AdditionsInstall.exe <-v|--version>\r\n"
     1031        "\r\n"
     1032        "Options\r\n:"
     1033        "  -s<path>, --source[=]<path>\r\n"
     1034        "      Specifies where the files to install are.  Default: Same as installer\r\n"
     1035        "  -d<path>, --destination[=]<path>\r\n"
     1036        "      Specifies where to install all the VBox OS/2 additions files.\r\n"
     1037        "      Default: C:\VBoxGA  (C is replaced by actual boot drive)\r\n"
     1038        "  -b<path>, --boot-drive[=]<path>\r\n"
     1039        "      Specifies the boot drive.  Default: C: (C is replaced by the actual one)\r\n"
     1040        "  -F, --no-shared-folders  /  -f, --shared-folders (default)\r\n"
     1041        "      Controls whether to put the shared folders IFS in Config.sys.\r\n"
     1042        "  -G, --no-graphics        /  -g, --graphics (default)\r\n"
     1043        "      Controls whether to replace OS2\\DLL\\GENGRADD.DLL with the VBox version.\r\n"
     1044        "  -M, --no-mouse           /  -m, --mouse (default)\r\n"
     1045        "      Controls whether to add the VBox mouse driver to Config.sys and disable\r\n"
     1046        "      the regular OS/2 one.\r\n"
     1047        "  -S, --no-service         /  -s, --service (default)\r\n"
     1048        "      Controls whether to add starting VBoxService from Startup.cmd.\r\n"
     1049        "  -T, --no-startup-cmd     /  -t, --startup-cmd (default)\r\n"
     1050        "      Controls whether to modify Startup.cmd.\r\n"
     1051        "  -C, --no-config-sys      /  -c, --config-sys (default)\r\n"
     1052        "      Controls whether to modify Config.sys.\r\n"
     1053        "  -L, --no-libc-dlls       /  -l, --libc-dlls (default)\r\n"
     1054        "      Controls whether copy the kLibC DLLs to OS2\\DLLS.\r\n"
     1055        "  -q, --quiet              /  -V, --verbose (default)\r\n"
     1056        "      Controls the installer noise level.\r\n"
     1057        "\r\n"
     1058        "Exit Codes:\r\n"
     1059        "   0 - Success. Reboot required.\r\n"
     1060        "   1 - Failure.\r\n"
     1061        "   2 - Syntax error.\r\n"
     1062        ;
    1851063    DoWriteNStr(g_hStdOut, RT_STR_TUPLE(g_szUsage));
    1861064    return RTEXITCODE_SUCCESS;
     
    1901068static RTEXITCODE ShowVersion(void)
    1911069{
    192     static const char g_szRev[] = "$Rev$\r\n";
    193     DoWriteNStr(g_hStdOut, RT_STR_TUPLE(g_szRev));
     1070    DoWriteNStr(g_hStdOut, RT_STR_TUPLE(VBOX_VERSION_STRING " r"));
     1071
     1072    const char *pszRev = "$Rev$";
     1073    while (!RT_C_IS_DIGIT(*pszRev))
     1074        pszRev++;
     1075    size_t cchRev = 1;
     1076    while (RT_C_IS_DIGIT(pszRev[cchRev]))
     1077        cchRev++;
     1078    DoWriteNStr(g_hStdOut, pszRev, cchRev);
     1079
     1080    DoWriteNStr(g_hStdOut, RT_STR_TUPLE("\r\n"));
    1941081    return RTEXITCODE_SUCCESS;
    195 
    1961082}
    1971083
     
    3341220            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("no-service")))
    3351221                ch = 'S';
    336             else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("modify-startup-cmd")))
     1222            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("startup-cmd")))
    3371223                ch = 't';
    338             else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("no-modify-startup-cmd")))
     1224            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("no-startup-cmd")))
    3391225                ch = 'T';
     1226            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("config-sys")))
     1227                ch = 'c';
     1228            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("no-config-sys")))
     1229                ch = 'C';
    3401230            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("libc-dlls")))
    3411231                ch = 'l';
    3421232            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("no-libc-dlls")))
    3431233                ch = 'L';
     1234            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("quiet")))
     1235                ch = 'q';
     1236            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("verbose")))
     1237                ch = 'V';
    3441238            else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("help")))
    3451239                ch = 'h';
     
    3801274                    break;
    3811275
    382                 case 'f':
    383                     g_fSharedFolders = true;
     1276#define SKIP_OPT_CASES(a_chSkip, a_chDontSkip, a_fFlag) \
     1277                case a_chDontSkip: g_fSkipMask &= ~(a_fFlag); break; \
     1278                case a_chSkip:     g_fSkipMask |=  (a_fFlag); break
     1279                SKIP_OPT_CASES('F', 'f', SKIP_SHARED_FOLDERS);
     1280                SKIP_OPT_CASES('G', 'g', SKIP_GRAPHICS);
     1281                SKIP_OPT_CASES('M', 'm', SKIP_MOUSE);
     1282                SKIP_OPT_CASES('E', 'e', SKIP_SERVICE);
     1283                SKIP_OPT_CASES('U', 'u', SKIP_STARTUP_CMD);
     1284                SKIP_OPT_CASES('C', 'c', SKIP_CONFIG_SYS);
     1285                SKIP_OPT_CASES('L', 'l', SKIP_LIBC_DLLS);
     1286#undef SKIP_OPT_CASES
     1287
     1288                case 'q':
     1289                    g_fVerbose = false;
    3841290                    break;
    385                 case 'F':
    386                     g_fSharedFolders = false;
    387                     break;
    388 
    389                 case 'g':
    390                     g_fGraphics = true;
    391                     break;
    392                 case 'G':
    393                     g_fGraphics = false;
    394                     break;
    395 
    396                 case 'm':
    397                     g_fMouse = true;
    398                     break;
    399                 case 'M':
    400                     g_fMouse = false;
    401                     break;
    402 
    403                 case 'e':
    404                     g_fService = true;
    405                     break;
    406                 case 'E':
    407                     g_fService = false;
    408                     break;
    409 
    410                 case 'u':
    411                     g_fModifyStartupCmd = true;
    412                     break;
    413                 case 'U':
    414                     g_fModifyStartupCmd = false;
    415                     break;
    416 
    417                 case 'l':
    418                     g_fLibcDlls = true;
    419                     break;
    420                 case 'L':
    421                     g_fLibcDlls = false;
     1291
     1292                case 'V':
     1293                    g_fVerbose = true;
    4221294                    break;
    4231295
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