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