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 permanent (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*
GetFullyQualifiedPath(IN CONST CHAR16 * Path)172 GetFullyQualifiedPath(
173   IN CONST CHAR16* Path
174   )
175 {
176   CHAR16        *PathToReturn;
177   UINTN         Size;
178   CONST CHAR16  *CurDir;
179 
180   PathToReturn  = NULL;
181   Size          = 0;
182 
183   ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));
184   //
185   // convert a local path to an absolute path
186   //
187   if (StrStr(Path, L":") == NULL) {
188     CurDir = gEfiShellProtocol->GetCurDir(NULL);
189     StrnCatGrow(&PathToReturn, &Size, CurDir, 0);
190     StrnCatGrow(&PathToReturn, &Size, L"\\", 0);
191     if (*Path == L'\\') {
192       Path++;
193     }
194   }
195   StrnCatGrow(&PathToReturn, &Size, Path, 0);
196 
197   PathCleanUpDirectories(PathToReturn);
198 
199   if (PathToReturn == NULL) {
200     return NULL;
201   }
202 
203   while (PathToReturn[StrLen(PathToReturn)-1] == L'*') {
204     PathToReturn[StrLen(PathToReturn)-1] = CHAR_NULL;
205   }
206 
207   return (PathToReturn);
208 }
209 
210 /**
211   Function to verify all intermediate directories in the path.
212 
213   @param[in] Path       The pointer to the path to fix.
214 
215   @retval EFI_SUCCESS   The operation was successful.
216 **/
217 EFI_STATUS
VerifyIntermediateDirectories(IN CONST CHAR16 * Path)218 VerifyIntermediateDirectories (
219   IN CONST CHAR16 *Path
220   )
221 {
222   EFI_STATUS      Status;
223   CHAR16          *PathCopy;
224   CHAR16          *TempSpot;
225   SHELL_FILE_HANDLE          FileHandle;
226 
227   ASSERT(Path != NULL);
228 
229   Status      = EFI_SUCCESS;
230   PathCopy    = NULL;
231   PathCopy    = StrnCatGrow(&PathCopy, NULL, Path, 0);
232   FileHandle  = NULL;
233 
234   if (PathCopy == NULL) {
235     return (EFI_OUT_OF_RESOURCES);
236   }
237 
238   for (TempSpot = &PathCopy[StrLen(PathCopy)-1] ; *TempSpot != CHAR_NULL && *TempSpot != L'\\' ; TempSpot = &PathCopy[StrLen(PathCopy)-1]){
239     *TempSpot = CHAR_NULL;
240   }
241   if (*TempSpot == L'\\') {
242     *TempSpot = CHAR_NULL;
243   }
244 
245   if (PathCopy != NULL && *PathCopy != CHAR_NULL) {
246     Status = VerifyIntermediateDirectories(PathCopy);
247 
248     if (PathCopy[StrLen(PathCopy)-1] != L':') {
249       if (!EFI_ERROR(Status)) {
250         Status = ShellOpenFileByName(PathCopy, &FileHandle, EFI_FILE_MODE_READ, 0);
251         if (FileHandle != NULL) {
252           ShellCloseFile(&FileHandle);
253         }
254       }
255     }
256   }
257 
258   SHELL_FREE_NON_NULL(PathCopy);
259 
260   return (Status);
261 }
262 
263 /**
264   Be lazy and borrow from baselib.
265 
266   @param[in] Char   The character to convert to upper case.
267 
268   @return Char as an upper case character.
269 **/
270 CHAR16
271 InternalCharToUpper (
272   IN CONST CHAR16                    Char
273   );
274 
275 /**
276   String comparison without regard to case for a limited number of characters.
277 
278   @param[in] Source   The first item to compare.
279   @param[in] Target   The second item to compare.
280   @param[in] Count    How many characters to compare.
281 
282   @retval NULL Source and Target are identical strings without regard to case.
283   @return The location in Source where there is a difference.
284 **/
285 CONST CHAR16*
StrniCmp(IN CONST CHAR16 * Source,IN CONST CHAR16 * Target,IN CONST UINTN Count)286 StrniCmp(
287   IN CONST CHAR16 *Source,
288   IN CONST CHAR16 *Target,
289   IN CONST UINTN  Count
290   )
291 {
292   UINTN   LoopCount;
293   CHAR16  Char1;
294   CHAR16  Char2;
295 
296   ASSERT(Source != NULL);
297   ASSERT(Target != NULL);
298 
299   for (LoopCount = 0 ; LoopCount < Count ; LoopCount++) {
300     Char1 = InternalCharToUpper(Source[LoopCount]);
301     Char2 = InternalCharToUpper(Target[LoopCount]);
302     if (Char1 != Char2) {
303       return (&Source[LoopCount]);
304     }
305   }
306   return (NULL);
307 }
308 
309 
310 /**
311   Cleans off all the quotes in the string.
312 
313   @param[in]     OriginalString   pointer to the string to be cleaned.
314   @param[out]   CleanString      The new string with all quotes removed.
315                                                   Memory allocated in the function and free
316                                                   by caller.
317 
318   @retval EFI_SUCCESS   The operation was successful.
319 **/
320 EFI_STATUS
ShellLevel2StripQuotes(IN CONST CHAR16 * OriginalString,OUT CHAR16 ** CleanString)321 ShellLevel2StripQuotes (
322   IN  CONST CHAR16     *OriginalString,
323   OUT CHAR16           **CleanString
324   )
325 {
326   CHAR16            *Walker;
327 
328   if (OriginalString == NULL || CleanString == NULL) {
329     return EFI_INVALID_PARAMETER;
330   }
331 
332   *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
333   if (*CleanString == NULL) {
334     return EFI_OUT_OF_RESOURCES;
335   }
336 
337   for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {
338     if (*Walker == L'\"') {
339       CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));
340     }
341   }
342 
343   return EFI_SUCCESS;
344 }
345 
346 
347