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