ShellPkg/SetVar: Fix typo in comments
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / SetVar.c
1 /** @file\r
2   Main file for SetVar shell Debug1 function.\r
3 \r
4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
5   Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
6   This program and the accompanying materials\r
7   are licensed and made available under the terms and conditions of the BSD License\r
8   which accompanies this distribution.  The full text of the license may be found at\r
9   http://opensource.org/licenses/bsd-license.php\r
10 \r
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include "UefiShellDebug1CommandsLib.h"\r
17 \r
18 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
19   {L"-guid", TypeValue},\r
20   {L"-bs", TypeFlag},\r
21   {L"-rt", TypeFlag},\r
22   {L"-nv", TypeFlag},\r
23   {NULL, TypeMax}\r
24   };\r
25 \r
26 typedef enum {\r
27   DataTypeHexNumber   = 0,\r
28   DataTypeHexArray    = 1,\r
29   DataTypeAscii       = 2,\r
30   DataTypeUnicode     = 3,\r
31   DataTypeDevicePath  = 4,\r
32   DataTypeUnKnow      = 5\r
33 } DATA_TYPE;\r
34 \r
35 typedef union {\r
36   UINT8     HexNumber8;\r
37   UINT16    HexNumber16;\r
38   UINT32    HexNumber32;\r
39   UINT64    HexNumber64;\r
40 } HEX_NUMBER;\r
41 \r
42 /**\r
43   Check if the input is a (potentially empty) string of hexadecimal nibbles.\r
44 \r
45   @param[in] String  The CHAR16 string to check.\r
46 \r
47   @retval FALSE  A character has been found in String for which\r
48                  ShellIsHexaDecimalDigitCharacter() returned FALSE.\r
49 \r
50   @retval TRUE   Otherwise. (Note that this covers the case when String is\r
51                  empty.)\r
52 **/\r
53 BOOLEAN\r
54 IsStringOfHexNibbles (\r
55   IN CONST CHAR16  *String\r
56   )\r
57 {\r
58   CONST CHAR16 *Pos;\r
59 \r
60   for (Pos = String; *Pos != L'\0'; ++Pos) {\r
61     if (!ShellIsHexaDecimalDigitCharacter (*Pos)) {\r
62       return FALSE;\r
63     }\r
64   }\r
65   return TRUE;\r
66 }\r
67 \r
68 /**\r
69   Function to check the TYPE of Data.\r
70 \r
71   @param[in]    Data          The Data to be check.\r
72 \r
73   @retval       DATA_TYPE     The TYPE of Data.\r
74 **/\r
75 DATA_TYPE\r
76 TestDataType (\r
77   IN CONST CHAR16  *Data\r
78   )\r
79 {\r
80   if (Data[0] == L'0' && (Data[1] == L'x' || Data[1] == L'X')) {\r
81     if (IsStringOfHexNibbles (Data+2) && StrLen (Data + 2) <= 16) {\r
82       return DataTypeHexNumber;\r
83     } else {\r
84       return DataTypeUnKnow;\r
85     }\r
86   } else if (Data[0] == L'H') {\r
87     if (IsStringOfHexNibbles (Data + 1) && StrLen (Data + 1) % 2 == 0) {\r
88       return DataTypeHexArray;\r
89     } else {\r
90       return DataTypeUnKnow;\r
91     }\r
92   } else if (Data[0] == L'S') {\r
93     return DataTypeAscii;\r
94   } else if (Data[0] == L'L') {\r
95     return DataTypeUnicode;\r
96   } else if (Data[0] == L'P' || StrnCmp (Data, L"--", 2) == 0) {\r
97     return DataTypeDevicePath;\r
98   }\r
99 \r
100   if (IsStringOfHexNibbles (Data) && StrLen (Data) % 2 == 0) {\r
101     return DataTypeHexArray;\r
102   }\r
103 \r
104   return DataTypeAscii;\r
105 }\r
106 \r
107 /**\r
108   Function to parse the Data by the type of Data, and save in the Buffer.\r
109 \r
110   @param[in]      Data                A pointer to a buffer to be parsed.\r
111   @param[out]     Buffer              A pointer to a buffer to hold the return data.\r
112   @param[in,out]  BufferSize          On input, indicates the size of Buffer in bytes.\r
113                                       On output,indicates the size of data return in Buffer.\r
114                                       Or the size in bytes of the buffer needed to obtain.\r
115 \r
116   @retval   EFI_INVALID_PARAMETER     The Buffer or BufferSize is NULL.\r
117   @retval   EFI_BUFFER_TOO_SMALL      The Buffer is too small to hold the data.\r
118   @retval   EFI_OUT_OF_RESOURCES      A memory allcation failed.\r
119   @retval   EFI_SUCCESS               The Data parsed successful and save in the Buffer.\r
120 **/\r
121 EFI_STATUS\r
122 ParseParameterData (\r
123   IN CONST CHAR16   *Data,\r
124   OUT VOID          *Buffer,\r
125   IN OUT UINTN      *BufferSize\r
126   )\r
127 {\r
128   UINT64                    HexNumber;\r
129   UINTN                     HexNumberLen;\r
130   UINTN                     Size;\r
131   CHAR8                     *AsciiBuffer;\r
132   DATA_TYPE                 DataType;\r
133   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
134   EFI_STATUS                Status;\r
135 \r
136   HexNumber                 = 0;\r
137   HexNumberLen              = 0;\r
138   Size                      = 0;\r
139   AsciiBuffer               = NULL;\r
140   DevPath                   = NULL;\r
141   Status                    = EFI_SUCCESS;\r
142 \r
143   if (Data == NULL || BufferSize == NULL) {\r
144     return EFI_INVALID_PARAMETER;\r
145   }\r
146 \r
147   DataType = TestDataType (Data);\r
148   if (DataType == DataTypeHexNumber) {\r
149     //\r
150     // hex number\r
151     //\r
152     StrHexToUint64S (Data + 2, NULL, &HexNumber);\r
153     HexNumberLen = StrLen (Data + 2);\r
154     if (HexNumberLen >= 1 && HexNumberLen <= 2) {\r
155       Size = 1;\r
156     } else if (HexNumberLen >= 3 && HexNumberLen <= 4) {\r
157       Size = 2;\r
158     } else if (HexNumberLen >= 5 && HexNumberLen <= 8) {\r
159       Size = 4;\r
160     } else if (HexNumberLen >= 9 && HexNumberLen <= 16) {\r
161       Size = 8;\r
162     }\r
163     if (Buffer != NULL && *BufferSize >= Size) {\r
164       CopyMem(Buffer, (VOID *)&HexNumber, Size);\r
165     } else {\r
166       Status = EFI_BUFFER_TOO_SMALL;\r
167     }\r
168     *BufferSize = Size;\r
169   } else if (DataType == DataTypeHexArray) {\r
170     //\r
171     // hex array\r
172     //\r
173     if (*Data == L'H') {\r
174       Data = Data + 1;\r
175     }\r
176 \r
177     Size = StrLen (Data) / 2;\r
178     if (Buffer != NULL && *BufferSize >= Size) {\r
179       StrHexToBytes(Data, StrLen  (Data), (UINT8 *)Buffer, Size);\r
180     } else {\r
181       Status = EFI_BUFFER_TOO_SMALL;\r
182     }\r
183     *BufferSize = Size;\r
184   } else if (DataType == DataTypeAscii) {\r
185     //\r
186     // ascii text\r
187     //\r
188     if (*Data == L'S') {\r
189       Data = Data + 1;\r
190     }\r
191     AsciiBuffer = AllocateZeroPool (StrSize (Data) / 2);\r
192     if (AsciiBuffer == NULL) {\r
193       Status = EFI_OUT_OF_RESOURCES;\r
194     } else {\r
195       AsciiSPrint (AsciiBuffer, StrSize (Data) / 2, "%s", (CHAR8 *)Data);\r
196 \r
197       Size = StrSize (Data) / 2 - 1;\r
198       if (Buffer != NULL && *BufferSize >= Size) {\r
199         CopyMem (Buffer, AsciiBuffer, Size);\r
200       } else {\r
201         Status = EFI_BUFFER_TOO_SMALL;\r
202       }\r
203       *BufferSize = Size;\r
204     }\r
205     SHELL_FREE_NON_NULL (AsciiBuffer);\r
206   } else if (DataType == DataTypeUnicode) {\r
207     //\r
208     // unicode text\r
209     //\r
210     if (*Data == L'L') {\r
211       Data = Data + 1;\r
212     }\r
213     Size = StrSize (Data) - sizeof (CHAR16);\r
214     if (Buffer != NULL && *BufferSize >= Size) {\r
215       CopyMem (Buffer, Data, Size);\r
216     } else {\r
217       Status = EFI_BUFFER_TOO_SMALL;\r
218     }\r
219     *BufferSize = Size;\r
220   } else if (DataType == DataTypeDevicePath) {\r
221     if (*Data == L'P') {\r
222       Data = Data + 1;\r
223     } else if (StrnCmp (Data, L"--", 2) == 0) {\r
224       Data = Data + 2;\r
225     }\r
226     DevPath = ConvertTextToDevicePath (Data);\r
227     if (DevPath == NULL) {\r
228       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar");\r
229       Status = EFI_INVALID_PARAMETER;\r
230     } else {\r
231       Size = GetDevicePathSize (DevPath);\r
232       if (Buffer != NULL && *BufferSize >= Size) {\r
233         CopyMem (Buffer, DevPath, Size);\r
234       } else {\r
235         Status = EFI_BUFFER_TOO_SMALL;\r
236       }\r
237       *BufferSize = Size;\r
238     }\r
239     SHELL_FREE_NON_NULL (DevPath);\r
240   } else {\r
241     Status = EFI_INVALID_PARAMETER;\r
242   }\r
243 \r
244   return Status;\r
245 }\r
246 \r
247 /**\r
248   Function to get each data from parameters.\r
249 \r
250   @param[in]    Package               The package of checked values.\r
251   @param[out]   Buffer                A pointer to a buffer to hold the return data.\r
252   @param[out]   BufferSize            Indicates the size of data in bytes return in Buffer.\r
253 \r
254   @retval   EFI_INVALID_PARAMETER     Buffer or BufferSize is NULL.\r
255   @retval   EFI_OUT_OF_RESOURCES      A memory allcation failed.\r
256   @retval   EFI_SUCCESS               Get each parameter data was successful.\r
257 **/\r
258 EFI_STATUS\r
259 GetVariableDataFromParameter (\r
260   IN CONST LIST_ENTRY *Package,\r
261   OUT UINT8           **Buffer,\r
262   OUT UINTN           *BufferSize\r
263   )\r
264 {\r
265   CONST CHAR16    *TempData;\r
266   UINTN           Index;\r
267   UINTN           TotalSize;\r
268   UINTN           Size;\r
269   UINT8           *BufferWalker;\r
270   EFI_STATUS      Status;\r
271 \r
272   TotalSize       = 0;\r
273   Size            = 0;\r
274   Status          = EFI_SUCCESS;\r
275 \r
276   if (BufferSize == NULL || Buffer == NULL || ShellCommandLineGetCount (Package) < 3) {\r
277     return EFI_INVALID_PARAMETER;\r
278   }\r
279 \r
280   for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) {\r
281     TempData = ShellCommandLineGetRawValue (Package, Index);\r
282     ASSERT (TempData != NULL);\r
283 \r
284     if (TempData[0] != L'=') {\r
285       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData);\r
286       return EFI_INVALID_PARAMETER;\r
287     }\r
288 \r
289     TempData = TempData + 1;\r
290     Size = 0;\r
291     Status = ParseParameterData (TempData, NULL, &Size);\r
292     if (EFI_ERROR (Status)) {\r
293       if (Status == EFI_BUFFER_TOO_SMALL) {\r
294         //\r
295         // We expect return EFI_BUFFER_TOO_SMALL when pass 'NULL' as second parameter to the function ParseParameterData.\r
296         //\r
297         TotalSize += Size;\r
298       } else {\r
299         if (Status == EFI_INVALID_PARAMETER) {\r
300           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData);\r
301         } else if (Status == EFI_NOT_FOUND) {\r
302           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar");\r
303         }\r
304         return Status;\r
305       }\r
306     }\r
307   }\r
308 \r
309   *BufferSize = TotalSize;\r
310   *Buffer = AllocateZeroPool (TotalSize);\r
311 \r
312   if (*Buffer == NULL) {\r
313     Status = EFI_OUT_OF_RESOURCES;\r
314   } else {\r
315     BufferWalker = *Buffer;\r
316     for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) {\r
317       TempData = ShellCommandLineGetRawValue (Package, Index);\r
318       TempData = TempData + 1;\r
319 \r
320       Size = TotalSize;\r
321       Status = ParseParameterData (TempData, (VOID *)BufferWalker, &Size);\r
322       if (!EFI_ERROR (Status)) {\r
323         BufferWalker = BufferWalker + Size;\r
324         TotalSize = TotalSize - Size;\r
325       } else {\r
326         return Status;\r
327       }\r
328     }\r
329   }\r
330 \r
331   return EFI_SUCCESS;\r
332 }\r
333 \r
334 /**\r
335   Function for 'setvar' command.\r
336 \r
337   @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
338   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
339 **/\r
340 SHELL_STATUS\r
341 EFIAPI\r
342 ShellCommandRunSetVar (\r
343   IN EFI_HANDLE        ImageHandle,\r
344   IN EFI_SYSTEM_TABLE  *SystemTable\r
345   )\r
346 {\r
347   EFI_STATUS          Status;\r
348   RETURN_STATUS       RStatus;\r
349   LIST_ENTRY          *Package;\r
350   CHAR16              *ProblemParam;\r
351   SHELL_STATUS        ShellStatus;\r
352   CONST CHAR16        *VariableName;\r
353   EFI_GUID            Guid;\r
354   CONST CHAR16        *StringGuid;\r
355   UINT32              Attributes;\r
356   VOID                *Buffer;\r
357   UINTN               Size;\r
358   UINTN               LoopVar;\r
359 \r
360   ShellStatus         = SHELL_SUCCESS;\r
361   Status              = EFI_SUCCESS;\r
362   Buffer              = NULL;\r
363   Size                = 0;\r
364   Attributes          = 0;\r
365 \r
366   //\r
367   // initialize the shell lib (we must be in non-auto-init...)\r
368   //\r
369   Status = ShellInitialize();\r
370   ASSERT_EFI_ERROR(Status);\r
371 \r
372   Status = CommandInit();\r
373   ASSERT_EFI_ERROR(Status);\r
374 \r
375   //\r
376   // parse the command line\r
377   //\r
378   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
379   if (EFI_ERROR(Status)) {\r
380     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
381       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"setvar", ProblemParam);  \r
382       FreePool(ProblemParam);\r
383       ShellStatus = SHELL_INVALID_PARAMETER;\r
384     } else {\r
385       ASSERT(FALSE);\r
386     }\r
387   } else {\r
388     if (ShellCommandLineGetCount(Package) < 2) {\r
389       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"setvar");  \r
390       ShellStatus = SHELL_INVALID_PARAMETER;\r
391     } else {\r
392       VariableName  = ShellCommandLineGetRawValue(Package, 1);\r
393       if (!ShellCommandLineGetFlag(Package, L"-guid")){\r
394         CopyGuid(&Guid, &gEfiGlobalVariableGuid);\r
395       } else {\r
396         StringGuid = ShellCommandLineGetValue(Package, L"-guid");\r
397         RStatus = StrToGuid (StringGuid, &Guid);\r
398         if (RETURN_ERROR (RStatus) || (StringGuid[GUID_STRING_LENGTH] != L'\0')) {\r
399           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", StringGuid);  \r
400           ShellStatus = SHELL_INVALID_PARAMETER;\r
401         }\r
402       }\r
403 \r
404       if (ShellCommandLineGetCount(Package) == 2) {\r
405         //\r
406         // Display\r
407         //\r
408         Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);\r
409         if (Status == EFI_BUFFER_TOO_SMALL) {\r
410           Buffer = AllocateZeroPool(Size);\r
411           Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);\r
412         }\r
413         if (!EFI_ERROR(Status) && Buffer != NULL) {\r
414           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_SETVAR_PRINT), gShellDebug1HiiHandle, &Guid, VariableName, Size);\r
415           for (LoopVar = 0; LoopVar < Size; LoopVar++) {\r
416             ShellPrintEx(-1, -1, L"%02x ", ((UINT8*)Buffer)[LoopVar]);\r
417           }\r
418           ShellPrintEx(-1, -1, L"\r\n");\r
419         } else {\r
420           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_GET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);\r
421           ShellStatus = SHELL_ACCESS_DENIED;\r
422         }\r
423       } else {\r
424         //\r
425         // Create, Delete or Modify.\r
426         //\r
427         Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);\r
428         if (Status == EFI_BUFFER_TOO_SMALL) {\r
429           Buffer = AllocateZeroPool(Size);\r
430           Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);\r
431         }\r
432         if (EFI_ERROR(Status) || Buffer == NULL) {\r
433           //\r
434           // Creating a new variable.  determine attributes from command line.\r
435           //\r
436           Attributes = 0;\r
437           if (ShellCommandLineGetFlag(Package, L"-bs")) {\r
438             Attributes |= EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
439           }\r
440           if (ShellCommandLineGetFlag(Package, L"-rt")) {\r
441             Attributes |= EFI_VARIABLE_RUNTIME_ACCESS |\r
442                           EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
443           }\r
444           if (ShellCommandLineGetFlag(Package, L"-nv")) {\r
445             Attributes |= EFI_VARIABLE_NON_VOLATILE;\r
446           }\r
447         }\r
448         SHELL_FREE_NON_NULL(Buffer);\r
449 \r
450         Size = 0;\r
451         Status = GetVariableDataFromParameter(Package, (UINT8 **)&Buffer, &Size);\r
452         if (!EFI_ERROR(Status)) {\r
453           Status = gRT->SetVariable((CHAR16*)VariableName, &Guid, Attributes, Size, Buffer);\r
454         }\r
455         if (EFI_ERROR(Status)) {\r
456           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);\r
457           ShellStatus = SHELL_ACCESS_DENIED;\r
458         } else {\r
459           ASSERT(ShellStatus == SHELL_SUCCESS);\r
460         }\r
461       }\r
462     }\r
463     ShellCommandLineFreeVarList (Package);\r
464   }\r
465 \r
466   if (Buffer != NULL) {\r
467     FreePool(Buffer);\r
468   }\r
469 \r
470   return (ShellStatus);\r
471 }\r