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