1 /** @file 2 Reading/writing MBR/DBR. 3 NOTE: 4 If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written. 5 If we process DBR, we will patch MBR to set first partition active if no active partition exists. 6 7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 8 This program and the accompanying materials 9 are licensed and made available under the terms and conditions of the BSD License 10 which accompanies this distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include <windows.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <Common/UefiBaseTypes.h> 22 23 #include "ParseInf.h" 24 #include "EfiUtilityMsgs.h" 25 #include "CommonLib.h" 26 27 // 28 // Utility Name 29 // 30 #define UTILITY_NAME "GenBootSector" 31 32 // 33 // Utility version information 34 // 35 #define UTILITY_MAJOR_VERSION 0 36 #define UTILITY_MINOR_VERSION 2 37 38 #define MAX_DRIVE 26 39 #define PARTITION_TABLE_OFFSET 0x1BE 40 41 #define SIZE_OF_PARTITION_ENTRY 0x10 42 43 #define PARTITION_ENTRY_STARTLBA_OFFSET 8 44 45 #define PARTITION_ENTRY_NUM 4 46 47 INT 48 GetDrvNumOffset ( 49 IN VOID *BootSector 50 ); 51 52 typedef enum { 53 PatchTypeUnknown, 54 PatchTypeFloppy, 55 PatchTypeIde, 56 PatchTypeUsb, 57 PatchTypeFileImage // input and output are all file image, patching action is same as PatchTypeFloppy 58 } PATCH_TYPE; 59 60 typedef enum { 61 PathUnknown, 62 PathFile, 63 PathFloppy, 64 PathUsb, 65 PathIde 66 } PATH_TYPE; 67 68 typedef enum { 69 ErrorSuccess, 70 ErrorFileCreate, 71 ErrorFileReadWrite, 72 ErrorNoMbr, 73 ErrorFatType, 74 ErrorPath, 75 } ERROR_STATUS; 76 77 CHAR *ErrorStatusDesc[] = { 78 "Success", 79 "Failed to create files", 80 "Failed to read/write files", 81 "No MBR exists", 82 "Failed to detect Fat type", 83 "Inavlid path" 84 }; 85 86 typedef struct _DRIVE_TYPE_DESC { 87 UINT Type; 88 CHAR *Description; 89 } DRIVE_TYPE_DESC; 90 91 #define DRIVE_TYPE_ITEM(x) {x, #x} 92 DRIVE_TYPE_DESC DriveTypeDesc[] = { 93 DRIVE_TYPE_ITEM (DRIVE_UNKNOWN), 94 DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR), 95 DRIVE_TYPE_ITEM (DRIVE_REMOVABLE), 96 DRIVE_TYPE_ITEM (DRIVE_FIXED), 97 DRIVE_TYPE_ITEM (DRIVE_REMOTE), 98 DRIVE_TYPE_ITEM (DRIVE_CDROM), 99 DRIVE_TYPE_ITEM (DRIVE_RAMDISK), 100 (UINT) -1, NULL 101 }; 102 103 typedef struct _DRIVE_INFO { 104 CHAR VolumeLetter; 105 DRIVE_TYPE_DESC *DriveType; 106 UINT DiskNumber; 107 } DRIVE_INFO; 108 109 typedef struct _PATH_INFO { 110 CHAR *Path; 111 CHAR PhysicalPath[260]; 112 PATH_TYPE Type; 113 BOOL Input; 114 } PATH_INFO; 115 116 #define BOOT_SECTOR_LBA_OFFSET 0x1FA 117 118 #define IsLetter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z')) 119 120 BOOL 121 GetDriveInfo ( 122 CHAR VolumeLetter, 123 DRIVE_INFO *DriveInfo 124 ) 125 /*++ 126 Routine Description: 127 Get drive information including disk number and drive type, 128 where disknumber is useful for reading/writing disk raw data. 129 NOTE: Floppy disk doesn't have disk number but it doesn't matter because 130 we can reading/writing floppy disk without disk number. 131 132 Arguments: 133 VolumeLetter : volume letter, e.g.: C for C:, A for A: 134 DriveInfo : pointer to DRIVE_INFO structure receiving drive information. 135 136 Return: 137 TRUE : successful 138 FALSE : failed 139 --*/ 140 { 141 HANDLE VolumeHandle; 142 STORAGE_DEVICE_NUMBER StorageDeviceNumber; 143 DWORD BytesReturned; 144 BOOL Success; 145 UINT DriveType; 146 UINT Index; 147 148 CHAR RootPath[] = "X:\\"; // "X:\" -> for GetDriveType 149 CHAR VolumeAccessPath[] = "\\\\.\\X:"; // "\\.\X:" -> to open the volume 150 151 RootPath[0] = VolumeAccessPath[4] = VolumeLetter; 152 DriveType = GetDriveType(RootPath); 153 if (DriveType != DRIVE_REMOVABLE && DriveType != DRIVE_FIXED) { 154 return FALSE; 155 } 156 157 DriveInfo->VolumeLetter = VolumeLetter; 158 VolumeHandle = CreateFile ( 159 VolumeAccessPath, 160 0, 161 FILE_SHARE_READ | FILE_SHARE_WRITE, 162 NULL, 163 OPEN_EXISTING, 164 0, 165 NULL 166 ); 167 if (VolumeHandle == INVALID_HANDLE_VALUE) { 168 fprintf ( 169 stderr, 170 "error E0005: CreateFile failed: Volume = %s, LastError = 0x%x\n", 171 VolumeAccessPath, 172 GetLastError () 173 ); 174 return FALSE; 175 } 176 177 // 178 // Get Disk Number. It should fail when operating on floppy. That's ok 179 // because Disk Number is only needed when operating on Hard or USB disk. 180 // 181 // To direct write to disk: 182 // for USB and HD: use path = \\.\PHYSICALDRIVEx, where x is Disk Number 183 // for floppy: use path = \\.\X:, where X can be A or B 184 // 185 Success = DeviceIoControl( 186 VolumeHandle, 187 IOCTL_STORAGE_GET_DEVICE_NUMBER, 188 NULL, 189 0, 190 &StorageDeviceNumber, 191 sizeof(StorageDeviceNumber), 192 &BytesReturned, 193 NULL 194 ); 195 // 196 // DeviceIoControl should fail if Volume is floppy or network drive. 197 // 198 if (!Success) { 199 DriveInfo->DiskNumber = (UINT) -1; 200 } else if (StorageDeviceNumber.DeviceType != FILE_DEVICE_DISK) { 201 // 202 // Only care about the disk. 203 // 204 return FALSE; 205 } else{ 206 DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber; 207 } 208 CloseHandle(VolumeHandle); 209 210 // 211 // Fill in the type string 212 // 213 DriveInfo->DriveType = NULL; 214 for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) { 215 if (DriveType == DriveTypeDesc[Index].Type) { 216 DriveInfo->DriveType = &DriveTypeDesc[Index]; 217 break; 218 } 219 } 220 221 if (DriveInfo->DriveType == NULL) { 222 // 223 // Should have a type. 224 // 225 fprintf (stderr, "error E3005: Fatal Error!!!\n"); 226 return FALSE; 227 } 228 return TRUE; 229 } 230 231 VOID 232 ListDrive ( 233 VOID 234 ) 235 /*++ 236 Routine Description: 237 List every drive in current system and their information. 238 239 --*/ 240 { 241 UINT Index; 242 DRIVE_INFO DriveInfo; 243 244 UINT Mask = GetLogicalDrives(); 245 246 for (Index = 0; Index < MAX_DRIVE; Index++) { 247 if (((Mask >> Index) & 0x1) == 1) { 248 if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) { 249 if (Index < 2) { 250 // Floppy will occupy 'A' and 'B' 251 fprintf ( 252 stdout, 253 "%c: - Type: %s\n", 254 DriveInfo.VolumeLetter, 255 DriveInfo.DriveType->Description 256 ); 257 } else { 258 fprintf ( 259 stdout, 260 "%c: - DiskNum: %u, Type: %s\n", 261 DriveInfo.VolumeLetter, 262 (unsigned) DriveInfo.DiskNumber, 263 DriveInfo.DriveType->Description 264 ); 265 } 266 } 267 } 268 } 269 270 } 271 272 INT 273 GetBootSectorOffset ( 274 HANDLE DiskHandle, 275 PATH_INFO *PathInfo 276 ) 277 /*++ 278 Description: 279 Get the offset of boot sector. 280 For non-MBR disk, offset is just 0 281 for disk with MBR, offset needs to be calculated by parsing MBR 282 283 NOTE: if no one is active, we will patch MBR to select first partition as active. 284 285 Arguments: 286 DiskHandle : HANDLE of disk 287 PathInfo : PATH_INFO structure. 288 WriteToDisk : TRUE indicates writing 289 290 Return: 291 -1 : failed 292 o.w. : Offset to boot sector 293 --*/ 294 { 295 BYTE DiskPartition[0x200]; 296 DWORD BytesReturn; 297 DWORD DbrOffset; 298 DWORD Index; 299 BOOL HasMbr; 300 301 DbrOffset = 0; 302 HasMbr = FALSE; 303 304 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN); 305 if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) { 306 return -1; 307 } 308 309 // 310 // Check Signature, Jmp, and Boot Indicator. 311 // if all pass, we assume MBR found. 312 // 313 314 // Check Signature: 55AA 315 if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) { 316 // Check Jmp: (EB ?? 90) or (E9 ?? ??) 317 if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) && 318 (DiskPartition[0] != 0xE9)) { 319 // Check Boot Indicator: 0x00 or 0x80 320 // Boot Indicator is the first byte of Partition Entry 321 HasMbr = TRUE; 322 for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) { 323 if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) { 324 HasMbr = FALSE; 325 break; 326 } 327 } 328 } 329 } 330 331 if (HasMbr) { 332 // 333 // Skip MBR 334 // 335 for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) { 336 // 337 // Found Boot Indicator. 338 // 339 if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) { 340 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET]; 341 break; 342 } 343 } 344 // 345 // If no boot indicator, we manually select 1st partition, and patch MBR. 346 // 347 if (Index == PARTITION_ENTRY_NUM) { 348 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET]; 349 if (!PathInfo->Input && (PathInfo->Type == PathUsb)) { 350 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN); 351 DiskPartition[PARTITION_TABLE_OFFSET] = 0x80; 352 WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL); 353 } 354 } 355 } 356 357 return DbrOffset; 358 } 359 360 /** 361 * Get window file handle for input/ouput disk/file. 362 * 363 * @param PathInfo 364 * @param ProcessMbr 365 * @param FileHandle 366 * 367 * @return ERROR_STATUS 368 */ 369 ERROR_STATUS 370 GetFileHandle ( 371 PATH_INFO *PathInfo, 372 BOOL ProcessMbr, 373 HANDLE *FileHandle, 374 DWORD *DbrOffset 375 ) 376 { 377 DWORD OpenFlag; 378 379 OpenFlag = OPEN_ALWAYS; 380 if (PathInfo->Input || PathInfo->Type != PathFile) { 381 OpenFlag = OPEN_EXISTING; 382 } 383 384 *FileHandle = CreateFile( 385 PathInfo->PhysicalPath, 386 GENERIC_READ | GENERIC_WRITE, 387 FILE_SHARE_READ, 388 NULL, 389 OpenFlag, 390 FILE_ATTRIBUTE_NORMAL, 391 NULL 392 ); 393 if (*FileHandle == INVALID_HANDLE_VALUE) { 394 return ErrorFileCreate; 395 } 396 397 if ((PathInfo->Type == PathIde) || (PathInfo->Type == PathUsb)){ 398 *DbrOffset = GetBootSectorOffset (*FileHandle, PathInfo); 399 if (!ProcessMbr) { 400 // 401 // 1. Process boot sector, set file pointer to the beginning of boot sector 402 // 403 SetFilePointer (*FileHandle, *DbrOffset * 0x200, NULL, FILE_BEGIN); 404 } else if(*DbrOffset == 0) { 405 // 406 // If user want to process Mbr, but no Mbr exists, simply return FALSE 407 // 408 return ErrorNoMbr; 409 } else { 410 // 411 // 2. Process MBR, set file pointer to 0 412 // 413 SetFilePointer (*FileHandle, 0, NULL, FILE_BEGIN); 414 } 415 } 416 417 return ErrorSuccess; 418 } 419 420 /** 421 Writing or reading boot sector or MBR according to the argument. 422 423 @param InputInfo PATH_INFO instance for input path 424 @param OutputInfo PATH_INFO instance for output path 425 @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector 426 427 @return ERROR_STATUS 428 **/ 429 ERROR_STATUS 430 ProcessBsOrMbr ( 431 PATH_INFO *InputInfo, 432 PATH_INFO *OutputInfo, 433 BOOL ProcessMbr 434 ) 435 { 436 BYTE DiskPartition[0x200] = {0}; 437 BYTE DiskPartitionBackup[0x200] = {0}; 438 DWORD BytesReturn; 439 INT DrvNumOffset; 440 HANDLE InputHandle; 441 HANDLE OutputHandle; 442 ERROR_STATUS Status; 443 DWORD InputDbrOffset; 444 DWORD OutputDbrOffset; 445 446 // 447 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr 448 // 449 Status = GetFileHandle(InputInfo, ProcessMbr, &InputHandle, &InputDbrOffset); 450 if (Status != ErrorSuccess) { 451 return Status; 452 } 453 454 // 455 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr 456 // 457 Status = GetFileHandle(OutputInfo, ProcessMbr, &OutputHandle, &OutputDbrOffset); 458 if (Status != ErrorSuccess) { 459 return Status; 460 } 461 462 // 463 // Read boot sector from source disk/file 464 // 465 if (!ReadFile (InputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) { 466 return ErrorFileReadWrite; 467 } 468 469 if (InputInfo->Type == PathUsb) { 470 // Manually set BS_DrvNum to 0x80 as window's format.exe has a bug which will clear this field discarding USB disk's MBR. 471 // offset of BS_DrvNum is 0x24 for FAT12/16 472 // 0x40 for FAT32 473 // 474 DrvNumOffset = GetDrvNumOffset (DiskPartition); 475 if (DrvNumOffset == -1) { 476 return ErrorFatType; 477 } 478 // 479 // Some legacy BIOS require 0x80 discarding MBR. 480 // Question left here: is it needed to check Mbr before set 0x80? 481 // 482 DiskPartition[DrvNumOffset] = ((InputDbrOffset > 0) ? 0x80 : 0); 483 } 484 485 if (InputInfo->Type == PathIde) { 486 // 487 // Patch LBAOffsetForBootSector 488 // 489 *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = InputDbrOffset; 490 } 491 492 if (OutputInfo->Type != PathFile) { 493 if (ProcessMbr) { 494 // 495 // Use original partition table 496 // 497 if (!ReadFile (OutputHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) { 498 return ErrorFileReadWrite; 499 } 500 memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40); 501 SetFilePointer (OutputHandle, 0, NULL, FILE_BEGIN); 502 503 } 504 } 505 506 // 507 // Write boot sector to taget disk/file 508 // 509 if (!WriteFile (OutputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) { 510 return ErrorFileReadWrite; 511 } 512 513 CloseHandle (InputHandle); 514 CloseHandle (OutputHandle); 515 516 return ErrorSuccess; 517 } 518 519 void 520 Version ( 521 void 522 ) 523 /*++ 524 525 Routine Description: 526 527 Displays the standard utility information to SDTOUT 528 529 Arguments: 530 531 None 532 533 Returns: 534 535 None 536 537 --*/ 538 { 539 printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); 540 } 541 542 VOID 543 PrintUsage ( 544 void 545 ) 546 { 547 printf ("Usage: GenBootSector [options] --cfg-file CFG_FILE\n\n\ 548 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.\n\n\ 549 Utility to retrieve and update the boot sector or MBR.\n\n\ 550 optional arguments:\n\ 551 -h, --help Show this help message and exit\n\ 552 --version Show program's version number and exit\n\ 553 -d [DEBUG], --debug [DEBUG]\n\ 554 Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\ 555 - 9 (max)\n\ 556 -v, --verbose Print informational statements\n\ 557 -q, --quiet Returns the exit code, error messages will be\n\ 558 displayed\n\ 559 -s, --silent Returns only the exit code; informational and error\n\ 560 messages are not displayed\n\ 561 -l, --list List disk drives\n\ 562 -i INPUT_FILENAME, --input INPUT_FILENAME\n\ 563 Input file name\n\ 564 -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\ 565 Output file name\n\ 566 -m, --mbr Also process the MBR\n\ 567 --sfo Reserved for future use\n"); 568 569 } 570 571 /** 572 Get path information, including physical path for windows platform. 573 574 @param PathInfo Point to PATH_INFO structure. 575 576 @return whether path is valid. 577 **/ 578 ERROR_STATUS 579 GetPathInfo ( 580 PATH_INFO *PathInfo 581 ) 582 { 583 DRIVE_INFO DriveInfo; 584 CHAR VolumeLetter; 585 CHAR DiskPathTemplate[] = "\\\\.\\PHYSICALDRIVE%u"; 586 CHAR FloppyPathTemplate[] = "\\\\.\\%c:"; 587 FILE *f; 588 589 // 590 // If path is disk path 591 // 592 if (IsLetter(PathInfo->Path[0]) && (PathInfo->Path[1] == ':') && (PathInfo->Path[2] == '\0')) { 593 VolumeLetter = PathInfo->Path[0]; 594 if ((VolumeLetter == 'A') || (VolumeLetter == 'a') || 595 (VolumeLetter == 'B') || (VolumeLetter == 'b')) { 596 PathInfo->Type = PathFloppy; 597 sprintf (PathInfo->PhysicalPath, FloppyPathTemplate, VolumeLetter); 598 return ErrorSuccess; 599 } 600 601 if (!GetDriveInfo(VolumeLetter, &DriveInfo)) { 602 fprintf (stderr, "ERROR: GetDriveInfo - 0x%x\n", GetLastError ()); 603 return ErrorPath; 604 } 605 606 if (!PathInfo->Input && (DriveInfo.DriveType->Type == DRIVE_FIXED)) { 607 fprintf (stderr, "ERROR: Could patch own IDE disk!\n"); 608 return ErrorPath; 609 } 610 611 sprintf(PathInfo->PhysicalPath, DiskPathTemplate, DriveInfo.DiskNumber); 612 if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) { 613 PathInfo->Type = PathUsb; 614 } else if (DriveInfo.DriveType->Type == DRIVE_FIXED) { 615 PathInfo->Type = PathIde; 616 } else { 617 fprintf (stderr, "ERROR, Invalid disk path - %s", PathInfo->Path); 618 return ErrorPath; 619 } 620 621 return ErrorSuccess; 622 } 623 624 PathInfo->Type = PathFile; 625 if (PathInfo->Input) { 626 // 627 // If path is file path, check whether file is valid. 628 // 629 f = fopen (LongFilePath (PathInfo->Path), "r"); 630 if (f == NULL) { 631 fprintf (stderr, "error E2003: File was not provided!\n"); 632 return ErrorPath; 633 } 634 } 635 PathInfo->Type = PathFile; 636 strcpy(PathInfo->PhysicalPath, PathInfo->Path); 637 638 return ErrorSuccess; 639 } 640 641 INT 642 main ( 643 INT argc, 644 CHAR *argv[] 645 ) 646 { 647 CHAR8 *AppName; 648 INTN Index; 649 BOOLEAN ProcessMbr; 650 ERROR_STATUS Status; 651 EFI_STATUS EfiStatus; 652 PATH_INFO InputPathInfo = {0}; 653 PATH_INFO OutputPathInfo = {0}; 654 UINT64 LogLevel; 655 656 SetUtilityName (UTILITY_NAME); 657 658 AppName = *argv; 659 argv ++; 660 argc --; 661 662 ProcessMbr = FALSE; 663 664 if (argc == 0) { 665 PrintUsage(); 666 return 0; 667 } 668 669 // 670 // Parse command line 671 // 672 for (Index = 0; Index < argc; Index ++) { 673 if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) { 674 ListDrive (); 675 return 0; 676 } 677 678 if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) { 679 ProcessMbr = TRUE; 680 continue; 681 } 682 683 if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) { 684 InputPathInfo.Path = argv[Index + 1]; 685 InputPathInfo.Input = TRUE; 686 if (InputPathInfo.Path == NULL) { 687 Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL"); 688 return 1; 689 } 690 if (InputPathInfo.Path[0] == '-') { 691 Error (NULL, 0, 1003, "Invalid option value", "Input file is missing"); 692 return 1; 693 } 694 ++Index; 695 continue; 696 } 697 698 if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) { 699 OutputPathInfo.Path = argv[Index + 1]; 700 OutputPathInfo.Input = FALSE; 701 if (OutputPathInfo.Path == NULL) { 702 Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL"); 703 return 1; 704 } 705 if (OutputPathInfo.Path[0] == '-') { 706 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing"); 707 return 1; 708 } 709 ++Index; 710 continue; 711 } 712 713 if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) { 714 PrintUsage (); 715 return 0; 716 } 717 718 if (stricmp (argv[Index], "--version") == 0) { 719 Version (); 720 return 0; 721 } 722 723 if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) { 724 continue; 725 } 726 727 if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) { 728 continue; 729 } 730 731 if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) { 732 EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel); 733 if (EFI_ERROR (EfiStatus)) { 734 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]); 735 return 1; 736 } 737 if (LogLevel > 9) { 738 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel); 739 return 1; 740 } 741 SetPrintLevel (LogLevel); 742 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]); 743 ++Index; 744 continue; 745 } 746 747 // 748 // Don't recognize the parameter. 749 // 750 Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]); 751 return 1; 752 } 753 754 if (InputPathInfo.Path == NULL) { 755 Error (NULL, 0, 1001, "Missing options", "Input file is missing"); 756 return 1; 757 } 758 759 if (OutputPathInfo.Path == NULL) { 760 Error (NULL, 0, 1001, "Missing options", "Output file is missing"); 761 return 1; 762 } 763 764 if (GetPathInfo(&InputPathInfo) != ErrorSuccess) { 765 Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found."); 766 return 1; 767 } 768 769 if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) { 770 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found."); 771 return 1; 772 } 773 774 // 775 // Process DBR (Patch or Read) 776 // 777 Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr); 778 779 if (Status == ErrorSuccess) { 780 fprintf ( 781 stdout, 782 "%s %s: successful!\n", 783 (OutputPathInfo.Type != PathFile) ? "Write" : "Read", 784 ProcessMbr ? "MBR" : "DBR" 785 ); 786 return 0; 787 } else { 788 fprintf ( 789 stderr, 790 "%s: %s %s: failed - %s (LastError: 0x%x)!\n", 791 (Status == ErrorNoMbr) ? "WARNING" : "ERROR", 792 (OutputPathInfo.Type != PathFile) ? "Write" : "Read", 793 ProcessMbr ? "MBR" : "DBR", 794 ErrorStatusDesc[Status], 795 GetLastError () 796 ); 797 return 1; 798 } 799 } 800