]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenBootSector/GenBootSector.c
BaseTools/GenBootSector: Fix file handles not being closed
[mirror_edk2.git] / BaseTools / Source / C / GenBootSector / GenBootSector.c
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 - 2016, 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%lx\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 CloseHandle(VolumeHandle);
205 return FALSE;
206 } else{
207 DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber;
208 }
209 CloseHandle(VolumeHandle);
210
211 //
212 // Fill in the type string
213 //
214 DriveInfo->DriveType = NULL;
215 for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) {
216 if (DriveType == DriveTypeDesc[Index].Type) {
217 DriveInfo->DriveType = &DriveTypeDesc[Index];
218 break;
219 }
220 }
221
222 if (DriveInfo->DriveType == NULL) {
223 //
224 // Should have a type.
225 //
226 fprintf (stderr, "error E3005: Fatal Error!!!\n");
227 return FALSE;
228 }
229 return TRUE;
230 }
231
232 VOID
233 ListDrive (
234 VOID
235 )
236 /*++
237 Routine Description:
238 List every drive in current system and their information.
239
240 --*/
241 {
242 UINT Index;
243 DRIVE_INFO DriveInfo;
244
245 UINT Mask = GetLogicalDrives();
246
247 for (Index = 0; Index < MAX_DRIVE; Index++) {
248 if (((Mask >> Index) & 0x1) == 1) {
249 if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) {
250 if (Index < 2) {
251 // Floppy will occupy 'A' and 'B'
252 fprintf (
253 stdout,
254 "%c: - Type: %s\n",
255 DriveInfo.VolumeLetter,
256 DriveInfo.DriveType->Description
257 );
258 } else {
259 fprintf (
260 stdout,
261 "%c: - DiskNum: %u, Type: %s\n",
262 DriveInfo.VolumeLetter,
263 (unsigned) DriveInfo.DiskNumber,
264 DriveInfo.DriveType->Description
265 );
266 }
267 }
268 }
269 }
270
271 }
272
273 INT
274 GetBootSectorOffset (
275 HANDLE DiskHandle,
276 PATH_INFO *PathInfo
277 )
278 /*++
279 Description:
280 Get the offset of boot sector.
281 For non-MBR disk, offset is just 0
282 for disk with MBR, offset needs to be calculated by parsing MBR
283
284 NOTE: if no one is active, we will patch MBR to select first partition as active.
285
286 Arguments:
287 DiskHandle : HANDLE of disk
288 PathInfo : PATH_INFO structure.
289 WriteToDisk : TRUE indicates writing
290
291 Return:
292 -1 : failed
293 o.w. : Offset to boot sector
294 --*/
295 {
296 BYTE DiskPartition[0x200];
297 DWORD BytesReturn;
298 DWORD DbrOffset;
299 DWORD Index;
300 BOOL HasMbr;
301
302 DbrOffset = 0;
303 HasMbr = FALSE;
304
305 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
306 if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
307 return -1;
308 }
309
310 //
311 // Check Signature, Jmp, and Boot Indicator.
312 // if all pass, we assume MBR found.
313 //
314
315 // Check Signature: 55AA
316 if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) {
317 // Check Jmp: (EB ?? 90) or (E9 ?? ??)
318 if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) &&
319 (DiskPartition[0] != 0xE9)) {
320 // Check Boot Indicator: 0x00 or 0x80
321 // Boot Indicator is the first byte of Partition Entry
322 HasMbr = TRUE;
323 for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) {
324 if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) {
325 HasMbr = FALSE;
326 break;
327 }
328 }
329 }
330 }
331
332 if (HasMbr) {
333 //
334 // Skip MBR
335 //
336 for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) {
337 //
338 // Found Boot Indicator.
339 //
340 if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) {
341 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET];
342 break;
343 }
344 }
345 //
346 // If no boot indicator, we manually select 1st partition, and patch MBR.
347 //
348 if (Index == PARTITION_ENTRY_NUM) {
349 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET];
350 if (!PathInfo->Input && (PathInfo->Type == PathUsb)) {
351 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
352 DiskPartition[PARTITION_TABLE_OFFSET] = 0x80;
353 WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL);
354 }
355 }
356 }
357
358 return DbrOffset;
359 }
360
361 /**
362 * Get window file handle for input/ouput disk/file.
363 *
364 * @param PathInfo
365 * @param ProcessMbr
366 * @param FileHandle
367 *
368 * @return ERROR_STATUS
369 */
370 ERROR_STATUS
371 GetFileHandle (
372 PATH_INFO *PathInfo,
373 BOOL ProcessMbr,
374 HANDLE *FileHandle,
375 DWORD *DbrOffset
376 )
377 {
378 DWORD OpenFlag;
379
380 OpenFlag = OPEN_ALWAYS;
381 if (PathInfo->Input || PathInfo->Type != PathFile) {
382 OpenFlag = OPEN_EXISTING;
383 }
384
385 *FileHandle = CreateFile(
386 PathInfo->PhysicalPath,
387 GENERIC_READ | GENERIC_WRITE,
388 FILE_SHARE_READ,
389 NULL,
390 OpenFlag,
391 FILE_ATTRIBUTE_NORMAL,
392 NULL
393 );
394 if (*FileHandle == INVALID_HANDLE_VALUE) {
395 return ErrorFileCreate;
396 }
397
398 if ((PathInfo->Type == PathIde) || (PathInfo->Type == PathUsb)){
399 *DbrOffset = GetBootSectorOffset (*FileHandle, PathInfo);
400 if (!ProcessMbr) {
401 //
402 // 1. Process boot sector, set file pointer to the beginning of boot sector
403 //
404 SetFilePointer (*FileHandle, *DbrOffset * 0x200, NULL, FILE_BEGIN);
405 } else if(*DbrOffset == 0) {
406 //
407 // If user want to process Mbr, but no Mbr exists, simply return FALSE
408 //
409 return ErrorNoMbr;
410 } else {
411 //
412 // 2. Process MBR, set file pointer to 0
413 //
414 SetFilePointer (*FileHandle, 0, NULL, FILE_BEGIN);
415 }
416 }
417
418 return ErrorSuccess;
419 }
420
421 /**
422 Writing or reading boot sector or MBR according to the argument.
423
424 @param InputInfo PATH_INFO instance for input path
425 @param OutputInfo PATH_INFO instance for output path
426 @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector
427
428 @return ERROR_STATUS
429 **/
430 ERROR_STATUS
431 ProcessBsOrMbr (
432 PATH_INFO *InputInfo,
433 PATH_INFO *OutputInfo,
434 BOOL ProcessMbr
435 )
436 {
437 BYTE DiskPartition[0x200] = {0};
438 BYTE DiskPartitionBackup[0x200] = {0};
439 DWORD BytesReturn;
440 INT DrvNumOffset;
441 HANDLE InputHandle = INVALID_HANDLE_VALUE;
442 HANDLE OutputHandle = INVALID_HANDLE_VALUE;
443 ERROR_STATUS Status;
444 DWORD InputDbrOffset;
445 DWORD OutputDbrOffset;
446
447 //
448 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
449 //
450 Status = GetFileHandle(InputInfo, ProcessMbr, &InputHandle, &InputDbrOffset);
451 if (Status != ErrorSuccess) {
452 goto Done;
453 }
454
455 //
456 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
457 //
458 Status = GetFileHandle(OutputInfo, ProcessMbr, &OutputHandle, &OutputDbrOffset);
459 if (Status != ErrorSuccess) {
460 goto Done;
461 }
462
463 //
464 // Read boot sector from source disk/file
465 //
466 if (!ReadFile (InputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
467 Status = ErrorFileReadWrite;
468 goto Done;
469 }
470
471 if (InputInfo->Type == PathUsb) {
472 // Manually set BS_DrvNum to 0x80 as window's format.exe has a bug which will clear this field discarding USB disk's MBR.
473 // offset of BS_DrvNum is 0x24 for FAT12/16
474 // 0x40 for FAT32
475 //
476 DrvNumOffset = GetDrvNumOffset (DiskPartition);
477 if (DrvNumOffset == -1) {
478 Status = ErrorFatType;
479 goto Done;
480 }
481 //
482 // Some legacy BIOS require 0x80 discarding MBR.
483 // Question left here: is it needed to check Mbr before set 0x80?
484 //
485 DiskPartition[DrvNumOffset] = ((InputDbrOffset > 0) ? 0x80 : 0);
486 }
487
488 if (InputInfo->Type == PathIde) {
489 //
490 // Patch LBAOffsetForBootSector
491 //
492 *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = InputDbrOffset;
493 }
494
495 if (OutputInfo->Type != PathFile) {
496 if (ProcessMbr) {
497 //
498 // Use original partition table
499 //
500 if (!ReadFile (OutputHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) {
501 Status = ErrorFileReadWrite;
502 goto Done;
503 }
504 memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40);
505 SetFilePointer (OutputHandle, 0, NULL, FILE_BEGIN);
506
507 }
508 }
509
510 //
511 // Write boot sector to taget disk/file
512 //
513 if (!WriteFile (OutputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
514 Status = ErrorFileReadWrite;
515 goto Done;
516 }
517
518 Done:
519 if (InputHandle != INVALID_HANDLE_VALUE) {
520 CloseHandle (InputHandle);
521 }
522 if (OutputHandle != INVALID_HANDLE_VALUE) {
523 CloseHandle (OutputHandle);
524 }
525
526 return Status;
527 }
528
529 void
530 Version (
531 void
532 )
533 /*++
534
535 Routine Description:
536
537 Displays the standard utility information to SDTOUT
538
539 Arguments:
540
541 None
542
543 Returns:
544
545 None
546
547 --*/
548 {
549 printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
550 }
551
552 VOID
553 PrintUsage (
554 void
555 )
556 {
557 printf ("Usage: GenBootSector [options] --cfg-file CFG_FILE\n\n\
558 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.\n\n\
559 Utility to retrieve and update the boot sector or MBR.\n\n\
560 optional arguments:\n\
561 -h, --help Show this help message and exit\n\
562 --version Show program's version number and exit\n\
563 -d [DEBUG], --debug [DEBUG]\n\
564 Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\
565 - 9 (max)\n\
566 -v, --verbose Print informational statements\n\
567 -q, --quiet Returns the exit code, error messages will be\n\
568 displayed\n\
569 -s, --silent Returns only the exit code; informational and error\n\
570 messages are not displayed\n\
571 -l, --list List disk drives\n\
572 -i INPUT_FILENAME, --input INPUT_FILENAME\n\
573 Input file name\n\
574 -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
575 Output file name\n\
576 -m, --mbr Also process the MBR\n\
577 --sfo Reserved for future use\n");
578
579 }
580
581 /**
582 Get path information, including physical path for windows platform.
583
584 @param PathInfo Point to PATH_INFO structure.
585
586 @return whether path is valid.
587 **/
588 ERROR_STATUS
589 GetPathInfo (
590 PATH_INFO *PathInfo
591 )
592 {
593 DRIVE_INFO DriveInfo;
594 CHAR VolumeLetter;
595 CHAR DiskPathTemplate[] = "\\\\.\\PHYSICALDRIVE%u";
596 CHAR FloppyPathTemplate[] = "\\\\.\\%c:";
597 FILE *f;
598
599 //
600 // If path is disk path
601 //
602 if (IsLetter(PathInfo->Path[0]) && (PathInfo->Path[1] == ':') && (PathInfo->Path[2] == '\0')) {
603 VolumeLetter = PathInfo->Path[0];
604 if ((VolumeLetter == 'A') || (VolumeLetter == 'a') ||
605 (VolumeLetter == 'B') || (VolumeLetter == 'b')) {
606 PathInfo->Type = PathFloppy;
607 sprintf (PathInfo->PhysicalPath, FloppyPathTemplate, VolumeLetter);
608 return ErrorSuccess;
609 }
610
611 if (!GetDriveInfo(VolumeLetter, &DriveInfo)) {
612 fprintf (stderr, "ERROR: GetDriveInfo - 0x%lx\n", GetLastError ());
613 return ErrorPath;
614 }
615
616 if (!PathInfo->Input && (DriveInfo.DriveType->Type == DRIVE_FIXED)) {
617 fprintf (stderr, "ERROR: Could patch own IDE disk!\n");
618 return ErrorPath;
619 }
620
621 sprintf(PathInfo->PhysicalPath, DiskPathTemplate, DriveInfo.DiskNumber);
622 if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) {
623 PathInfo->Type = PathUsb;
624 } else if (DriveInfo.DriveType->Type == DRIVE_FIXED) {
625 PathInfo->Type = PathIde;
626 } else {
627 fprintf (stderr, "ERROR, Invalid disk path - %s", PathInfo->Path);
628 return ErrorPath;
629 }
630
631 return ErrorSuccess;
632 }
633
634 PathInfo->Type = PathFile;
635 if (PathInfo->Input) {
636 //
637 // If path is file path, check whether file is valid.
638 //
639 f = fopen (LongFilePath (PathInfo->Path), "r");
640 if (f == NULL) {
641 fprintf (stderr, "error E2003: File was not provided!\n");
642 return ErrorPath;
643 }
644 fclose (f);
645 }
646 PathInfo->Type = PathFile;
647 strcpy(PathInfo->PhysicalPath, PathInfo->Path);
648
649 return ErrorSuccess;
650 }
651
652 INT
653 main (
654 INT argc,
655 CHAR *argv[]
656 )
657 {
658 CHAR8 *AppName;
659 INTN Index;
660 BOOLEAN ProcessMbr;
661 ERROR_STATUS Status;
662 EFI_STATUS EfiStatus;
663 PATH_INFO InputPathInfo = {0};
664 PATH_INFO OutputPathInfo = {0};
665 UINT64 LogLevel;
666
667 SetUtilityName (UTILITY_NAME);
668
669 AppName = *argv;
670 argv ++;
671 argc --;
672
673 ProcessMbr = FALSE;
674
675 if (argc == 0) {
676 PrintUsage();
677 return 0;
678 }
679
680 //
681 // Parse command line
682 //
683 for (Index = 0; Index < argc; Index ++) {
684 if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) {
685 ListDrive ();
686 return 0;
687 }
688
689 if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {
690 ProcessMbr = TRUE;
691 continue;
692 }
693
694 if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {
695 InputPathInfo.Path = argv[Index + 1];
696 InputPathInfo.Input = TRUE;
697 if (InputPathInfo.Path == NULL) {
698 Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL");
699 return 1;
700 }
701 if (InputPathInfo.Path[0] == '-') {
702 Error (NULL, 0, 1003, "Invalid option value", "Input file is missing");
703 return 1;
704 }
705 ++Index;
706 continue;
707 }
708
709 if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {
710 OutputPathInfo.Path = argv[Index + 1];
711 OutputPathInfo.Input = FALSE;
712 if (OutputPathInfo.Path == NULL) {
713 Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL");
714 return 1;
715 }
716 if (OutputPathInfo.Path[0] == '-') {
717 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing");
718 return 1;
719 }
720 ++Index;
721 continue;
722 }
723
724 if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) {
725 PrintUsage ();
726 return 0;
727 }
728
729 if (stricmp (argv[Index], "--version") == 0) {
730 Version ();
731 return 0;
732 }
733
734 if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) {
735 continue;
736 }
737
738 if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) {
739 continue;
740 }
741
742 if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) {
743 EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel);
744 if (EFI_ERROR (EfiStatus)) {
745 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]);
746 return 1;
747 }
748 if (LogLevel > 9) {
749 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel);
750 return 1;
751 }
752 SetPrintLevel (LogLevel);
753 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]);
754 ++Index;
755 continue;
756 }
757
758 //
759 // Don't recognize the parameter.
760 //
761 Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]);
762 return 1;
763 }
764
765 if (InputPathInfo.Path == NULL) {
766 Error (NULL, 0, 1001, "Missing options", "Input file is missing");
767 return 1;
768 }
769
770 if (OutputPathInfo.Path == NULL) {
771 Error (NULL, 0, 1001, "Missing options", "Output file is missing");
772 return 1;
773 }
774
775 if (GetPathInfo(&InputPathInfo) != ErrorSuccess) {
776 Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found.");
777 return 1;
778 }
779
780 if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) {
781 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found.");
782 return 1;
783 }
784
785 //
786 // Process DBR (Patch or Read)
787 //
788 Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);
789
790 if (Status == ErrorSuccess) {
791 fprintf (
792 stdout,
793 "%s %s: successful!\n",
794 (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
795 ProcessMbr ? "MBR" : "DBR"
796 );
797 return 0;
798 } else {
799 fprintf (
800 stderr,
801 "%s: %s %s: failed - %s (LastError: 0x%lx)!\n",
802 (Status == ErrorNoMbr) ? "WARNING" : "ERROR",
803 (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
804 ProcessMbr ? "MBR" : "DBR",
805 ErrorStatusDesc[Status],
806 GetLastError ()
807 );
808 return 1;
809 }
810 }