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