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