Sync EDKII BaseTools to BaseTools project r1903.
[efi/edk2/.git] / edk2 / BaseTools / Source / C / GnuGenBootSector / GnuGenBootSector.c
1 /** @file\r
2 \r
3 Copyright 2006 - 2010, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   GnuGenBootSector.c\r
15   \r
16 Abstract:\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 "CommonLib.h"\r
25 #include <errno.h>\r
26 #include <stdlib.h>\r
27 #include <string.h>\r
28 #include <Common/UefiBaseTypes.h>\r
29 \r
30 #include "ParseInf.h"\r
31 #include "EfiUtilityMsgs.h"\r
32 \r
33 //\r
34 // Utility Name\r
35 //\r
36 #define UTILITY_NAME  "GnuGenBootSector"\r
37 \r
38 //\r
39 // Utility version information\r
40 //\r
41 #define UTILITY_MAJOR_VERSION 0\r
42 #define UTILITY_MINOR_VERSION 1\r
43 \r
44 #define MAX_DRIVE                             26\r
45 #define PARTITION_TABLE_OFFSET                0x1BE\r
46 \r
47 #define SIZE_OF_PARTITION_ENTRY               0x10\r
48 \r
49 #define PARTITION_ENTRY_STARTLBA_OFFSET       8\r
50 \r
51 #define PARTITION_ENTRY_NUM                   4\r
52 \r
53 #define DRIVE_UNKNOWN     0\r
54 #define DRIVE_NO_ROOT_DIR 1\r
55 #define DRIVE_REMOVABLE   2\r
56 #define DRIVE_FIXED       3\r
57 #define DRIVE_REMOTE      4\r
58 #define DRIVE_CDROM       5\r
59 #define DRIVE_RAMDISK     6\r
60 \r
61 typedef struct _DRIVE_TYPE_DESC {\r
62   UINTN  Type;\r
63   CHAR8  *Description;\r
64 } DRIVE_TYPE_DESC;\r
65 \r
66 #define DRIVE_TYPE_ITEM(x) {x, #x}\r
67 \r
68 DRIVE_TYPE_DESC DriveTypeDesc[] = {\r
69   DRIVE_TYPE_ITEM (DRIVE_UNKNOWN),\r
70   DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR),\r
71   DRIVE_TYPE_ITEM (DRIVE_REMOVABLE),\r
72   DRIVE_TYPE_ITEM (DRIVE_FIXED),\r
73   DRIVE_TYPE_ITEM (DRIVE_REMOTE),\r
74   DRIVE_TYPE_ITEM (DRIVE_CDROM),\r
75   DRIVE_TYPE_ITEM (DRIVE_RAMDISK),\r
76   {(UINTN) -1, NULL}\r
77 };\r
78 \r
79 typedef struct _DRIVE_INFO {\r
80   CHAR8             VolumeLetter;\r
81   DRIVE_TYPE_DESC   *DriveType;\r
82   UINTN             DiskNumber;\r
83 } DRIVE_INFO;\r
84 \r
85 typedef enum {\r
86   PathUnknown,\r
87   PathFile,\r
88   PathFloppy,\r
89   PathUsb,\r
90   PathIde\r
91 } PATH_TYPE;\r
92 \r
93 typedef struct _PATH_INFO {\r
94   CHAR8            *Path;\r
95   CHAR8            PhysicalPath[260];\r
96   PATH_TYPE        Type;\r
97   BOOLEAN          Input;\r
98 } PATH_INFO;\r
99 \r
100 typedef enum {\r
101   ErrorSuccess,\r
102   ErrorFileCreate,\r
103   ErrorFileReadWrite,\r
104   ErrorNoMbr,\r
105   ErrorFatType,\r
106   ErrorPath,\r
107 } ERROR_STATUS;\r
108 \r
109 CHAR8 *ErrorStatusDesc[] = {\r
110   "Success",\r
111   "Failed to create files",\r
112   "Failed to read/write files",\r
113   "No MBR exists",\r
114   "Failed to detect Fat type",\r
115   "Inavlid path"\r
116 };\r
117 \r
118 \r
119 //UnSupported Windows API functions.\r
120 UINTN GetLogicalDrives(void) { return 1; }\r
121 \r
122 \r
123 \r
124 /**\r
125   Get path information, including physical path for Linux platform.\r
126 \r
127   @param PathInfo   Point to PATH_INFO structure.\r
128 \r
129   @return whether path is valid.\r
130 **/\r
131 ERROR_STATUS\r
132 GetPathInfo (\r
133   PATH_INFO   *PathInfo\r
134   )\r
135 {\r
136   FILE        *f;\r
137 \r
138   if (strncmp(PathInfo->Path, "/dev/", 5) == 0) {\r
139     //\r
140     // Process disk path here.\r
141     // \r
142     \r
143     // Process floppy disk\r
144     if (PathInfo->Path[5] == 'f' && PathInfo->Path[6] == 'd' && PathInfo->Path[8] == '\0') {\r
145       PathInfo->Type = PathFloppy;\r
146       strcpy (PathInfo->PhysicalPath, PathInfo->Path);\r
147       \r
148       return ErrorSuccess;\r
149     } else {\r
150     // Other disk types is not supported yet.\r
151     fprintf (stderr, "ERROR: It's not a floppy disk!\n");\r
152     return ErrorPath;\r
153     }  \r
154      \r
155     // Try to open the device.   \r
156     f = fopen(PathInfo->Path,"r");\r
157     if (f == NULL) {\r
158       printf ("error :open device failed!\n");\r
159       return ErrorPath;\r
160     }\r
161     fclose (f);\r
162     return ErrorSuccess;\r
163   }\r
164  \r
165   // Process file path here.\r
166   PathInfo->Type = PathFile;\r
167   if (PathInfo->Input) {\r
168     // If path is file path, check whether file is valid.\r
169     printf("Path = %s\n",PathInfo->Path);\r
170     f = fopen (PathInfo->Path, "r");\r
171     if (f == NULL) {\r
172       fprintf (stderr, "Test error E2003: File was not provided!\n");\r
173       return ErrorPath;\r
174     }\r
175     fclose (f);\r
176   }\r
177 \r
178   strcpy(PathInfo->PhysicalPath, PathInfo->Path);\r
179   return ErrorSuccess;\r
180 \r
181 }\r
182 \r
183 VOID\r
184 ListDrive (\r
185   VOID\r
186   )\r
187 {\r
188   printf("-l or -list not supported!\n");\r
189 }\r
190 \r
191 /**\r
192   Writing or reading boot sector or MBR according to the argument. \r
193    \r
194   @param InputInfo PATH_INFO instance for input path\r
195   @param OutputInfo PATH_INFO instance for output path\r
196   @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector\r
197   \r
198   @return ERROR_STATUS\r
199  **/\r
200 ERROR_STATUS\r
201 ProcessBsOrMbr (\r
202   PATH_INFO     *InputInfo,\r
203   PATH_INFO     *OutputInfo,\r
204   BOOLEAN       ProcessMbr\r
205   )\r
206 {\r
207   CHAR8 FirstSector[0x200] = {0};\r
208   CHAR8 FirstSectorBackup[0x200] = {0};\r
209   \r
210   FILE *InputFile;\r
211   FILE *OutputFile;\r
212   \r
213   \r
214   InputFile = fopen(InputInfo->PhysicalPath, "r");\r
215   if (InputFile == NULL) {\r
216     return ErrorFileReadWrite;\r
217   }\r
218    \r
219   if (0x200 != fread(FirstSector, 1, 0x200, InputFile)) {\r
220     fclose(InputFile);\r
221     return ErrorFileReadWrite;\r
222   }\r
223   \r
224   fclose(InputFile);\r
225   \r
226   //Not support USB and IDE.\r
227   if (InputInfo->Type == PathUsb) {\r
228     printf("USB has not been supported yet!");\r
229     return ErrorSuccess;\r
230   }\r
231   \r
232   if (InputInfo->Type == PathIde) {\r
233     printf("IDE has not been supported yet!");\r
234     return ErrorSuccess;\r
235   } \r
236   \r
237   //Process Floppy Disk\r
238   OutputFile = fopen(OutputInfo->PhysicalPath, "w");\r
239   if (OutputFile == NULL) {\r
240     return ErrorFileReadWrite;\r
241   }  \r
242   \r
243   if (OutputInfo->Type != PathFile) {\r
244     if (ProcessMbr) {\r
245       //\r
246       // Use original partition table\r
247       //\r
248       if (0x200 != fread (FirstSectorBackup, 1, 0x200, OutputFile)) {\r
249         fclose(OutputFile);\r
250         return ErrorFileReadWrite; \r
251         }\r
252       memcpy (FirstSector + 0x1BE, FirstSectorBackup + 0x1BE, 0x40);  \r
253     }\r
254   }\r
255   if(0x200 != fwrite(FirstSector, 1, 0x200, OutputFile)) {\r
256     fclose(OutputFile);\r
257     return ErrorFileReadWrite;\r
258   }\r
259   \r
260   fclose(OutputFile);\r
261   return ErrorSuccess;\r
262 }\r
263 \r
264 \r
265 /**\r
266 \r
267   Displays the standard utility information to SDTOUT\r
268 \r
269 **/\r
270 VOID\r
271 Version (\r
272   VOID\r
273   )\r
274 {\r
275   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
276   printf ("Copyright (c) 2007-2010 Intel Corporation. All rights reserved.\n");\r
277 }\r
278 \r
279 \r
280 VOID\r
281 PrintUsage (\r
282   VOID\r
283     )\r
284 {\r
285   Version();\r
286   printf ("\nUsage: \n\\r
287    GenBootSector\n\\r
288      [-l, --list list disks]\n\\r
289      [-i, --input Filename]\n\\r
290      [-o, --output Filename]\n\\r
291      [-m, --mbr process the MBR also]\n\\r
292      [-v, --verbose]\n\\r
293      [--version]\n\\r
294      [-q, --quiet disable all messages except fatal errors]\n\\r
295      [-d, --debug[#]\n\\r
296      [-h, --help]\n");\r
297 }\r
298 \r
299 int\r
300 main (\r
301   int  argc,\r
302   char *argv[]\r
303   )\r
304 {\r
305   CHAR8          *AppName;\r
306   INTN           Index;\r
307   BOOLEAN        ProcessMbr;\r
308   ERROR_STATUS   Status;\r
309   EFI_STATUS     EfiStatus;\r
310   PATH_INFO      InputPathInfo;\r
311   PATH_INFO      OutputPathInfo;\r
312   UINT64         LogLevel;\r
313 \r
314   SetUtilityName (UTILITY_NAME);\r
315   \r
316   ZeroMem(&InputPathInfo, sizeof(PATH_INFO));\r
317   ZeroMem(&OutputPathInfo, sizeof(PATH_INFO));\r
318   \r
319   AppName = *argv;\r
320   argv ++;\r
321   argc --;\r
322   \r
323   ProcessMbr    = FALSE;\r
324 \r
325   if (argc == 0) {\r
326     PrintUsage();\r
327     return 0;\r
328   }\r
329    \r
330   //\r
331   // Parse command line\r
332   //\r
333   for (Index = 0; Index < argc; Index ++) {\r
334     if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) {\r
335       ListDrive ();\r
336       return 0;\r
337     } \r
338     \r
339     if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {\r
340       ProcessMbr = TRUE;\r
341       continue;\r
342     }\r
343     \r
344     if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {\r
345       InputPathInfo.Path  = argv[Index + 1];\r
346       InputPathInfo.Input = TRUE;\r
347       if (InputPathInfo.Path == NULL) {\r
348         Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL");\r
349         return 1;\r
350       } \r
351       if (InputPathInfo.Path[0] == '-') {\r
352         Error (NULL, 0, 1003, "Invalid option value", "Input file is missing");\r
353         return 1;       \r
354       }\r
355       ++Index;\r
356       continue;\r
357     }\r
358     \r
359     if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {\r
360       OutputPathInfo.Path  = argv[Index + 1];\r
361       OutputPathInfo.Input = FALSE;\r
362       if (OutputPathInfo.Path == NULL) {\r
363         Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL");\r
364         return 1;\r
365       } \r
366       if (OutputPathInfo.Path[0] == '-') {\r
367         Error (NULL, 0, 1003, "Invalid option value", "Output file is missing");\r
368         return 1;       \r
369       }\r
370       ++Index;\r
371       continue;\r
372     }\r
373     \r
374     if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) {\r
375       PrintUsage ();\r
376       return 0;\r
377     }\r
378     \r
379     if (stricmp (argv[Index], "--version") == 0) {\r
380       Version ();\r
381       return 0;\r
382     } \r
383     \r
384     if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) {\r
385       continue;\r
386     } \r
387     \r
388     if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) {\r
389       continue;\r
390     } \r
391     \r
392     if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) {\r
393       EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel);\r
394       if (EFI_ERROR (EfiStatus)) {\r
395         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]);\r
396         return 1;\r
397       }\r
398       if (LogLevel > 9) {\r
399         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel);\r
400         return 1;\r
401       }\r
402       SetPrintLevel (LogLevel);\r
403       DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]);\r
404       ++Index;\r
405       continue;\r
406     }\r
407 \r
408     //\r
409     // Don't recognize the parameter.\r
410     //\r
411     Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]);\r
412     return 1;\r
413   }\r
414   \r
415   if (InputPathInfo.Path == NULL) {\r
416     Error (NULL, 0, 1001, "Missing options", "Input file is missing");\r
417     return 1;\r
418   }\r
419 \r
420   if (OutputPathInfo.Path == NULL) {\r
421     Error (NULL, 0, 1001, "Missing options", "Output file is missing");\r
422     return 1;\r
423   }\r
424   \r
425   if (GetPathInfo(&InputPathInfo) != ErrorSuccess) {\r
426     Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found.");\r
427     return 1;\r
428   }\r
429 \r
430   if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) {\r
431     Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found.");\r
432     return 1;\r
433   }\r
434   \r
435   //\r
436   // Process DBR (Patch or Read)\r
437   //\r
438   Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);\r
439 \r
440   if (Status == ErrorSuccess) {\r
441     fprintf (\r
442       stdout, \r
443       "%s %s: successful!\n", \r
444       (OutputPathInfo.Type != PathFile) ? "Write" : "Read", \r
445       ProcessMbr ? "MBR" : "DBR"\r
446       );\r
447     return 0;\r
448   } else {\r
449     fprintf (\r
450       stderr, \r
451       "%s: %s %s: failed - %s (LastError: 0x%x)!\n",\r
452       (Status == ErrorNoMbr) ? "WARNING" : "ERROR",\r
453       (OutputPathInfo.Type != PathFile) ? "Write" : "Read", \r
454       ProcessMbr ? "MBR" : "DBR", \r
455       ErrorStatusDesc[Status],\r
456       errno \r
457       );\r
458     return 1;\r
459   }\r
460 }\r