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