1 /** @file
2   Main file for SetVar shell Debug1 function.
3 
4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "UefiShellDebug1CommandsLib.h"
17 
18 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
19   {L"-guid", TypeValue},
20   {L"-bs", TypeFlag},
21   {L"-rt", TypeFlag},
22   {L"-nv", TypeFlag},
23   {NULL, TypeMax}
24   };
25 
26 
27 /**
28   Check if the input is a (potentially empty) string of hexadecimal nibbles.
29 
30   @param[in] String  The CHAR16 string to check.
31 
32   @retval FALSE  A character has been found in String for which
33                  ShellIsHexaDecimalDigitCharacter() returned FALSE.
34 
35   @retval TRUE   Otherwise. (Note that this covers the case when String is
36                  empty.)
37 **/
38 BOOLEAN
IsStringOfHexNibbles(IN CONST CHAR16 * String)39 IsStringOfHexNibbles (
40   IN CONST CHAR16  *String
41   )
42 {
43   CONST CHAR16 *Pos;
44 
45   for (Pos = String; *Pos != L'\0'; ++Pos) {
46     if (!ShellIsHexaDecimalDigitCharacter (*Pos)) {
47       return FALSE;
48     }
49   }
50   return TRUE;
51 }
52 
53 
54 /**
55   Function for 'setvar' command.
56 
57   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
58   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
59 **/
60 SHELL_STATUS
61 EFIAPI
ShellCommandRunSetVar(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)62 ShellCommandRunSetVar (
63   IN EFI_HANDLE        ImageHandle,
64   IN EFI_SYSTEM_TABLE  *SystemTable
65   )
66 {
67   EFI_STATUS          Status;
68   LIST_ENTRY          *Package;
69   CHAR16              *ProblemParam;
70   SHELL_STATUS        ShellStatus;
71   CONST CHAR16        *VariableName;
72   CONST CHAR16        *Data;
73   EFI_GUID            Guid;
74   CONST CHAR16        *StringGuid;
75   UINT32              Attributes;
76   VOID                *Buffer;
77   UINTN               Size;
78   UINTN               LoopVar;
79   EFI_DEVICE_PATH_PROTOCOL           *DevPath;
80 
81   ShellStatus         = SHELL_SUCCESS;
82   Status              = EFI_SUCCESS;
83   Buffer              = NULL;
84   Size                = 0;
85   Attributes          = 0;
86   DevPath             = NULL;
87 
88   //
89   // initialize the shell lib (we must be in non-auto-init...)
90   //
91   Status = ShellInitialize();
92   ASSERT_EFI_ERROR(Status);
93 
94   Status = CommandInit();
95   ASSERT_EFI_ERROR(Status);
96 
97   //
98   // parse the command line
99   //
100   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
101   if (EFI_ERROR(Status)) {
102     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
103       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"setvar", ProblemParam);
104       FreePool(ProblemParam);
105       ShellStatus = SHELL_INVALID_PARAMETER;
106     } else {
107       ASSERT(FALSE);
108     }
109   } else {
110     if (ShellCommandLineGetCount(Package) < 2) {
111       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"setvar");
112       ShellStatus = SHELL_INVALID_PARAMETER;
113     } else if (ShellCommandLineGetCount(Package) > 3) {
114       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"setvar");
115       ShellStatus = SHELL_INVALID_PARAMETER;
116     } else {
117       VariableName  = ShellCommandLineGetRawValue(Package, 1);
118       Data          = ShellCommandLineGetRawValue(Package, 2);
119       if (!ShellCommandLineGetFlag(Package, L"-guid")){
120         CopyGuid(&Guid, &gEfiGlobalVariableGuid);
121       } else {
122         StringGuid = ShellCommandLineGetValue(Package, L"-guid");
123         Status = ConvertStringToGuid(StringGuid, &Guid);
124         if (EFI_ERROR(Status)) {
125           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", StringGuid);
126           ShellStatus = SHELL_INVALID_PARAMETER;
127         }
128       }
129       if (Data == NULL || Data[0] !=  L'=') {
130         //
131         // Display what's there
132         //
133         Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);
134         if (Status == EFI_BUFFER_TOO_SMALL) {
135           Buffer = AllocateZeroPool(Size);
136           Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);
137         }
138         if (!EFI_ERROR(Status)&& Buffer != NULL) {
139           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_PRINT), gShellDebug1HiiHandle, &Guid, VariableName, Size);
140           for (LoopVar = 0 ; LoopVar < Size ; LoopVar++) {
141             ShellPrintEx(-1, -1, L"%02x ", ((UINT8*)Buffer)[LoopVar]);
142           }
143           ShellPrintEx(-1, -1, L"\r\n");
144         } else {
145           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_GET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
146           ShellStatus = SHELL_ACCESS_DENIED;
147         }
148       } else if (StrCmp(Data, L"=") == 0) {
149         //
150         // Delete what's there!
151         //
152         Status = gRT->SetVariable((CHAR16*)VariableName, &Guid, Attributes, 0, NULL);
153         if (EFI_ERROR(Status)) {
154           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
155           ShellStatus = SHELL_ACCESS_DENIED;
156         } else {
157           ASSERT(ShellStatus == SHELL_SUCCESS);
158         }
159       } else {
160         //
161         // Change what's there or create a new one.
162         //
163 
164         ASSERT(Data[0] == L'=');
165         Data++;
166         ASSERT(Data[0] != L'\0');
167 
168         //
169         // Determine if the variable exists and get the attributes
170         //
171         Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);
172         if (Status == EFI_BUFFER_TOO_SMALL) {
173           Buffer = AllocateZeroPool(Size);
174           Status = gRT->GetVariable((CHAR16*)VariableName, &Guid, &Attributes, &Size, Buffer);
175         }
176 
177         if (EFI_ERROR(Status) || Buffer == NULL) {
178           //
179           // Creating a new variable.  determine attributes from command line.
180           //
181           Attributes = 0;
182           if (ShellCommandLineGetFlag(Package, L"-bs")) {
183             Attributes |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
184           }
185           if (ShellCommandLineGetFlag(Package, L"-rt")) {
186             Attributes |= EFI_VARIABLE_RUNTIME_ACCESS |
187                           EFI_VARIABLE_BOOTSERVICE_ACCESS;
188           }
189           if (ShellCommandLineGetFlag(Package, L"-nv")) {
190             Attributes |= EFI_VARIABLE_NON_VOLATILE;
191           }
192         }
193         SHELL_FREE_NON_NULL(Buffer);
194 
195         //
196         // What type is the new data.
197         //
198         if (IsStringOfHexNibbles(Data)) {
199           if (StrLen(Data) % 2 != 0) {
200             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", Data);
201             ShellStatus = SHELL_INVALID_PARAMETER;
202           } else {
203             //
204             // arbitrary buffer
205             //
206             Buffer = AllocateZeroPool((StrLen(Data) / 2));
207             if (Buffer == NULL) {
208               Status = EFI_OUT_OF_RESOURCES;
209             } else {
210               for (LoopVar = 0 ; LoopVar < (StrLen(Data) / 2) ; LoopVar++) {
211                 ((UINT8*)Buffer)[LoopVar] = (UINT8)(HexCharToUintn(Data[LoopVar*2]) * 16);
212                 ((UINT8*)Buffer)[LoopVar] = (UINT8)(((UINT8*)Buffer)[LoopVar] + HexCharToUintn(Data[LoopVar*2+1]));
213               }
214               Status = gRT->SetVariable((CHAR16*)VariableName, &Guid, Attributes, StrLen(Data) / 2, Buffer);
215             }
216             if (EFI_ERROR(Status)) {
217               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
218               ShellStatus = SHELL_ACCESS_DENIED;
219             } else {
220               ASSERT(ShellStatus == SHELL_SUCCESS);
221             }
222           }
223         } else if (StrnCmp(Data, L"\"", 1) == 0) {
224           //
225           // ascii text
226           //
227           Data++;
228           Buffer = AllocateZeroPool(StrSize(Data) / 2);
229           if (Buffer == NULL) {
230             Status = EFI_OUT_OF_RESOURCES;
231           } else {
232             AsciiSPrint(Buffer, StrSize(Data) / 2, "%s", Data);
233             ((CHAR8*)Buffer)[AsciiStrLen(Buffer)-1] = CHAR_NULL;
234             Status = gRT->SetVariable((CHAR16*)VariableName, &Guid, Attributes, AsciiStrSize(Buffer)-sizeof(CHAR8), Buffer);
235           }
236           if (EFI_ERROR(Status)) {
237             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
238             ShellStatus = SHELL_ACCESS_DENIED;
239           } else {
240             ASSERT(ShellStatus == SHELL_SUCCESS);
241           }
242         } else if (StrnCmp(Data, L"L\"", 2) == 0) {
243           //
244           // ucs2 text
245           //
246           Data++;
247           Data++;
248           Buffer = AllocateZeroPool(StrSize(Data));
249           if (Buffer == NULL) {
250             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"setvar");
251             ShellStatus = SHELL_OUT_OF_RESOURCES;
252           } else {
253             UnicodeSPrint(Buffer, StrSize(Data), L"%s", Data);
254             ((CHAR16*)Buffer)[StrLen(Buffer)-1] = CHAR_NULL;
255 
256             Status = gRT->SetVariable((CHAR16*)VariableName, &Guid, Attributes, StrSize(Buffer)-sizeof(CHAR16), Buffer);
257             if (EFI_ERROR(Status)) {
258               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
259               ShellStatus = SHELL_ACCESS_DENIED;
260             } else {
261               ASSERT(ShellStatus == SHELL_SUCCESS);
262             }
263           }
264         } else if (StrnCmp(Data, L"--", 2) == 0) {
265           //
266           // device path in text format
267           //
268           Data++;
269           Data++;
270           DevPath = ConvertTextToDevicePath(Data);
271           if (DevPath == NULL) {
272             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar");
273             ShellStatus = SHELL_INVALID_PARAMETER;
274           } else {
275             Status = gRT->SetVariable((CHAR16*)VariableName, &Guid, Attributes, GetDevicePathSize(DevPath), DevPath);
276             if (EFI_ERROR(Status)) {
277               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_SET), gShellDebug1HiiHandle, L"setvar", &Guid, VariableName);
278               ShellStatus = SHELL_ACCESS_DENIED;
279             } else {
280               ASSERT(ShellStatus == SHELL_SUCCESS);
281             }
282           }
283         } else {
284           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", Data);
285           ShellStatus = SHELL_INVALID_PARAMETER;
286         }
287       }
288     }
289     ShellCommandLineFreeVarList (Package);
290   }
291 
292   if (Buffer != NULL) {
293     FreePool(Buffer);
294   }
295 
296   if (DevPath != NULL) {
297     FreePool(DevPath);
298   }
299 
300   return (ShellStatus);
301 }
302