]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ShellPkg/Application/Shell/ShellProtocol.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
... / ...
CommitLineData
1/** @file\r
2 Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
3 manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
4\r
5 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
7 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12#include "Shell.h"\r
13\r
14#define INIT_NAME_BUFFER_SIZE 128\r
15\r
16/**\r
17 Close an open file handle.\r
18\r
19 This function closes a specified file handle. All "dirty" cached file data is\r
20 flushed to the device, and the file is closed. In all cases the handle is\r
21 closed.\r
22\r
23 @param[in] FileHandle The file handle to close.\r
24\r
25 @retval EFI_SUCCESS The file handle was closed successfully.\r
26**/\r
27EFI_STATUS\r
28EFIAPI\r
29EfiShellClose (\r
30 IN SHELL_FILE_HANDLE FileHandle\r
31 )\r
32{\r
33 ShellFileHandleRemove (FileHandle);\r
34 return (FileHandleClose (ConvertShellHandleToEfiFileProtocol (FileHandle)));\r
35}\r
36\r
37/**\r
38 Internal worker to determine whether there is a BlockIo somewhere\r
39 upon the device path specified.\r
40\r
41 @param[in] DevicePath The device path to test.\r
42\r
43 @retval TRUE gEfiBlockIoProtocolGuid was installed on a handle with this device path\r
44 @retval FALSE gEfiBlockIoProtocolGuid was not found.\r
45**/\r
46BOOLEAN\r
47InternalShellProtocolIsBlockIoPresent (\r
48 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
49 )\r
50{\r
51 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
52 EFI_STATUS Status;\r
53 EFI_HANDLE Handle;\r
54\r
55 Handle = NULL;\r
56\r
57 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
58 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathCopy, &Handle);\r
59\r
60 if ((Handle != NULL) && (!EFI_ERROR (Status))) {\r
61 return (TRUE);\r
62 }\r
63\r
64 return (FALSE);\r
65}\r
66\r
67/**\r
68 Internal worker to determine whether there is a file system somewhere\r
69 upon the device path specified.\r
70\r
71 @param[in] DevicePath The device path to test.\r
72\r
73 @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path\r
74 @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found.\r
75**/\r
76BOOLEAN\r
77InternalShellProtocolIsSimpleFileSystemPresent (\r
78 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
79 )\r
80{\r
81 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
82 EFI_STATUS Status;\r
83 EFI_HANDLE Handle;\r
84\r
85 Handle = NULL;\r
86\r
87 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
88 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
89\r
90 if ((Handle != NULL) && (!EFI_ERROR (Status))) {\r
91 return (TRUE);\r
92 }\r
93\r
94 return (FALSE);\r
95}\r
96\r
97/**\r
98 This function creates a mapping for a device path.\r
99\r
100 If both DevicePath and Mapping are NULL, this will reset the mapping to default values.\r
101\r
102 @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping,\r
103 then the mapping will be deleted.\r
104 @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':'\r
105\r
106 @retval EFI_SUCCESS Mapping created or deleted successfully.\r
107 @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the\r
108 boot service function LocateDevicePath().\r
109 @retval EFI_ACCESS_DENIED The mapping is a built-in alias.\r
110 @retval EFI_INVALID_PARAMETER Mapping was NULL\r
111 @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'\r
112 @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.\r
113 @retval EFI_NOT_FOUND There was no mapping found to delete\r
114 @retval EFI_OUT_OF_RESOURCES Memory allocation failed\r
115**/\r
116EFI_STATUS\r
117EFIAPI\r
118EfiShellSetMap (\r
119 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,\r
120 IN CONST CHAR16 *Mapping\r
121 )\r
122{\r
123 EFI_STATUS Status;\r
124 SHELL_MAP_LIST *MapListNode;\r
125\r
126 if (Mapping == NULL) {\r
127 return (EFI_INVALID_PARAMETER);\r
128 }\r
129\r
130 if (Mapping[StrLen (Mapping)-1] != ':') {\r
131 return (EFI_INVALID_PARAMETER);\r
132 }\r
133\r
134 //\r
135 // Delete the mapping\r
136 //\r
137 if (DevicePath == NULL) {\r
138 if (IsListEmpty (&gShellMapList.Link)) {\r
139 return (EFI_NOT_FOUND);\r
140 }\r
141\r
142 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)\r
143 ; !IsNull (&gShellMapList.Link, &MapListNode->Link)\r
144 ; MapListNode = (SHELL_MAP_LIST *)GetNextNode (&gShellMapList.Link, &MapListNode->Link)\r
145 )\r
146 {\r
147 if (StringNoCaseCompare (&MapListNode->MapName, &Mapping) == 0) {\r
148 RemoveEntryList (&MapListNode->Link);\r
149 SHELL_FREE_NON_NULL (MapListNode->DevicePath);\r
150 SHELL_FREE_NON_NULL (MapListNode->MapName);\r
151 SHELL_FREE_NON_NULL (MapListNode->CurrentDirectoryPath);\r
152 FreePool (MapListNode);\r
153 return (EFI_SUCCESS);\r
154 }\r
155 } // for loop\r
156\r
157 //\r
158 // We didn't find one to delete\r
159 //\r
160 return (EFI_NOT_FOUND);\r
161 }\r
162\r
163 //\r
164 // make sure this is a valid to add device path\r
165 //\r
166 /// @todo add BlockIo to this test...\r
167 if ( !InternalShellProtocolIsSimpleFileSystemPresent (DevicePath)\r
168 && !InternalShellProtocolIsBlockIoPresent (DevicePath))\r
169 {\r
170 return (EFI_INVALID_PARAMETER);\r
171 }\r
172\r
173 //\r
174 // First make sure there is no old mapping\r
175 //\r
176 Status = EfiShellSetMap (NULL, Mapping);\r
177 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) {\r
178 return (Status);\r
179 }\r
180\r
181 //\r
182 // now add the new one.\r
183 //\r
184 Status = ShellCommandAddMapItemAndUpdatePath (Mapping, DevicePath, 0, FALSE);\r
185\r
186 return (Status);\r
187}\r
188\r
189/**\r
190 Gets the device path from the mapping.\r
191\r
192 This function gets the device path associated with a mapping.\r
193\r
194 @param Mapping A pointer to the mapping\r
195\r
196 @retval !=NULL Pointer to the device path that corresponds to the\r
197 device mapping. The returned pointer does not need\r
198 to be freed.\r
199 @retval NULL There is no device path associated with the\r
200 specified mapping.\r
201**/\r
202CONST EFI_DEVICE_PATH_PROTOCOL *\r
203EFIAPI\r
204EfiShellGetDevicePathFromMap (\r
205 IN CONST CHAR16 *Mapping\r
206 )\r
207{\r
208 SHELL_MAP_LIST *MapListItem;\r
209 CHAR16 *NewName;\r
210 UINTN Size;\r
211\r
212 NewName = NULL;\r
213 Size = 0;\r
214\r
215 StrnCatGrow (&NewName, &Size, Mapping, 0);\r
216 if (Mapping[StrLen (Mapping)-1] != L':') {\r
217 StrnCatGrow (&NewName, &Size, L":", 0);\r
218 }\r
219\r
220 MapListItem = ShellCommandFindMapItem (NewName);\r
221\r
222 FreePool (NewName);\r
223\r
224 if (MapListItem != NULL) {\r
225 return (MapListItem->DevicePath);\r
226 }\r
227\r
228 return (NULL);\r
229}\r
230\r
231/**\r
232 Gets the mapping(s) that most closely matches the device path.\r
233\r
234 This function gets the mapping which corresponds to the device path *DevicePath. If\r
235 there is no exact match, then the mapping which most closely matches *DevicePath\r
236 is returned, and *DevicePath is updated to point to the remaining portion of the\r
237 device path. If there is an exact match, the mapping is returned and *DevicePath\r
238 points to the end-of-device-path node.\r
239\r
240 If there are multiple map names they will be semi-colon separated in the\r
241 NULL-terminated string.\r
242\r
243 @param DevicePath On entry, points to a device path pointer. On\r
244 exit, updates the pointer to point to the\r
245 portion of the device path after the mapping.\r
246\r
247 @retval NULL No mapping was found.\r
248 @return !=NULL Pointer to NULL-terminated mapping. The buffer\r
249 is callee allocated and should be freed by the caller.\r
250**/\r
251CONST CHAR16 *\r
252EFIAPI\r
253EfiShellGetMapFromDevicePath (\r
254 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
255 )\r
256{\r
257 SHELL_MAP_LIST *Node;\r
258 CHAR16 *PathForReturn;\r
259 UINTN PathSize;\r
260\r
261 // EFI_HANDLE PathHandle;\r
262 // EFI_HANDLE MapHandle;\r
263 // EFI_STATUS Status;\r
264 // EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
265 // EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
266\r
267 if ((DevicePath == NULL) || (*DevicePath == NULL)) {\r
268 return (NULL);\r
269 }\r
270\r
271 PathForReturn = NULL;\r
272 PathSize = 0;\r
273\r
274 for ( Node = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)\r
275 ; !IsNull (&gShellMapList.Link, &Node->Link)\r
276 ; Node = (SHELL_MAP_LIST *)GetNextNode (&gShellMapList.Link, &Node->Link)\r
277 )\r
278 {\r
279 //\r
280 // check for exact match\r
281 //\r
282 if (DevicePathCompare (DevicePath, &Node->DevicePath) == 0) {\r
283 ASSERT ((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
284 if (PathSize != 0) {\r
285 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L";", 0);\r
286 }\r
287\r
288 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, Node->MapName, 0);\r
289 }\r
290 }\r
291\r
292 if (PathForReturn != NULL) {\r
293 while (!IsDevicePathEndType (*DevicePath)) {\r
294 *DevicePath = NextDevicePathNode (*DevicePath);\r
295 }\r
296\r
297 //\r
298 // Do not call SetDevicePathEndNode() if the device path node is already the\r
299 // end of an entire device path.\r
300 //\r
301 if (!IsDevicePathEnd (*DevicePath)) {\r
302 SetDevicePathEndNode (*DevicePath);\r
303 }\r
304 }\r
305\r
306 /*\r
307 ///@todo finish code for inexact matches.\r
308 if (PathForReturn == NULL) {\r
309 PathSize = 0;\r
310\r
311 DevicePathCopy = DuplicateDevicePath(*DevicePath);\r
312 ASSERT(DevicePathCopy != NULL);\r
313 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
314 ASSERT_EFI_ERROR(Status);\r
315 //\r
316 // check each of the device paths we have to get the root of the path for consist mappings\r
317 //\r
318 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
319 ; !IsNull(&gShellMapList.Link, &Node->Link)\r
320 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
321 ){\r
322 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {\r
323 continue;\r
324 }\r
325 MapPathCopy = DuplicateDevicePath(Node->DevicePath);\r
326 ASSERT(MapPathCopy != NULL);\r
327 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
328 if (MapHandle == PathHandle) {\r
329\r
330 *DevicePath = DevicePathCopy;\r
331\r
332 MapPathCopy = NULL;\r
333 DevicePathCopy = NULL;\r
334 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
335 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
336 break;\r
337 }\r
338 }\r
339 //\r
340 // now add on the non-consistent mappings\r
341 //\r
342 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
343 ; !IsNull(&gShellMapList.Link, &Node->Link)\r
344 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
345 ){\r
346 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {\r
347 continue;\r
348 }\r
349 MapPathCopy = Node->DevicePath;\r
350 ASSERT(MapPathCopy != NULL);\r
351 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
352 if (MapHandle == PathHandle) {\r
353 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
354 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
355 break;\r
356 }\r
357 }\r
358 }\r
359 */\r
360\r
361 return (AddBufferToFreeList (PathForReturn));\r
362}\r
363\r
364/**\r
365 Converts a device path to a file system-style path.\r
366\r
367 This function converts a device path to a file system path by replacing part, or all, of\r
368 the device path with the file-system mapping. If there are more than one application\r
369 file system mappings, the one that most closely matches Path will be used.\r
370\r
371 @param Path The pointer to the device path\r
372\r
373 @retval NULL the device path could not be found.\r
374 @return all The pointer of the NULL-terminated file path. The path\r
375 is callee-allocated and should be freed by the caller.\r
376**/\r
377CHAR16 *\r
378EFIAPI\r
379EfiShellGetFilePathFromDevicePath (\r
380 IN CONST EFI_DEVICE_PATH_PROTOCOL *Path\r
381 )\r
382{\r
383 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
384 EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
385 SHELL_MAP_LIST *MapListItem;\r
386 CHAR16 *PathForReturn;\r
387 UINTN PathSize;\r
388 EFI_HANDLE PathHandle;\r
389 EFI_HANDLE MapHandle;\r
390 EFI_STATUS Status;\r
391 FILEPATH_DEVICE_PATH *FilePath;\r
392 FILEPATH_DEVICE_PATH *AlignedNode;\r
393\r
394 PathForReturn = NULL;\r
395 PathSize = 0;\r
396\r
397 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL *)Path;\r
398 ASSERT (DevicePathCopy != NULL);\r
399 if (DevicePathCopy == NULL) {\r
400 return (NULL);\r
401 }\r
402\r
403 /// @todo BlockIo?\r
404 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
405\r
406 if (EFI_ERROR (Status)) {\r
407 return (NULL);\r
408 }\r
409\r
410 //\r
411 // check each of the device paths we have to get the root of the path\r
412 //\r
413 for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)\r
414 ; !IsNull (&gShellMapList.Link, &MapListItem->Link)\r
415 ; MapListItem = (SHELL_MAP_LIST *)GetNextNode (&gShellMapList.Link, &MapListItem->Link)\r
416 )\r
417 {\r
418 MapPathCopy = (EFI_DEVICE_PATH_PROTOCOL *)MapListItem->DevicePath;\r
419 ASSERT (MapPathCopy != NULL);\r
420 /// @todo BlockIo?\r
421 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
422 if (MapHandle == PathHandle) {\r
423 ASSERT ((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
424 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, MapListItem->MapName, 0);\r
425 //\r
426 // go through all the remaining nodes in the device path\r
427 //\r
428 for ( FilePath = (FILEPATH_DEVICE_PATH *)DevicePathCopy\r
429 ; !IsDevicePathEnd (&FilePath->Header)\r
430 ; FilePath = (FILEPATH_DEVICE_PATH *)NextDevicePathNode (&FilePath->Header)\r
431 )\r
432 {\r
433 //\r
434 // If any node is not a file path node, then the conversion can not be completed\r
435 //\r
436 if ((DevicePathType (&FilePath->Header) != MEDIA_DEVICE_PATH) ||\r
437 (DevicePathSubType (&FilePath->Header) != MEDIA_FILEPATH_DP))\r
438 {\r
439 FreePool (PathForReturn);\r
440 return NULL;\r
441 }\r
442\r
443 //\r
444 // append the path part onto the filepath.\r
445 //\r
446 ASSERT ((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
447\r
448 AlignedNode = AllocateCopyPool (DevicePathNodeLength (FilePath), FilePath);\r
449 if (AlignedNode == NULL) {\r
450 FreePool (PathForReturn);\r
451 return NULL;\r
452 }\r
453\r
454 // File Path Device Path Nodes 'can optionally add a "\" separator to\r
455 // the beginning and/or the end of the Path Name string.'\r
456 // (UEFI Spec 2.4 section 9.3.6.4).\r
457 // If necessary, add a "\", but otherwise don't\r
458 // (This is specified in the above section, and also implied by the\r
459 // UEFI Shell spec section 3.7)\r
460 if ((PathSize != 0) &&\r
461 (PathForReturn != NULL) &&\r
462 (PathForReturn[PathSize / sizeof (CHAR16) - 1] != L'\\') &&\r
463 (AlignedNode->PathName[0] != L'\\'))\r
464 {\r
465 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);\r
466 }\r
467\r
468 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
469 FreePool (AlignedNode);\r
470 } // for loop of remaining nodes\r
471 }\r
472\r
473 if (PathForReturn != NULL) {\r
474 break;\r
475 }\r
476 } // for loop of paths to check\r
477\r
478 return (PathForReturn);\r
479}\r
480\r
481/**\r
482 Converts a file system style name to a device path.\r
483\r
484 This function converts a file system style name to a device path, by replacing any\r
485 mapping references to the associated device path.\r
486\r
487 @param[in] Path The pointer to the path.\r
488\r
489 @return The pointer of the file path. The file path is callee\r
490 allocated and should be freed by the caller.\r
491 @retval NULL The path could not be found.\r
492 @retval NULL There was not enough available memory.\r
493**/\r
494EFI_DEVICE_PATH_PROTOCOL *\r
495EFIAPI\r
496EfiShellGetDevicePathFromFilePath (\r
497 IN CONST CHAR16 *Path\r
498 )\r
499{\r
500 CHAR16 *MapName;\r
501 CHAR16 *NewPath;\r
502 CONST CHAR16 *Cwd;\r
503 UINTN Size;\r
504 CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
505 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
506 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopyForFree;\r
507 EFI_DEVICE_PATH_PROTOCOL *DevicePathForReturn;\r
508 EFI_HANDLE Handle;\r
509 EFI_STATUS Status;\r
510\r
511 if (Path == NULL) {\r
512 return (NULL);\r
513 }\r
514\r
515 MapName = NULL;\r
516 NewPath = NULL;\r
517\r
518 if (StrStr (Path, L":") == NULL) {\r
519 Cwd = EfiShellGetCurDir (NULL);\r
520 if (Cwd == NULL) {\r
521 return (NULL);\r
522 }\r
523\r
524 Size = StrSize (Cwd) + StrSize (Path);\r
525 NewPath = AllocateZeroPool (Size);\r
526 if (NewPath == NULL) {\r
527 return (NULL);\r
528 }\r
529\r
530 StrCpyS (NewPath, Size/sizeof (CHAR16), Cwd);\r
531 StrCatS (NewPath, Size/sizeof (CHAR16), L"\\");\r
532 if (*Path == L'\\') {\r
533 Path++;\r
534 while (PathRemoveLastItem (NewPath)) {\r
535 }\r
536 }\r
537\r
538 StrCatS (NewPath, Size/sizeof (CHAR16), Path);\r
539 DevicePathForReturn = EfiShellGetDevicePathFromFilePath (NewPath);\r
540 FreePool (NewPath);\r
541 return (DevicePathForReturn);\r
542 }\r
543\r
544 Size = 0;\r
545 //\r
546 // find the part before (but including) the : for the map name\r
547 //\r
548 ASSERT ((MapName == NULL && Size == 0) || (MapName != NULL));\r
549 MapName = StrnCatGrow (&MapName, &Size, Path, (StrStr (Path, L":")-Path+1));\r
550 if ((MapName == NULL) || (MapName[StrLen (MapName)-1] != L':')) {\r
551 return (NULL);\r
552 }\r
553\r
554 //\r
555 // look up the device path in the map\r
556 //\r
557 DevicePath = EfiShellGetDevicePathFromMap (MapName);\r
558 if (DevicePath == NULL) {\r
559 //\r
560 // Must have been a bad Mapname\r
561 //\r
562 return (NULL);\r
563 }\r
564\r
565 //\r
566 // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)\r
567 //\r
568 DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath (DevicePath);\r
569 if (DevicePathCopy == NULL) {\r
570 FreePool (MapName);\r
571 return (NULL);\r
572 }\r
573\r
574 //\r
575 // get the handle\r
576 //\r
577 /// @todo BlockIo?\r
578 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
579 if (EFI_ERROR (Status)) {\r
580 if (DevicePathCopyForFree != NULL) {\r
581 FreePool (DevicePathCopyForFree);\r
582 }\r
583\r
584 FreePool (MapName);\r
585 return (NULL);\r
586 }\r
587\r
588 //\r
589 // build the full device path\r
590 //\r
591 if ((*(Path+StrLen (MapName)) != CHAR_NULL) &&\r
592 (*(Path+StrLen (MapName)+1) == CHAR_NULL))\r
593 {\r
594 DevicePathForReturn = FileDevicePath (Handle, L"\\");\r
595 } else {\r
596 DevicePathForReturn = FileDevicePath (Handle, Path+StrLen (MapName));\r
597 }\r
598\r
599 FreePool (MapName);\r
600 if (DevicePathCopyForFree != NULL) {\r
601 FreePool (DevicePathCopyForFree);\r
602 }\r
603\r
604 return (DevicePathForReturn);\r
605}\r
606\r
607/**\r
608 Gets the name of the device specified by the device handle.\r
609\r
610 This function gets the user-readable name of the device specified by the device\r
611 handle. If no user-readable name could be generated, then *BestDeviceName will be\r
612 NULL and EFI_NOT_FOUND will be returned.\r
613\r
614 If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the\r
615 device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on\r
616 DeviceHandle.\r
617\r
618 If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the\r
619 device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.\r
620 If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and\r
621 EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then\r
622 EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.\r
623\r
624 @param DeviceHandle The handle of the device.\r
625 @param Flags Determines the possible sources of component names.\r
626 Valid bits are:\r
627 EFI_DEVICE_NAME_USE_COMPONENT_NAME\r
628 EFI_DEVICE_NAME_USE_DEVICE_PATH\r
629 @param Language A pointer to the language specified for the device\r
630 name, in the same format as described in the UEFI\r
631 specification, Appendix M\r
632 @param BestDeviceName On return, points to the callee-allocated NULL-\r
633 terminated name of the device. If no device name\r
634 could be found, points to NULL. The name must be\r
635 freed by the caller...\r
636\r
637 @retval EFI_SUCCESS Get the name successfully.\r
638 @retval EFI_NOT_FOUND Fail to get the device name.\r
639 @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.\r
640 @retval EFI_INVALID_PARAMETER BestDeviceName was NULL\r
641 @retval EFI_INVALID_PARAMETER DeviceHandle was NULL\r
642**/\r
643EFI_STATUS\r
644EFIAPI\r
645EfiShellGetDeviceName (\r
646 IN EFI_HANDLE DeviceHandle,\r
647 IN EFI_SHELL_DEVICE_NAME_FLAGS Flags,\r
648 IN CHAR8 *Language,\r
649 OUT CHAR16 **BestDeviceName\r
650 )\r
651{\r
652 EFI_STATUS Status;\r
653 EFI_COMPONENT_NAME2_PROTOCOL *CompName2;\r
654 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
655 EFI_HANDLE *HandleList;\r
656 UINTN HandleCount;\r
657 UINTN LoopVar;\r
658 CHAR16 *DeviceNameToReturn;\r
659 CHAR8 *Lang;\r
660 UINTN ParentControllerCount;\r
661 EFI_HANDLE *ParentControllerBuffer;\r
662 UINTN ParentDriverCount;\r
663 EFI_HANDLE *ParentDriverBuffer;\r
664\r
665 if ((BestDeviceName == NULL) ||\r
666 (DeviceHandle == NULL)\r
667 )\r
668 {\r
669 return (EFI_INVALID_PARAMETER);\r
670 }\r
671\r
672 //\r
673 // make sure one of the 2 supported bits is on\r
674 //\r
675 if (((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) == 0) &&\r
676 ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) == 0))\r
677 {\r
678 return (EFI_INVALID_PARAMETER);\r
679 }\r
680\r
681 DeviceNameToReturn = NULL;\r
682 *BestDeviceName = NULL;\r
683 HandleList = NULL;\r
684 HandleCount = 0;\r
685 Lang = NULL;\r
686\r
687 if ((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) != 0) {\r
688 Status = ParseHandleDatabaseByRelationship (\r
689 NULL,\r
690 DeviceHandle,\r
691 HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER,\r
692 &HandleCount,\r
693 &HandleList\r
694 );\r
695 for (LoopVar = 0; LoopVar < HandleCount; LoopVar++) {\r
696 //\r
697 // Go through those handles until we get one that passes for GetComponentName\r
698 //\r
699 Status = gBS->OpenProtocol (\r
700 HandleList[LoopVar],\r
701 &gEfiComponentName2ProtocolGuid,\r
702 (VOID **)&CompName2,\r
703 gImageHandle,\r
704 NULL,\r
705 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
706 );\r
707 if (EFI_ERROR (Status)) {\r
708 Status = gBS->OpenProtocol (\r
709 HandleList[LoopVar],\r
710 &gEfiComponentNameProtocolGuid,\r
711 (VOID **)&CompName2,\r
712 gImageHandle,\r
713 NULL,\r
714 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
715 );\r
716 }\r
717\r
718 if (EFI_ERROR (Status)) {\r
719 continue;\r
720 }\r
721\r
722 Lang = GetBestLanguageForDriver (CompName2->SupportedLanguages, Language, FALSE);\r
723 Status = CompName2->GetControllerName (CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);\r
724 FreePool (Lang);\r
725 Lang = NULL;\r
726 if (!EFI_ERROR (Status) && (DeviceNameToReturn != NULL)) {\r
727 break;\r
728 }\r
729 }\r
730\r
731 if (HandleList != NULL) {\r
732 FreePool (HandleList);\r
733 }\r
734\r
735 //\r
736 // Now check the parent controller using this as the child.\r
737 //\r
738 if (DeviceNameToReturn == NULL) {\r
739 PARSE_HANDLE_DATABASE_PARENTS (DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);\r
740 for (LoopVar = 0; LoopVar < ParentControllerCount; LoopVar++) {\r
741 PARSE_HANDLE_DATABASE_UEFI_DRIVERS (ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);\r
742 for (HandleCount = 0; HandleCount < ParentDriverCount; HandleCount++) {\r
743 //\r
744 // try using that driver's component name with controller and our driver as the child.\r
745 //\r
746 Status = gBS->OpenProtocol (\r
747 ParentDriverBuffer[HandleCount],\r
748 &gEfiComponentName2ProtocolGuid,\r
749 (VOID **)&CompName2,\r
750 gImageHandle,\r
751 NULL,\r
752 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
753 );\r
754 if (EFI_ERROR (Status)) {\r
755 Status = gBS->OpenProtocol (\r
756 ParentDriverBuffer[HandleCount],\r
757 &gEfiComponentNameProtocolGuid,\r
758 (VOID **)&CompName2,\r
759 gImageHandle,\r
760 NULL,\r
761 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
762 );\r
763 }\r
764\r
765 if (EFI_ERROR (Status)) {\r
766 continue;\r
767 }\r
768\r
769 Lang = GetBestLanguageForDriver (CompName2->SupportedLanguages, Language, FALSE);\r
770 Status = CompName2->GetControllerName (CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn);\r
771 FreePool (Lang);\r
772 Lang = NULL;\r
773 if (!EFI_ERROR (Status) && (DeviceNameToReturn != NULL)) {\r
774 break;\r
775 }\r
776 }\r
777\r
778 SHELL_FREE_NON_NULL (ParentDriverBuffer);\r
779 if (!EFI_ERROR (Status) && (DeviceNameToReturn != NULL)) {\r
780 break;\r
781 }\r
782 }\r
783\r
784 SHELL_FREE_NON_NULL (ParentControllerBuffer);\r
785 }\r
786\r
787 //\r
788 // dont return on fail since we will try device path if that bit is on\r
789 //\r
790 if (DeviceNameToReturn != NULL) {\r
791 ASSERT (BestDeviceName != NULL);\r
792 StrnCatGrow (BestDeviceName, NULL, DeviceNameToReturn, 0);\r
793 return (EFI_SUCCESS);\r
794 }\r
795 }\r
796\r
797 if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {\r
798 Status = gBS->OpenProtocol (\r
799 DeviceHandle,\r
800 &gEfiDevicePathProtocolGuid,\r
801 (VOID **)&DevicePath,\r
802 gImageHandle,\r
803 NULL,\r
804 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
805 );\r
806 if (!EFI_ERROR (Status)) {\r
807 //\r
808 // use device path to text on the device path\r
809 //\r
810 *BestDeviceName = ConvertDevicePathToText (DevicePath, TRUE, TRUE);\r
811 return (EFI_SUCCESS);\r
812 }\r
813 }\r
814\r
815 //\r
816 // none of the selected bits worked.\r
817 //\r
818 return (EFI_NOT_FOUND);\r
819}\r
820\r
821/**\r
822 Opens the root directory of a device on a handle\r
823\r
824 This function opens the root directory of a device and returns a file handle to it.\r
825\r
826 @param DeviceHandle The handle of the device that contains the volume.\r
827 @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
828 device.\r
829\r
830 @retval EFI_SUCCESS Root opened successfully.\r
831 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
832 could not be opened.\r
833 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
834 @retval EFI_DEVICE_ERROR The device had an error.\r
835 @retval Others Error status returned from EFI_SIMPLE_FILE_SYSTEM_PROTOCOL->OpenVolume().\r
836**/\r
837EFI_STATUS\r
838EFIAPI\r
839EfiShellOpenRootByHandle (\r
840 IN EFI_HANDLE DeviceHandle,\r
841 OUT SHELL_FILE_HANDLE *FileHandle\r
842 )\r
843{\r
844 EFI_STATUS Status;\r
845 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;\r
846 EFI_FILE_PROTOCOL *RealFileHandle;\r
847 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
848\r
849 //\r
850 // get the simple file system interface\r
851 //\r
852 Status = gBS->OpenProtocol (\r
853 DeviceHandle,\r
854 &gEfiSimpleFileSystemProtocolGuid,\r
855 (VOID **)&SimpleFileSystem,\r
856 gImageHandle,\r
857 NULL,\r
858 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
859 );\r
860 if (EFI_ERROR (Status)) {\r
861 return (EFI_NOT_FOUND);\r
862 }\r
863\r
864 Status = gBS->OpenProtocol (\r
865 DeviceHandle,\r
866 &gEfiDevicePathProtocolGuid,\r
867 (VOID **)&DevPath,\r
868 gImageHandle,\r
869 NULL,\r
870 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
871 );\r
872 if (EFI_ERROR (Status)) {\r
873 return (EFI_NOT_FOUND);\r
874 }\r
875\r
876 //\r
877 // Open the root volume now...\r
878 //\r
879 Status = SimpleFileSystem->OpenVolume (SimpleFileSystem, &RealFileHandle);\r
880 if (EFI_ERROR (Status)) {\r
881 return Status;\r
882 }\r
883\r
884 *FileHandle = ConvertEfiFileProtocolToShellHandle (RealFileHandle, EfiShellGetMapFromDevicePath (&DevPath));\r
885 return (EFI_SUCCESS);\r
886}\r
887\r
888/**\r
889 Opens the root directory of a device.\r
890\r
891 This function opens the root directory of a device and returns a file handle to it.\r
892\r
893 @param DevicePath Points to the device path corresponding to the device where the\r
894 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.\r
895 @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
896 device.\r
897\r
898 @retval EFI_SUCCESS Root opened successfully.\r
899 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
900 could not be opened.\r
901 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
902 @retval EFI_DEVICE_ERROR The device had an error\r
903 @retval EFI_INVALID_PARAMETER FileHandle is NULL.\r
904**/\r
905EFI_STATUS\r
906EFIAPI\r
907EfiShellOpenRoot (\r
908 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
909 OUT SHELL_FILE_HANDLE *FileHandle\r
910 )\r
911{\r
912 EFI_STATUS Status;\r
913 EFI_HANDLE Handle;\r
914\r
915 if (FileHandle == NULL) {\r
916 return (EFI_INVALID_PARAMETER);\r
917 }\r
918\r
919 //\r
920 // find the handle of the device with that device handle and the file system\r
921 //\r
922 /// @todo BlockIo?\r
923 Status = gBS->LocateDevicePath (\r
924 &gEfiSimpleFileSystemProtocolGuid,\r
925 &DevicePath,\r
926 &Handle\r
927 );\r
928 if (EFI_ERROR (Status)) {\r
929 return (EFI_NOT_FOUND);\r
930 }\r
931\r
932 return (EfiShellOpenRootByHandle (Handle, FileHandle));\r
933}\r
934\r
935/**\r
936 Returns whether any script files are currently being processed.\r
937\r
938 @retval TRUE There is at least one script file active.\r
939 @retval FALSE No script files are active now.\r
940\r
941**/\r
942BOOLEAN\r
943EFIAPI\r
944EfiShellBatchIsActive (\r
945 VOID\r
946 )\r
947{\r
948 if (ShellCommandGetCurrentScriptFile () == NULL) {\r
949 return (FALSE);\r
950 }\r
951\r
952 return (TRUE);\r
953}\r
954\r
955/**\r
956 Worker function to open a file based on a device path. this will open the root\r
957 of the volume and then traverse down to the file itself.\r
958\r
959 @param DevicePath Device Path of the file.\r
960 @param FileHandle Pointer to the file upon a successful return.\r
961 @param OpenMode mode to open file in.\r
962 @param Attributes the File Attributes to use when creating a new file.\r
963\r
964 @retval EFI_SUCCESS the file is open and FileHandle is valid\r
965 @retval EFI_UNSUPPORTED the device path contained non-path elements\r
966 @retval other an error occurred.\r
967**/\r
968EFI_STATUS\r
969InternalOpenFileDevicePath (\r
970 IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
971 OUT SHELL_FILE_HANDLE *FileHandle,\r
972 IN UINT64 OpenMode,\r
973 IN UINT64 Attributes OPTIONAL\r
974 )\r
975{\r
976 EFI_STATUS Status;\r
977 FILEPATH_DEVICE_PATH *FilePathNode;\r
978 EFI_HANDLE Handle;\r
979 SHELL_FILE_HANDLE ShellHandle;\r
980 EFI_FILE_PROTOCOL *Handle1;\r
981 EFI_FILE_PROTOCOL *Handle2;\r
982 FILEPATH_DEVICE_PATH *AlignedNode;\r
983\r
984 if (FileHandle == NULL) {\r
985 return (EFI_INVALID_PARAMETER);\r
986 }\r
987\r
988 *FileHandle = NULL;\r
989 Handle1 = NULL;\r
990 Handle2 = NULL;\r
991 Handle = NULL;\r
992 ShellHandle = NULL;\r
993 FilePathNode = NULL;\r
994 AlignedNode = NULL;\r
995\r
996 Status = EfiShellOpenRoot (DevicePath, &ShellHandle);\r
997\r
998 if (!EFI_ERROR (Status)) {\r
999 Handle1 = ConvertShellHandleToEfiFileProtocol (ShellHandle);\r
1000 if (Handle1 != NULL) {\r
1001 //\r
1002 // chop off the beginning part before the file system part...\r
1003 //\r
1004 /// @todo BlockIo?\r
1005 Status = gBS->LocateDevicePath (\r
1006 &gEfiSimpleFileSystemProtocolGuid,\r
1007 &DevicePath,\r
1008 &Handle\r
1009 );\r
1010 if (!EFI_ERROR (Status)) {\r
1011 //\r
1012 // To access as a file system, the file path should only\r
1013 // contain file path components. Follow the file path nodes\r
1014 // and find the target file\r
1015 //\r
1016 for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
1017 ; !IsDevicePathEnd (&FilePathNode->Header)\r
1018 ; FilePathNode = (FILEPATH_DEVICE_PATH *)NextDevicePathNode (&FilePathNode->Header)\r
1019 )\r
1020 {\r
1021 SHELL_FREE_NON_NULL (AlignedNode);\r
1022 AlignedNode = AllocateCopyPool (DevicePathNodeLength (FilePathNode), FilePathNode);\r
1023 //\r
1024 // For file system access each node should be a file path component\r
1025 //\r
1026 if ((DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH) ||\r
1027 (DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP)\r
1028 )\r
1029 {\r
1030 Status = EFI_UNSUPPORTED;\r
1031 break;\r
1032 }\r
1033\r
1034 //\r
1035 // Open this file path node\r
1036 //\r
1037 Handle2 = Handle1;\r
1038 Handle1 = NULL;\r
1039\r
1040 //\r
1041 // if this is the last node in the DevicePath always create (if that was requested).\r
1042 //\r
1043 if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
1044 Status = Handle2->Open (\r
1045 Handle2,\r
1046 &Handle1,\r
1047 AlignedNode->PathName,\r
1048 OpenMode,\r
1049 Attributes\r
1050 );\r
1051 } else {\r
1052 //\r
1053 // This is not the last node and we dont want to 'create' existing\r
1054 // directory entries...\r
1055 //\r
1056\r
1057 //\r
1058 // open without letting it create\r
1059 // prevents error on existing files/directories\r
1060 //\r
1061 Status = Handle2->Open (\r
1062 Handle2,\r
1063 &Handle1,\r
1064 AlignedNode->PathName,\r
1065 OpenMode &~EFI_FILE_MODE_CREATE,\r
1066 Attributes\r
1067 );\r
1068 //\r
1069 // if above failed now open and create the 'item'\r
1070 // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
1071 //\r
1072 if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
1073 Status = Handle2->Open (\r
1074 Handle2,\r
1075 &Handle1,\r
1076 AlignedNode->PathName,\r
1077 OpenMode,\r
1078 Attributes\r
1079 );\r
1080 }\r
1081 }\r
1082\r
1083 //\r
1084 // Close the last node\r
1085 //\r
1086 ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2);\r
1087\r
1088 //\r
1089 // If there's been an error, stop\r
1090 //\r
1091 if (EFI_ERROR (Status)) {\r
1092 break;\r
1093 }\r
1094 } // for loop\r
1095 }\r
1096 }\r
1097 }\r
1098\r
1099 SHELL_FREE_NON_NULL (AlignedNode);\r
1100 if (EFI_ERROR (Status)) {\r
1101 if (Handle1 != NULL) {\r
1102 ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle1);\r
1103 }\r
1104 } else {\r
1105 *FileHandle = ConvertEfiFileProtocolToShellHandle (Handle1, ShellFileHandleGetPath (ShellHandle));\r
1106 }\r
1107\r
1108 return (Status);\r
1109}\r
1110\r
1111/**\r
1112 Creates a file or directory by name.\r
1113\r
1114 This function creates an empty new file or directory with the specified attributes and\r
1115 returns the new file's handle. If the file already exists and is read-only, then\r
1116 EFI_INVALID_PARAMETER will be returned.\r
1117\r
1118 If the file already existed, it is truncated and its attributes updated. If the file is\r
1119 created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.\r
1120\r
1121 If the file name begins with >v, then the file handle which is returned refers to the\r
1122 shell environment variable with the specified name. If the shell environment variable\r
1123 already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.\r
1124\r
1125 @param FileName Pointer to NULL-terminated file path\r
1126 @param FileAttribs The new file's attributes. the different attributes are\r
1127 described in EFI_FILE_PROTOCOL.Open().\r
1128 @param FileHandle On return, points to the created file handle or directory's handle\r
1129\r
1130 @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle.\r
1131 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1132 @retval EFI_UNSUPPORTED could not open the file path\r
1133 @retval EFI_NOT_FOUND the specified file could not be found on the device, or could not\r
1134 file the file system on the device.\r
1135 @retval EFI_NO_MEDIA the device has no medium.\r
1136 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
1137 longer supported.\r
1138 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
1139 the DirName.\r
1140 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1141 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
1142 when the media is write-protected.\r
1143 @retval EFI_ACCESS_DENIED The service denied access to the file.\r
1144 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
1145 @retval EFI_VOLUME_FULL The volume is full.\r
1146**/\r
1147EFI_STATUS\r
1148EFIAPI\r
1149EfiShellCreateFile (\r
1150 IN CONST CHAR16 *FileName,\r
1151 IN UINT64 FileAttribs,\r
1152 OUT SHELL_FILE_HANDLE *FileHandle\r
1153 )\r
1154{\r
1155 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1156 EFI_STATUS Status;\r
1157 BOOLEAN Volatile;\r
1158\r
1159 //\r
1160 // Is this for an environment variable\r
1161 // do we start with >v\r
1162 //\r
1163 if (StrStr (FileName, L">v") == FileName) {\r
1164 Status = IsVolatileEnv (FileName + 2, &Volatile);\r
1165 if (EFI_ERROR (Status)) {\r
1166 return Status;\r
1167 }\r
1168\r
1169 if (!Volatile) {\r
1170 return (EFI_INVALID_PARAMETER);\r
1171 }\r
1172\r
1173 *FileHandle = CreateFileInterfaceEnv (FileName+2);\r
1174 return (EFI_SUCCESS);\r
1175 }\r
1176\r
1177 //\r
1178 // We are opening a regular file.\r
1179 //\r
1180 DevicePath = EfiShellGetDevicePathFromFilePath (FileName);\r
1181 if (DevicePath == NULL) {\r
1182 return (EFI_NOT_FOUND);\r
1183 }\r
1184\r
1185 Status = InternalOpenFileDevicePath (DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs);\r
1186 FreePool (DevicePath);\r
1187\r
1188 return (Status);\r
1189}\r
1190\r
1191/**\r
1192 Register a GUID and a localized human readable name for it.\r
1193\r
1194 If Guid is not assigned a name, then assign GuidName to Guid. This list of GUID\r
1195 names must be used whenever a shell command outputs GUID information.\r
1196\r
1197 This function is only available when the major and minor versions in the\r
1198 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
1199\r
1200 @param[in] Guid A pointer to the GUID being registered.\r
1201 @param[in] GuidName A pointer to the localized name for the GUID being registered.\r
1202\r
1203 @retval EFI_SUCCESS The operation was successful.\r
1204 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
1205 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
1206 @retval EFI_ACCESS_DENIED Guid already is assigned a name.\r
1207**/\r
1208EFI_STATUS\r
1209EFIAPI\r
1210EfiShellRegisterGuidName (\r
1211 IN CONST EFI_GUID *Guid,\r
1212 IN CONST CHAR16 *GuidName\r
1213 )\r
1214{\r
1215 return (AddNewGuidNameMapping (Guid, GuidName, NULL));\r
1216}\r
1217\r
1218/**\r
1219 Opens a file or a directory by file name.\r
1220\r
1221 This function opens the specified file in the specified OpenMode and returns a file\r
1222 handle.\r
1223 If the file name begins with >v, then the file handle which is returned refers to the\r
1224 shell environment variable with the specified name. If the shell environment variable\r
1225 exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then\r
1226 EFI_INVALID_PARAMETER is returned.\r
1227\r
1228 If the file name is >i, then the file handle which is returned refers to the standard\r
1229 input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER\r
1230 is returned.\r
1231\r
1232 If the file name is >o, then the file handle which is returned refers to the standard\r
1233 output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
1234 is returned.\r
1235\r
1236 If the file name is >e, then the file handle which is returned refers to the standard\r
1237 error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
1238 is returned.\r
1239\r
1240 If the file name is NUL, then the file handle that is returned refers to the standard NUL\r
1241 file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is\r
1242 returned.\r
1243\r
1244 If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the\r
1245 FileHandle is NULL.\r
1246\r
1247 @param FileName Points to the NULL-terminated UCS-2 encoded file name.\r
1248 @param FileHandle On return, points to the file handle.\r
1249 @param OpenMode File open mode. Either EFI_FILE_MODE_READ or\r
1250 EFI_FILE_MODE_WRITE from section 12.4 of the UEFI\r
1251 Specification.\r
1252 @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle.\r
1253 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.\r
1254 @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL.\r
1255 @retval EFI_NOT_FOUND The specified file could not be found on the device or the file\r
1256 system could not be found on the device. FileHandle is NULL.\r
1257 @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL.\r
1258 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
1259 longer supported. FileHandle is NULL.\r
1260 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
1261 the FileName. FileHandle is NULL.\r
1262 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL.\r
1263 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
1264 when the media is write-protected. FileHandle is NULL.\r
1265 @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL.\r
1266 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle\r
1267 is NULL.\r
1268 @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL.\r
1269**/\r
1270EFI_STATUS\r
1271EFIAPI\r
1272EfiShellOpenFileByName (\r
1273 IN CONST CHAR16 *FileName,\r
1274 OUT SHELL_FILE_HANDLE *FileHandle,\r
1275 IN UINT64 OpenMode\r
1276 )\r
1277{\r
1278 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1279 EFI_STATUS Status;\r
1280 BOOLEAN Volatile;\r
1281\r
1282 *FileHandle = NULL;\r
1283\r
1284 //\r
1285 // Is this for StdIn\r
1286 //\r
1287 if (StrCmp (FileName, L">i") == 0) {\r
1288 //\r
1289 // make sure not writing to StdIn\r
1290 //\r
1291 if ((OpenMode & EFI_FILE_MODE_WRITE) != 0) {\r
1292 return (EFI_INVALID_PARAMETER);\r
1293 }\r
1294\r
1295 *FileHandle = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
1296 ASSERT (*FileHandle != NULL);\r
1297 return (EFI_SUCCESS);\r
1298 }\r
1299\r
1300 //\r
1301 // Is this for StdOut\r
1302 //\r
1303 if (StrCmp (FileName, L">o") == 0) {\r
1304 //\r
1305 // make sure not writing to StdIn\r
1306 //\r
1307 if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
1308 return (EFI_INVALID_PARAMETER);\r
1309 }\r
1310\r
1311 *FileHandle = &FileInterfaceStdOut;\r
1312 return (EFI_SUCCESS);\r
1313 }\r
1314\r
1315 //\r
1316 // Is this for NUL / NULL file\r
1317 //\r
1318 if ((gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)FileName, L"NUL") == 0) ||\r
1319 (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)FileName, L"NULL") == 0))\r
1320 {\r
1321 *FileHandle = &FileInterfaceNulFile;\r
1322 return (EFI_SUCCESS);\r
1323 }\r
1324\r
1325 //\r
1326 // Is this for StdErr\r
1327 //\r
1328 if (StrCmp (FileName, L">e") == 0) {\r
1329 //\r
1330 // make sure not writing to StdIn\r
1331 //\r
1332 if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
1333 return (EFI_INVALID_PARAMETER);\r
1334 }\r
1335\r
1336 *FileHandle = &FileInterfaceStdErr;\r
1337 return (EFI_SUCCESS);\r
1338 }\r
1339\r
1340 //\r
1341 // Is this for an environment variable\r
1342 // do we start with >v\r
1343 //\r
1344 if (StrStr (FileName, L">v") == FileName) {\r
1345 Status = IsVolatileEnv (FileName + 2, &Volatile);\r
1346 if (EFI_ERROR (Status)) {\r
1347 return Status;\r
1348 }\r
1349\r
1350 if (!Volatile &&\r
1351 ((OpenMode & EFI_FILE_MODE_WRITE) != 0))\r
1352 {\r
1353 return (EFI_INVALID_PARAMETER);\r
1354 }\r
1355\r
1356 *FileHandle = CreateFileInterfaceEnv (FileName+2);\r
1357 return (EFI_SUCCESS);\r
1358 }\r
1359\r
1360 //\r
1361 // We are opening a regular file.\r
1362 //\r
1363 DevicePath = EfiShellGetDevicePathFromFilePath (FileName);\r
1364\r
1365 if (DevicePath == NULL) {\r
1366 return (EFI_NOT_FOUND);\r
1367 }\r
1368\r
1369 //\r
1370 // Copy the device path, open the file, then free the memory\r
1371 //\r
1372 Status = InternalOpenFileDevicePath (DevicePath, FileHandle, OpenMode, 0); // 0 = no specific file attributes\r
1373 FreePool (DevicePath);\r
1374\r
1375 return (Status);\r
1376}\r
1377\r
1378/**\r
1379 Deletes the file specified by the file name.\r
1380\r
1381 This function deletes a file.\r
1382\r
1383 @param FileName Points to the NULL-terminated file name.\r
1384\r
1385 @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.\r
1386 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
1387 @sa EfiShellCreateFile\r
1388**/\r
1389EFI_STATUS\r
1390EFIAPI\r
1391EfiShellDeleteFileByName (\r
1392 IN CONST CHAR16 *FileName\r
1393 )\r
1394{\r
1395 SHELL_FILE_HANDLE FileHandle;\r
1396 EFI_STATUS Status;\r
1397\r
1398 FileHandle = NULL;\r
1399\r
1400 //\r
1401 // get a handle to the file\r
1402 //\r
1403 Status = EfiShellCreateFile (\r
1404 FileName,\r
1405 0,\r
1406 &FileHandle\r
1407 );\r
1408 if (EFI_ERROR (Status)) {\r
1409 return (Status);\r
1410 }\r
1411\r
1412 //\r
1413 // now delete the file\r
1414 //\r
1415 ShellFileHandleRemove (FileHandle);\r
1416 return (ShellInfoObject.NewEfiShellProtocol->DeleteFile (FileHandle));\r
1417}\r
1418\r
1419/**\r
1420 Disables the page break output mode.\r
1421**/\r
1422VOID\r
1423EFIAPI\r
1424EfiShellDisablePageBreak (\r
1425 VOID\r
1426 )\r
1427{\r
1428 ShellInfoObject.PageBreakEnabled = FALSE;\r
1429}\r
1430\r
1431/**\r
1432 Enables the page break output mode.\r
1433**/\r
1434VOID\r
1435EFIAPI\r
1436EfiShellEnablePageBreak (\r
1437 VOID\r
1438 )\r
1439{\r
1440 ShellInfoObject.PageBreakEnabled = TRUE;\r
1441}\r
1442\r
1443/**\r
1444 internal worker function to load and run an image via device path.\r
1445\r
1446 @param ParentImageHandle A handle of the image that is executing the specified\r
1447 command line.\r
1448 @param DevicePath device path of the file to execute\r
1449 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1450 containing the command line. If NULL then the command-\r
1451 line will be empty.\r
1452 @param Environment Points to a NULL-terminated array of environment\r
1453 variables with the format 'x=y', where x is the\r
1454 environment variable name and y is the value. If this\r
1455 is NULL, then the current shell environment is used.\r
1456\r
1457 @param[out] StartImageStatus Returned status from gBS->StartImage.\r
1458\r
1459 @retval EFI_SUCCESS The command executed successfully. The status code\r
1460 returned by the command is pointed to by StatusCode.\r
1461 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1462 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1463 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1464**/\r
1465EFI_STATUS\r
1466InternalShellExecuteDevicePath (\r
1467 IN CONST EFI_HANDLE *ParentImageHandle,\r
1468 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1469 IN CONST CHAR16 *CommandLine OPTIONAL,\r
1470 IN CONST CHAR16 **Environment OPTIONAL,\r
1471 OUT EFI_STATUS *StartImageStatus OPTIONAL\r
1472 )\r
1473{\r
1474 EFI_STATUS Status;\r
1475 EFI_STATUS StartStatus;\r
1476 EFI_STATUS CleanupStatus;\r
1477 EFI_HANDLE NewHandle;\r
1478 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
1479 LIST_ENTRY OrigEnvs;\r
1480 EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
1481 CHAR16 *ImagePath;\r
1482 UINTN Index;\r
1483 CHAR16 *Walker;\r
1484 CHAR16 *NewCmdLine;\r
1485\r
1486 if (ParentImageHandle == NULL) {\r
1487 return (EFI_INVALID_PARAMETER);\r
1488 }\r
1489\r
1490 InitializeListHead (&OrigEnvs);\r
1491 ZeroMem (&ShellParamsProtocol, sizeof (EFI_SHELL_PARAMETERS_PROTOCOL));\r
1492\r
1493 NewHandle = NULL;\r
1494\r
1495 NewCmdLine = AllocateCopyPool (StrSize (CommandLine), CommandLine);\r
1496 if (NewCmdLine == NULL) {\r
1497 return EFI_OUT_OF_RESOURCES;\r
1498 }\r
1499\r
1500 for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL; Walker++) {\r
1501 if ((*Walker == L'^') && (*(Walker+1) == L'#')) {\r
1502 CopyMem (Walker, Walker+1, StrSize (Walker) - sizeof (Walker[0]));\r
1503 }\r
1504 }\r
1505\r
1506 //\r
1507 // Load the image with:\r
1508 // FALSE - not from boot manager and NULL, 0 being not already in memory\r
1509 //\r
1510 Status = gBS->LoadImage (\r
1511 FALSE,\r
1512 *ParentImageHandle,\r
1513 (EFI_DEVICE_PATH_PROTOCOL *)DevicePath,\r
1514 NULL,\r
1515 0,\r
1516 &NewHandle\r
1517 );\r
1518\r
1519 if (EFI_ERROR (Status)) {\r
1520 if (NewHandle != NULL) {\r
1521 gBS->UnloadImage (NewHandle);\r
1522 }\r
1523\r
1524 FreePool (NewCmdLine);\r
1525 return (Status);\r
1526 }\r
1527\r
1528 Status = gBS->OpenProtocol (\r
1529 NewHandle,\r
1530 &gEfiLoadedImageProtocolGuid,\r
1531 (VOID **)&LoadedImage,\r
1532 gImageHandle,\r
1533 NULL,\r
1534 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1535 );\r
1536\r
1537 if (!EFI_ERROR (Status)) {\r
1538 //\r
1539 // If the image is not an app abort it.\r
1540 //\r
1541 if (LoadedImage->ImageCodeType != EfiLoaderCode) {\r
1542 ShellPrintHiiEx (\r
1543 -1,\r
1544 -1,\r
1545 NULL,\r
1546 STRING_TOKEN (STR_SHELL_IMAGE_NOT_APP),\r
1547 ShellInfoObject.HiiHandle\r
1548 );\r
1549 goto UnloadImage;\r
1550 }\r
1551\r
1552 ASSERT (LoadedImage->LoadOptionsSize == 0);\r
1553 if (NewCmdLine != NULL) {\r
1554 LoadedImage->LoadOptionsSize = (UINT32)StrSize (NewCmdLine);\r
1555 LoadedImage->LoadOptions = (VOID *)NewCmdLine;\r
1556 }\r
1557\r
1558 //\r
1559 // Save our current environment settings for later restoration if necessary\r
1560 //\r
1561 if (Environment != NULL) {\r
1562 Status = GetEnvironmentVariableList (&OrigEnvs);\r
1563 if (!EFI_ERROR (Status)) {\r
1564 Status = SetEnvironmentVariables (Environment);\r
1565 }\r
1566 }\r
1567\r
1568 //\r
1569 // Initialize and install a shell parameters protocol on the image.\r
1570 //\r
1571 ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
1572 ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut;\r
1573 ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
1574 Status = UpdateArgcArgv (&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL);\r
1575 if (EFI_ERROR (Status)) {\r
1576 goto UnloadImage;\r
1577 }\r
1578\r
1579 //\r
1580 // Replace Argv[0] with the full path of the binary we're executing:\r
1581 // If the command line was "foo", the binary might be called "foo.efi".\r
1582 // "The first entry in [Argv] is always the full file path of the\r
1583 // executable" - UEFI Shell Spec section 2.3\r
1584 //\r
1585 ImagePath = EfiShellGetFilePathFromDevicePath (DevicePath);\r
1586 // The image we're executing isn't necessarily in a filesystem - it might\r
1587 // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will\r
1588 // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.\r
1589 if (ImagePath != NULL) {\r
1590 if (ShellParamsProtocol.Argv == NULL) {\r
1591 // Command line was empty or null.\r
1592 // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)\r
1593 ShellParamsProtocol.Argv = AllocatePool (sizeof (CHAR16 *));\r
1594 if (ShellParamsProtocol.Argv == NULL) {\r
1595 Status = EFI_OUT_OF_RESOURCES;\r
1596 goto UnloadImage;\r
1597 }\r
1598\r
1599 ShellParamsProtocol.Argc = 1;\r
1600 } else {\r
1601 // Free the string UpdateArgcArgv put in Argv[0];\r
1602 FreePool (ShellParamsProtocol.Argv[0]);\r
1603 }\r
1604\r
1605 ShellParamsProtocol.Argv[0] = ImagePath;\r
1606 }\r
1607\r
1608 Status = gBS->InstallProtocolInterface (&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol);\r
1609 ASSERT_EFI_ERROR (Status);\r
1610\r
1611 /// @todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
1612\r
1613 //\r
1614 // now start the image and if the caller wanted the return code pass it to them...\r
1615 //\r
1616 if (!EFI_ERROR (Status)) {\r
1617 StartStatus = gBS->StartImage (\r
1618 NewHandle,\r
1619 0,\r
1620 NULL\r
1621 );\r
1622 if (StartImageStatus != NULL) {\r
1623 *StartImageStatus = StartStatus;\r
1624 }\r
1625\r
1626 CleanupStatus = gBS->UninstallProtocolInterface (\r
1627 NewHandle,\r
1628 &gEfiShellParametersProtocolGuid,\r
1629 &ShellParamsProtocol\r
1630 );\r
1631 ASSERT_EFI_ERROR (CleanupStatus);\r
1632\r
1633 goto FreeAlloc;\r
1634 }\r
1635\r
1636UnloadImage:\r
1637 // Unload image - We should only get here if we didn't call StartImage\r
1638 gBS->UnloadImage (NewHandle);\r
1639\r
1640FreeAlloc:\r
1641 // Free Argv (Allocated in UpdateArgcArgv)\r
1642 if (ShellParamsProtocol.Argv != NULL) {\r
1643 for (Index = 0; Index < ShellParamsProtocol.Argc; Index++) {\r
1644 if (ShellParamsProtocol.Argv[Index] != NULL) {\r
1645 FreePool (ShellParamsProtocol.Argv[Index]);\r
1646 }\r
1647 }\r
1648\r
1649 FreePool (ShellParamsProtocol.Argv);\r
1650 }\r
1651 }\r
1652\r
1653 // Restore environment variables\r
1654 if (!IsListEmpty (&OrigEnvs)) {\r
1655 CleanupStatus = SetEnvironmentVariableList (&OrigEnvs);\r
1656 ASSERT_EFI_ERROR (CleanupStatus);\r
1657 }\r
1658\r
1659 FreePool (NewCmdLine);\r
1660\r
1661 return (Status);\r
1662}\r
1663\r
1664/**\r
1665 internal worker function to load and run an image in the current shell.\r
1666\r
1667 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1668 containing the command line. If NULL then the command-\r
1669 line will be empty.\r
1670 @param Environment Points to a NULL-terminated array of environment\r
1671 variables with the format 'x=y', where x is the\r
1672 environment variable name and y is the value. If this\r
1673 is NULL, then the current shell environment is used.\r
1674\r
1675 @param[out] StartImageStatus Returned status from the command line.\r
1676\r
1677 @retval EFI_SUCCESS The command executed successfully. The status code\r
1678 returned by the command is pointed to by StatusCode.\r
1679 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1680 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1681 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1682**/\r
1683EFI_STATUS\r
1684InternalShellExecute (\r
1685 IN CONST CHAR16 *CommandLine OPTIONAL,\r
1686 IN CONST CHAR16 **Environment OPTIONAL,\r
1687 OUT EFI_STATUS *StartImageStatus OPTIONAL\r
1688 )\r
1689{\r
1690 EFI_STATUS Status;\r
1691 EFI_STATUS CleanupStatus;\r
1692 LIST_ENTRY OrigEnvs;\r
1693\r
1694 InitializeListHead (&OrigEnvs);\r
1695\r
1696 //\r
1697 // Save our current environment settings for later restoration if necessary\r
1698 //\r
1699 if (Environment != NULL) {\r
1700 Status = GetEnvironmentVariableList (&OrigEnvs);\r
1701 if (!EFI_ERROR (Status)) {\r
1702 Status = SetEnvironmentVariables (Environment);\r
1703 } else {\r
1704 return Status;\r
1705 }\r
1706 }\r
1707\r
1708 Status = RunShellCommand (CommandLine, StartImageStatus);\r
1709\r
1710 // Restore environment variables\r
1711 if (!IsListEmpty (&OrigEnvs)) {\r
1712 CleanupStatus = SetEnvironmentVariableList (&OrigEnvs);\r
1713 ASSERT_EFI_ERROR (CleanupStatus);\r
1714 }\r
1715\r
1716 return (Status);\r
1717}\r
1718\r
1719/**\r
1720 Determine if the UEFI Shell is currently running with nesting enabled or disabled.\r
1721\r
1722 @retval FALSE nesting is required\r
1723 @retval other nesting is enabled\r
1724**/\r
1725STATIC\r
1726BOOLEAN\r
1727NestingEnabled (\r
1728 VOID\r
1729 )\r
1730{\r
1731 EFI_STATUS Status;\r
1732 CHAR16 *Temp;\r
1733 CHAR16 *Temp2;\r
1734 UINTN TempSize;\r
1735 BOOLEAN RetVal;\r
1736\r
1737 RetVal = TRUE;\r
1738 Temp = NULL;\r
1739 Temp2 = NULL;\r
1740\r
1741 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {\r
1742 TempSize = 0;\r
1743 Temp = NULL;\r
1744 Status = SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName, &TempSize, Temp);\r
1745 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1746 Temp = AllocateZeroPool (TempSize + sizeof (CHAR16));\r
1747 if (Temp != NULL) {\r
1748 Status = SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName, &TempSize, Temp);\r
1749 }\r
1750 }\r
1751\r
1752 Temp2 = StrnCatGrow (&Temp2, NULL, mNoNestingTrue, 0);\r
1753 if ((Temp != NULL) && (Temp2 != NULL) && (StringNoCaseCompare (&Temp, &Temp2) == 0)) {\r
1754 //\r
1755 // Use the no nesting method.\r
1756 //\r
1757 RetVal = FALSE;\r
1758 }\r
1759 }\r
1760\r
1761 SHELL_FREE_NON_NULL (Temp);\r
1762 SHELL_FREE_NON_NULL (Temp2);\r
1763 return (RetVal);\r
1764}\r
1765\r
1766/**\r
1767 Execute the command line.\r
1768\r
1769 This function creates a nested instance of the shell and executes the specified\r
1770 command (CommandLine) with the specified environment (Environment). Upon return,\r
1771 the status code returned by the specified command is placed in StatusCode.\r
1772\r
1773 If Environment is NULL, then the current environment is used and all changes made\r
1774 by the commands executed will be reflected in the current environment. If the\r
1775 Environment is non-NULL, then the changes made will be discarded.\r
1776\r
1777 The CommandLine is executed from the current working directory on the current\r
1778 device.\r
1779\r
1780 @param ParentImageHandle A handle of the image that is executing the specified\r
1781 command line.\r
1782 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1783 containing the command line. If NULL then the command-\r
1784 line will be empty.\r
1785 @param Environment Points to a NULL-terminated array of environment\r
1786 variables with the format 'x=y', where x is the\r
1787 environment variable name and y is the value. If this\r
1788 is NULL, then the current shell environment is used.\r
1789 @param StatusCode Points to the status code returned by the CommandLine.\r
1790\r
1791 @retval EFI_SUCCESS The command executed successfully. The status code\r
1792 returned by the command is pointed to by StatusCode.\r
1793 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1794 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1795 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1796 @retval EFI_UNSUPPORTED The support level required for this function is not present.\r
1797\r
1798 @sa InternalShellExecuteDevicePath\r
1799**/\r
1800EFI_STATUS\r
1801EFIAPI\r
1802EfiShellExecute (\r
1803 IN EFI_HANDLE *ParentImageHandle,\r
1804 IN CHAR16 *CommandLine OPTIONAL,\r
1805 IN CHAR16 **Environment OPTIONAL,\r
1806 OUT EFI_STATUS *StatusCode OPTIONAL\r
1807 )\r
1808{\r
1809 EFI_STATUS Status;\r
1810 CHAR16 *Temp;\r
1811 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1812 UINTN Size;\r
1813\r
1814 if ((PcdGet8 (PcdShellSupportLevel) < 1)) {\r
1815 return (EFI_UNSUPPORTED);\r
1816 }\r
1817\r
1818 if (NestingEnabled ()) {\r
1819 DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
1820\r
1821 DEBUG_CODE_BEGIN ();\r
1822 Temp = ConvertDevicePathToText (ShellInfoObject.FileDevPath, TRUE, TRUE);\r
1823 FreePool (Temp);\r
1824 Temp = ConvertDevicePathToText (ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
1825 FreePool (Temp);\r
1826 Temp = ConvertDevicePathToText (DevPath, TRUE, TRUE);\r
1827 FreePool (Temp);\r
1828 DEBUG_CODE_END ();\r
1829\r
1830 Temp = NULL;\r
1831 Size = 0;\r
1832 ASSERT ((Temp == NULL && Size == 0) || (Temp != NULL));\r
1833 StrnCatGrow (&Temp, &Size, L"Shell.efi -exit ", 0);\r
1834 StrnCatGrow (&Temp, &Size, CommandLine, 0);\r
1835\r
1836 Status = InternalShellExecuteDevicePath (\r
1837 ParentImageHandle,\r
1838 DevPath,\r
1839 Temp,\r
1840 (CONST CHAR16 **)Environment,\r
1841 StatusCode\r
1842 );\r
1843\r
1844 //\r
1845 // de-allocate and return\r
1846 //\r
1847 FreePool (DevPath);\r
1848 FreePool (Temp);\r
1849 } else {\r
1850 Status = InternalShellExecute (\r
1851 (CONST CHAR16 *)CommandLine,\r
1852 (CONST CHAR16 **)Environment,\r
1853 StatusCode\r
1854 );\r
1855 }\r
1856\r
1857 return (Status);\r
1858}\r
1859\r
1860/**\r
1861 Utility cleanup function for EFI_SHELL_FILE_INFO objects.\r
1862\r
1863 1) frees all pointers (non-NULL)\r
1864 2) Closes the SHELL_FILE_HANDLE\r
1865\r
1866 @param FileListNode pointer to the list node to free\r
1867**/\r
1868VOID\r
1869InternalFreeShellFileInfoNode (\r
1870 IN EFI_SHELL_FILE_INFO *FileListNode\r
1871 )\r
1872{\r
1873 if (FileListNode->Info != NULL) {\r
1874 FreePool ((VOID *)FileListNode->Info);\r
1875 }\r
1876\r
1877 if (FileListNode->FileName != NULL) {\r
1878 FreePool ((VOID *)FileListNode->FileName);\r
1879 }\r
1880\r
1881 if (FileListNode->FullName != NULL) {\r
1882 FreePool ((VOID *)FileListNode->FullName);\r
1883 }\r
1884\r
1885 if (FileListNode->Handle != NULL) {\r
1886 ShellInfoObject.NewEfiShellProtocol->CloseFile (FileListNode->Handle);\r
1887 }\r
1888\r
1889 FreePool (FileListNode);\r
1890}\r
1891\r
1892/**\r
1893 Frees the file list.\r
1894\r
1895 This function cleans up the file list and any related data structures. It has no\r
1896 impact on the files themselves.\r
1897\r
1898 @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is\r
1899 defined in OpenFileList()\r
1900\r
1901 @retval EFI_SUCCESS Free the file list successfully.\r
1902 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
1903**/\r
1904EFI_STATUS\r
1905EFIAPI\r
1906EfiShellFreeFileList (\r
1907 IN EFI_SHELL_FILE_INFO **FileList\r
1908 )\r
1909{\r
1910 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
1911\r
1912 if ((FileList == NULL) || (*FileList == NULL)) {\r
1913 return (EFI_INVALID_PARAMETER);\r
1914 }\r
1915\r
1916 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
1917 ; !IsListEmpty (&(*FileList)->Link)\r
1918 ; ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
1919 )\r
1920 {\r
1921 RemoveEntryList (&ShellFileListItem->Link);\r
1922 InternalFreeShellFileInfoNode (ShellFileListItem);\r
1923 }\r
1924\r
1925 InternalFreeShellFileInfoNode (*FileList);\r
1926 *FileList = NULL;\r
1927 return (EFI_SUCCESS);\r
1928}\r
1929\r
1930/**\r
1931 Deletes the duplicate file names files in the given file list.\r
1932\r
1933 This function deletes the reduplicate files in the given file list.\r
1934\r
1935 @param FileList A pointer to the first entry in the file list.\r
1936\r
1937 @retval EFI_SUCCESS Always success.\r
1938 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
1939**/\r
1940EFI_STATUS\r
1941EFIAPI\r
1942EfiShellRemoveDupInFileList (\r
1943 IN EFI_SHELL_FILE_INFO **FileList\r
1944 )\r
1945{\r
1946 EFI_STATUS Status;\r
1947 EFI_SHELL_FILE_INFO *Duplicates;\r
1948 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
1949 EFI_SHELL_FILE_INFO *ShellFileListItem2;\r
1950 EFI_SHELL_FILE_INFO *TempNode;\r
1951\r
1952 if ((FileList == NULL) || (*FileList == NULL)) {\r
1953 return (EFI_INVALID_PARAMETER);\r
1954 }\r
1955\r
1956 Status = ShellSortFileList (\r
1957 FileList,\r
1958 &Duplicates,\r
1959 ShellSortFileListByFullName\r
1960 );\r
1961 if (!EFI_ERROR (Status)) {\r
1962 EfiShellFreeFileList (&Duplicates);\r
1963 return EFI_SUCCESS;\r
1964 }\r
1965\r
1966 //\r
1967 // Fall back to the slow method that needs no extra memory, and so cannot\r
1968 // fail.\r
1969 //\r
1970 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
1971 ; !IsNull (&(*FileList)->Link, &ShellFileListItem->Link)\r
1972 ; ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem->Link)\r
1973 )\r
1974 {\r
1975 for ( ShellFileListItem2 = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem->Link)\r
1976 ; !IsNull (&(*FileList)->Link, &ShellFileListItem2->Link)\r
1977 ; ShellFileListItem2 = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem2->Link)\r
1978 )\r
1979 {\r
1980 if (gUnicodeCollation->StriColl (\r
1981 gUnicodeCollation,\r
1982 (CHAR16 *)ShellFileListItem->FullName,\r
1983 (CHAR16 *)ShellFileListItem2->FullName\r
1984 ) == 0\r
1985 )\r
1986 {\r
1987 TempNode = (EFI_SHELL_FILE_INFO *)GetPreviousNode (\r
1988 &(*FileList)->Link,\r
1989 &ShellFileListItem2->Link\r
1990 );\r
1991 RemoveEntryList (&ShellFileListItem2->Link);\r
1992 InternalFreeShellFileInfoNode (ShellFileListItem2);\r
1993 // Set ShellFileListItem2 to PreviousNode so we don't access Freed\r
1994 // memory in GetNextNode in the loop expression above.\r
1995 ShellFileListItem2 = TempNode;\r
1996 }\r
1997 }\r
1998 }\r
1999\r
2000 return (EFI_SUCCESS);\r
2001}\r
2002\r
2003//\r
2004// This is the same structure as the external version, but it has no CONST qualifiers.\r
2005//\r
2006typedef struct {\r
2007 LIST_ENTRY Link; ///< Linked list members.\r
2008 EFI_STATUS Status; ///< Status of opening the file. Valid only if Handle != NULL.\r
2009 CHAR16 *FullName; ///< Fully qualified filename.\r
2010 CHAR16 *FileName; ///< name of this file.\r
2011 SHELL_FILE_HANDLE Handle; ///< Handle for interacting with the opened file or NULL if closed.\r
2012 EFI_FILE_INFO *Info; ///< Pointer to the FileInfo struct for this file or NULL.\r
2013} EFI_SHELL_FILE_INFO_NO_CONST;\r
2014\r
2015/**\r
2016 Allocates and duplicates a EFI_SHELL_FILE_INFO node.\r
2017\r
2018 @param[in] Node The node to copy from.\r
2019 @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise.\r
2020\r
2021 @retval NULL a memory allocation error occurred\r
2022 @return != NULL a pointer to the new node\r
2023**/\r
2024EFI_SHELL_FILE_INFO *\r
2025InternalDuplicateShellFileInfo (\r
2026 IN EFI_SHELL_FILE_INFO *Node,\r
2027 IN BOOLEAN Save\r
2028 )\r
2029{\r
2030 EFI_SHELL_FILE_INFO_NO_CONST *NewNode;\r
2031\r
2032 //\r
2033 // try to confirm that the objects are in sync\r
2034 //\r
2035 ASSERT (sizeof (EFI_SHELL_FILE_INFO_NO_CONST) == sizeof (EFI_SHELL_FILE_INFO));\r
2036\r
2037 NewNode = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
2038 if (NewNode == NULL) {\r
2039 return (NULL);\r
2040 }\r
2041\r
2042 NewNode->FullName = AllocateCopyPool (StrSize (Node->FullName), Node->FullName);\r
2043 NewNode->FileName = AllocateCopyPool (StrSize (Node->FileName), Node->FileName);\r
2044 NewNode->Info = AllocateCopyPool ((UINTN)Node->Info->Size, Node->Info);\r
2045 if ( (NewNode->FullName == NULL)\r
2046 || (NewNode->FileName == NULL)\r
2047 || (NewNode->Info == NULL)\r
2048 )\r
2049 {\r
2050 SHELL_FREE_NON_NULL (NewNode->FullName);\r
2051 SHELL_FREE_NON_NULL (NewNode->FileName);\r
2052 SHELL_FREE_NON_NULL (NewNode->Info);\r
2053 SHELL_FREE_NON_NULL (NewNode);\r
2054 return (NULL);\r
2055 }\r
2056\r
2057 NewNode->Status = Node->Status;\r
2058 NewNode->Handle = Node->Handle;\r
2059 if (!Save) {\r
2060 Node->Handle = NULL;\r
2061 }\r
2062\r
2063 return ((EFI_SHELL_FILE_INFO *)NewNode);\r
2064}\r
2065\r
2066/**\r
2067 Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation\r
2068 failed it will return NULL.\r
2069\r
2070 @param[in] BasePath the Path to prepend onto filename for FullPath\r
2071 @param[in] Status Status member initial value.\r
2072 @param[in] FileName FileName member initial value.\r
2073 @param[in] Handle Handle member initial value.\r
2074 @param[in] Info Info struct to copy.\r
2075\r
2076 @retval NULL An error occurred.\r
2077 @return a pointer to the newly allocated structure.\r
2078**/\r
2079EFI_SHELL_FILE_INFO *\r
2080CreateAndPopulateShellFileInfo (\r
2081 IN CONST CHAR16 *BasePath,\r
2082 IN CONST EFI_STATUS Status,\r
2083 IN CONST CHAR16 *FileName,\r
2084 IN CONST SHELL_FILE_HANDLE Handle,\r
2085 IN CONST EFI_FILE_INFO *Info\r
2086 )\r
2087{\r
2088 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2089 CHAR16 *TempString;\r
2090 UINTN Size;\r
2091\r
2092 TempString = NULL;\r
2093 Size = 0;\r
2094\r
2095 ShellFileListItem = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
2096 if (ShellFileListItem == NULL) {\r
2097 return (NULL);\r
2098 }\r
2099\r
2100 if ((Info != NULL) && (Info->Size != 0)) {\r
2101 ShellFileListItem->Info = AllocateZeroPool ((UINTN)Info->Size);\r
2102 if (ShellFileListItem->Info == NULL) {\r
2103 FreePool (ShellFileListItem);\r
2104 return (NULL);\r
2105 }\r
2106\r
2107 CopyMem (ShellFileListItem->Info, Info, (UINTN)Info->Size);\r
2108 } else {\r
2109 ShellFileListItem->Info = NULL;\r
2110 }\r
2111\r
2112 if (FileName != NULL) {\r
2113 ASSERT (TempString == NULL);\r
2114 ShellFileListItem->FileName = StrnCatGrow (&TempString, 0, FileName, 0);\r
2115 if (ShellFileListItem->FileName == NULL) {\r
2116 FreePool (ShellFileListItem->Info);\r
2117 FreePool (ShellFileListItem);\r
2118 return (NULL);\r
2119 }\r
2120 } else {\r
2121 ShellFileListItem->FileName = NULL;\r
2122 }\r
2123\r
2124 Size = 0;\r
2125 TempString = NULL;\r
2126 if (BasePath != NULL) {\r
2127 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
2128 TempString = StrnCatGrow (&TempString, &Size, BasePath, 0);\r
2129 if (TempString == NULL) {\r
2130 FreePool ((VOID *)ShellFileListItem->FileName);\r
2131 SHELL_FREE_NON_NULL (ShellFileListItem->Info);\r
2132 FreePool (ShellFileListItem);\r
2133 return (NULL);\r
2134 }\r
2135 }\r
2136\r
2137 if (ShellFileListItem->FileName != NULL) {\r
2138 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
2139 TempString = StrnCatGrow (&TempString, &Size, ShellFileListItem->FileName, 0);\r
2140 if (TempString == NULL) {\r
2141 FreePool ((VOID *)ShellFileListItem->FileName);\r
2142 FreePool (ShellFileListItem->Info);\r
2143 FreePool (ShellFileListItem);\r
2144 return (NULL);\r
2145 }\r
2146 }\r
2147\r
2148 TempString = PathCleanUpDirectories (TempString);\r
2149\r
2150 ShellFileListItem->FullName = TempString;\r
2151 ShellFileListItem->Status = Status;\r
2152 ShellFileListItem->Handle = Handle;\r
2153\r
2154 return (ShellFileListItem);\r
2155}\r
2156\r
2157/**\r
2158 Find all files in a specified directory.\r
2159\r
2160 @param FileDirHandle Handle of the directory to search.\r
2161 @param FileList On return, points to the list of files in the directory\r
2162 or NULL if there are no files in the directory.\r
2163\r
2164 @retval EFI_SUCCESS File information was returned successfully.\r
2165 @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted.\r
2166 @retval EFI_DEVICE_ERROR The device reported an error.\r
2167 @retval EFI_NO_MEDIA The device media is not present.\r
2168 @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.\r
2169 @return An error from FileHandleGetFileName().\r
2170**/\r
2171EFI_STATUS\r
2172EFIAPI\r
2173EfiShellFindFilesInDir (\r
2174 IN SHELL_FILE_HANDLE FileDirHandle,\r
2175 OUT EFI_SHELL_FILE_INFO **FileList\r
2176 )\r
2177{\r
2178 EFI_SHELL_FILE_INFO *ShellFileList;\r
2179 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2180 EFI_FILE_INFO *FileInfo;\r
2181 EFI_STATUS Status;\r
2182 BOOLEAN NoFile;\r
2183 CHAR16 *TempString;\r
2184 CHAR16 *BasePath;\r
2185 UINTN Size;\r
2186 CHAR16 *TempSpot;\r
2187\r
2188 BasePath = NULL;\r
2189 Status = FileHandleGetFileName (FileDirHandle, &BasePath);\r
2190 if (EFI_ERROR (Status)) {\r
2191 return (Status);\r
2192 }\r
2193\r
2194 if (ShellFileHandleGetPath (FileDirHandle) != NULL) {\r
2195 TempString = NULL;\r
2196 Size = 0;\r
2197 TempString = StrnCatGrow (&TempString, &Size, ShellFileHandleGetPath (FileDirHandle), 0);\r
2198 if (TempString == NULL) {\r
2199 SHELL_FREE_NON_NULL (BasePath);\r
2200 return (EFI_OUT_OF_RESOURCES);\r
2201 }\r
2202\r
2203 TempSpot = StrStr (TempString, L";");\r
2204\r
2205 if (TempSpot != NULL) {\r
2206 *TempSpot = CHAR_NULL;\r
2207 }\r
2208\r
2209 TempString = StrnCatGrow (&TempString, &Size, BasePath, 0);\r
2210 if (TempString == NULL) {\r
2211 SHELL_FREE_NON_NULL (BasePath);\r
2212 return (EFI_OUT_OF_RESOURCES);\r
2213 }\r
2214\r
2215 SHELL_FREE_NON_NULL (BasePath);\r
2216 BasePath = TempString;\r
2217 }\r
2218\r
2219 NoFile = FALSE;\r
2220 ShellFileList = NULL;\r
2221 ShellFileListItem = NULL;\r
2222 FileInfo = NULL;\r
2223 Status = EFI_SUCCESS;\r
2224\r
2225 for ( Status = FileHandleFindFirstFile (FileDirHandle, &FileInfo)\r
2226 ; !EFI_ERROR (Status) && !NoFile\r
2227 ; Status = FileHandleFindNextFile (FileDirHandle, FileInfo, &NoFile)\r
2228 )\r
2229 {\r
2230 if (ShellFileList == NULL) {\r
2231 ShellFileList = (EFI_SHELL_FILE_INFO *)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
2232 if (ShellFileList == NULL) {\r
2233 SHELL_FREE_NON_NULL (BasePath);\r
2234 return EFI_OUT_OF_RESOURCES;\r
2235 }\r
2236\r
2237 InitializeListHead (&ShellFileList->Link);\r
2238 }\r
2239\r
2240 //\r
2241 // allocate a new EFI_SHELL_FILE_INFO and populate it...\r
2242 //\r
2243 ShellFileListItem = CreateAndPopulateShellFileInfo (\r
2244 BasePath,\r
2245 EFI_SUCCESS, // success since we didn't fail to open it...\r
2246 FileInfo->FileName,\r
2247 NULL, // no handle since not open\r
2248 FileInfo\r
2249 );\r
2250 if (ShellFileListItem == NULL) {\r
2251 Status = EFI_OUT_OF_RESOURCES;\r
2252 //\r
2253 // Free resources outside the loop.\r
2254 //\r
2255 break;\r
2256 }\r
2257\r
2258 InsertTailList (&ShellFileList->Link, &ShellFileListItem->Link);\r
2259 }\r
2260\r
2261 if (EFI_ERROR (Status)) {\r
2262 EfiShellFreeFileList (&ShellFileList);\r
2263 *FileList = NULL;\r
2264 } else {\r
2265 *FileList = ShellFileList;\r
2266 }\r
2267\r
2268 SHELL_FREE_NON_NULL (BasePath);\r
2269 return (Status);\r
2270}\r
2271\r
2272/**\r
2273 Get the GUID value from a human readable name.\r
2274\r
2275 If GuidName is a known GUID name, then update Guid to have the correct value for\r
2276 that GUID.\r
2277\r
2278 This function is only available when the major and minor versions in the\r
2279 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
2280\r
2281 @param[in] GuidName A pointer to the localized name for the GUID being queried.\r
2282 @param[out] Guid A pointer to the GUID structure to be filled in.\r
2283\r
2284 @retval EFI_SUCCESS The operation was successful.\r
2285 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
2286 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
2287 @retval EFI_NOT_FOUND GuidName is not a known GUID Name.\r
2288**/\r
2289EFI_STATUS\r
2290EFIAPI\r
2291EfiShellGetGuidFromName (\r
2292 IN CONST CHAR16 *GuidName,\r
2293 OUT EFI_GUID *Guid\r
2294 )\r
2295{\r
2296 EFI_GUID *NewGuid;\r
2297 EFI_STATUS Status;\r
2298\r
2299 if ((Guid == NULL) || (GuidName == NULL)) {\r
2300 return (EFI_INVALID_PARAMETER);\r
2301 }\r
2302\r
2303 Status = GetGuidFromStringName (GuidName, NULL, &NewGuid);\r
2304\r
2305 if (!EFI_ERROR (Status)) {\r
2306 CopyGuid (Guid, NewGuid);\r
2307 }\r
2308\r
2309 return (Status);\r
2310}\r
2311\r
2312/**\r
2313 Get the human readable name for a GUID from the value.\r
2314\r
2315 If Guid is assigned a name, then update *GuidName to point to the name. The callee\r
2316 should not modify the value.\r
2317\r
2318 This function is only available when the major and minor versions in the\r
2319 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
2320\r
2321 @param[in] Guid A pointer to the GUID being queried.\r
2322 @param[out] GuidName A pointer to a pointer the localized to name for the GUID being requested\r
2323\r
2324 @retval EFI_SUCCESS The operation was successful.\r
2325 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
2326 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
2327 @retval EFI_NOT_FOUND Guid is not assigned a name.\r
2328**/\r
2329EFI_STATUS\r
2330EFIAPI\r
2331EfiShellGetGuidName (\r
2332 IN CONST EFI_GUID *Guid,\r
2333 OUT CONST CHAR16 **GuidName\r
2334 )\r
2335{\r
2336 CHAR16 *Name;\r
2337\r
2338 if ((Guid == NULL) || (GuidName == NULL)) {\r
2339 return (EFI_INVALID_PARAMETER);\r
2340 }\r
2341\r
2342 Name = GetStringNameFromGuid (Guid, NULL);\r
2343 if ((Name == NULL) || (StrLen (Name) == 0)) {\r
2344 SHELL_FREE_NON_NULL (Name);\r
2345 return (EFI_NOT_FOUND);\r
2346 }\r
2347\r
2348 *GuidName = AddBufferToFreeList (Name);\r
2349\r
2350 return (EFI_SUCCESS);\r
2351}\r
2352\r
2353/**\r
2354 If FileHandle is a directory then the function reads from FileHandle and reads in\r
2355 each of the FileInfo structures. If one of them matches the Pattern's first\r
2356 "level" then it opens that handle and calls itself on that handle.\r
2357\r
2358 If FileHandle is a file and matches all of the remaining Pattern (which would be\r
2359 on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.\r
2360\r
2361 Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call\r
2362 FreeFileList with FileList.\r
2363\r
2364 @param[in] FilePattern The FilePattern to check against.\r
2365 @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
2366 @param[in] FileHandle The FileHandle to start with\r
2367 @param[in, out] FileList pointer to pointer to list of found files.\r
2368 @param[in] ParentNode The node for the parent. Same file as identified by HANDLE.\r
2369 @param[in] MapName The file system name this file is on.\r
2370\r
2371 @retval EFI_SUCCESS all files were found and the FileList contains a list.\r
2372 @retval EFI_NOT_FOUND no files were found\r
2373 @retval EFI_OUT_OF_RESOURCES a memory allocation failed\r
2374**/\r
2375EFI_STATUS\r
2376ShellSearchHandle (\r
2377 IN CONST CHAR16 *FilePattern,\r
2378 IN EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation,\r
2379 IN SHELL_FILE_HANDLE FileHandle,\r
2380 IN OUT EFI_SHELL_FILE_INFO **FileList,\r
2381 IN CONST EFI_SHELL_FILE_INFO *ParentNode OPTIONAL,\r
2382 IN CONST CHAR16 *MapName\r
2383 )\r
2384{\r
2385 EFI_STATUS Status;\r
2386 CONST CHAR16 *NextFilePatternStart;\r
2387 CHAR16 *CurrentFilePattern;\r
2388 EFI_SHELL_FILE_INFO *ShellInfo;\r
2389 EFI_SHELL_FILE_INFO *ShellInfoNode;\r
2390 EFI_SHELL_FILE_INFO *NewShellNode;\r
2391 EFI_FILE_INFO *FileInfo;\r
2392 BOOLEAN Directory;\r
2393 CHAR16 *NewFullName;\r
2394 UINTN Size;\r
2395\r
2396 if ( (FilePattern == NULL)\r
2397 || (UnicodeCollation == NULL)\r
2398 || (FileList == NULL)\r
2399 )\r
2400 {\r
2401 return (EFI_INVALID_PARAMETER);\r
2402 }\r
2403\r
2404 ShellInfo = NULL;\r
2405 CurrentFilePattern = NULL;\r
2406\r
2407 if (*FilePattern == L'\\') {\r
2408 FilePattern++;\r
2409 }\r
2410\r
2411 for ( NextFilePatternStart = FilePattern\r
2412 ; *NextFilePatternStart != CHAR_NULL && *NextFilePatternStart != L'\\'\r
2413 ; NextFilePatternStart++)\r
2414 {\r
2415 }\r
2416\r
2417 CurrentFilePattern = AllocateZeroPool ((NextFilePatternStart-FilePattern+1)*sizeof (CHAR16));\r
2418 if (CurrentFilePattern == NULL) {\r
2419 return EFI_OUT_OF_RESOURCES;\r
2420 }\r
2421\r
2422 StrnCpyS (CurrentFilePattern, NextFilePatternStart-FilePattern+1, FilePattern, NextFilePatternStart-FilePattern);\r
2423\r
2424 if ( (CurrentFilePattern[0] == CHAR_NULL)\r
2425 && (NextFilePatternStart[0] == CHAR_NULL)\r
2426 )\r
2427 {\r
2428 //\r
2429 // we want the parent or root node (if no parent)\r
2430 //\r
2431 if (ParentNode == NULL) {\r
2432 //\r
2433 // We want the root node. create the node.\r
2434 //\r
2435 FileInfo = FileHandleGetInfo (FileHandle);\r
2436 NewShellNode = CreateAndPopulateShellFileInfo (\r
2437 MapName,\r
2438 EFI_SUCCESS,\r
2439 L"\\",\r
2440 FileHandle,\r
2441 FileInfo\r
2442 );\r
2443 SHELL_FREE_NON_NULL (FileInfo);\r
2444 } else {\r
2445 //\r
2446 // Add the current parameter FileHandle to the list, then end...\r
2447 //\r
2448 NewShellNode = InternalDuplicateShellFileInfo ((EFI_SHELL_FILE_INFO *)ParentNode, TRUE);\r
2449 }\r
2450\r
2451 if (NewShellNode == NULL) {\r
2452 Status = EFI_OUT_OF_RESOURCES;\r
2453 } else {\r
2454 NewShellNode->Handle = NULL;\r
2455 if (*FileList == NULL) {\r
2456 *FileList = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
2457 InitializeListHead (&((*FileList)->Link));\r
2458 }\r
2459\r
2460 //\r
2461 // Add to the returning to use list\r
2462 //\r
2463 InsertTailList (&(*FileList)->Link, &NewShellNode->Link);\r
2464\r
2465 Status = EFI_SUCCESS;\r
2466 }\r
2467 } else {\r
2468 Status = EfiShellFindFilesInDir (FileHandle, &ShellInfo);\r
2469\r
2470 if (!EFI_ERROR (Status)) {\r
2471 if (StrStr (NextFilePatternStart, L"\\") != NULL) {\r
2472 Directory = TRUE;\r
2473 } else {\r
2474 Directory = FALSE;\r
2475 }\r
2476\r
2477 for ( ShellInfoNode = (EFI_SHELL_FILE_INFO *)GetFirstNode (&ShellInfo->Link)\r
2478 ; !IsNull (&ShellInfo->Link, &ShellInfoNode->Link)\r
2479 ; ShellInfoNode = (EFI_SHELL_FILE_INFO *)GetNextNode (&ShellInfo->Link, &ShellInfoNode->Link)\r
2480 )\r
2481 {\r
2482 if (UnicodeCollation->MetaiMatch (UnicodeCollation, (CHAR16 *)ShellInfoNode->FileName, CurrentFilePattern)) {\r
2483 if ((ShellInfoNode->FullName != NULL) && (StrStr (ShellInfoNode->FullName, L":") == NULL)) {\r
2484 Size = StrSize (ShellInfoNode->FullName) + StrSize (MapName);\r
2485 NewFullName = AllocateZeroPool (Size);\r
2486 if (NewFullName == NULL) {\r
2487 Status = EFI_OUT_OF_RESOURCES;\r
2488 } else {\r
2489 StrCpyS (NewFullName, Size / sizeof (CHAR16), MapName);\r
2490 StrCatS (NewFullName, Size / sizeof (CHAR16), ShellInfoNode->FullName);\r
2491 FreePool ((VOID *)ShellInfoNode->FullName);\r
2492 ShellInfoNode->FullName = NewFullName;\r
2493 }\r
2494 }\r
2495\r
2496 if (Directory && !EFI_ERROR (Status) && (ShellInfoNode->FullName != NULL) && (ShellInfoNode->FileName != NULL)) {\r
2497 //\r
2498 // should be a directory\r
2499 //\r
2500\r
2501 //\r
2502 // don't open the . and .. directories\r
2503 //\r
2504 if ( (StrCmp (ShellInfoNode->FileName, L".") != 0)\r
2505 && (StrCmp (ShellInfoNode->FileName, L"..") != 0)\r
2506 )\r
2507 {\r
2508 //\r
2509 //\r
2510 //\r
2511 if (EFI_ERROR (Status)) {\r
2512 break;\r
2513 }\r
2514\r
2515 //\r
2516 // Open the directory since we need that handle in the next recursion.\r
2517 //\r
2518 ShellInfoNode->Status = EfiShellOpenFileByName (ShellInfoNode->FullName, &ShellInfoNode->Handle, EFI_FILE_MODE_READ);\r
2519\r
2520 //\r
2521 // recurse with the next part of the pattern\r
2522 //\r
2523 Status = ShellSearchHandle (NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName);\r
2524 EfiShellClose (ShellInfoNode->Handle);\r
2525 ShellInfoNode->Handle = NULL;\r
2526 }\r
2527 } else if (!EFI_ERROR (Status)) {\r
2528 //\r
2529 // should be a file\r
2530 //\r
2531\r
2532 //\r
2533 // copy the information we need into a new Node\r
2534 //\r
2535 NewShellNode = InternalDuplicateShellFileInfo (ShellInfoNode, FALSE);\r
2536 if (NewShellNode == NULL) {\r
2537 Status = EFI_OUT_OF_RESOURCES;\r
2538 }\r
2539\r
2540 if (*FileList == NULL) {\r
2541 *FileList = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
2542 InitializeListHead (&((*FileList)->Link));\r
2543 }\r
2544\r
2545 //\r
2546 // Add to the returning to use list\r
2547 //\r
2548 InsertTailList (&(*FileList)->Link, &NewShellNode->Link);\r
2549 }\r
2550 }\r
2551\r
2552 if (EFI_ERROR (Status)) {\r
2553 break;\r
2554 }\r
2555 }\r
2556\r
2557 if (EFI_ERROR (Status)) {\r
2558 EfiShellFreeFileList (&ShellInfo);\r
2559 } else {\r
2560 Status = EfiShellFreeFileList (&ShellInfo);\r
2561 }\r
2562 }\r
2563 }\r
2564\r
2565 if ((*FileList == NULL) || ((*FileList != NULL) && IsListEmpty (&(*FileList)->Link))) {\r
2566 Status = EFI_NOT_FOUND;\r
2567 }\r
2568\r
2569 FreePool (CurrentFilePattern);\r
2570 return (Status);\r
2571}\r
2572\r
2573/**\r
2574 Find files that match a specified pattern.\r
2575\r
2576 This function searches for all files and directories that match the specified\r
2577 FilePattern. The FilePattern can contain wild-card characters. The resulting file\r
2578 information is placed in the file list FileList.\r
2579\r
2580 Wildcards are processed\r
2581 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.\r
2582\r
2583 The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo\r
2584 field is set to NULL.\r
2585\r
2586 if *FileList is not NULL then it must be a pre-existing and properly initialized list.\r
2587\r
2588 @param FilePattern Points to a NULL-terminated shell file path, including wildcards.\r
2589 @param FileList On return, points to the start of a file list containing the names\r
2590 of all matching files or else points to NULL if no matching files\r
2591 were found. only on a EFI_SUCCESS return will; this be non-NULL.\r
2592\r
2593 @retval EFI_SUCCESS Files found. FileList is a valid list.\r
2594 @retval EFI_NOT_FOUND No files found.\r
2595 @retval EFI_NO_MEDIA The device has no media\r
2596 @retval EFI_DEVICE_ERROR The device reported an error\r
2597 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted\r
2598**/\r
2599EFI_STATUS\r
2600EFIAPI\r
2601EfiShellFindFiles (\r
2602 IN CONST CHAR16 *FilePattern,\r
2603 OUT EFI_SHELL_FILE_INFO **FileList\r
2604 )\r
2605{\r
2606 EFI_STATUS Status;\r
2607 CHAR16 *PatternCopy;\r
2608 CHAR16 *PatternCurrentLocation;\r
2609 EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r
2610 SHELL_FILE_HANDLE RootFileHandle;\r
2611 CHAR16 *MapName;\r
2612 UINTN Count;\r
2613\r
2614 if ( (FilePattern == NULL)\r
2615 || (FileList == NULL)\r
2616 || (StrStr (FilePattern, L":") == NULL)\r
2617 )\r
2618 {\r
2619 return (EFI_INVALID_PARAMETER);\r
2620 }\r
2621\r
2622 Status = EFI_SUCCESS;\r
2623 RootDevicePath = NULL;\r
2624 RootFileHandle = NULL;\r
2625 MapName = NULL;\r
2626 PatternCopy = AllocateCopyPool (StrSize (FilePattern), FilePattern);\r
2627 if (PatternCopy == NULL) {\r
2628 return (EFI_OUT_OF_RESOURCES);\r
2629 }\r
2630\r
2631 PatternCopy = PathCleanUpDirectories (PatternCopy);\r
2632\r
2633 Count = StrStr (PatternCopy, L":") - PatternCopy + 1;\r
2634 ASSERT (Count <= StrLen (PatternCopy));\r
2635\r
2636 ASSERT (MapName == NULL);\r
2637 MapName = StrnCatGrow (&MapName, NULL, PatternCopy, Count);\r
2638 if (MapName == NULL) {\r
2639 Status = EFI_OUT_OF_RESOURCES;\r
2640 } else {\r
2641 RootDevicePath = EfiShellGetDevicePathFromFilePath (PatternCopy);\r
2642 if (RootDevicePath == NULL) {\r
2643 Status = EFI_INVALID_PARAMETER;\r
2644 } else {\r
2645 Status = EfiShellOpenRoot (RootDevicePath, &RootFileHandle);\r
2646 if (!EFI_ERROR (Status)) {\r
2647 for ( PatternCurrentLocation = PatternCopy\r
2648 ; *PatternCurrentLocation != ':'\r
2649 ; PatternCurrentLocation++)\r
2650 {\r
2651 }\r
2652\r
2653 PatternCurrentLocation++;\r
2654 Status = ShellSearchHandle (PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName);\r
2655 EfiShellClose (RootFileHandle);\r
2656 }\r
2657\r
2658 FreePool (RootDevicePath);\r
2659 }\r
2660 }\r
2661\r
2662 SHELL_FREE_NON_NULL (PatternCopy);\r
2663 SHELL_FREE_NON_NULL (MapName);\r
2664\r
2665 return (Status);\r
2666}\r
2667\r
2668/**\r
2669 Opens the files that match the path specified.\r
2670\r
2671 This function opens all of the files specified by Path. Wildcards are processed\r
2672 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each\r
2673 matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.\r
2674\r
2675 @param Path A pointer to the path string.\r
2676 @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or\r
2677 EFI_FILE_MODE_WRITE.\r
2678 @param FileList Points to the start of a list of files opened.\r
2679\r
2680 @retval EFI_SUCCESS Create the file list successfully.\r
2681 @return Others Can't create the file list.\r
2682**/\r
2683EFI_STATUS\r
2684EFIAPI\r
2685EfiShellOpenFileList (\r
2686 IN CHAR16 *Path,\r
2687 IN UINT64 OpenMode,\r
2688 IN OUT EFI_SHELL_FILE_INFO **FileList\r
2689 )\r
2690{\r
2691 EFI_STATUS Status;\r
2692 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2693 CHAR16 *Path2;\r
2694 UINTN Path2Size;\r
2695 CONST CHAR16 *CurDir;\r
2696 BOOLEAN Found;\r
2697\r
2698 PathCleanUpDirectories (Path);\r
2699\r
2700 Path2Size = 0;\r
2701 Path2 = NULL;\r
2702\r
2703 if ((FileList == NULL) || (*FileList == NULL)) {\r
2704 return (EFI_INVALID_PARAMETER);\r
2705 }\r
2706\r
2707 if ((*Path == L'.') && (*(Path+1) == L'\\')) {\r
2708 Path += 2;\r
2709 }\r
2710\r
2711 //\r
2712 // convert a local path to an absolute path\r
2713 //\r
2714 if (StrStr (Path, L":") == NULL) {\r
2715 CurDir = EfiShellGetCurDir (NULL);\r
2716 ASSERT ((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2717 StrnCatGrow (&Path2, &Path2Size, CurDir, 0);\r
2718 StrnCatGrow (&Path2, &Path2Size, L"\\", 0);\r
2719 if (*Path == L'\\') {\r
2720 Path++;\r
2721 while (PathRemoveLastItem (Path2)) {\r
2722 }\r
2723 }\r
2724\r
2725 ASSERT ((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2726 StrnCatGrow (&Path2, &Path2Size, Path, 0);\r
2727 } else {\r
2728 ASSERT (Path2 == NULL);\r
2729 StrnCatGrow (&Path2, NULL, Path, 0);\r
2730 }\r
2731\r
2732 PathCleanUpDirectories (Path2);\r
2733\r
2734 //\r
2735 // do the search\r
2736 //\r
2737 Status = EfiShellFindFiles (Path2, FileList);\r
2738\r
2739 FreePool (Path2);\r
2740\r
2741 if (EFI_ERROR (Status)) {\r
2742 return (Status);\r
2743 }\r
2744\r
2745 Found = FALSE;\r
2746 //\r
2747 // We had no errors so open all the files (that are not already opened...)\r
2748 //\r
2749 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
2750 ; !IsNull (&(*FileList)->Link, &ShellFileListItem->Link)\r
2751 ; ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem->Link)\r
2752 )\r
2753 {\r
2754 if ((ShellFileListItem->Status == 0) && (ShellFileListItem->Handle == NULL)) {\r
2755 ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode);\r
2756 Found = TRUE;\r
2757 }\r
2758 }\r
2759\r
2760 if (!Found) {\r
2761 return (EFI_NOT_FOUND);\r
2762 }\r
2763\r
2764 return (EFI_SUCCESS);\r
2765}\r
2766\r
2767/**\r
2768 Gets the environment variable and Attributes, or list of environment variables. Can be\r
2769 used instead of GetEnv().\r
2770\r
2771 This function returns the current value of the specified environment variable and\r
2772 the Attributes. If no variable name was specified, then all of the known\r
2773 variables will be returned.\r
2774\r
2775 @param[in] Name A pointer to the environment variable name. If Name is NULL,\r
2776 then the function will return all of the defined shell\r
2777 environment variables. In the case where multiple environment\r
2778 variables are being returned, each variable will be terminated\r
2779 by a NULL, and the list will be terminated by a double NULL.\r
2780 @param[out] Attributes If not NULL, a pointer to the returned attributes bitmask for\r
2781 the environment variable. In the case where Name is NULL, and\r
2782 multiple environment variables are being returned, Attributes\r
2783 is undefined.\r
2784\r
2785 @retval NULL The environment variable doesn't exist.\r
2786 @return A non-NULL value points to the variable's value. The returned\r
2787 pointer does not need to be freed by the caller.\r
2788**/\r
2789CONST CHAR16 *\r
2790EFIAPI\r
2791EfiShellGetEnvEx (\r
2792 IN CONST CHAR16 *Name,\r
2793 OUT UINT32 *Attributes OPTIONAL\r
2794 )\r
2795{\r
2796 EFI_STATUS Status;\r
2797 VOID *Buffer;\r
2798 UINTN Size;\r
2799 ENV_VAR_LIST *Node;\r
2800 CHAR16 *CurrentWriteLocation;\r
2801\r
2802 Size = 0;\r
2803 Buffer = NULL;\r
2804\r
2805 if (Name == NULL) {\r
2806 //\r
2807 // Build the semi-colon delimited list. (2 passes)\r
2808 //\r
2809 for ( Node = (ENV_VAR_LIST *)GetFirstNode (&gShellEnvVarList.Link)\r
2810 ; !IsNull (&gShellEnvVarList.Link, &Node->Link)\r
2811 ; Node = (ENV_VAR_LIST *)GetNextNode (&gShellEnvVarList.Link, &Node->Link)\r
2812 )\r
2813 {\r
2814 ASSERT (Node->Key != NULL);\r
2815 Size += StrSize (Node->Key);\r
2816 }\r
2817\r
2818 Size += 2*sizeof (CHAR16);\r
2819\r
2820 Buffer = AllocateZeroPool (Size);\r
2821 if (Buffer == NULL) {\r
2822 return (NULL);\r
2823 }\r
2824\r
2825 CurrentWriteLocation = (CHAR16 *)Buffer;\r
2826\r
2827 for ( Node = (ENV_VAR_LIST *)GetFirstNode (&gShellEnvVarList.Link)\r
2828 ; !IsNull (&gShellEnvVarList.Link, &Node->Link)\r
2829 ; Node = (ENV_VAR_LIST *)GetNextNode (&gShellEnvVarList.Link, &Node->Link)\r
2830 )\r
2831 {\r
2832 ASSERT (Node->Key != NULL);\r
2833 StrCpyS (\r
2834 CurrentWriteLocation,\r
2835 (Size)/sizeof (CHAR16) - (CurrentWriteLocation - ((CHAR16 *)Buffer)),\r
2836 Node->Key\r
2837 );\r
2838 CurrentWriteLocation += StrLen (CurrentWriteLocation) + 1;\r
2839 }\r
2840 } else {\r
2841 //\r
2842 // We are doing a specific environment variable\r
2843 //\r
2844 Status = ShellFindEnvVarInList (Name, (CHAR16 **)&Buffer, &Size, Attributes);\r
2845\r
2846 if (EFI_ERROR (Status)) {\r
2847 //\r
2848 // get the size we need for this EnvVariable\r
2849 //\r
2850 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES (Name, Attributes, &Size, Buffer);\r
2851 if (Status == EFI_BUFFER_TOO_SMALL) {\r
2852 //\r
2853 // Allocate the space and recall the get function\r
2854 //\r
2855 Buffer = AllocateZeroPool (Size);\r
2856 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES (Name, Attributes, &Size, Buffer);\r
2857 }\r
2858\r
2859 //\r
2860 // we didn't get it (might not exist)\r
2861 // free the memory if we allocated any and return NULL\r
2862 //\r
2863 if (EFI_ERROR (Status)) {\r
2864 if (Buffer != NULL) {\r
2865 FreePool (Buffer);\r
2866 }\r
2867\r
2868 return (NULL);\r
2869 } else {\r
2870 //\r
2871 // If we did not find the environment variable in the gShellEnvVarList\r
2872 // but get it from UEFI variable storage successfully then we need update\r
2873 // the gShellEnvVarList.\r
2874 //\r
2875 ShellFreeEnvVarList ();\r
2876 Status = ShellInitEnvVarList ();\r
2877 ASSERT (Status == EFI_SUCCESS);\r
2878 }\r
2879 }\r
2880 }\r
2881\r
2882 //\r
2883 // return the buffer\r
2884 //\r
2885 return (AddBufferToFreeList (Buffer));\r
2886}\r
2887\r
2888/**\r
2889 Gets either a single or list of environment variables.\r
2890\r
2891 If name is not NULL then this function returns the current value of the specified\r
2892 environment variable.\r
2893\r
2894 If Name is NULL, then a list of all environment variable names is returned. Each is a\r
2895 NULL terminated string with a double NULL terminating the list.\r
2896\r
2897 @param Name A pointer to the environment variable name. If\r
2898 Name is NULL, then the function will return all\r
2899 of the defined shell environment variables. In\r
2900 the case where multiple environment variables are\r
2901 being returned, each variable will be terminated by\r
2902 a NULL, and the list will be terminated by a double\r
2903 NULL.\r
2904\r
2905 @retval !=NULL A pointer to the returned string.\r
2906 The returned pointer does not need to be freed by the caller.\r
2907\r
2908 @retval NULL The environment variable doesn't exist or there are\r
2909 no environment variables.\r
2910**/\r
2911CONST CHAR16 *\r
2912EFIAPI\r
2913EfiShellGetEnv (\r
2914 IN CONST CHAR16 *Name\r
2915 )\r
2916{\r
2917 return (EfiShellGetEnvEx (Name, NULL));\r
2918}\r
2919\r
2920/**\r
2921 Internal variable setting function. Allows for setting of the read only variables.\r
2922\r
2923 @param Name Points to the NULL-terminated environment variable name.\r
2924 @param Value Points to the NULL-terminated environment variable value. If the value is an\r
2925 empty string then the environment variable is deleted.\r
2926 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
2927\r
2928 @retval EFI_SUCCESS The environment variable was successfully updated.\r
2929**/\r
2930EFI_STATUS\r
2931InternalEfiShellSetEnv (\r
2932 IN CONST CHAR16 *Name,\r
2933 IN CONST CHAR16 *Value,\r
2934 IN BOOLEAN Volatile\r
2935 )\r
2936{\r
2937 EFI_STATUS Status;\r
2938\r
2939 if ((Value == NULL) || (StrLen (Value) == 0)) {\r
2940 Status = SHELL_DELETE_ENVIRONMENT_VARIABLE (Name);\r
2941 if (!EFI_ERROR (Status)) {\r
2942 ShellRemvoeEnvVarFromList (Name);\r
2943 }\r
2944 } else {\r
2945 SHELL_DELETE_ENVIRONMENT_VARIABLE (Name);\r
2946 Status = ShellAddEnvVarToList (\r
2947 Name,\r
2948 Value,\r
2949 StrSize (Value),\r
2950 EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE)\r
2951 );\r
2952 if (!EFI_ERROR (Status)) {\r
2953 Status = Volatile\r
2954 ? SHELL_SET_ENVIRONMENT_VARIABLE_V (Name, StrSize (Value) - sizeof (CHAR16), Value)\r
2955 : SHELL_SET_ENVIRONMENT_VARIABLE_NV (Name, StrSize (Value) - sizeof (CHAR16), Value);\r
2956 if (EFI_ERROR (Status)) {\r
2957 ShellRemvoeEnvVarFromList (Name);\r
2958 }\r
2959 }\r
2960 }\r
2961\r
2962 return Status;\r
2963}\r
2964\r
2965/**\r
2966 Sets the environment variable.\r
2967\r
2968 This function changes the current value of the specified environment variable. If the\r
2969 environment variable exists and the Value is an empty string, then the environment\r
2970 variable is deleted. If the environment variable exists and the Value is not an empty\r
2971 string, then the value of the environment variable is changed. If the environment\r
2972 variable does not exist and the Value is an empty string, there is no action. If the\r
2973 environment variable does not exist and the Value is a non-empty string, then the\r
2974 environment variable is created and assigned the specified value.\r
2975\r
2976 For a description of volatile and non-volatile environment variables, see UEFI Shell\r
2977 2.0 specification section 3.6.1.\r
2978\r
2979 @param Name Points to the NULL-terminated environment variable name.\r
2980 @param Value Points to the NULL-terminated environment variable value. If the value is an\r
2981 empty string then the environment variable is deleted.\r
2982 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
2983\r
2984 @retval EFI_SUCCESS The environment variable was successfully updated.\r
2985**/\r
2986EFI_STATUS\r
2987EFIAPI\r
2988EfiShellSetEnv (\r
2989 IN CONST CHAR16 *Name,\r
2990 IN CONST CHAR16 *Value,\r
2991 IN BOOLEAN Volatile\r
2992 )\r
2993{\r
2994 if ((Name == NULL) || (*Name == CHAR_NULL)) {\r
2995 return (EFI_INVALID_PARAMETER);\r
2996 }\r
2997\r
2998 //\r
2999 // Make sure we dont 'set' a predefined read only variable\r
3000 //\r
3001 if ((StrCmp (Name, L"cwd") == 0) ||\r
3002 (StrCmp (Name, L"lasterror") == 0) ||\r
3003 (StrCmp (Name, L"profiles") == 0) ||\r
3004 (StrCmp (Name, L"uefishellsupport") == 0) ||\r
3005 (StrCmp (Name, L"uefishellversion") == 0) ||\r
3006 (StrCmp (Name, L"uefiversion") == 0) ||\r
3007 (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest &&\r
3008 (StrCmp (Name, mNoNestingEnvVarName) == 0))\r
3009 )\r
3010 {\r
3011 return (EFI_INVALID_PARAMETER);\r
3012 }\r
3013\r
3014 return (InternalEfiShellSetEnv (Name, Value, Volatile));\r
3015}\r
3016\r
3017/**\r
3018 Returns the current directory on the specified device.\r
3019\r
3020 If FileSystemMapping is NULL, it returns the current working directory. If the\r
3021 FileSystemMapping is not NULL, it returns the current directory associated with the\r
3022 FileSystemMapping. In both cases, the returned name includes the file system\r
3023 mapping (i.e. fs0:\current-dir).\r
3024\r
3025 Note that the current directory string should exclude the tailing backslash character.\r
3026\r
3027 @param FileSystemMapping A pointer to the file system mapping. If NULL,\r
3028 then the current working directory is returned.\r
3029\r
3030 @retval !=NULL The current directory.\r
3031 @retval NULL Current directory does not exist.\r
3032**/\r
3033CONST CHAR16 *\r
3034EFIAPI\r
3035EfiShellGetCurDir (\r
3036 IN CONST CHAR16 *FileSystemMapping OPTIONAL\r
3037 )\r
3038{\r
3039 CHAR16 *PathToReturn;\r
3040 UINTN Size;\r
3041 SHELL_MAP_LIST *MapListItem;\r
3042\r
3043 if (!IsListEmpty (&gShellMapList.Link)) {\r
3044 //\r
3045 // if parameter is NULL, use current\r
3046 //\r
3047 if (FileSystemMapping == NULL) {\r
3048 return (EfiShellGetEnv (L"cwd"));\r
3049 } else {\r
3050 Size = 0;\r
3051 PathToReturn = NULL;\r
3052 MapListItem = ShellCommandFindMapItem (FileSystemMapping);\r
3053 if (MapListItem != NULL) {\r
3054 ASSERT ((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));\r
3055 PathToReturn = StrnCatGrow (&PathToReturn, &Size, MapListItem->MapName, 0);\r
3056 PathToReturn = StrnCatGrow (&PathToReturn, &Size, MapListItem->CurrentDirectoryPath, 0);\r
3057 }\r
3058 }\r
3059\r
3060 return (AddBufferToFreeList (PathToReturn));\r
3061 } else {\r
3062 return (NULL);\r
3063 }\r
3064}\r
3065\r
3066/**\r
3067 Changes the current directory on the specified device.\r
3068\r
3069 If the FileSystem is NULL, and the directory Dir does not contain a file system's\r
3070 mapped name, this function changes the current working directory.\r
3071\r
3072 If the FileSystem is NULL and the directory Dir contains a mapped name, then the\r
3073 current file system and the current directory on that file system are changed.\r
3074\r
3075 If FileSystem is NULL, and Dir is not NULL, then this changes the current working file\r
3076 system.\r
3077\r
3078 If FileSystem is not NULL and Dir is not NULL, then this function changes the current\r
3079 directory on the specified file system.\r
3080\r
3081 If the current working directory or the current working file system is changed then the\r
3082 %cwd% environment variable will be updated\r
3083\r
3084 Note that the current directory string should exclude the tailing backslash character.\r
3085\r
3086 @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working\r
3087 directory is changed.\r
3088 @param Dir Points to the NULL-terminated directory on the device specified by FileSystem.\r
3089\r
3090 @retval EFI_SUCCESS The operation was successful\r
3091 @retval EFI_NOT_FOUND The file system could not be found\r
3092**/\r
3093EFI_STATUS\r
3094EFIAPI\r
3095EfiShellSetCurDir (\r
3096 IN CONST CHAR16 *FileSystem OPTIONAL,\r
3097 IN CONST CHAR16 *Dir\r
3098 )\r
3099{\r
3100 CHAR16 *MapName;\r
3101 SHELL_MAP_LIST *MapListItem;\r
3102 UINTN Size;\r
3103 EFI_STATUS Status;\r
3104 CHAR16 *TempString;\r
3105 CHAR16 *DirectoryName;\r
3106 UINTN TempLen;\r
3107\r
3108 Size = 0;\r
3109 MapName = NULL;\r
3110 MapListItem = NULL;\r
3111 TempString = NULL;\r
3112 DirectoryName = NULL;\r
3113\r
3114 if (((FileSystem == NULL) && (Dir == NULL)) || (Dir == NULL)) {\r
3115 return (EFI_INVALID_PARAMETER);\r
3116 }\r
3117\r
3118 if (IsListEmpty (&gShellMapList.Link)) {\r
3119 return (EFI_NOT_FOUND);\r
3120 }\r
3121\r
3122 DirectoryName = StrnCatGrow (&DirectoryName, NULL, Dir, 0);\r
3123 ASSERT (DirectoryName != NULL);\r
3124\r
3125 PathCleanUpDirectories (DirectoryName);\r
3126\r
3127 if (FileSystem == NULL) {\r
3128 //\r
3129 // determine the file system mapping to use\r
3130 //\r
3131 if (StrStr (DirectoryName, L":") != NULL) {\r
3132 ASSERT (MapName == NULL);\r
3133 MapName = StrnCatGrow (&MapName, NULL, DirectoryName, (StrStr (DirectoryName, L":")-DirectoryName+1));\r
3134 }\r
3135\r
3136 //\r
3137 // find the file system mapping's entry in the list\r
3138 // or use current\r
3139 //\r
3140 if (MapName != NULL) {\r
3141 MapListItem = ShellCommandFindMapItem (MapName);\r
3142\r
3143 //\r
3144 // make that the current file system mapping\r
3145 //\r
3146 if (MapListItem != NULL) {\r
3147 gShellCurMapping = MapListItem;\r
3148 }\r
3149 } else {\r
3150 MapListItem = gShellCurMapping;\r
3151 }\r
3152\r
3153 if (MapListItem == NULL) {\r
3154 FreePool (DirectoryName);\r
3155 SHELL_FREE_NON_NULL (MapName);\r
3156 return (EFI_NOT_FOUND);\r
3157 }\r
3158\r
3159 //\r
3160 // now update the MapListItem's current directory\r
3161 //\r
3162 if ((MapListItem->CurrentDirectoryPath != NULL) && (DirectoryName[StrLen (DirectoryName) - 1] != L':')) {\r
3163 FreePool (MapListItem->CurrentDirectoryPath);\r
3164 MapListItem->CurrentDirectoryPath = NULL;\r
3165 }\r
3166\r
3167 if (MapName != NULL) {\r
3168 TempLen = StrLen (MapName);\r
3169 if (TempLen != StrLen (DirectoryName)) {\r
3170 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3171 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen (MapName), 0);\r
3172 }\r
3173\r
3174 FreePool (MapName);\r
3175 } else {\r
3176 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3177 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
3178 }\r
3179\r
3180 if (((MapListItem->CurrentDirectoryPath != NULL) && (MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] == L'\\')) || (MapListItem->CurrentDirectoryPath == NULL)) {\r
3181 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3182 if (MapListItem->CurrentDirectoryPath != NULL) {\r
3183 MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
3184 }\r
3185 }\r
3186 } else {\r
3187 //\r
3188 // cant have a mapping in the directory...\r
3189 //\r
3190 if (StrStr (DirectoryName, L":") != NULL) {\r
3191 FreePool (DirectoryName);\r
3192 return (EFI_INVALID_PARAMETER);\r
3193 }\r
3194\r
3195 //\r
3196 // FileSystem != NULL\r
3197 //\r
3198 MapListItem = ShellCommandFindMapItem (FileSystem);\r
3199 if (MapListItem == NULL) {\r
3200 FreePool (DirectoryName);\r
3201 return (EFI_INVALID_PARAMETER);\r
3202 }\r
3203\r
3204 // gShellCurMapping = MapListItem;\r
3205 if (DirectoryName != NULL) {\r
3206 //\r
3207 // change current dir on that file system\r
3208 //\r
3209\r
3210 if (MapListItem->CurrentDirectoryPath != NULL) {\r
3211 FreePool (MapListItem->CurrentDirectoryPath);\r
3212 DEBUG_CODE (\r
3213 MapListItem->CurrentDirectoryPath = NULL;\r
3214 );\r
3215 }\r
3216\r
3217 // ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3218 // MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);\r
3219 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3220 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
3221 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3222 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
3223 if ((MapListItem->CurrentDirectoryPath != NULL) && (MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] == L'\\')) {\r
3224 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3225 MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
3226 }\r
3227 }\r
3228 }\r
3229\r
3230 FreePool (DirectoryName);\r
3231 //\r
3232 // if updated the current directory then update the environment variable\r
3233 //\r
3234 if (MapListItem == gShellCurMapping) {\r
3235 Size = 0;\r
3236 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
3237 StrnCatGrow (&TempString, &Size, MapListItem->MapName, 0);\r
3238 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
3239 StrnCatGrow (&TempString, &Size, MapListItem->CurrentDirectoryPath, 0);\r
3240 Status = InternalEfiShellSetEnv (L"cwd", TempString, TRUE);\r
3241 FreePool (TempString);\r
3242 return (Status);\r
3243 }\r
3244\r
3245 return (EFI_SUCCESS);\r
3246}\r
3247\r
3248/**\r
3249 Return help information about a specific command.\r
3250\r
3251 This function returns the help information for the specified command. The help text\r
3252 can be internal to the shell or can be from a UEFI Shell manual page.\r
3253\r
3254 If Sections is specified, then each section name listed will be compared in a casesensitive\r
3255 manner, to the section names described in Appendix B. If the section exists,\r
3256 it will be appended to the returned help text. If the section does not exist, no\r
3257 information will be returned. If Sections is NULL, then all help text information\r
3258 available will be returned.\r
3259\r
3260 @param Command Points to the NULL-terminated UEFI Shell command name.\r
3261 @param Sections Points to the NULL-terminated comma-delimited\r
3262 section names to return. If NULL, then all\r
3263 sections will be returned.\r
3264 @param HelpText On return, points to a callee-allocated buffer\r
3265 containing all specified help text.\r
3266\r
3267 @retval EFI_SUCCESS The help text was returned.\r
3268 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the\r
3269 returned help text.\r
3270 @retval EFI_INVALID_PARAMETER HelpText is NULL\r
3271 @retval EFI_NOT_FOUND There is no help text available for Command.\r
3272**/\r
3273EFI_STATUS\r
3274EFIAPI\r
3275EfiShellGetHelpText (\r
3276 IN CONST CHAR16 *Command,\r
3277 IN CONST CHAR16 *Sections OPTIONAL,\r
3278 OUT CHAR16 **HelpText\r
3279 )\r
3280{\r
3281 CONST CHAR16 *ManFileName;\r
3282 CHAR16 *FixCommand;\r
3283 EFI_STATUS Status;\r
3284\r
3285 ASSERT (HelpText != NULL);\r
3286 FixCommand = NULL;\r
3287\r
3288 ManFileName = ShellCommandGetManFileNameHandler (Command);\r
3289\r
3290 if (ManFileName != NULL) {\r
3291 return (ProcessManFile (ManFileName, Command, Sections, NULL, HelpText));\r
3292 } else {\r
3293 if ( (StrLen (Command) > 4)\r
3294 && ((Command[StrLen (Command)-1] == L'i') || (Command[StrLen (Command)-1] == L'I'))\r
3295 && ((Command[StrLen (Command)-2] == L'f') || (Command[StrLen (Command)-2] == L'F'))\r
3296 && ((Command[StrLen (Command)-3] == L'e') || (Command[StrLen (Command)-3] == L'E'))\r
3297 && (Command[StrLen (Command)-4] == L'.')\r
3298 )\r
3299 {\r
3300 FixCommand = AllocateZeroPool (StrSize (Command) - 4 * sizeof (CHAR16));\r
3301 if (FixCommand == NULL) {\r
3302 return EFI_OUT_OF_RESOURCES;\r
3303 }\r
3304\r
3305 StrnCpyS (\r
3306 FixCommand,\r
3307 (StrSize (Command) - 4 * sizeof (CHAR16))/sizeof (CHAR16),\r
3308 Command,\r
3309 StrLen (Command)-4\r
3310 );\r
3311 Status = ProcessManFile (FixCommand, FixCommand, Sections, NULL, HelpText);\r
3312 FreePool (FixCommand);\r
3313 return Status;\r
3314 } else {\r
3315 return (ProcessManFile (Command, Command, Sections, NULL, HelpText));\r
3316 }\r
3317 }\r
3318}\r
3319\r
3320/**\r
3321 Gets the enable status of the page break output mode.\r
3322\r
3323 User can use this function to determine current page break mode.\r
3324\r
3325 @retval TRUE The page break output mode is enabled.\r
3326 @retval FALSE The page break output mode is disabled.\r
3327**/\r
3328BOOLEAN\r
3329EFIAPI\r
3330EfiShellGetPageBreak (\r
3331 VOID\r
3332 )\r
3333{\r
3334 return (ShellInfoObject.PageBreakEnabled);\r
3335}\r
3336\r
3337/**\r
3338 Judges whether the active shell is the root shell.\r
3339\r
3340 This function makes the user to know that whether the active Shell is the root shell.\r
3341\r
3342 @retval TRUE The active Shell is the root Shell.\r
3343 @retval FALSE The active Shell is NOT the root Shell.\r
3344**/\r
3345BOOLEAN\r
3346EFIAPI\r
3347EfiShellIsRootShell (\r
3348 VOID\r
3349 )\r
3350{\r
3351 return (ShellInfoObject.RootShellInstance);\r
3352}\r
3353\r
3354/**\r
3355 function to return a semi-colon delimited list of all alias' in the current shell\r
3356\r
3357 up to caller to free the memory.\r
3358\r
3359 @retval NULL No alias' were found\r
3360 @retval NULL An error occurred getting alias'\r
3361 @return !NULL a list of all alias'\r
3362**/\r
3363CHAR16 *\r
3364InternalEfiShellGetListAlias (\r
3365 VOID\r
3366 )\r
3367{\r
3368 EFI_STATUS Status;\r
3369 EFI_GUID Guid;\r
3370 CHAR16 *VariableName;\r
3371 UINTN NameSize;\r
3372 UINTN NameBufferSize;\r
3373 CHAR16 *RetVal;\r
3374 UINTN RetSize;\r
3375\r
3376 NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
3377 VariableName = AllocateZeroPool (NameBufferSize);\r
3378 RetSize = 0;\r
3379 RetVal = NULL;\r
3380\r
3381 if (VariableName == NULL) {\r
3382 return (NULL);\r
3383 }\r
3384\r
3385 VariableName[0] = CHAR_NULL;\r
3386\r
3387 while (TRUE) {\r
3388 NameSize = NameBufferSize;\r
3389 Status = gRT->GetNextVariableName (&NameSize, VariableName, &Guid);\r
3390 if (Status == EFI_NOT_FOUND) {\r
3391 break;\r
3392 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
3393 NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;\r
3394 SHELL_FREE_NON_NULL (VariableName);\r
3395 VariableName = AllocateZeroPool (NameBufferSize);\r
3396 if (VariableName == NULL) {\r
3397 Status = EFI_OUT_OF_RESOURCES;\r
3398 SHELL_FREE_NON_NULL (RetVal);\r
3399 RetVal = NULL;\r
3400 break;\r
3401 }\r
3402\r
3403 NameSize = NameBufferSize;\r
3404 Status = gRT->GetNextVariableName (&NameSize, VariableName, &Guid);\r
3405 }\r
3406\r
3407 if (EFI_ERROR (Status)) {\r
3408 SHELL_FREE_NON_NULL (RetVal);\r
3409 RetVal = NULL;\r
3410 break;\r
3411 }\r
3412\r
3413 if (CompareGuid (&Guid, &gShellAliasGuid)) {\r
3414 ASSERT ((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
3415 RetVal = StrnCatGrow (&RetVal, &RetSize, VariableName, 0);\r
3416 RetVal = StrnCatGrow (&RetVal, &RetSize, L";", 0);\r
3417 } // compare guid\r
3418 } // while\r
3419\r
3420 SHELL_FREE_NON_NULL (VariableName);\r
3421\r
3422 return (RetVal);\r
3423}\r
3424\r
3425/**\r
3426 Convert a null-terminated unicode string, in-place, to all lowercase.\r
3427 Then return it.\r
3428\r
3429 @param Str The null-terminated string to be converted to all lowercase.\r
3430\r
3431 @return The null-terminated string converted into all lowercase.\r
3432**/\r
3433CHAR16 *\r
3434ToLower (\r
3435 CHAR16 *Str\r
3436 )\r
3437{\r
3438 UINTN Index;\r
3439\r
3440 for (Index = 0; Str[Index] != L'\0'; Index++) {\r
3441 if ((Str[Index] >= L'A') && (Str[Index] <= L'Z')) {\r
3442 Str[Index] -= (CHAR16)(L'A' - L'a');\r
3443 }\r
3444 }\r
3445\r
3446 return Str;\r
3447}\r
3448\r
3449/**\r
3450 This function returns the command associated with a alias or a list of all\r
3451 alias'.\r
3452\r
3453 @param[in] Alias Points to the NULL-terminated shell alias.\r
3454 If this parameter is NULL, then all\r
3455 aliases will be returned in ReturnedData.\r
3456 @param[out] Volatile upon return of a single command if TRUE indicates\r
3457 this is stored in a volatile fashion. FALSE otherwise.\r
3458\r
3459 @return If Alias is not NULL, it will return a pointer to\r
3460 the NULL-terminated command for that alias.\r
3461 If Alias is NULL, ReturnedData points to a ';'\r
3462 delimited list of alias (e.g.\r
3463 ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.\r
3464 @retval NULL an error occurred\r
3465 @retval NULL Alias was not a valid Alias\r
3466**/\r
3467CONST CHAR16 *\r
3468EFIAPI\r
3469EfiShellGetAlias (\r
3470 IN CONST CHAR16 *Alias,\r
3471 OUT BOOLEAN *Volatile OPTIONAL\r
3472 )\r
3473{\r
3474 CHAR16 *RetVal;\r
3475 UINTN RetSize;\r
3476 UINT32 Attribs;\r
3477 EFI_STATUS Status;\r
3478 CHAR16 *AliasLower;\r
3479 CHAR16 *AliasVal;\r
3480\r
3481 // Convert to lowercase to make aliases case-insensitive\r
3482 if (Alias != NULL) {\r
3483 AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
3484 if (AliasLower == NULL) {\r
3485 return NULL;\r
3486 }\r
3487\r
3488 ToLower (AliasLower);\r
3489\r
3490 if (Volatile == NULL) {\r
3491 GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL);\r
3492 FreePool (AliasLower);\r
3493 return (AddBufferToFreeList (AliasVal));\r
3494 }\r
3495\r
3496 RetSize = 0;\r
3497 RetVal = NULL;\r
3498 Status = gRT->GetVariable (AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
3499 if (Status == EFI_BUFFER_TOO_SMALL) {\r
3500 RetVal = AllocateZeroPool (RetSize);\r
3501 Status = gRT->GetVariable (AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
3502 }\r
3503\r
3504 if (EFI_ERROR (Status)) {\r
3505 if (RetVal != NULL) {\r
3506 FreePool (RetVal);\r
3507 }\r
3508\r
3509 FreePool (AliasLower);\r
3510 return (NULL);\r
3511 }\r
3512\r
3513 if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) {\r
3514 *Volatile = FALSE;\r
3515 } else {\r
3516 *Volatile = TRUE;\r
3517 }\r
3518\r
3519 FreePool (AliasLower);\r
3520 return (AddBufferToFreeList (RetVal));\r
3521 }\r
3522\r
3523 return (AddBufferToFreeList (InternalEfiShellGetListAlias ()));\r
3524}\r
3525\r
3526/**\r
3527 Changes a shell command alias.\r
3528\r
3529 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
3530\r
3531 this function does not check for built in alias'.\r
3532\r
3533 @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
3534 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
3535 Command refers to an alias, that alias will be deleted.\r
3536 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
3537 Alias being set will be stored in a non-volatile fashion.\r
3538\r
3539 @retval EFI_SUCCESS Alias created or deleted successfully.\r
3540 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
3541**/\r
3542EFI_STATUS\r
3543InternalSetAlias (\r
3544 IN CONST CHAR16 *Command,\r
3545 IN CONST CHAR16 *Alias,\r
3546 IN BOOLEAN Volatile\r
3547 )\r
3548{\r
3549 EFI_STATUS Status;\r
3550 CHAR16 *AliasLower;\r
3551 BOOLEAN DeleteAlias;\r
3552\r
3553 DeleteAlias = FALSE;\r
3554 if (Alias == NULL) {\r
3555 //\r
3556 // We must be trying to remove one if Alias is NULL\r
3557 // remove an alias (but passed in COMMAND parameter)\r
3558 //\r
3559 Alias = Command;\r
3560 DeleteAlias = TRUE;\r
3561 }\r
3562\r
3563 ASSERT (Alias != NULL);\r
3564\r
3565 //\r
3566 // Convert to lowercase to make aliases case-insensitive\r
3567 //\r
3568 AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
3569 if (AliasLower == NULL) {\r
3570 return EFI_OUT_OF_RESOURCES;\r
3571 }\r
3572\r
3573 ToLower (AliasLower);\r
3574\r
3575 if (DeleteAlias) {\r
3576 Status = gRT->SetVariable (AliasLower, &gShellAliasGuid, 0, 0, NULL);\r
3577 } else {\r
3578 Status = gRT->SetVariable (\r
3579 AliasLower,\r
3580 &gShellAliasGuid,\r
3581 EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE),\r
3582 StrSize (Command),\r
3583 (VOID *)Command\r
3584 );\r
3585 }\r
3586\r
3587 FreePool (AliasLower);\r
3588\r
3589 return Status;\r
3590}\r
3591\r
3592/**\r
3593 Changes a shell command alias.\r
3594\r
3595 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
3596\r
3597\r
3598 @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
3599 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
3600 Command refers to an alias, that alias will be deleted.\r
3601 @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If\r
3602 FALSE and the alias already exists, then the existing alias is unchanged and\r
3603 EFI_ACCESS_DENIED is returned.\r
3604 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
3605 Alias being set will be stored in a non-volatile fashion.\r
3606\r
3607 @retval EFI_SUCCESS Alias created or deleted successfully.\r
3608 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
3609 @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to\r
3610 FALSE.\r
3611 @retval EFI_INVALID_PARAMETER Command is null or the empty string.\r
3612**/\r
3613EFI_STATUS\r
3614EFIAPI\r
3615EfiShellSetAlias (\r
3616 IN CONST CHAR16 *Command,\r
3617 IN CONST CHAR16 *Alias,\r
3618 IN BOOLEAN Replace,\r
3619 IN BOOLEAN Volatile\r
3620 )\r
3621{\r
3622 if (ShellCommandIsOnAliasList ((Alias == NULL) ? Command : Alias)) {\r
3623 //\r
3624 // cant set over a built in alias\r
3625 //\r
3626 return (EFI_ACCESS_DENIED);\r
3627 } else if ((Command == NULL) || (*Command == CHAR_NULL) || (StrLen (Command) == 0)) {\r
3628 //\r
3629 // Command is null or empty\r
3630 //\r
3631 return (EFI_INVALID_PARAMETER);\r
3632 } else if ((EfiShellGetAlias (Command, NULL) != NULL) && !Replace) {\r
3633 //\r
3634 // Alias already exists, Replace not set\r
3635 //\r
3636 return (EFI_ACCESS_DENIED);\r
3637 } else {\r
3638 return (InternalSetAlias (Command, Alias, Volatile));\r
3639 }\r
3640}\r
3641\r
3642// Pure FILE_HANDLE operations are passed to FileHandleLib\r
3643// these functions are indicated by the *\r
3644EFI_SHELL_PROTOCOL mShellProtocol = {\r
3645 EfiShellExecute,\r
3646 EfiShellGetEnv,\r
3647 EfiShellSetEnv,\r
3648 EfiShellGetAlias,\r
3649 EfiShellSetAlias,\r
3650 EfiShellGetHelpText,\r
3651 EfiShellGetDevicePathFromMap,\r
3652 EfiShellGetMapFromDevicePath,\r
3653 EfiShellGetDevicePathFromFilePath,\r
3654 EfiShellGetFilePathFromDevicePath,\r
3655 EfiShellSetMap,\r
3656 EfiShellGetCurDir,\r
3657 EfiShellSetCurDir,\r
3658 EfiShellOpenFileList,\r
3659 EfiShellFreeFileList,\r
3660 EfiShellRemoveDupInFileList,\r
3661 EfiShellBatchIsActive,\r
3662 EfiShellIsRootShell,\r
3663 EfiShellEnablePageBreak,\r
3664 EfiShellDisablePageBreak,\r
3665 EfiShellGetPageBreak,\r
3666 EfiShellGetDeviceName,\r
3667 (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo, // *\r
3668 (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo, // *\r
3669 EfiShellOpenFileByName,\r
3670 EfiShellClose,\r
3671 EfiShellCreateFile,\r
3672 (EFI_SHELL_READ_FILE)FileHandleRead, // *\r
3673 (EFI_SHELL_WRITE_FILE)FileHandleWrite, // *\r
3674 (EFI_SHELL_DELETE_FILE)FileHandleDelete, // *\r
3675 EfiShellDeleteFileByName,\r
3676 (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition, // *\r
3677 (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition, // *\r
3678 (EFI_SHELL_FLUSH_FILE)FileHandleFlush, // *\r
3679 EfiShellFindFiles,\r
3680 EfiShellFindFilesInDir,\r
3681 (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize, // *\r
3682 EfiShellOpenRoot,\r
3683 EfiShellOpenRootByHandle,\r
3684 NULL,\r
3685 SHELL_MAJOR_VERSION,\r
3686 SHELL_MINOR_VERSION,\r
3687\r
3688 // New for UEFI Shell 2.1\r
3689 EfiShellRegisterGuidName,\r
3690 EfiShellGetGuidName,\r
3691 EfiShellGetGuidFromName,\r
3692 EfiShellGetEnvEx\r
3693};\r
3694\r
3695/**\r
3696 Function to create and install on the current handle.\r
3697\r
3698 Will overwrite any existing ShellProtocols in the system to be sure that\r
3699 the current shell is in control.\r
3700\r
3701 This must be removed via calling CleanUpShellProtocol().\r
3702\r
3703 @param[in, out] NewShell The pointer to the pointer to the structure\r
3704 to install.\r
3705\r
3706 @retval EFI_SUCCESS The operation was successful.\r
3707 @return An error from LocateHandle, CreateEvent, or other core function.\r
3708**/\r
3709EFI_STATUS\r
3710CreatePopulateInstallShellProtocol (\r
3711 IN OUT EFI_SHELL_PROTOCOL **NewShell\r
3712 )\r
3713{\r
3714 EFI_STATUS Status;\r
3715 UINTN BufferSize;\r
3716 EFI_HANDLE *Buffer;\r
3717 UINTN HandleCounter;\r
3718 SHELL_PROTOCOL_HANDLE_LIST *OldProtocolNode;\r
3719 EFI_SHELL_PROTOCOL *OldShell;\r
3720\r
3721 if (NewShell == NULL) {\r
3722 return (EFI_INVALID_PARAMETER);\r
3723 }\r
3724\r
3725 BufferSize = 0;\r
3726 Buffer = NULL;\r
3727 OldProtocolNode = NULL;\r
3728 InitializeListHead (&ShellInfoObject.OldShellList.Link);\r
3729\r
3730 //\r
3731 // Initialize EfiShellProtocol object...\r
3732 //\r
3733 Status = gBS->CreateEvent (\r
3734 0,\r
3735 0,\r
3736 NULL,\r
3737 NULL,\r
3738 &mShellProtocol.ExecutionBreak\r
3739 );\r
3740 if (EFI_ERROR (Status)) {\r
3741 return (Status);\r
3742 }\r
3743\r
3744 //\r
3745 // Get the size of the buffer we need.\r
3746 //\r
3747 Status = gBS->LocateHandle (\r
3748 ByProtocol,\r
3749 &gEfiShellProtocolGuid,\r
3750 NULL,\r
3751 &BufferSize,\r
3752 Buffer\r
3753 );\r
3754 if (Status == EFI_BUFFER_TOO_SMALL) {\r
3755 //\r
3756 // Allocate and recall with buffer of correct size\r
3757 //\r
3758 Buffer = AllocateZeroPool (BufferSize);\r
3759 if (Buffer == NULL) {\r
3760 return (EFI_OUT_OF_RESOURCES);\r
3761 }\r
3762\r
3763 Status = gBS->LocateHandle (\r
3764 ByProtocol,\r
3765 &gEfiShellProtocolGuid,\r
3766 NULL,\r
3767 &BufferSize,\r
3768 Buffer\r
3769 );\r
3770 if (EFI_ERROR (Status)) {\r
3771 FreePool (Buffer);\r
3772 return (Status);\r
3773 }\r
3774\r
3775 //\r
3776 // now overwrite each of them, but save the info to restore when we end.\r
3777 //\r
3778 for (HandleCounter = 0; HandleCounter < (BufferSize/sizeof (EFI_HANDLE)); HandleCounter++) {\r
3779 Status = gBS->OpenProtocol (\r
3780 Buffer[HandleCounter],\r
3781 &gEfiShellProtocolGuid,\r
3782 (VOID **)&OldShell,\r
3783 gImageHandle,\r
3784 NULL,\r
3785 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
3786 );\r
3787 if (!EFI_ERROR (Status)) {\r
3788 OldProtocolNode = AllocateZeroPool (sizeof (SHELL_PROTOCOL_HANDLE_LIST));\r
3789 if (OldProtocolNode == NULL) {\r
3790 if (!IsListEmpty (&ShellInfoObject.OldShellList.Link)) {\r
3791 CleanUpShellProtocol (&mShellProtocol);\r
3792 }\r
3793\r
3794 Status = EFI_OUT_OF_RESOURCES;\r
3795 break;\r
3796 }\r
3797\r
3798 //\r
3799 // reinstall over the old one...\r
3800 //\r
3801 OldProtocolNode->Handle = Buffer[HandleCounter];\r
3802 OldProtocolNode->Interface = OldShell;\r
3803 Status = gBS->ReinstallProtocolInterface (\r
3804 OldProtocolNode->Handle,\r
3805 &gEfiShellProtocolGuid,\r
3806 OldProtocolNode->Interface,\r
3807 (VOID *)(&mShellProtocol)\r
3808 );\r
3809 if (!EFI_ERROR (Status)) {\r
3810 //\r
3811 // we reinstalled successfully. log this so we can reverse it later.\r
3812 //\r
3813\r
3814 //\r
3815 // add to the list for subsequent...\r
3816 //\r
3817 InsertTailList (&ShellInfoObject.OldShellList.Link, &OldProtocolNode->Link);\r
3818 }\r
3819 }\r
3820 }\r
3821\r
3822 FreePool (Buffer);\r
3823 } else if (Status == EFI_NOT_FOUND) {\r
3824 ASSERT (IsListEmpty (&ShellInfoObject.OldShellList.Link));\r
3825 //\r
3826 // no one else published yet. just publish it ourselves.\r
3827 //\r
3828 Status = gBS->InstallProtocolInterface (\r
3829 &gImageHandle,\r
3830 &gEfiShellProtocolGuid,\r
3831 EFI_NATIVE_INTERFACE,\r
3832 (VOID *)(&mShellProtocol)\r
3833 );\r
3834 }\r
3835\r
3836 if (PcdGetBool (PcdShellSupportOldProtocols)) {\r
3837 /// @todo support ShellEnvironment2\r
3838 /// @todo do we need to support ShellEnvironment (not ShellEnvironment2) also?\r
3839 }\r
3840\r
3841 if (!EFI_ERROR (Status)) {\r
3842 *NewShell = &mShellProtocol;\r
3843 }\r
3844\r
3845 return (Status);\r
3846}\r
3847\r
3848/**\r
3849 Opposite of CreatePopulateInstallShellProtocol.\r
3850\r
3851 Free all memory and restore the system to the state it was in before calling\r
3852 CreatePopulateInstallShellProtocol.\r
3853\r
3854 @param[in, out] NewShell The pointer to the new shell protocol structure.\r
3855\r
3856 @retval EFI_SUCCESS The operation was successful.\r
3857**/\r
3858EFI_STATUS\r
3859CleanUpShellProtocol (\r
3860 IN OUT EFI_SHELL_PROTOCOL *NewShell\r
3861 )\r
3862{\r
3863 SHELL_PROTOCOL_HANDLE_LIST *Node2;\r
3864\r
3865 //\r
3866 // if we need to restore old protocols...\r
3867 //\r
3868 if (!IsListEmpty (&ShellInfoObject.OldShellList.Link)) {\r
3869 for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode (&ShellInfoObject.OldShellList.Link)\r
3870 ; !IsListEmpty (&ShellInfoObject.OldShellList.Link)\r
3871 ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode (&ShellInfoObject.OldShellList.Link)\r
3872 )\r
3873 {\r
3874 RemoveEntryList (&Node2->Link);\r
3875 gBS->ReinstallProtocolInterface (Node2->Handle, &gEfiShellProtocolGuid, NewShell, Node2->Interface);\r
3876 FreePool (Node2);\r
3877 }\r
3878 } else {\r
3879 //\r
3880 // no need to restore\r
3881 //\r
3882 gBS->UninstallProtocolInterface (gImageHandle, &gEfiShellProtocolGuid, NewShell);\r
3883 }\r
3884\r
3885 return EFI_SUCCESS;\r
3886}\r
3887\r
3888/**\r
3889 Cleanup the shell environment.\r
3890\r
3891 @param[in, out] NewShell The pointer to the new shell protocol structure.\r
3892\r
3893 @retval EFI_SUCCESS The operation was successful.\r
3894**/\r
3895EFI_STATUS\r
3896CleanUpShellEnvironment (\r
3897 IN OUT EFI_SHELL_PROTOCOL *NewShell\r
3898 )\r
3899{\r
3900 EFI_STATUS Status;\r
3901 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
3902\r
3903 CleanUpShellProtocol (NewShell);\r
3904\r
3905 Status = gBS->CloseEvent (NewShell->ExecutionBreak);\r
3906 NewShell->ExecutionBreak = NULL;\r
3907\r
3908 Status = gBS->OpenProtocol (\r
3909 gST->ConsoleInHandle,\r
3910 &gEfiSimpleTextInputExProtocolGuid,\r
3911 (VOID **)&SimpleEx,\r
3912 gImageHandle,\r
3913 NULL,\r
3914 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
3915 );\r
3916\r
3917 if (!EFI_ERROR (Status)) {\r
3918 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle1);\r
3919 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle2);\r
3920 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle3);\r
3921 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle4);\r
3922 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle1);\r
3923 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle2);\r
3924 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle3);\r
3925 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle4);\r
3926 }\r
3927\r
3928 return (Status);\r
3929}\r
3930\r
3931/**\r
3932 Notification function for keystrokes.\r
3933\r
3934 @param[in] KeyData The key that was pressed.\r
3935\r
3936 @retval EFI_SUCCESS The operation was successful.\r
3937**/\r
3938EFI_STATUS\r
3939EFIAPI\r
3940NotificationFunction (\r
3941 IN EFI_KEY_DATA *KeyData\r
3942 )\r
3943{\r
3944 if (((KeyData->Key.UnicodeChar == L'c') &&\r
3945 ((KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED)) || (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED)))) ||\r
3946 (KeyData->Key.UnicodeChar == 3)\r
3947 )\r
3948 {\r
3949 if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
3950 return (EFI_UNSUPPORTED);\r
3951 }\r
3952\r
3953 return (gBS->SignalEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak));\r
3954 } else if ((KeyData->Key.UnicodeChar == L's') &&\r
3955 ((KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED)) || (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED)))\r
3956 )\r
3957 {\r
3958 ShellInfoObject.HaltOutput = TRUE;\r
3959 }\r
3960\r
3961 return (EFI_SUCCESS);\r
3962}\r
3963\r
3964/**\r
3965 Function to start monitoring for CTRL-C using SimpleTextInputEx. This\r
3966 feature's enabled state was not known when the shell initially launched.\r
3967\r
3968 @retval EFI_SUCCESS The feature is enabled.\r
3969 @retval EFI_OUT_OF_RESOURCES There is not enough memory available.\r
3970**/\r
3971EFI_STATUS\r
3972InernalEfiShellStartMonitor (\r
3973 VOID\r
3974 )\r
3975{\r
3976 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
3977 EFI_KEY_DATA KeyData;\r
3978 EFI_STATUS Status;\r
3979\r
3980 Status = gBS->OpenProtocol (\r
3981 gST->ConsoleInHandle,\r
3982 &gEfiSimpleTextInputExProtocolGuid,\r
3983 (VOID **)&SimpleEx,\r
3984 gImageHandle,\r
3985 NULL,\r
3986 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
3987 );\r
3988 if (EFI_ERROR (Status)) {\r
3989 ShellPrintHiiEx (\r
3990 -1,\r
3991 -1,\r
3992 NULL,\r
3993 STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
3994 ShellInfoObject.HiiHandle\r
3995 );\r
3996 return (EFI_SUCCESS);\r
3997 }\r
3998\r
3999 if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
4000 return (EFI_UNSUPPORTED);\r
4001 }\r
4002\r
4003 KeyData.KeyState.KeyToggleState = 0;\r
4004 KeyData.Key.ScanCode = 0;\r
4005 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
4006 KeyData.Key.UnicodeChar = L'c';\r
4007\r
4008 Status = SimpleEx->RegisterKeyNotify (\r
4009 SimpleEx,\r
4010 &KeyData,\r
4011 NotificationFunction,\r
4012 &ShellInfoObject.CtrlCNotifyHandle1\r
4013 );\r
4014\r
4015 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
4016 if (!EFI_ERROR (Status)) {\r
4017 Status = SimpleEx->RegisterKeyNotify (\r
4018 SimpleEx,\r
4019 &KeyData,\r
4020 NotificationFunction,\r
4021 &ShellInfoObject.CtrlCNotifyHandle2\r
4022 );\r
4023 }\r
4024\r
4025 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
4026 KeyData.Key.UnicodeChar = 3;\r
4027 if (!EFI_ERROR (Status)) {\r
4028 Status = SimpleEx->RegisterKeyNotify (\r
4029 SimpleEx,\r
4030 &KeyData,\r
4031 NotificationFunction,\r
4032 &ShellInfoObject.CtrlCNotifyHandle3\r
4033 );\r
4034 }\r
4035\r
4036 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
4037 if (!EFI_ERROR (Status)) {\r
4038 Status = SimpleEx->RegisterKeyNotify (\r
4039 SimpleEx,\r
4040 &KeyData,\r
4041 NotificationFunction,\r
4042 &ShellInfoObject.CtrlCNotifyHandle4\r
4043 );\r
4044 }\r
4045\r
4046 return (Status);\r
4047}\r