]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenBootSector/GenBootSector.c
BaseTools/GenBootSector: Add/refine boundary checks for strcpy/strcat
[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 - 2017, 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 //
635 // Check the path length
636 //
637 if (strlen (PathInfo->Path) >= (sizeof (PathInfo->PhysicalPath) / sizeof (PathInfo->PhysicalPath[0]))) {
638 fprintf (stderr, "ERROR, Path is too long for - %s", PathInfo->Path);
639 return ErrorPath;
640 }
641
642 PathInfo->Type = PathFile;
643 if (PathInfo->Input) {
644 //
645 // If path is file path, check whether file is valid.
646 //
647 f = fopen (LongFilePath (PathInfo->Path), "r");
648 if (f == NULL) {
649 fprintf (stderr, "error E2003: File was not provided!\n");
650 return ErrorPath;
651 }
652 fclose (f);
653 }
654 PathInfo->Type = PathFile;
655 strncpy(
656 PathInfo->PhysicalPath,
657 PathInfo->Path,
658 sizeof (PathInfo->PhysicalPath) / sizeof (PathInfo->PhysicalPath[0]) - 1
659 );
660 PathInfo->PhysicalPath[sizeof (PathInfo->PhysicalPath) / sizeof (PathInfo->PhysicalPath[0]) - 1] = 0;
661
662 return ErrorSuccess;
663 }
664
665 INT
666 main (
667 INT argc,
668 CHAR *argv[]
669 )
670 {
671 CHAR8 *AppName;
672 INTN Index;
673 BOOLEAN ProcessMbr;
674 ERROR_STATUS Status;
675 EFI_STATUS EfiStatus;
676 PATH_INFO InputPathInfo = {0};
677 PATH_INFO OutputPathInfo = {0};
678 UINT64 LogLevel;
679
680 SetUtilityName (UTILITY_NAME);
681
682 AppName = *argv;
683 argv ++;
684 argc --;
685
686 ProcessMbr = FALSE;
687
688 if (argc == 0) {
689 PrintUsage();
690 return 0;
691 }
692
693 //
694 // Parse command line
695 //
696 for (Index = 0; Index < argc; Index ++) {
697 if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) {
698 ListDrive ();
699 return 0;
700 }
701
702 if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {
703 ProcessMbr = TRUE;
704 continue;
705 }
706
707 if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {
708 InputPathInfo.Path = argv[Index + 1];
709 InputPathInfo.Input = TRUE;
710 if (InputPathInfo.Path == NULL) {
711 Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL");
712 return 1;
713 }
714 if (InputPathInfo.Path[0] == '-') {
715 Error (NULL, 0, 1003, "Invalid option value", "Input file is missing");
716 return 1;
717 }
718 ++Index;
719 continue;
720 }
721
722 if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {
723 OutputPathInfo.Path = argv[Index + 1];
724 OutputPathInfo.Input = FALSE;
725 if (OutputPathInfo.Path == NULL) {
726 Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL");
727 return 1;
728 }
729 if (OutputPathInfo.Path[0] == '-') {
730 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing");
731 return 1;
732 }
733 ++Index;
734 continue;
735 }
736
737 if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) {
738 PrintUsage ();
739 return 0;
740 }
741
742 if (stricmp (argv[Index], "--version") == 0) {
743 Version ();
744 return 0;
745 }
746
747 if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) {
748 continue;
749 }
750
751 if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) {
752 continue;
753 }
754
755 if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) {
756 EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel);
757 if (EFI_ERROR (EfiStatus)) {
758 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]);
759 return 1;
760 }
761 if (LogLevel > 9) {
762 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel);
763 return 1;
764 }
765 SetPrintLevel (LogLevel);
766 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]);
767 ++Index;
768 continue;
769 }
770
771 //
772 // Don't recognize the parameter.
773 //
774 Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]);
775 return 1;
776 }
777
778 if (InputPathInfo.Path == NULL) {
779 Error (NULL, 0, 1001, "Missing options", "Input file is missing");
780 return 1;
781 }
782
783 if (OutputPathInfo.Path == NULL) {
784 Error (NULL, 0, 1001, "Missing options", "Output file is missing");
785 return 1;
786 }
787
788 if (GetPathInfo(&InputPathInfo) != ErrorSuccess) {
789 Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found.");
790 return 1;
791 }
792
793 if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) {
794 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found.");
795 return 1;
796 }
797
798 //
799 // Process DBR (Patch or Read)
800 //
801 Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);
802
803 if (Status == ErrorSuccess) {
804 fprintf (
805 stdout,
806 "%s %s: successful!\n",
807 (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
808 ProcessMbr ? "MBR" : "DBR"
809 );
810 return 0;
811 } else {
812 fprintf (
813 stderr,
814 "%s: %s %s: failed - %s (LastError: 0x%lx)!\n",
815 (Status == ErrorNoMbr) ? "WARNING" : "ERROR",
816 (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
817 ProcessMbr ? "MBR" : "DBR",
818 ErrorStatusDesc[Status],
819 GetLastError ()
820 );
821 return 1;
822 }
823 }