1 /** @file
2   Main file for NULL named library for level 2 shell command functions.
3 
4   these functions are:
5   attrib,
6   cd,
7   cp,
8   date*,
9   time*,
10   load,
11   ls,
12   map,
13   mkdir,
14   mv,
15   parse,
16   rm,
17   reset,
18   set,
19   timezone*,
20   vol
21 
22   * functions are non-interactive only
23 
24   Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
25   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
26   SPDX-License-Identifier: BSD-2-Clause-Patent
27 
28 **/
29 #include "UefiShellLevel2CommandsLib.h"
30 
31 CONST CHAR16 mFileName[] = L"ShellCommands";
32 EFI_HII_HANDLE gShellLevel2HiiHandle = NULL;
33 
34 /**
35   Get the filename to get help text from if not using HII.
36 
37   @retval The filename.
38 **/
39 CONST CHAR16*
40 EFIAPI
ShellCommandGetManFileNameLevel2(VOID)41 ShellCommandGetManFileNameLevel2 (
42   VOID
43   )
44 {
45   return (mFileName);
46 }
47 
48 /**
49   Constructor for the Shell Level 2 Commands library.
50 
51   Install the handlers for level 2 UEFI Shell 2.0 commands.
52 
53   @param ImageHandle    the image handle of the process
54   @param SystemTable    the EFI System Table pointer
55 
56   @retval EFI_SUCCESS        the shell command handlers were installed sucessfully
57   @retval EFI_UNSUPPORTED    the shell level required was not found.
58 **/
59 EFI_STATUS
60 EFIAPI
ShellLevel2CommandsLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)61 ShellLevel2CommandsLibConstructor (
62   IN EFI_HANDLE        ImageHandle,
63   IN EFI_SYSTEM_TABLE  *SystemTable
64   )
65 {
66   //
67   // if shell level is less than 2 do nothing
68   //
69   if (PcdGet8(PcdShellSupportLevel) < 2) {
70     return (EFI_SUCCESS);
71   }
72 
73   gShellLevel2HiiHandle = HiiAddPackages (&gShellLevel2HiiGuid, gImageHandle, UefiShellLevel2CommandsLibStrings, NULL);
74   if (gShellLevel2HiiHandle == NULL) {
75     return (EFI_DEVICE_ERROR);
76   }
77 
78   //
79   // install our shell command handlers that are always installed
80   //
81   ShellCommandRegisterCommandName(L"attrib",   ShellCommandRunAttrib  , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_ATTRIB) );
82   ShellCommandRegisterCommandName(L"cd",       ShellCommandRunCd      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CD)     );
83   ShellCommandRegisterCommandName(L"cp",       ShellCommandRunCp      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CP)     );
84   ShellCommandRegisterCommandName(L"load",     ShellCommandRunLoad    , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LOAD)   );
85   ShellCommandRegisterCommandName(L"map",      ShellCommandRunMap     , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MAP)    );
86   ShellCommandRegisterCommandName(L"mkdir",    ShellCommandRunMkDir   , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MKDIR)  );
87   ShellCommandRegisterCommandName(L"mv",       ShellCommandRunMv      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MV)     );
88   ShellCommandRegisterCommandName(L"parse",    ShellCommandRunParse   , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_PARSE)  );
89   ShellCommandRegisterCommandName(L"reset",    ShellCommandRunReset   , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RESET)  );
90   ShellCommandRegisterCommandName(L"set",      ShellCommandRunSet     , ShellCommandGetManFileNameLevel2, 2, L"",FALSE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_SET)    );
91   ShellCommandRegisterCommandName(L"ls",       ShellCommandRunLs      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LS)     );
92   ShellCommandRegisterCommandName(L"rm",       ShellCommandRunRm      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RM)     );
93   ShellCommandRegisterCommandName(L"vol",      ShellCommandRunVol     , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_VOL)    );
94 
95   //
96   // support for permanent (built in) aliases
97   //
98   ShellCommandRegisterAlias(L"rm", L"del");
99   ShellCommandRegisterAlias(L"ls", L"dir");
100   ShellCommandRegisterAlias(L"cp", L"copy");
101   ShellCommandRegisterAlias(L"mkdir", L"md");
102   ShellCommandRegisterAlias(L"cd ..", L"cd..");
103   ShellCommandRegisterAlias(L"cd \\", L"cd\\");
104   ShellCommandRegisterAlias(L"mv", L"ren");
105   ShellCommandRegisterAlias(L"mv", L"move");
106   ShellCommandRegisterAlias(L"map", L"mount");
107   //
108   // These are installed in level 2 or 3...
109   //
110   if (PcdGet8(PcdShellSupportLevel) == 2 || PcdGet8(PcdShellSupportLevel) == 3) {
111     ShellCommandRegisterCommandName(L"date",     ShellCommandRunDate    , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE)   );
112     ShellCommandRegisterCommandName(L"time",     ShellCommandRunTime    , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME)   );
113     ShellCommandRegisterCommandName(L"timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE));
114   } else {
115     DEBUG_CODE_BEGIN();
116     //
117     // we want to be able to test these so install them under a different name in debug mode...
118     //
119     ShellCommandRegisterCommandName(L"l2date",     ShellCommandRunDate    , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE)   );
120     ShellCommandRegisterCommandName(L"l2time",     ShellCommandRunTime    , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME)   );
121     ShellCommandRegisterCommandName(L"l2timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE));
122     DEBUG_CODE_END();
123   }
124 
125   return (EFI_SUCCESS);
126 }
127 
128 /**
129   Destructor for the library.  free any resources.
130 
131   @param ImageHandle    The image handle of the process.
132   @param SystemTable    The EFI System Table pointer.
133 
134   @retval EFI_SUCCESS   Always returned.
135 **/
136 EFI_STATUS
137 EFIAPI
ShellLevel2CommandsLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)138 ShellLevel2CommandsLibDestructor (
139   IN EFI_HANDLE        ImageHandle,
140   IN EFI_SYSTEM_TABLE  *SystemTable
141   )
142 {
143   if (gShellLevel2HiiHandle != NULL) {
144     HiiRemovePackages(gShellLevel2HiiHandle);
145   }
146   return (EFI_SUCCESS);
147 }
148 
149 /**
150   returns a fully qualified directory (contains a map drive at the begining)
151   path from a unknown directory path.
152 
153   If Path is already fully qualified this will return a duplicat otherwise this
154   will use get the current directory and use that to build the fully qualified
155   version.
156 
157   if the return value is not NULL it must be caller freed.
158 
159   @param[in] Path         The unknown Path Value
160 
161   @retval NULL            A memory allocation failed
162   @retval NULL            A fully qualified path could not be discovered.
163   @retval other           An allocated pointer to a fuly qualified path.
164 **/
165 CHAR16*
GetFullyQualifiedPath(IN CONST CHAR16 * Path)166 GetFullyQualifiedPath(
167   IN CONST CHAR16* Path
168   )
169 {
170   CHAR16        *PathToReturn;
171   UINTN         Size;
172   CONST CHAR16  *CurDir;
173 
174   PathToReturn  = NULL;
175   Size          = 0;
176 
177   ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));
178   //
179   // convert a local path to an absolute path
180   //
181   if (StrStr(Path, L":") == NULL) {
182     CurDir = gEfiShellProtocol->GetCurDir(NULL);
183     StrnCatGrow(&PathToReturn, &Size, CurDir, 0);
184     StrnCatGrow(&PathToReturn, &Size, L"\\", 0);
185     if (*Path == L'\\') {
186       Path++;
187     }
188   }
189   StrnCatGrow(&PathToReturn, &Size, Path, 0);
190 
191   PathCleanUpDirectories(PathToReturn);
192 
193   if (PathToReturn == NULL) {
194     return NULL;
195   }
196 
197   while (PathToReturn[StrLen(PathToReturn)-1] == L'*') {
198     PathToReturn[StrLen(PathToReturn)-1] = CHAR_NULL;
199   }
200 
201   return (PathToReturn);
202 }
203 
204 /**
205   Function to verify all intermediate directories in the path.
206 
207   @param[in] Path       The pointer to the path to fix.
208 
209   @retval EFI_SUCCESS   The operation was successful.
210 **/
211 EFI_STATUS
VerifyIntermediateDirectories(IN CONST CHAR16 * Path)212 VerifyIntermediateDirectories (
213   IN CONST CHAR16 *Path
214   )
215 {
216   EFI_STATUS      Status;
217   CHAR16          *PathCopy;
218   CHAR16          *TempSpot;
219   SHELL_FILE_HANDLE          FileHandle;
220 
221   ASSERT(Path != NULL);
222 
223   Status      = EFI_SUCCESS;
224   PathCopy    = NULL;
225   PathCopy    = StrnCatGrow(&PathCopy, NULL, Path, 0);
226   FileHandle  = NULL;
227 
228   if (PathCopy == NULL) {
229     return (EFI_OUT_OF_RESOURCES);
230   }
231 
232   for (TempSpot = &PathCopy[StrLen(PathCopy)-1] ; *TempSpot != CHAR_NULL && *TempSpot != L'\\' ; TempSpot = &PathCopy[StrLen(PathCopy)-1]){
233     *TempSpot = CHAR_NULL;
234   }
235   if (*TempSpot == L'\\') {
236     *TempSpot = CHAR_NULL;
237   }
238 
239   if (PathCopy != NULL && *PathCopy != CHAR_NULL) {
240     Status = VerifyIntermediateDirectories(PathCopy);
241 
242     if (PathCopy[StrLen(PathCopy)-1] != L':') {
243       if (!EFI_ERROR(Status)) {
244         Status = ShellOpenFileByName(PathCopy, &FileHandle, EFI_FILE_MODE_READ, 0);
245         if (FileHandle != NULL) {
246           ShellCloseFile(&FileHandle);
247         }
248       }
249     }
250   }
251 
252   SHELL_FREE_NON_NULL(PathCopy);
253 
254   return (Status);
255 }
256 
257 /**
258   String comparison without regard to case for a limited number of characters.
259 
260   @param[in] Source   The first item to compare.
261   @param[in] Target   The second item to compare.
262   @param[in] Count    How many characters to compare.
263 
264   @retval 0    Source and Target are identical strings without regard to case.
265   @retval !=0  Source is not identical to Target.
266 
267 **/
268 INTN
StrniCmp(IN CONST CHAR16 * Source,IN CONST CHAR16 * Target,IN CONST UINTN Count)269 StrniCmp(
270   IN CONST CHAR16 *Source,
271   IN CONST CHAR16 *Target,
272   IN CONST UINTN  Count
273   )
274 {
275   CHAR16                    *SourceCopy;
276   CHAR16                    *TargetCopy;
277   UINTN                     SourceLength;
278   UINTN                     TargetLength;
279   INTN                      Result;
280 
281   if (Count == 0) {
282     return 0;
283   }
284 
285   SourceLength = StrLen (Source);
286   TargetLength = StrLen (Target);
287   SourceLength = MIN (SourceLength, Count);
288   TargetLength = MIN (TargetLength, Count);
289   SourceCopy = AllocateCopyPool ((SourceLength + 1) * sizeof (CHAR16), Source);
290   if (SourceCopy == NULL) {
291     return -1;
292   }
293   TargetCopy = AllocateCopyPool ((TargetLength + 1) * sizeof (CHAR16), Target);
294   if (TargetCopy == NULL) {
295     FreePool (SourceCopy);
296     return -1;
297   }
298 
299   SourceCopy[SourceLength] = L'\0';
300   TargetCopy[TargetLength] = L'\0';
301   Result = gUnicodeCollation->StriColl (gUnicodeCollation, SourceCopy, TargetCopy);
302   FreePool (SourceCopy);
303   FreePool (TargetCopy);
304   return Result;
305 }
306 
307 
308 /**
309   Cleans off all the quotes in the string.
310 
311   @param[in]     OriginalString   pointer to the string to be cleaned.
312   @param[out]   CleanString      The new string with all quotes removed.
313                                                   Memory allocated in the function and free
314                                                   by caller.
315 
316   @retval EFI_SUCCESS   The operation was successful.
317 **/
318 EFI_STATUS
ShellLevel2StripQuotes(IN CONST CHAR16 * OriginalString,OUT CHAR16 ** CleanString)319 ShellLevel2StripQuotes (
320   IN  CONST CHAR16     *OriginalString,
321   OUT CHAR16           **CleanString
322   )
323 {
324   CHAR16            *Walker;
325 
326   if (OriginalString == NULL || CleanString == NULL) {
327     return EFI_INVALID_PARAMETER;
328   }
329 
330   *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
331   if (*CleanString == NULL) {
332     return EFI_OUT_OF_RESOURCES;
333   }
334 
335   for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {
336     if (*Walker == L'\"') {
337       CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));
338     }
339   }
340 
341   return EFI_SUCCESS;
342 }
343 
344 
345