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