| /** @file | |
| Reading/writing MBR/DBR. | |
| NOTE: | |
| If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written. | |
| If we process DBR, we will patch MBR to set first partition active if no active partition exists. | |
| Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <windows.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <Common/UefiBaseTypes.h> | |
| #include "ParseInf.h" | |
| #include "EfiUtilityMsgs.h" | |
| #include "CommonLib.h" | |
| // | |
| // Utility Name | |
| // | |
| #define UTILITY_NAME "GenBootSector" | |
| // | |
| // Utility version information | |
| // | |
| #define UTILITY_MAJOR_VERSION 0 | |
| #define UTILITY_MINOR_VERSION 2 | |
| #define MAX_DRIVE 26 | |
| #define PARTITION_TABLE_OFFSET 0x1BE | |
| #define SIZE_OF_PARTITION_ENTRY 0x10 | |
| #define PARTITION_ENTRY_STARTLBA_OFFSET 8 | |
| #define PARTITION_ENTRY_NUM 4 | |
| INT | |
| GetDrvNumOffset ( | |
| IN VOID *BootSector | |
| ); | |
| typedef enum { | |
| PatchTypeUnknown, | |
| PatchTypeFloppy, | |
| PatchTypeIde, | |
| PatchTypeUsb, | |
| PatchTypeFileImage // input and output are all file image, patching action is same as PatchTypeFloppy | |
| } PATCH_TYPE; | |
| typedef enum { | |
| PathUnknown, | |
| PathFile, | |
| PathFloppy, | |
| PathUsb, | |
| PathIde | |
| } PATH_TYPE; | |
| typedef enum { | |
| ErrorSuccess, | |
| ErrorFileCreate, | |
| ErrorFileReadWrite, | |
| ErrorNoMbr, | |
| ErrorFatType, | |
| ErrorPath, | |
| } ERROR_STATUS; | |
| CHAR *ErrorStatusDesc[] = { | |
| "Success", | |
| "Failed to create files", | |
| "Failed to read/write files", | |
| "No MBR exists", | |
| "Failed to detect Fat type", | |
| "Inavlid path" | |
| }; | |
| typedef struct _DRIVE_TYPE_DESC { | |
| UINT Type; | |
| CHAR *Description; | |
| } DRIVE_TYPE_DESC; | |
| #define DRIVE_TYPE_ITEM(x) {x, #x} | |
| DRIVE_TYPE_DESC DriveTypeDesc[] = { | |
| DRIVE_TYPE_ITEM (DRIVE_UNKNOWN), | |
| DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR), | |
| DRIVE_TYPE_ITEM (DRIVE_REMOVABLE), | |
| DRIVE_TYPE_ITEM (DRIVE_FIXED), | |
| DRIVE_TYPE_ITEM (DRIVE_REMOTE), | |
| DRIVE_TYPE_ITEM (DRIVE_CDROM), | |
| DRIVE_TYPE_ITEM (DRIVE_RAMDISK), | |
| (UINT) -1, NULL | |
| }; | |
| typedef struct _DRIVE_INFO { | |
| CHAR VolumeLetter; | |
| DRIVE_TYPE_DESC *DriveType; | |
| UINT DiskNumber; | |
| } DRIVE_INFO; | |
| typedef struct _PATH_INFO { | |
| CHAR *Path; | |
| CHAR PhysicalPath[260]; | |
| PATH_TYPE Type; | |
| BOOL Input; | |
| } PATH_INFO; | |
| #define BOOT_SECTOR_LBA_OFFSET 0x1FA | |
| #define IsLetter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z')) | |
| BOOL | |
| GetDriveInfo ( | |
| CHAR VolumeLetter, | |
| DRIVE_INFO *DriveInfo | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get drive information including disk number and drive type, | |
| where disknumber is useful for reading/writing disk raw data. | |
| NOTE: Floppy disk doesn't have disk number but it doesn't matter because | |
| we can reading/writing floppy disk without disk number. | |
| Arguments: | |
| VolumeLetter : volume letter, e.g.: C for C:, A for A: | |
| DriveInfo : pointer to DRIVE_INFO structure receiving drive information. | |
| Return: | |
| TRUE : successful | |
| FALSE : failed | |
| --*/ | |
| { | |
| HANDLE VolumeHandle; | |
| STORAGE_DEVICE_NUMBER StorageDeviceNumber; | |
| DWORD BytesReturned; | |
| BOOL Success; | |
| UINT DriveType; | |
| UINT Index; | |
| CHAR RootPath[] = "X:\\"; // "X:\" -> for GetDriveType | |
| CHAR VolumeAccessPath[] = "\\\\.\\X:"; // "\\.\X:" -> to open the volume | |
| RootPath[0] = VolumeAccessPath[4] = VolumeLetter; | |
| DriveType = GetDriveType(RootPath); | |
| if (DriveType != DRIVE_REMOVABLE && DriveType != DRIVE_FIXED) { | |
| return FALSE; | |
| } | |
| DriveInfo->VolumeLetter = VolumeLetter; | |
| VolumeHandle = CreateFile ( | |
| VolumeAccessPath, | |
| 0, | |
| FILE_SHARE_READ | FILE_SHARE_WRITE, | |
| NULL, | |
| OPEN_EXISTING, | |
| 0, | |
| NULL | |
| ); | |
| if (VolumeHandle == INVALID_HANDLE_VALUE) { | |
| fprintf ( | |
| stderr, | |
| "error E0005: CreateFile failed: Volume = %s, LastError = 0x%lx\n", | |
| VolumeAccessPath, | |
| GetLastError () | |
| ); | |
| return FALSE; | |
| } | |
| // | |
| // Get Disk Number. It should fail when operating on floppy. That's ok | |
| // because Disk Number is only needed when operating on Hard or USB disk. | |
| // | |
| // To direct write to disk: | |
| // for USB and HD: use path = \\.\PHYSICALDRIVEx, where x is Disk Number | |
| // for floppy: use path = \\.\X:, where X can be A or B | |
| // | |
| Success = DeviceIoControl( | |
| VolumeHandle, | |
| IOCTL_STORAGE_GET_DEVICE_NUMBER, | |
| NULL, | |
| 0, | |
| &StorageDeviceNumber, | |
| sizeof(StorageDeviceNumber), | |
| &BytesReturned, | |
| NULL | |
| ); | |
| // | |
| // DeviceIoControl should fail if Volume is floppy or network drive. | |
| // | |
| if (!Success) { | |
| DriveInfo->DiskNumber = (UINT) -1; | |
| } else if (StorageDeviceNumber.DeviceType != FILE_DEVICE_DISK) { | |
| // | |
| // Only care about the disk. | |
| // | |
| CloseHandle(VolumeHandle); | |
| return FALSE; | |
| } else{ | |
| DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber; | |
| } | |
| CloseHandle(VolumeHandle); | |
| // | |
| // Fill in the type string | |
| // | |
| DriveInfo->DriveType = NULL; | |
| for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) { | |
| if (DriveType == DriveTypeDesc[Index].Type) { | |
| DriveInfo->DriveType = &DriveTypeDesc[Index]; | |
| break; | |
| } | |
| } | |
| if (DriveInfo->DriveType == NULL) { | |
| // | |
| // Should have a type. | |
| // | |
| fprintf (stderr, "error E3005: Fatal Error!!!\n"); | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| VOID | |
| ListDrive ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| List every drive in current system and their information. | |
| --*/ | |
| { | |
| UINT Index; | |
| DRIVE_INFO DriveInfo; | |
| UINT Mask = GetLogicalDrives(); | |
| for (Index = 0; Index < MAX_DRIVE; Index++) { | |
| if (((Mask >> Index) & 0x1) == 1) { | |
| if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) { | |
| if (Index < 2) { | |
| // Floppy will occupy 'A' and 'B' | |
| fprintf ( | |
| stdout, | |
| "%c: - Type: %s\n", | |
| DriveInfo.VolumeLetter, | |
| DriveInfo.DriveType->Description | |
| ); | |
| } else { | |
| fprintf ( | |
| stdout, | |
| "%c: - DiskNum: %u, Type: %s\n", | |
| DriveInfo.VolumeLetter, | |
| (unsigned) DriveInfo.DiskNumber, | |
| DriveInfo.DriveType->Description | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| INT | |
| GetBootSectorOffset ( | |
| HANDLE DiskHandle, | |
| PATH_INFO *PathInfo | |
| ) | |
| /*++ | |
| Description: | |
| Get the offset of boot sector. | |
| For non-MBR disk, offset is just 0 | |
| for disk with MBR, offset needs to be calculated by parsing MBR | |
| NOTE: if no one is active, we will patch MBR to select first partition as active. | |
| Arguments: | |
| DiskHandle : HANDLE of disk | |
| PathInfo : PATH_INFO structure. | |
| WriteToDisk : TRUE indicates writing | |
| Return: | |
| -1 : failed | |
| o.w. : Offset to boot sector | |
| --*/ | |
| { | |
| BYTE DiskPartition[0x200]; | |
| DWORD BytesReturn; | |
| DWORD DbrOffset; | |
| DWORD Index; | |
| BOOL HasMbr; | |
| DbrOffset = 0; | |
| HasMbr = FALSE; | |
| SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN); | |
| if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) { | |
| return -1; | |
| } | |
| // | |
| // Check Signature, Jmp, and Boot Indicator. | |
| // if all pass, we assume MBR found. | |
| // | |
| // Check Signature: 55AA | |
| if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) { | |
| // Check Jmp: (EB ?? 90) or (E9 ?? ??) | |
| if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) && | |
| (DiskPartition[0] != 0xE9)) { | |
| // Check Boot Indicator: 0x00 or 0x80 | |
| // Boot Indicator is the first byte of Partition Entry | |
| HasMbr = TRUE; | |
| for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) { | |
| if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) { | |
| HasMbr = FALSE; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (HasMbr) { | |
| // | |
| // Skip MBR | |
| // | |
| for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) { | |
| // | |
| // Found Boot Indicator. | |
| // | |
| if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) { | |
| DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET]; | |
| break; | |
| } | |
| } | |
| // | |
| // If no boot indicator, we manually select 1st partition, and patch MBR. | |
| // | |
| if (Index == PARTITION_ENTRY_NUM) { | |
| DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET]; | |
| if (!PathInfo->Input && (PathInfo->Type == PathUsb)) { | |
| SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN); | |
| DiskPartition[PARTITION_TABLE_OFFSET] = 0x80; | |
| WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL); | |
| } | |
| } | |
| } | |
| return DbrOffset; | |
| } | |
| /** | |
| * Get window file handle for input/ouput disk/file. | |
| * | |
| * @param PathInfo | |
| * @param ProcessMbr | |
| * @param FileHandle | |
| * | |
| * @return ERROR_STATUS | |
| */ | |
| ERROR_STATUS | |
| GetFileHandle ( | |
| PATH_INFO *PathInfo, | |
| BOOL ProcessMbr, | |
| HANDLE *FileHandle, | |
| DWORD *DbrOffset | |
| ) | |
| { | |
| DWORD OpenFlag; | |
| OpenFlag = OPEN_ALWAYS; | |
| if (PathInfo->Input || PathInfo->Type != PathFile) { | |
| OpenFlag = OPEN_EXISTING; | |
| } | |
| *FileHandle = CreateFile( | |
| PathInfo->PhysicalPath, | |
| GENERIC_READ | GENERIC_WRITE, | |
| FILE_SHARE_READ, | |
| NULL, | |
| OpenFlag, | |
| FILE_ATTRIBUTE_NORMAL, | |
| NULL | |
| ); | |
| if (*FileHandle == INVALID_HANDLE_VALUE) { | |
| return ErrorFileCreate; | |
| } | |
| if ((PathInfo->Type == PathIde) || (PathInfo->Type == PathUsb)){ | |
| *DbrOffset = GetBootSectorOffset (*FileHandle, PathInfo); | |
| if (!ProcessMbr) { | |
| // | |
| // 1. Process boot sector, set file pointer to the beginning of boot sector | |
| // | |
| SetFilePointer (*FileHandle, *DbrOffset * 0x200, NULL, FILE_BEGIN); | |
| } else if(*DbrOffset == 0) { | |
| // | |
| // If user want to process Mbr, but no Mbr exists, simply return FALSE | |
| // | |
| return ErrorNoMbr; | |
| } else { | |
| // | |
| // 2. Process MBR, set file pointer to 0 | |
| // | |
| SetFilePointer (*FileHandle, 0, NULL, FILE_BEGIN); | |
| } | |
| } | |
| return ErrorSuccess; | |
| } | |
| /** | |
| Writing or reading boot sector or MBR according to the argument. | |
| @param InputInfo PATH_INFO instance for input path | |
| @param OutputInfo PATH_INFO instance for output path | |
| @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector | |
| @return ERROR_STATUS | |
| **/ | |
| ERROR_STATUS | |
| ProcessBsOrMbr ( | |
| PATH_INFO *InputInfo, | |
| PATH_INFO *OutputInfo, | |
| BOOL ProcessMbr | |
| ) | |
| { | |
| BYTE DiskPartition[0x200] = {0}; | |
| BYTE DiskPartitionBackup[0x200] = {0}; | |
| DWORD BytesReturn; | |
| INT DrvNumOffset; | |
| HANDLE InputHandle = INVALID_HANDLE_VALUE; | |
| HANDLE OutputHandle = INVALID_HANDLE_VALUE; | |
| ERROR_STATUS Status; | |
| DWORD InputDbrOffset; | |
| DWORD OutputDbrOffset; | |
| // | |
| // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr | |
| // | |
| Status = GetFileHandle(InputInfo, ProcessMbr, &InputHandle, &InputDbrOffset); | |
| if (Status != ErrorSuccess) { | |
| goto Done; | |
| } | |
| // | |
| // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr | |
| // | |
| Status = GetFileHandle(OutputInfo, ProcessMbr, &OutputHandle, &OutputDbrOffset); | |
| if (Status != ErrorSuccess) { | |
| goto Done; | |
| } | |
| // | |
| // Read boot sector from source disk/file | |
| // | |
| if (!ReadFile (InputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) { | |
| Status = ErrorFileReadWrite; | |
| goto Done; | |
| } | |
| if (InputInfo->Type == PathUsb) { | |
| // Manually set BS_DrvNum to 0x80 as window's format.exe has a bug which will clear this field discarding USB disk's MBR. | |
| // offset of BS_DrvNum is 0x24 for FAT12/16 | |
| // 0x40 for FAT32 | |
| // | |
| DrvNumOffset = GetDrvNumOffset (DiskPartition); | |
| if (DrvNumOffset == -1) { | |
| Status = ErrorFatType; | |
| goto Done; | |
| } | |
| // | |
| // Some legacy BIOS require 0x80 discarding MBR. | |
| // Question left here: is it needed to check Mbr before set 0x80? | |
| // | |
| DiskPartition[DrvNumOffset] = ((InputDbrOffset > 0) ? 0x80 : 0); | |
| } | |
| if (InputInfo->Type == PathIde) { | |
| // | |
| // Patch LBAOffsetForBootSector | |
| // | |
| *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = InputDbrOffset; | |
| } | |
| if (OutputInfo->Type != PathFile) { | |
| if (ProcessMbr) { | |
| // | |
| // Use original partition table | |
| // | |
| if (!ReadFile (OutputHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) { | |
| Status = ErrorFileReadWrite; | |
| goto Done; | |
| } | |
| memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40); | |
| SetFilePointer (OutputHandle, 0, NULL, FILE_BEGIN); | |
| } | |
| } | |
| // | |
| // Write boot sector to taget disk/file | |
| // | |
| if (!WriteFile (OutputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) { | |
| Status = ErrorFileReadWrite; | |
| goto Done; | |
| } | |
| Done: | |
| if (InputHandle != INVALID_HANDLE_VALUE) { | |
| CloseHandle (InputHandle); | |
| } | |
| if (OutputHandle != INVALID_HANDLE_VALUE) { | |
| CloseHandle (OutputHandle); | |
| } | |
| return Status; | |
| } | |
| void | |
| Version ( | |
| void | |
| ) | |
| /*++ | |
| Routine Description: | |
| Displays the standard utility information to SDTOUT | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); | |
| } | |
| VOID | |
| PrintUsage ( | |
| void | |
| ) | |
| { | |
| printf ("Usage: GenBootSector [options] --cfg-file CFG_FILE\n\n\ | |
| Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.\n\n\ | |
| Utility to retrieve and update the boot sector or MBR.\n\n\ | |
| optional arguments:\n\ | |
| -h, --help Show this help message and exit\n\ | |
| --version Show program's version number and exit\n\ | |
| -d [DEBUG], --debug [DEBUG]\n\ | |
| Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\ | |
| - 9 (max)\n\ | |
| -v, --verbose Print informational statements\n\ | |
| -q, --quiet Returns the exit code, error messages will be\n\ | |
| displayed\n\ | |
| -s, --silent Returns only the exit code; informational and error\n\ | |
| messages are not displayed\n\ | |
| -l, --list List disk drives\n\ | |
| -i INPUT_FILENAME, --input INPUT_FILENAME\n\ | |
| Input file name\n\ | |
| -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\ | |
| Output file name\n\ | |
| -m, --mbr Also process the MBR\n\ | |
| --sfo Reserved for future use\n"); | |
| } | |
| /** | |
| Get path information, including physical path for windows platform. | |
| @param PathInfo Point to PATH_INFO structure. | |
| @return whether path is valid. | |
| **/ | |
| ERROR_STATUS | |
| GetPathInfo ( | |
| PATH_INFO *PathInfo | |
| ) | |
| { | |
| DRIVE_INFO DriveInfo; | |
| CHAR VolumeLetter; | |
| CHAR DiskPathTemplate[] = "\\\\.\\PHYSICALDRIVE%u"; | |
| CHAR FloppyPathTemplate[] = "\\\\.\\%c:"; | |
| FILE *f; | |
| // | |
| // If path is disk path | |
| // | |
| if (IsLetter(PathInfo->Path[0]) && (PathInfo->Path[1] == ':') && (PathInfo->Path[2] == '\0')) { | |
| VolumeLetter = PathInfo->Path[0]; | |
| if ((VolumeLetter == 'A') || (VolumeLetter == 'a') || | |
| (VolumeLetter == 'B') || (VolumeLetter == 'b')) { | |
| PathInfo->Type = PathFloppy; | |
| sprintf (PathInfo->PhysicalPath, FloppyPathTemplate, VolumeLetter); | |
| return ErrorSuccess; | |
| } | |
| if (!GetDriveInfo(VolumeLetter, &DriveInfo)) { | |
| fprintf (stderr, "ERROR: GetDriveInfo - 0x%lx\n", GetLastError ()); | |
| return ErrorPath; | |
| } | |
| if (!PathInfo->Input && (DriveInfo.DriveType->Type == DRIVE_FIXED)) { | |
| fprintf (stderr, "ERROR: Could patch own IDE disk!\n"); | |
| return ErrorPath; | |
| } | |
| sprintf(PathInfo->PhysicalPath, DiskPathTemplate, DriveInfo.DiskNumber); | |
| if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) { | |
| PathInfo->Type = PathUsb; | |
| } else if (DriveInfo.DriveType->Type == DRIVE_FIXED) { | |
| PathInfo->Type = PathIde; | |
| } else { | |
| fprintf (stderr, "ERROR, Invalid disk path - %s", PathInfo->Path); | |
| return ErrorPath; | |
| } | |
| return ErrorSuccess; | |
| } | |
| PathInfo->Type = PathFile; | |
| if (PathInfo->Input) { | |
| // | |
| // If path is file path, check whether file is valid. | |
| // | |
| f = fopen (LongFilePath (PathInfo->Path), "r"); | |
| if (f == NULL) { | |
| fprintf (stderr, "error E2003: File was not provided!\n"); | |
| return ErrorPath; | |
| } | |
| fclose (f); | |
| } | |
| PathInfo->Type = PathFile; | |
| strcpy(PathInfo->PhysicalPath, PathInfo->Path); | |
| return ErrorSuccess; | |
| } | |
| INT | |
| main ( | |
| INT argc, | |
| CHAR *argv[] | |
| ) | |
| { | |
| CHAR8 *AppName; | |
| INTN Index; | |
| BOOLEAN ProcessMbr; | |
| ERROR_STATUS Status; | |
| EFI_STATUS EfiStatus; | |
| PATH_INFO InputPathInfo = {0}; | |
| PATH_INFO OutputPathInfo = {0}; | |
| UINT64 LogLevel; | |
| SetUtilityName (UTILITY_NAME); | |
| AppName = *argv; | |
| argv ++; | |
| argc --; | |
| ProcessMbr = FALSE; | |
| if (argc == 0) { | |
| PrintUsage(); | |
| return 0; | |
| } | |
| // | |
| // Parse command line | |
| // | |
| for (Index = 0; Index < argc; Index ++) { | |
| if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) { | |
| ListDrive (); | |
| return 0; | |
| } | |
| if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) { | |
| ProcessMbr = TRUE; | |
| continue; | |
| } | |
| if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) { | |
| InputPathInfo.Path = argv[Index + 1]; | |
| InputPathInfo.Input = TRUE; | |
| if (InputPathInfo.Path == NULL) { | |
| Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL"); | |
| return 1; | |
| } | |
| if (InputPathInfo.Path[0] == '-') { | |
| Error (NULL, 0, 1003, "Invalid option value", "Input file is missing"); | |
| return 1; | |
| } | |
| ++Index; | |
| continue; | |
| } | |
| if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) { | |
| OutputPathInfo.Path = argv[Index + 1]; | |
| OutputPathInfo.Input = FALSE; | |
| if (OutputPathInfo.Path == NULL) { | |
| Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL"); | |
| return 1; | |
| } | |
| if (OutputPathInfo.Path[0] == '-') { | |
| Error (NULL, 0, 1003, "Invalid option value", "Output file is missing"); | |
| return 1; | |
| } | |
| ++Index; | |
| continue; | |
| } | |
| if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) { | |
| PrintUsage (); | |
| return 0; | |
| } | |
| if (stricmp (argv[Index], "--version") == 0) { | |
| Version (); | |
| return 0; | |
| } | |
| if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) { | |
| continue; | |
| } | |
| if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) { | |
| continue; | |
| } | |
| if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) { | |
| EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel); | |
| if (EFI_ERROR (EfiStatus)) { | |
| Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]); | |
| return 1; | |
| } | |
| if (LogLevel > 9) { | |
| Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel); | |
| return 1; | |
| } | |
| SetPrintLevel (LogLevel); | |
| DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]); | |
| ++Index; | |
| continue; | |
| } | |
| // | |
| // Don't recognize the parameter. | |
| // | |
| Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]); | |
| return 1; | |
| } | |
| if (InputPathInfo.Path == NULL) { | |
| Error (NULL, 0, 1001, "Missing options", "Input file is missing"); | |
| return 1; | |
| } | |
| if (OutputPathInfo.Path == NULL) { | |
| Error (NULL, 0, 1001, "Missing options", "Output file is missing"); | |
| return 1; | |
| } | |
| if (GetPathInfo(&InputPathInfo) != ErrorSuccess) { | |
| Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found."); | |
| return 1; | |
| } | |
| if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) { | |
| Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found."); | |
| return 1; | |
| } | |
| // | |
| // Process DBR (Patch or Read) | |
| // | |
| Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr); | |
| if (Status == ErrorSuccess) { | |
| fprintf ( | |
| stdout, | |
| "%s %s: successful!\n", | |
| (OutputPathInfo.Type != PathFile) ? "Write" : "Read", | |
| ProcessMbr ? "MBR" : "DBR" | |
| ); | |
| return 0; | |
| } else { | |
| fprintf ( | |
| stderr, | |
| "%s: %s %s: failed - %s (LastError: 0x%lx)!\n", | |
| (Status == ErrorNoMbr) ? "WARNING" : "ERROR", | |
| (OutputPathInfo.Type != PathFile) ? "Write" : "Read", | |
| ProcessMbr ? "MBR" : "DBR", | |
| ErrorStatusDesc[Status], | |
| GetLastError () | |
| ); | |
| return 1; | |
| } | |
| } |