- Timestamp:
- Jan 7, 2022 3:05:59 AM (3 years ago)
- Location:
- trunk/src/VBox/Additions/os2
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/os2/Makefile.kmk
r93128 r93136 47 47 # A barebone installer. 48 48 # 49 if 049 if 1 50 50 PROGRAMS += VBoxOs2AdditionsInstall 51 51 endif … … 85 85 VBoxOs2AdditionsInstall_SOURCES += \ 86 86 VBoxOs2AdditionsInstallA.asm \ 87 $(VBOX_PATH_RUNTIME_SRC)/common/string/strcpy.cpp \ 88 $(VBOX_PATH_RUNTIME_SRC)/common/string/strchr.cpp \ 87 89 $(VBOX_PATH_RUNTIME_SRC)/common/string/strlen.cpp \ 88 90 $(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 90 96 VBoxOs2AdditionsInstall_LIBS = \ 91 97 $(PATH_TOOL_OPENWATCOM)/lib386/os2/os2386.lib -
trunk/src/VBox/Additions/os2/VBoxOs2AdditionsInstall.cpp
r93128 r93136 27 27 #include <iprt/ctype.h> 28 28 #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 *********************************************************************************************************************************/ 49 typedef 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; 29 58 30 59 … … 44 73 /** The length of g_szDstPath, including a trailing slash. */ 45 74 static 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. */ 76 static uint8_t g_fSkipMask = 0; 77 /** Verbose or quiet. */ 78 static bool g_fVerbose = true; 58 79 59 80 /** The standard output handle. */ 60 static HFILE const g_hStdOut = (HFILE)1;81 static HFILE const g_hStdOut = (HFILE)1; 61 82 /** The standard error handle. */ 62 static HFILE const g_hStdErr = (HFILE)2; 63 83 static HFILE const g_hStdErr = (HFILE)2; 84 85 86 /** File editor for Config.sys. */ 87 static FILEEDITOR g_ConfigSys; 88 /** File editor for Startup.cmd. */ 89 static FILEEDITOR g_StartupCmd; 90 91 92 /********************************************************************************************************************************* 93 * Messaging. * 94 *********************************************************************************************************************************/ 64 95 65 96 static void DoWriteNStr(HFILE hFile, const char *psz, size_t cch) … … 74 105 { 75 106 DoWriteNStr(hFile, psz, strlen(psz)); 107 } 108 109 110 /** Writes a variable number of strings to @a hFile, stopping at NULL. */ 111 static 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); 76 124 } 77 125 … … 103 151 } 104 152 105 106 static RTEXITCODE ApiError(const char *pszMsg, APIRET rc) 153 static RTEXITCODE ApiErrorN(APIRET rc, unsigned cMsgs, ...) 107 154 { 108 155 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); 110 164 DoWriteNStr(g_hStdErr, RT_STR_TUPLE(": ")); 111 165 DoWriteNumber(g_hStdErr, rc); 112 166 DoWriteNStr(g_hStdErr, RT_STR_TUPLE("\r\n")); 113 return RTEXITCODE_SYNTAX; 114 } 115 167 return RTEXITCODE_FAILURE; 168 } 169 170 171 DECLINLINE(RTEXITCODE) ApiError(const char *pszMsg, APIRET rc) 172 { 173 return ApiErrorN(rc, 1, pszMsg); 174 } 116 175 117 176 … … 125 184 126 185 186 /********************************************************************************************************************************* 187 * Editor. * 188 *********************************************************************************************************************************/ 189 190 /** 191 * Reads a file into the editor. 192 */ 193 static 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 */ 266 static 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 */ 369 static 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 */ 418 static 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 */ 447 static 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 *********************************************************************************************************************************/ 127 467 128 468 /** … … 131 471 static RTEXITCODE CheckForGradd(void) 132 472 { 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?"); 133 478 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 */ 492 static 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. */ 536 static 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. */ 546 static 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. */ 556 static 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; 134 562 } 135 563 … … 140 568 static RTEXITCODE PrepareConfigSys(void) 141 569 { 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 142 828 return RTEXITCODE_SUCCESS; 143 829 } … … 149 835 static RTEXITCODE PrepareStartupCmd(void) 150 836 { 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 151 845 return RTEXITCODE_SUCCESS; 846 } 847 848 849 /** 850 * Worker for CopyFiles that handles one copying operation. 851 */ 852 static 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, "\""); 152 896 } 153 897 … … 158 902 static RTEXITCODE CopyFiles(void) 159 903 { 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; 161 986 } 162 987 … … 167 992 static RTEXITCODE WriteConfigSys(void) 168 993 { 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); 170 998 } 171 999 … … 176 1004 static RTEXITCODE WriteStartupCmd(void) 177 1005 { 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 *********************************************************************************************************************************/ 181 1016 182 1017 static RTEXITCODE ShowUsage(void) 183 1018 { 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 ; 185 1063 DoWriteNStr(g_hStdOut, RT_STR_TUPLE(g_szUsage)); 186 1064 return RTEXITCODE_SUCCESS; … … 190 1068 static RTEXITCODE ShowVersion(void) 191 1069 { 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")); 194 1081 return RTEXITCODE_SUCCESS; 195 196 1082 } 197 1083 … … 334 1220 else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("no-service"))) 335 1221 ch = 'S'; 336 else if (MatchOptWord(&pszArgs, RT_STR_TUPLE(" modify-startup-cmd")))1222 else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("startup-cmd"))) 337 1223 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"))) 339 1225 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'; 340 1230 else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("libc-dlls"))) 341 1231 ch = 'l'; 342 1232 else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("no-libc-dlls"))) 343 1233 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'; 344 1238 else if (MatchOptWord(&pszArgs, RT_STR_TUPLE("help"))) 345 1239 ch = 'h'; … … 380 1274 break; 381 1275 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; 384 1290 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; 422 1294 break; 423 1295
Note:
See TracChangeset
for help on using the changeset viewer.