Vishal Bhoj | 82c8071 | 2015-12-15 21:13:33 +0530 | [diff] [blame^] | 1 | /** @file
|
| 2 | Provides interface to shell internal functions for shell commands.
|
| 3 |
|
| 4 | (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.<BR>
|
| 5 | Copyright (c) 2009 - 2014, 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 "UefiShellCommandLib.h"
|
| 17 |
|
| 18 | // STATIC local variables
|
| 19 | STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList;
|
| 20 | STATIC SCRIPT_FILE_LIST mScriptList;
|
| 21 | STATIC ALIAS_LIST mAliasList;
|
| 22 | STATIC BOOLEAN mEchoState;
|
| 23 | STATIC BOOLEAN mExitRequested;
|
| 24 | STATIC UINT64 mExitCode;
|
| 25 | STATIC BOOLEAN mExitScript;
|
| 26 | STATIC CHAR16 *mProfileList;
|
| 27 | STATIC UINTN mProfileListSize;
|
| 28 | STATIC UINTN mFsMaxCount = 0;
|
| 29 | STATIC UINTN mBlkMaxCount = 0;
|
| 30 | STATIC BUFFER_LIST mFileHandleList;
|
| 31 |
|
| 32 | // global variables required by library class.
|
| 33 | EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL;
|
| 34 | SHELL_MAP_LIST gShellMapList;
|
| 35 | SHELL_MAP_LIST *gShellCurDir = NULL;
|
| 36 |
|
| 37 | CONST CHAR16* SupportLevel[] = {
|
| 38 | L"Minimal",
|
| 39 | L"Scripting",
|
| 40 | L"Basic",
|
| 41 | L"Interactive"
|
| 42 | };
|
| 43 |
|
| 44 | /**
|
| 45 | Function to make sure that the global protocol pointers are valid.
|
| 46 | must be called after constructor before accessing the pointers.
|
| 47 | **/
|
| 48 | EFI_STATUS
|
| 49 | EFIAPI
|
| 50 | CommandInit(
|
| 51 | VOID
|
| 52 | )
|
| 53 | {
|
| 54 | EFI_STATUS Status;
|
| 55 | if (gUnicodeCollation == NULL) {
|
| 56 | Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
|
| 57 | if (EFI_ERROR(Status)) {
|
| 58 | return (EFI_DEVICE_ERROR);
|
| 59 | }
|
| 60 | }
|
| 61 | return (EFI_SUCCESS);
|
| 62 | }
|
| 63 |
|
| 64 | /**
|
| 65 | Constructor for the Shell Command library.
|
| 66 |
|
| 67 | Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
|
| 68 |
|
| 69 | @param ImageHandle the image handle of the process
|
| 70 | @param SystemTable the EFI System Table pointer
|
| 71 |
|
| 72 | @retval EFI_SUCCESS the initialization was complete sucessfully
|
| 73 | **/
|
| 74 | RETURN_STATUS
|
| 75 | EFIAPI
|
| 76 | ShellCommandLibConstructor (
|
| 77 | IN EFI_HANDLE ImageHandle,
|
| 78 | IN EFI_SYSTEM_TABLE *SystemTable
|
| 79 | )
|
| 80 | {
|
| 81 | EFI_STATUS Status;
|
| 82 | InitializeListHead(&gShellMapList.Link);
|
| 83 | InitializeListHead(&mCommandList.Link);
|
| 84 | InitializeListHead(&mAliasList.Link);
|
| 85 | InitializeListHead(&mScriptList.Link);
|
| 86 | InitializeListHead(&mFileHandleList.Link);
|
| 87 | mEchoState = TRUE;
|
| 88 |
|
| 89 | mExitRequested = FALSE;
|
| 90 | mExitScript = FALSE;
|
| 91 | mProfileListSize = 0;
|
| 92 | mProfileList = NULL;
|
| 93 |
|
| 94 | if (gUnicodeCollation == NULL) {
|
| 95 | Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
|
| 96 | if (EFI_ERROR(Status)) {
|
| 97 | return (EFI_DEVICE_ERROR);
|
| 98 | }
|
| 99 | }
|
| 100 |
|
| 101 | return (RETURN_SUCCESS);
|
| 102 | }
|
| 103 |
|
| 104 | /**
|
| 105 | Frees list of file handles.
|
| 106 |
|
| 107 | @param[in] List The list to free.
|
| 108 | **/
|
| 109 | VOID
|
| 110 | EFIAPI
|
| 111 | FreeFileHandleList (
|
| 112 | IN BUFFER_LIST *List
|
| 113 | )
|
| 114 | {
|
| 115 | BUFFER_LIST *BufferListEntry;
|
| 116 |
|
| 117 | if (List == NULL){
|
| 118 | return;
|
| 119 | }
|
| 120 | //
|
| 121 | // enumerate through the buffer list and free all memory
|
| 122 | //
|
| 123 | for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
|
| 124 | ; !IsListEmpty (&List->Link)
|
| 125 | ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
|
| 126 | ){
|
| 127 | RemoveEntryList(&BufferListEntry->Link);
|
| 128 | ASSERT(BufferListEntry->Buffer != NULL);
|
| 129 | SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path);
|
| 130 | SHELL_FREE_NON_NULL(BufferListEntry->Buffer);
|
| 131 | SHELL_FREE_NON_NULL(BufferListEntry);
|
| 132 | }
|
| 133 | }
|
| 134 |
|
| 135 | /**
|
| 136 | Destructor for the library. free any resources.
|
| 137 |
|
| 138 | @param ImageHandle the image handle of the process
|
| 139 | @param SystemTable the EFI System Table pointer
|
| 140 |
|
| 141 | @retval RETURN_SUCCESS this function always returns success
|
| 142 | **/
|
| 143 | RETURN_STATUS
|
| 144 | EFIAPI
|
| 145 | ShellCommandLibDestructor (
|
| 146 | IN EFI_HANDLE ImageHandle,
|
| 147 | IN EFI_SYSTEM_TABLE *SystemTable
|
| 148 | )
|
| 149 | {
|
| 150 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
| 151 | ALIAS_LIST *Node2;
|
| 152 | SCRIPT_FILE_LIST *Node3;
|
| 153 | SHELL_MAP_LIST *MapNode;
|
| 154 | //
|
| 155 | // enumerate throught the list and free all the memory
|
| 156 | //
|
| 157 | while (!IsListEmpty (&mCommandList.Link)) {
|
| 158 | Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);
|
| 159 | RemoveEntryList(&Node->Link);
|
| 160 | SHELL_FREE_NON_NULL(Node->CommandString);
|
| 161 | FreePool(Node);
|
| 162 | DEBUG_CODE(Node = NULL;);
|
| 163 | }
|
| 164 |
|
| 165 | //
|
| 166 | // enumerate through the alias list and free all memory
|
| 167 | //
|
| 168 | while (!IsListEmpty (&mAliasList.Link)) {
|
| 169 | Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);
|
| 170 | RemoveEntryList(&Node2->Link);
|
| 171 | SHELL_FREE_NON_NULL(Node2->CommandString);
|
| 172 | SHELL_FREE_NON_NULL(Node2->Alias);
|
| 173 | SHELL_FREE_NON_NULL(Node2);
|
| 174 | DEBUG_CODE(Node2 = NULL;);
|
| 175 | }
|
| 176 |
|
| 177 | //
|
| 178 | // enumerate throught the list and free all the memory
|
| 179 | //
|
| 180 | while (!IsListEmpty (&mScriptList.Link)) {
|
| 181 | Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
|
| 182 | RemoveEntryList(&Node3->Link);
|
| 183 | DeleteScriptFileStruct(Node3->Data);
|
| 184 | FreePool(Node3);
|
| 185 | }
|
| 186 |
|
| 187 | //
|
| 188 | // enumerate throught the mappings list and free all the memory
|
| 189 | //
|
| 190 | if (!IsListEmpty(&gShellMapList.Link)) {
|
| 191 | for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
|
| 192 | ; !IsListEmpty (&gShellMapList.Link)
|
| 193 | ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
|
| 194 | ){
|
| 195 | ASSERT(MapNode != NULL);
|
| 196 | RemoveEntryList(&MapNode->Link);
|
| 197 | SHELL_FREE_NON_NULL(MapNode->DevicePath);
|
| 198 | SHELL_FREE_NON_NULL(MapNode->MapName);
|
| 199 | SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);
|
| 200 | FreePool(MapNode);
|
| 201 | }
|
| 202 | }
|
| 203 | if (!IsListEmpty(&mFileHandleList.Link)){
|
| 204 | FreeFileHandleList(&mFileHandleList);
|
| 205 | }
|
| 206 |
|
| 207 | if (mProfileList != NULL) {
|
| 208 | FreePool(mProfileList);
|
| 209 | }
|
| 210 |
|
| 211 | gUnicodeCollation = NULL;
|
| 212 | gShellCurDir = NULL;
|
| 213 |
|
| 214 | return (RETURN_SUCCESS);
|
| 215 | }
|
| 216 |
|
| 217 | /**
|
| 218 | Find a dynamic command protocol instance given a command name string.
|
| 219 |
|
| 220 | @param CommandString the command name string
|
| 221 |
|
| 222 | @return instance the command protocol instance, if dynamic command instance found
|
| 223 | @retval NULL no dynamic command protocol instance found for name
|
| 224 | **/
|
| 225 | CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *
|
| 226 | EFIAPI
|
| 227 | ShellCommandFindDynamicCommand (
|
| 228 | IN CONST CHAR16 *CommandString
|
| 229 | )
|
| 230 | {
|
| 231 | EFI_STATUS Status;
|
| 232 | EFI_HANDLE *CommandHandleList;
|
| 233 | EFI_HANDLE *NextCommand;
|
| 234 | EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
|
| 235 |
|
| 236 | CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);
|
| 237 | if (CommandHandleList == NULL) {
|
| 238 | //
|
| 239 | // not found or out of resources
|
| 240 | //
|
| 241 | return NULL;
|
| 242 | }
|
| 243 |
|
| 244 | for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {
|
| 245 | Status = gBS->HandleProtocol(
|
| 246 | *NextCommand,
|
| 247 | &gEfiShellDynamicCommandProtocolGuid,
|
| 248 | (VOID **)&DynamicCommand
|
| 249 | );
|
| 250 |
|
| 251 | if (EFI_ERROR(Status)) {
|
| 252 | continue;
|
| 253 | }
|
| 254 |
|
| 255 | if (gUnicodeCollation->StriColl(
|
| 256 | gUnicodeCollation,
|
| 257 | (CHAR16*)CommandString,
|
| 258 | (CHAR16*)DynamicCommand->CommandName) == 0
|
| 259 | ){
|
| 260 | FreePool(CommandHandleList);
|
| 261 | return (DynamicCommand);
|
| 262 | }
|
| 263 | }
|
| 264 |
|
| 265 | FreePool(CommandHandleList);
|
| 266 | return (NULL);
|
| 267 | }
|
| 268 |
|
| 269 | /**
|
| 270 | Checks if a command exists as a dynamic command protocol instance
|
| 271 |
|
| 272 | @param[in] CommandString The command string to check for on the list.
|
| 273 | **/
|
| 274 | BOOLEAN
|
| 275 | EFIAPI
|
| 276 | ShellCommandDynamicCommandExists (
|
| 277 | IN CONST CHAR16 *CommandString
|
| 278 | )
|
| 279 | {
|
| 280 | return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL));
|
| 281 | }
|
| 282 |
|
| 283 | /**
|
| 284 | Checks if a command is already on the internal command list.
|
| 285 |
|
| 286 | @param[in] CommandString The command string to check for on the list.
|
| 287 | **/
|
| 288 | BOOLEAN
|
| 289 | EFIAPI
|
| 290 | ShellCommandIsCommandOnInternalList(
|
| 291 | IN CONST CHAR16 *CommandString
|
| 292 | )
|
| 293 | {
|
| 294 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
| 295 |
|
| 296 | //
|
| 297 | // assert for NULL parameter
|
| 298 | //
|
| 299 | ASSERT(CommandString != NULL);
|
| 300 |
|
| 301 | //
|
| 302 | // check for the command
|
| 303 | //
|
| 304 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
|
| 305 | ; !IsNull(&mCommandList.Link, &Node->Link)
|
| 306 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
|
| 307 | ){
|
| 308 | ASSERT(Node->CommandString != NULL);
|
| 309 | if (gUnicodeCollation->StriColl(
|
| 310 | gUnicodeCollation,
|
| 311 | (CHAR16*)CommandString,
|
| 312 | Node->CommandString) == 0
|
| 313 | ){
|
| 314 | return (TRUE);
|
| 315 | }
|
| 316 | }
|
| 317 | return (FALSE);
|
| 318 | }
|
| 319 |
|
| 320 | /**
|
| 321 | Checks if a command exists, either internally or through the dynamic command protocol.
|
| 322 |
|
| 323 | @param[in] CommandString The command string to check for on the list.
|
| 324 | **/
|
| 325 | BOOLEAN
|
| 326 | EFIAPI
|
| 327 | ShellCommandIsCommandOnList(
|
| 328 | IN CONST CHAR16 *CommandString
|
| 329 | )
|
| 330 | {
|
| 331 | if (ShellCommandIsCommandOnInternalList(CommandString)) {
|
| 332 | return TRUE;
|
| 333 | }
|
| 334 |
|
| 335 | return ShellCommandDynamicCommandExists(CommandString);
|
| 336 | }
|
| 337 |
|
| 338 | /**
|
| 339 | Get the help text for a dynamic command.
|
| 340 |
|
| 341 | @param[in] CommandString The command name.
|
| 342 |
|
| 343 | @retval NULL No help text was found.
|
| 344 | @return String of help text. Caller required to free.
|
| 345 | **/
|
| 346 | CHAR16*
|
| 347 | EFIAPI
|
| 348 | ShellCommandGetDynamicCommandHelp(
|
| 349 | IN CONST CHAR16 *CommandString
|
| 350 | )
|
| 351 | {
|
| 352 | EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
|
| 353 |
|
| 354 | DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);
|
| 355 | if (DynamicCommand == NULL) {
|
| 356 | return (NULL);
|
| 357 | }
|
| 358 |
|
| 359 | //
|
| 360 | // TODO: how to get proper language?
|
| 361 | //
|
| 362 | return DynamicCommand->GetHelp(DynamicCommand, "en");
|
| 363 | }
|
| 364 |
|
| 365 | /**
|
| 366 | Get the help text for an internal command.
|
| 367 |
|
| 368 | @param[in] CommandString The command name.
|
| 369 |
|
| 370 | @retval NULL No help text was found.
|
| 371 | @return String of help text. Caller reuiqred to free.
|
| 372 | **/
|
| 373 | CHAR16*
|
| 374 | EFIAPI
|
| 375 | ShellCommandGetInternalCommandHelp(
|
| 376 | IN CONST CHAR16 *CommandString
|
| 377 | )
|
| 378 | {
|
| 379 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
| 380 |
|
| 381 | //
|
| 382 | // assert for NULL parameter
|
| 383 | //
|
| 384 | ASSERT(CommandString != NULL);
|
| 385 |
|
| 386 | //
|
| 387 | // check for the command
|
| 388 | //
|
| 389 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
|
| 390 | ; !IsNull(&mCommandList.Link, &Node->Link)
|
| 391 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
|
| 392 | ){
|
| 393 | ASSERT(Node->CommandString != NULL);
|
| 394 | if (gUnicodeCollation->StriColl(
|
| 395 | gUnicodeCollation,
|
| 396 | (CHAR16*)CommandString,
|
| 397 | Node->CommandString) == 0
|
| 398 | ){
|
| 399 | return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL));
|
| 400 | }
|
| 401 | }
|
| 402 | return (NULL);
|
| 403 | }
|
| 404 |
|
| 405 | /**
|
| 406 | Get the help text for a command.
|
| 407 |
|
| 408 | @param[in] CommandString The command name.
|
| 409 |
|
| 410 | @retval NULL No help text was found.
|
| 411 | @return String of help text.Caller reuiqred to free.
|
| 412 | **/
|
| 413 | CHAR16*
|
| 414 | EFIAPI
|
| 415 | ShellCommandGetCommandHelp (
|
| 416 | IN CONST CHAR16 *CommandString
|
| 417 | )
|
| 418 | {
|
| 419 | CHAR16 *HelpStr;
|
| 420 | HelpStr = ShellCommandGetInternalCommandHelp(CommandString);
|
| 421 |
|
| 422 | if (HelpStr == NULL) {
|
| 423 | HelpStr = ShellCommandGetDynamicCommandHelp(CommandString);
|
| 424 | }
|
| 425 |
|
| 426 | return HelpStr;
|
| 427 | }
|
| 428 |
|
| 429 |
|
| 430 | /**
|
| 431 | Registers handlers of type SHELL_RUN_COMMAND and
|
| 432 | SHELL_GET_MAN_FILENAME for each shell command.
|
| 433 |
|
| 434 | If the ShellSupportLevel is greater than the value of the
|
| 435 | PcdShellSupportLevel then return RETURN_UNSUPPORTED.
|
| 436 |
|
| 437 | Registers the handlers specified by GetHelpInfoHandler and CommandHandler
|
| 438 | with the command specified by CommandString. If the command named by
|
| 439 | CommandString has already been registered, then return
|
| 440 | RETURN_ALREADY_STARTED.
|
| 441 |
|
| 442 | If there are not enough resources available to register the handlers then
|
| 443 | RETURN_OUT_OF_RESOURCES is returned.
|
| 444 |
|
| 445 | If CommandString is NULL, then ASSERT().
|
| 446 | If GetHelpInfoHandler is NULL, then ASSERT().
|
| 447 | If CommandHandler is NULL, then ASSERT().
|
| 448 | If ProfileName is NULL, then ASSERT().
|
| 449 |
|
| 450 | @param[in] CommandString Pointer to the command name. This is the
|
| 451 | name to look for on the command line in
|
| 452 | the shell.
|
| 453 | @param[in] CommandHandler Pointer to a function that runs the
|
| 454 | specified command.
|
| 455 | @param[in] GetManFileName Pointer to a function that provides man
|
| 456 | filename.
|
| 457 | @param[in] ShellMinSupportLevel minimum Shell Support Level which has this
|
| 458 | function.
|
| 459 | @param[in] ProfileName profile name to require for support of this
|
| 460 | function.
|
| 461 | @param[in] CanAffectLE indicates whether this command's return value
|
| 462 | can change the LASTERROR environment variable.
|
| 463 | @param[in] HiiHandle Handle of this command's HII entry.
|
| 464 | @param[in] ManFormatHelp HII locator for the help text.
|
| 465 |
|
| 466 | @retval RETURN_SUCCESS The handlers were registered.
|
| 467 | @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
|
| 468 | register the shell command.
|
| 469 | @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the
|
| 470 | currently allowed support level.
|
| 471 | @retval RETURN_ALREADY_STARTED The CommandString represents a command that
|
| 472 | is already registered. Only 1 handler set for
|
| 473 | a given command is allowed.
|
| 474 | @sa SHELL_GET_MAN_FILENAME
|
| 475 | @sa SHELL_RUN_COMMAND
|
| 476 | **/
|
| 477 | RETURN_STATUS
|
| 478 | EFIAPI
|
| 479 | ShellCommandRegisterCommandName (
|
| 480 | IN CONST CHAR16 *CommandString,
|
| 481 | IN SHELL_RUN_COMMAND CommandHandler,
|
| 482 | IN SHELL_GET_MAN_FILENAME GetManFileName,
|
| 483 | IN UINT32 ShellMinSupportLevel,
|
| 484 | IN CONST CHAR16 *ProfileName,
|
| 485 | IN CONST BOOLEAN CanAffectLE,
|
| 486 | IN CONST EFI_HANDLE HiiHandle,
|
| 487 | IN CONST EFI_STRING_ID ManFormatHelp
|
| 488 | )
|
| 489 | {
|
| 490 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
| 491 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command;
|
| 492 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand;
|
| 493 | INTN LexicalMatchValue;
|
| 494 |
|
| 495 | //
|
| 496 | // Initialize local variables.
|
| 497 | //
|
| 498 | Command = NULL;
|
| 499 | PrevCommand = NULL;
|
| 500 | LexicalMatchValue = 0;
|
| 501 |
|
| 502 | //
|
| 503 | // ASSERTs for NULL parameters
|
| 504 | //
|
| 505 | ASSERT(CommandString != NULL);
|
| 506 | ASSERT(GetManFileName != NULL);
|
| 507 | ASSERT(CommandHandler != NULL);
|
| 508 | ASSERT(ProfileName != NULL);
|
| 509 |
|
| 510 | //
|
| 511 | // check for shell support level
|
| 512 | //
|
| 513 | if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) {
|
| 514 | return (RETURN_UNSUPPORTED);
|
| 515 | }
|
| 516 |
|
| 517 | //
|
| 518 | // check for already on the list
|
| 519 | //
|
| 520 | if (ShellCommandIsCommandOnList(CommandString)) {
|
| 521 | return (RETURN_ALREADY_STARTED);
|
| 522 | }
|
| 523 |
|
| 524 | //
|
| 525 | // allocate memory for new struct
|
| 526 | //
|
| 527 | Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));
|
| 528 | ASSERT(Node != NULL);
|
| 529 | Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);
|
| 530 | ASSERT(Node->CommandString != NULL);
|
| 531 |
|
| 532 | Node->GetManFileName = GetManFileName;
|
| 533 | Node->CommandHandler = CommandHandler;
|
| 534 | Node->LastError = CanAffectLE;
|
| 535 | Node->HiiHandle = HiiHandle;
|
| 536 | Node->ManFormatHelp = ManFormatHelp;
|
| 537 |
|
| 538 | if ( StrLen(ProfileName)>0
|
| 539 | && ((mProfileList != NULL
|
| 540 | && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)
|
| 541 | ){
|
| 542 | ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));
|
| 543 | if (mProfileList == NULL) {
|
| 544 | //
|
| 545 | // If this is the first make a leading ';'
|
| 546 | //
|
| 547 | StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
|
| 548 | }
|
| 549 | StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);
|
| 550 | StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
|
| 551 | }
|
| 552 |
|
| 553 | //
|
| 554 | // Insert a new entry on top of the list
|
| 555 | //
|
| 556 | InsertHeadList (&mCommandList.Link, &Node->Link);
|
| 557 |
|
| 558 | //
|
| 559 | // Move a new registered command to its sorted ordered location in the list
|
| 560 | //
|
| 561 | for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),
|
| 562 | PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
|
| 563 | ; !IsNull (&mCommandList.Link, &Command->Link)
|
| 564 | ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {
|
| 565 |
|
| 566 | //
|
| 567 | // Get Lexical Comparison Value between PrevCommand and Command list entry
|
| 568 | //
|
| 569 | LexicalMatchValue = gUnicodeCollation->StriColl (
|
| 570 | gUnicodeCollation,
|
| 571 | PrevCommand->CommandString,
|
| 572 | Command->CommandString
|
| 573 | );
|
| 574 |
|
| 575 | //
|
| 576 | // Swap PrevCommand and Command list entry if PrevCommand list entry
|
| 577 | // is alphabetically greater than Command list entry
|
| 578 | //
|
| 579 | if (LexicalMatchValue > 0){
|
| 580 | Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);
|
| 581 | } else if (LexicalMatchValue < 0) {
|
| 582 | //
|
| 583 | // PrevCommand entry is lexically lower than Command entry
|
| 584 | //
|
| 585 | break;
|
| 586 | }
|
| 587 | }
|
| 588 |
|
| 589 | return (RETURN_SUCCESS);
|
| 590 | }
|
| 591 |
|
| 592 | /**
|
| 593 | Function to get the current Profile string.
|
| 594 |
|
| 595 | @retval NULL There are no installed profiles.
|
| 596 | @return A semi-colon delimited list of profiles.
|
| 597 | **/
|
| 598 | CONST CHAR16 *
|
| 599 | EFIAPI
|
| 600 | ShellCommandGetProfileList (
|
| 601 | VOID
|
| 602 | )
|
| 603 | {
|
| 604 | return (mProfileList);
|
| 605 | }
|
| 606 |
|
| 607 | /**
|
| 608 | Checks if a command string has been registered for CommandString and if so it runs
|
| 609 | the previously registered handler for that command with the command line.
|
| 610 |
|
| 611 | If CommandString is NULL, then ASSERT().
|
| 612 |
|
| 613 | If Sections is specified, then each section name listed will be compared in a casesensitive
|
| 614 | manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
|
| 615 | it will be appended to the returned help text. If the section does not exist, no
|
| 616 | information will be returned. If Sections is NULL, then all help text information
|
| 617 | available will be returned.
|
| 618 |
|
| 619 | @param[in] CommandString Pointer to the command name. This is the name
|
| 620 | found on the command line in the shell.
|
| 621 | @param[in, out] RetVal Pointer to the return vaule from the command handler.
|
| 622 |
|
| 623 | @param[in, out] CanAffectLE indicates whether this command's return value
|
| 624 | needs to be placed into LASTERROR environment variable.
|
| 625 |
|
| 626 | @retval RETURN_SUCCESS The handler was run.
|
| 627 | @retval RETURN_NOT_FOUND The CommandString did not match a registered
|
| 628 | command name.
|
| 629 | @sa SHELL_RUN_COMMAND
|
| 630 | **/
|
| 631 | RETURN_STATUS
|
| 632 | EFIAPI
|
| 633 | ShellCommandRunCommandHandler (
|
| 634 | IN CONST CHAR16 *CommandString,
|
| 635 | IN OUT SHELL_STATUS *RetVal,
|
| 636 | IN OUT BOOLEAN *CanAffectLE OPTIONAL
|
| 637 | )
|
| 638 | {
|
| 639 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
| 640 | EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
|
| 641 |
|
| 642 | //
|
| 643 | // assert for NULL parameters
|
| 644 | //
|
| 645 | ASSERT(CommandString != NULL);
|
| 646 |
|
| 647 | //
|
| 648 | // check for the command
|
| 649 | //
|
| 650 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
|
| 651 | ; !IsNull(&mCommandList.Link, &Node->Link)
|
| 652 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
|
| 653 | ){
|
| 654 | ASSERT(Node->CommandString != NULL);
|
| 655 | if (gUnicodeCollation->StriColl(
|
| 656 | gUnicodeCollation,
|
| 657 | (CHAR16*)CommandString,
|
| 658 | Node->CommandString) == 0
|
| 659 | ){
|
| 660 | if (CanAffectLE != NULL) {
|
| 661 | *CanAffectLE = Node->LastError;
|
| 662 | }
|
| 663 | if (RetVal != NULL) {
|
| 664 | *RetVal = Node->CommandHandler(NULL, gST);
|
| 665 | } else {
|
| 666 | Node->CommandHandler(NULL, gST);
|
| 667 | }
|
| 668 | return (RETURN_SUCCESS);
|
| 669 | }
|
| 670 | }
|
| 671 |
|
| 672 | //
|
| 673 | // An internal command was not found, try to find a dynamic command
|
| 674 | //
|
| 675 | DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);
|
| 676 | if (DynamicCommand != NULL) {
|
| 677 | if (RetVal != NULL) {
|
| 678 | *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
|
| 679 | } else {
|
| 680 | DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
|
| 681 | }
|
| 682 | return (RETURN_SUCCESS);
|
| 683 | }
|
| 684 |
|
| 685 | return (RETURN_NOT_FOUND);
|
| 686 | }
|
| 687 |
|
| 688 | /**
|
| 689 | Checks if a command string has been registered for CommandString and if so it
|
| 690 | returns the MAN filename specified for that command.
|
| 691 |
|
| 692 | If CommandString is NULL, then ASSERT().
|
| 693 |
|
| 694 | @param[in] CommandString Pointer to the command name. This is the name
|
| 695 | found on the command line in the shell.\
|
| 696 |
|
| 697 | @retval NULL the commandString was not a registered command.
|
| 698 | @return other the name of the MAN file.
|
| 699 | @sa SHELL_GET_MAN_FILENAME
|
| 700 | **/
|
| 701 | CONST CHAR16*
|
| 702 | EFIAPI
|
| 703 | ShellCommandGetManFileNameHandler (
|
| 704 | IN CONST CHAR16 *CommandString
|
| 705 | )
|
| 706 | {
|
| 707 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
| 708 |
|
| 709 | //
|
| 710 | // assert for NULL parameters
|
| 711 | //
|
| 712 | ASSERT(CommandString != NULL);
|
| 713 |
|
| 714 | //
|
| 715 | // check for the command
|
| 716 | //
|
| 717 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
|
| 718 | ; !IsNull(&mCommandList.Link, &Node->Link)
|
| 719 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
|
| 720 | ){
|
| 721 | ASSERT(Node->CommandString != NULL);
|
| 722 | if (gUnicodeCollation->StriColl(
|
| 723 | gUnicodeCollation,
|
| 724 | (CHAR16*)CommandString,
|
| 725 | Node->CommandString) == 0
|
| 726 | ){
|
| 727 | return (Node->GetManFileName());
|
| 728 | }
|
| 729 | }
|
| 730 | return (NULL);
|
| 731 | }
|
| 732 |
|
| 733 | /**
|
| 734 | Get the list of all available shell internal commands. This is a linked list
|
| 735 | (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
|
| 736 | list functions. do not modify the values.
|
| 737 |
|
| 738 | @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
|
| 739 |
|
| 740 | @return a Linked list of all available shell commands.
|
| 741 | **/
|
| 742 | CONST COMMAND_LIST*
|
| 743 | EFIAPI
|
| 744 | ShellCommandGetCommandList (
|
| 745 | IN CONST BOOLEAN Sort
|
| 746 | )
|
| 747 | {
|
| 748 | // if (!Sort) {
|
| 749 | // return ((COMMAND_LIST*)(&mCommandList));
|
| 750 | // }
|
| 751 | return ((COMMAND_LIST*)(&mCommandList));
|
| 752 | }
|
| 753 |
|
| 754 | /**
|
| 755 | Registers aliases to be set as part of the initialization of the shell application.
|
| 756 |
|
| 757 | If Command is NULL, then ASSERT().
|
| 758 | If Alias is NULL, then ASSERT().
|
| 759 |
|
| 760 | @param[in] Command Pointer to the Command
|
| 761 | @param[in] Alias Pointer to Alias
|
| 762 |
|
| 763 | @retval RETURN_SUCCESS The handlers were registered.
|
| 764 | @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
|
| 765 | register the shell command.
|
| 766 | **/
|
| 767 | RETURN_STATUS
|
| 768 | EFIAPI
|
| 769 | ShellCommandRegisterAlias (
|
| 770 | IN CONST CHAR16 *Command,
|
| 771 | IN CONST CHAR16 *Alias
|
| 772 | )
|
| 773 | {
|
| 774 | ALIAS_LIST *Node;
|
| 775 | ALIAS_LIST *CommandAlias;
|
| 776 | ALIAS_LIST *PrevCommandAlias;
|
| 777 | INTN LexicalMatchValue;
|
| 778 |
|
| 779 | //
|
| 780 | // Asserts for NULL
|
| 781 | //
|
| 782 | ASSERT(Command != NULL);
|
| 783 | ASSERT(Alias != NULL);
|
| 784 |
|
| 785 | //
|
| 786 | // allocate memory for new struct
|
| 787 | //
|
| 788 | Node = AllocateZeroPool(sizeof(ALIAS_LIST));
|
| 789 | ASSERT(Node != NULL);
|
| 790 | Node->CommandString = AllocateCopyPool(StrSize(Command), Command);
|
| 791 | Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);
|
| 792 | ASSERT(Node->CommandString != NULL);
|
| 793 | ASSERT(Node->Alias != NULL);
|
| 794 |
|
| 795 | InsertHeadList (&mAliasList.Link, &Node->Link);
|
| 796 |
|
| 797 | //
|
| 798 | // Move a new pre-defined registered alias to its sorted ordered location in the list
|
| 799 | //
|
| 800 | for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),
|
| 801 | PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)
|
| 802 | ; !IsNull (&mAliasList.Link, &CommandAlias->Link)
|
| 803 | ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {
|
| 804 | //
|
| 805 | // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry
|
| 806 | //
|
| 807 | LexicalMatchValue = gUnicodeCollation->StriColl (
|
| 808 | gUnicodeCollation,
|
| 809 | PrevCommandAlias->Alias,
|
| 810 | CommandAlias->Alias
|
| 811 | );
|
| 812 |
|
| 813 | //
|
| 814 | // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry
|
| 815 | // is alphabetically greater than CommandAlias list entry
|
| 816 | //
|
| 817 | if (LexicalMatchValue > 0) {
|
| 818 | CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);
|
| 819 | } else if (LexicalMatchValue < 0) {
|
| 820 | //
|
| 821 | // PrevCommandAlias entry is lexically lower than CommandAlias entry
|
| 822 | //
|
| 823 | break;
|
| 824 | }
|
| 825 | }
|
| 826 |
|
| 827 | return (RETURN_SUCCESS);
|
| 828 | }
|
| 829 |
|
| 830 | /**
|
| 831 | Get the list of all shell alias commands. This is a linked list
|
| 832 | (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
|
| 833 | list functions. do not modify the values.
|
| 834 |
|
| 835 | @return a Linked list of all requested shell alias'.
|
| 836 | **/
|
| 837 | CONST ALIAS_LIST*
|
| 838 | EFIAPI
|
| 839 | ShellCommandGetInitAliasList (
|
| 840 | VOID
|
| 841 | )
|
| 842 | {
|
| 843 | return (&mAliasList);
|
| 844 | }
|
| 845 |
|
| 846 | /**
|
| 847 | Determine if a given alias is on the list of built in alias'.
|
| 848 |
|
| 849 | @param[in] Alias The alias to test for
|
| 850 |
|
| 851 | @retval TRUE The alias is a built in alias
|
| 852 | @retval FALSE The alias is not a built in alias
|
| 853 | **/
|
| 854 | BOOLEAN
|
| 855 | EFIAPI
|
| 856 | ShellCommandIsOnAliasList(
|
| 857 | IN CONST CHAR16 *Alias
|
| 858 | )
|
| 859 | {
|
| 860 | ALIAS_LIST *Node;
|
| 861 |
|
| 862 | //
|
| 863 | // assert for NULL parameter
|
| 864 | //
|
| 865 | ASSERT(Alias != NULL);
|
| 866 |
|
| 867 | //
|
| 868 | // check for the Alias
|
| 869 | //
|
| 870 | for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)
|
| 871 | ; !IsNull(&mAliasList.Link, &Node->Link)
|
| 872 | ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)
|
| 873 | ){
|
| 874 | ASSERT(Node->CommandString != NULL);
|
| 875 | ASSERT(Node->Alias != NULL);
|
| 876 | if (gUnicodeCollation->StriColl(
|
| 877 | gUnicodeCollation,
|
| 878 | (CHAR16*)Alias,
|
| 879 | Node->CommandString) == 0
|
| 880 | ){
|
| 881 | return (TRUE);
|
| 882 | }
|
| 883 | if (gUnicodeCollation->StriColl(
|
| 884 | gUnicodeCollation,
|
| 885 | (CHAR16*)Alias,
|
| 886 | Node->Alias) == 0
|
| 887 | ){
|
| 888 | return (TRUE);
|
| 889 | }
|
| 890 | }
|
| 891 | return (FALSE);
|
| 892 | }
|
| 893 |
|
| 894 | /**
|
| 895 | Function to determine current state of ECHO. Echo determins if lines from scripts
|
| 896 | and ECHO commands are enabled.
|
| 897 |
|
| 898 | @retval TRUE Echo is currently enabled
|
| 899 | @retval FALSE Echo is currently disabled
|
| 900 | **/
|
| 901 | BOOLEAN
|
| 902 | EFIAPI
|
| 903 | ShellCommandGetEchoState(
|
| 904 | VOID
|
| 905 | )
|
| 906 | {
|
| 907 | return (mEchoState);
|
| 908 | }
|
| 909 |
|
| 910 | /**
|
| 911 | Function to set current state of ECHO. Echo determins if lines from scripts
|
| 912 | and ECHO commands are enabled.
|
| 913 |
|
| 914 | If State is TRUE, Echo will be enabled.
|
| 915 | If State is FALSE, Echo will be disabled.
|
| 916 |
|
| 917 | @param[in] State How to set echo.
|
| 918 | **/
|
| 919 | VOID
|
| 920 | EFIAPI
|
| 921 | ShellCommandSetEchoState(
|
| 922 | IN BOOLEAN State
|
| 923 | )
|
| 924 | {
|
| 925 | mEchoState = State;
|
| 926 | }
|
| 927 |
|
| 928 | /**
|
| 929 | Indicate that the current shell or script should exit.
|
| 930 |
|
| 931 | @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
|
| 932 | @param[in] ErrorCode The 64 bit error code to return.
|
| 933 | **/
|
| 934 | VOID
|
| 935 | EFIAPI
|
| 936 | ShellCommandRegisterExit (
|
| 937 | IN BOOLEAN ScriptOnly,
|
| 938 | IN CONST UINT64 ErrorCode
|
| 939 | )
|
| 940 | {
|
| 941 | mExitRequested = (BOOLEAN)(!mExitRequested);
|
| 942 | if (mExitRequested) {
|
| 943 | mExitScript = ScriptOnly;
|
| 944 | } else {
|
| 945 | mExitScript = FALSE;
|
| 946 | }
|
| 947 | mExitCode = ErrorCode;
|
| 948 | }
|
| 949 |
|
| 950 | /**
|
| 951 | Retrieve the Exit indicator.
|
| 952 |
|
| 953 | @retval TRUE Exit was indicated.
|
| 954 | @retval FALSE Exis was not indicated.
|
| 955 | **/
|
| 956 | BOOLEAN
|
| 957 | EFIAPI
|
| 958 | ShellCommandGetExit (
|
| 959 | VOID
|
| 960 | )
|
| 961 | {
|
| 962 | return (mExitRequested);
|
| 963 | }
|
| 964 |
|
| 965 | /**
|
| 966 | Retrieve the Exit code.
|
| 967 |
|
| 968 | If ShellCommandGetExit returns FALSE than the return from this is undefined.
|
| 969 |
|
| 970 | @return the value passed into RegisterExit.
|
| 971 | **/
|
| 972 | UINT64
|
| 973 | EFIAPI
|
| 974 | ShellCommandGetExitCode (
|
| 975 | VOID
|
| 976 | )
|
| 977 | {
|
| 978 | return (mExitCode);
|
| 979 | }
|
| 980 | /**
|
| 981 | Retrieve the Exit script indicator.
|
| 982 |
|
| 983 | If ShellCommandGetExit returns FALSE than the return from this is undefined.
|
| 984 |
|
| 985 | @retval TRUE ScriptOnly was indicated.
|
| 986 | @retval FALSE ScriptOnly was not indicated.
|
| 987 | **/
|
| 988 | BOOLEAN
|
| 989 | EFIAPI
|
| 990 | ShellCommandGetScriptExit (
|
| 991 | VOID
|
| 992 | )
|
| 993 | {
|
| 994 | return (mExitScript);
|
| 995 | }
|
| 996 |
|
| 997 | /**
|
| 998 | Function to cleanup all memory from a SCRIPT_FILE structure.
|
| 999 |
|
| 1000 | @param[in] Script The pointer to the structure to cleanup.
|
| 1001 | **/
|
| 1002 | VOID
|
| 1003 | EFIAPI
|
| 1004 | DeleteScriptFileStruct (
|
| 1005 | IN SCRIPT_FILE *Script
|
| 1006 | )
|
| 1007 | {
|
| 1008 | UINT8 LoopVar;
|
| 1009 |
|
| 1010 | if (Script == NULL) {
|
| 1011 | return;
|
| 1012 | }
|
| 1013 |
|
| 1014 | for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {
|
| 1015 | SHELL_FREE_NON_NULL(Script->Argv[LoopVar]);
|
| 1016 | }
|
| 1017 | if (Script->Argv != NULL) {
|
| 1018 | SHELL_FREE_NON_NULL(Script->Argv);
|
| 1019 | }
|
| 1020 | Script->CurrentCommand = NULL;
|
| 1021 | while (!IsListEmpty (&Script->CommandList)) {
|
| 1022 | Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);
|
| 1023 | if (Script->CurrentCommand != NULL) {
|
| 1024 | RemoveEntryList(&Script->CurrentCommand->Link);
|
| 1025 | if (Script->CurrentCommand->Cl != NULL) {
|
| 1026 | SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl);
|
| 1027 | }
|
| 1028 | if (Script->CurrentCommand->Data != NULL) {
|
| 1029 | SHELL_FREE_NON_NULL(Script->CurrentCommand->Data);
|
| 1030 | }
|
| 1031 | SHELL_FREE_NON_NULL(Script->CurrentCommand);
|
| 1032 | }
|
| 1033 | }
|
| 1034 | SHELL_FREE_NON_NULL(Script->ScriptName);
|
| 1035 | SHELL_FREE_NON_NULL(Script);
|
| 1036 | }
|
| 1037 |
|
| 1038 | /**
|
| 1039 | Function to return a pointer to the currently running script file object.
|
| 1040 |
|
| 1041 | @retval NULL A script file is not currently running.
|
| 1042 | @return A pointer to the current script file object.
|
| 1043 | **/
|
| 1044 | SCRIPT_FILE*
|
| 1045 | EFIAPI
|
| 1046 | ShellCommandGetCurrentScriptFile (
|
| 1047 | VOID
|
| 1048 | )
|
| 1049 | {
|
| 1050 | SCRIPT_FILE_LIST *List;
|
| 1051 | if (IsListEmpty (&mScriptList.Link)) {
|
| 1052 | return (NULL);
|
| 1053 | }
|
| 1054 | List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));
|
| 1055 | return (List->Data);
|
| 1056 | }
|
| 1057 |
|
| 1058 | /**
|
| 1059 | Function to set a new script as the currently running one.
|
| 1060 |
|
| 1061 | This function will correctly stack and unstack nested scripts.
|
| 1062 |
|
| 1063 | @param[in] Script Pointer to new script information structure. if NULL
|
| 1064 | will remove and de-allocate the top-most Script structure.
|
| 1065 |
|
| 1066 | @return A pointer to the current running script file after this
|
| 1067 | change. NULL if removing the final script.
|
| 1068 | **/
|
| 1069 | SCRIPT_FILE*
|
| 1070 | EFIAPI
|
| 1071 | ShellCommandSetNewScript (
|
| 1072 | IN SCRIPT_FILE *Script OPTIONAL
|
| 1073 | )
|
| 1074 | {
|
| 1075 | SCRIPT_FILE_LIST *Node;
|
| 1076 | if (Script == NULL) {
|
| 1077 | if (IsListEmpty (&mScriptList.Link)) {
|
| 1078 | return (NULL);
|
| 1079 | }
|
| 1080 | Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
|
| 1081 | RemoveEntryList(&Node->Link);
|
| 1082 | DeleteScriptFileStruct(Node->Data);
|
| 1083 | FreePool(Node);
|
| 1084 | } else {
|
| 1085 | Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));
|
| 1086 | if (Node == NULL) {
|
| 1087 | return (NULL);
|
| 1088 | }
|
| 1089 | Node->Data = Script;
|
| 1090 | InsertHeadList(&mScriptList.Link, &Node->Link);
|
| 1091 | }
|
| 1092 | return (ShellCommandGetCurrentScriptFile());
|
| 1093 | }
|
| 1094 |
|
| 1095 | /**
|
| 1096 | Function to generate the next default mapping name.
|
| 1097 |
|
| 1098 | If the return value is not NULL then it must be callee freed.
|
| 1099 |
|
| 1100 | @param Type What kind of mapping name to make.
|
| 1101 |
|
| 1102 | @retval NULL a memory allocation failed.
|
| 1103 | @return a new map name string
|
| 1104 | **/
|
| 1105 | CHAR16*
|
| 1106 | EFIAPI
|
| 1107 | ShellCommandCreateNewMappingName(
|
| 1108 | IN CONST SHELL_MAPPING_TYPE Type
|
| 1109 | )
|
| 1110 | {
|
| 1111 | CHAR16 *String;
|
| 1112 | ASSERT(Type < MappingTypeMax);
|
| 1113 |
|
| 1114 | String = NULL;
|
| 1115 |
|
| 1116 | String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));
|
| 1117 | UnicodeSPrint(
|
| 1118 | String,
|
| 1119 | PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),
|
| 1120 | Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",
|
| 1121 | Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);
|
| 1122 |
|
| 1123 | return (String);
|
| 1124 | }
|
| 1125 |
|
| 1126 | /**
|
| 1127 | Function to add a map node to the list of map items and update the "path" environment variable (optionally).
|
| 1128 |
|
| 1129 | If Path is TRUE (during initialization only), the path environment variable will also be updated to include
|
| 1130 | default paths on the new map name...
|
| 1131 |
|
| 1132 | Path should be FALSE when this function is called from the protocol SetMap function.
|
| 1133 |
|
| 1134 | @param[in] Name The human readable mapped name.
|
| 1135 | @param[in] DevicePath The Device Path for this map.
|
| 1136 | @param[in] Flags The Flags attribute for this map item.
|
| 1137 | @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
|
| 1138 |
|
| 1139 | @retval EFI_SUCCESS The addition was sucessful.
|
| 1140 | @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
|
| 1141 | @retval EFI_INVALID_PARAMETER A parameter was invalid.
|
| 1142 | **/
|
| 1143 | EFI_STATUS
|
| 1144 | EFIAPI
|
| 1145 | ShellCommandAddMapItemAndUpdatePath(
|
| 1146 | IN CONST CHAR16 *Name,
|
| 1147 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
| 1148 | IN CONST UINT64 Flags,
|
| 1149 | IN CONST BOOLEAN Path
|
| 1150 | )
|
| 1151 | {
|
| 1152 | EFI_STATUS Status;
|
| 1153 | SHELL_MAP_LIST *MapListNode;
|
| 1154 | CONST CHAR16 *OriginalPath;
|
| 1155 | CHAR16 *NewPath;
|
| 1156 | UINTN NewPathSize;
|
| 1157 |
|
| 1158 | NewPathSize = 0;
|
| 1159 | NewPath = NULL;
|
| 1160 | OriginalPath = NULL;
|
| 1161 | Status = EFI_SUCCESS;
|
| 1162 |
|
| 1163 | MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));
|
| 1164 | if (MapListNode == NULL) {
|
| 1165 | Status = EFI_OUT_OF_RESOURCES;
|
| 1166 | } else {
|
| 1167 | MapListNode->Flags = Flags;
|
| 1168 | MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);
|
| 1169 | MapListNode->DevicePath = DuplicateDevicePath(DevicePath);
|
| 1170 | if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){
|
| 1171 | Status = EFI_OUT_OF_RESOURCES;
|
| 1172 | } else {
|
| 1173 | InsertTailList(&gShellMapList.Link, &MapListNode->Link);
|
| 1174 | }
|
| 1175 | }
|
| 1176 | if (EFI_ERROR(Status)) {
|
| 1177 | if (MapListNode != NULL) {
|
| 1178 | if (MapListNode->DevicePath != NULL) {
|
| 1179 | FreePool(MapListNode->DevicePath);
|
| 1180 | }
|
| 1181 | if (MapListNode->MapName != NULL) {
|
| 1182 | FreePool(MapListNode->MapName);
|
| 1183 | }
|
| 1184 | FreePool(MapListNode);
|
| 1185 | }
|
| 1186 | } else if (Path) {
|
| 1187 | //
|
| 1188 | // Since there was no error and Path was TRUE
|
| 1189 | // Now add the correct path for that mapping
|
| 1190 | //
|
| 1191 | OriginalPath = gEfiShellProtocol->GetEnv(L"path");
|
| 1192 | ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));
|
| 1193 | if (OriginalPath != NULL) {
|
| 1194 | StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);
|
| 1195 | } else {
|
| 1196 | StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);
|
| 1197 | }
|
| 1198 | StrnCatGrow(&NewPath, &NewPathSize, L";", 0);
|
| 1199 | StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
|
| 1200 | StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);
|
| 1201 | StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
|
| 1202 | StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);
|
| 1203 | StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
|
| 1204 | StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);
|
| 1205 |
|
| 1206 | Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);
|
| 1207 | ASSERT_EFI_ERROR(Status);
|
| 1208 | FreePool(NewPath);
|
| 1209 | }
|
| 1210 | return (Status);
|
| 1211 | }
|
| 1212 |
|
| 1213 | /**
|
| 1214 | Creates the default map names for each device path in the system with
|
| 1215 | a protocol depending on the Type.
|
| 1216 |
|
| 1217 | Creates the consistent map names for each device path in the system with
|
| 1218 | a protocol depending on the Type.
|
| 1219 |
|
| 1220 | Note: This will reset all mappings in the system("map -r").
|
| 1221 |
|
| 1222 | Also sets up the default path environment variable if Type is FileSystem.
|
| 1223 |
|
| 1224 | @retval EFI_SUCCESS All map names were created sucessfully.
|
| 1225 | @retval EFI_NOT_FOUND No protocols were found in the system.
|
| 1226 | @return Error returned from gBS->LocateHandle().
|
| 1227 |
|
| 1228 | @sa LocateHandle
|
| 1229 | **/
|
| 1230 | EFI_STATUS
|
| 1231 | EFIAPI
|
| 1232 | ShellCommandCreateInitialMappingsAndPaths(
|
| 1233 | VOID
|
| 1234 | )
|
| 1235 | {
|
| 1236 | EFI_STATUS Status;
|
| 1237 | EFI_HANDLE *HandleList;
|
| 1238 | UINTN Count;
|
| 1239 | EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
|
| 1240 | CHAR16 *NewDefaultName;
|
| 1241 | CHAR16 *NewConsistName;
|
| 1242 | EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
|
| 1243 | SHELL_MAP_LIST *MapListNode;
|
| 1244 |
|
| 1245 | HandleList = NULL;
|
| 1246 |
|
| 1247 | //
|
| 1248 | // Reset the static members back to zero
|
| 1249 | //
|
| 1250 | mFsMaxCount = 0;
|
| 1251 | mBlkMaxCount = 0;
|
| 1252 |
|
| 1253 | gEfiShellProtocol->SetEnv(L"path", L"", TRUE);
|
| 1254 |
|
| 1255 | //
|
| 1256 | // First empty out the existing list.
|
| 1257 | //
|
| 1258 | if (!IsListEmpty(&gShellMapList.Link)) {
|
| 1259 | for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
|
| 1260 | ; !IsListEmpty(&gShellMapList.Link)
|
| 1261 | ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
|
| 1262 | ){
|
| 1263 | RemoveEntryList(&MapListNode->Link);
|
| 1264 | FreePool(MapListNode);
|
| 1265 | } // for loop
|
| 1266 | }
|
| 1267 |
|
| 1268 | //
|
| 1269 | // Find each handle with Simple File System
|
| 1270 | //
|
| 1271 | HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
|
| 1272 | if (HandleList != NULL) {
|
| 1273 | //
|
| 1274 | // Do a count of the handles
|
| 1275 | //
|
| 1276 | for (Count = 0 ; HandleList[Count] != NULL ; Count++);
|
| 1277 |
|
| 1278 | //
|
| 1279 | // Get all Device Paths
|
| 1280 | //
|
| 1281 | DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
|
| 1282 | ASSERT(DevicePathList != NULL);
|
| 1283 |
|
| 1284 | for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
|
| 1285 | DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
|
| 1286 | }
|
| 1287 |
|
| 1288 | //
|
| 1289 | // Sort all DevicePaths
|
| 1290 | //
|
| 1291 | PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
|
| 1292 |
|
| 1293 | ShellCommandConsistMappingInitialize(&ConsistMappingTable);
|
| 1294 | //
|
| 1295 | // Assign new Mappings to all...
|
| 1296 | //
|
| 1297 | for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
|
| 1298 | //
|
| 1299 | // Get default name first
|
| 1300 | //
|
| 1301 | NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
|
| 1302 | ASSERT(NewDefaultName != NULL);
|
| 1303 | Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);
|
| 1304 | ASSERT_EFI_ERROR(Status);
|
| 1305 | FreePool(NewDefaultName);
|
| 1306 |
|
| 1307 | //
|
| 1308 | // Now do consistent name
|
| 1309 | //
|
| 1310 | NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
|
| 1311 | if (NewConsistName != NULL) {
|
| 1312 | Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);
|
| 1313 | ASSERT_EFI_ERROR(Status);
|
| 1314 | FreePool(NewConsistName);
|
| 1315 | }
|
| 1316 | }
|
| 1317 |
|
| 1318 | ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
|
| 1319 |
|
| 1320 | SHELL_FREE_NON_NULL(HandleList);
|
| 1321 | SHELL_FREE_NON_NULL(DevicePathList);
|
| 1322 |
|
| 1323 | HandleList = NULL;
|
| 1324 | } else {
|
| 1325 | Count = (UINTN)-1;
|
| 1326 | }
|
| 1327 |
|
| 1328 | //
|
| 1329 | // Find each handle with Block Io
|
| 1330 | //
|
| 1331 | HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);
|
| 1332 | if (HandleList != NULL) {
|
| 1333 | for (Count = 0 ; HandleList[Count] != NULL ; Count++);
|
| 1334 |
|
| 1335 | //
|
| 1336 | // Get all Device Paths
|
| 1337 | //
|
| 1338 | DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
|
| 1339 | ASSERT(DevicePathList != NULL);
|
| 1340 |
|
| 1341 | for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
|
| 1342 | DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
|
| 1343 | }
|
| 1344 |
|
| 1345 | //
|
| 1346 | // Sort all DevicePaths
|
| 1347 | //
|
| 1348 | PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
|
| 1349 |
|
| 1350 | //
|
| 1351 | // Assign new Mappings to all...
|
| 1352 | //
|
| 1353 | for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
|
| 1354 | //
|
| 1355 | // Get default name first
|
| 1356 | //
|
| 1357 | NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);
|
| 1358 | ASSERT(NewDefaultName != NULL);
|
| 1359 | Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);
|
| 1360 | ASSERT_EFI_ERROR(Status);
|
| 1361 | FreePool(NewDefaultName);
|
| 1362 | }
|
| 1363 |
|
| 1364 | SHELL_FREE_NON_NULL(HandleList);
|
| 1365 | SHELL_FREE_NON_NULL(DevicePathList);
|
| 1366 | } else if (Count == (UINTN)-1) {
|
| 1367 | return (EFI_NOT_FOUND);
|
| 1368 | }
|
| 1369 |
|
| 1370 | return (EFI_SUCCESS);
|
| 1371 | }
|
| 1372 |
|
| 1373 | /**
|
| 1374 | Add mappings for any devices without one. Do not change any existing maps.
|
| 1375 |
|
| 1376 | @retval EFI_SUCCESS The operation was successful.
|
| 1377 | **/
|
| 1378 | EFI_STATUS
|
| 1379 | EFIAPI
|
| 1380 | ShellCommandUpdateMapping (
|
| 1381 | VOID
|
| 1382 | )
|
| 1383 | {
|
| 1384 | EFI_STATUS Status;
|
| 1385 | EFI_HANDLE *HandleList;
|
| 1386 | UINTN Count;
|
| 1387 | EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
|
| 1388 | CHAR16 *NewDefaultName;
|
| 1389 | CHAR16 *NewConsistName;
|
| 1390 | EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
|
| 1391 |
|
| 1392 | HandleList = NULL;
|
| 1393 | Status = EFI_SUCCESS;
|
| 1394 |
|
| 1395 | //
|
| 1396 | // remove mappings that represent removed devices.
|
| 1397 | //
|
| 1398 |
|
| 1399 | //
|
| 1400 | // Find each handle with Simple File System
|
| 1401 | //
|
| 1402 | HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
|
| 1403 | if (HandleList != NULL) {
|
| 1404 | //
|
| 1405 | // Do a count of the handles
|
| 1406 | //
|
| 1407 | for (Count = 0 ; HandleList[Count] != NULL ; Count++);
|
| 1408 |
|
| 1409 | //
|
| 1410 | // Get all Device Paths
|
| 1411 | //
|
| 1412 | DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
|
| 1413 | if (DevicePathList == NULL) {
|
| 1414 | return (EFI_OUT_OF_RESOURCES);
|
| 1415 | }
|
| 1416 |
|
| 1417 | for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
|
| 1418 | DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
|
| 1419 | }
|
| 1420 |
|
| 1421 | //
|
| 1422 | // Sort all DevicePaths
|
| 1423 | //
|
| 1424 | PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
|
| 1425 |
|
| 1426 | ShellCommandConsistMappingInitialize(&ConsistMappingTable);
|
| 1427 |
|
| 1428 | //
|
| 1429 | // Assign new Mappings to remainders
|
| 1430 | //
|
| 1431 | for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {
|
| 1432 | //
|
| 1433 | // Skip ones that already have
|
| 1434 | //
|
| 1435 | if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {
|
| 1436 | continue;
|
| 1437 | }
|
| 1438 | //
|
| 1439 | // Get default name
|
| 1440 | //
|
| 1441 | NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
|
| 1442 | if (NewDefaultName == NULL) {
|
| 1443 | Status = EFI_OUT_OF_RESOURCES;
|
| 1444 | break;
|
| 1445 | }
|
| 1446 |
|
| 1447 | //
|
| 1448 | // Call shell protocol SetMap function now...
|
| 1449 | //
|
| 1450 | Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);
|
| 1451 |
|
| 1452 | if (!EFI_ERROR(Status)) {
|
| 1453 | //
|
| 1454 | // Now do consistent name
|
| 1455 | //
|
| 1456 | NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
|
| 1457 | if (NewConsistName != NULL) {
|
| 1458 | Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);
|
| 1459 | FreePool(NewConsistName);
|
| 1460 | }
|
| 1461 | }
|
| 1462 |
|
| 1463 | FreePool(NewDefaultName);
|
| 1464 | }
|
| 1465 | ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
|
| 1466 | SHELL_FREE_NON_NULL(HandleList);
|
| 1467 | SHELL_FREE_NON_NULL(DevicePathList);
|
| 1468 |
|
| 1469 | HandleList = NULL;
|
| 1470 | } else {
|
| 1471 | Count = (UINTN)-1;
|
| 1472 | }
|
| 1473 | //
|
| 1474 | // Do it all over again for gEfiBlockIoProtocolGuid
|
| 1475 | //
|
| 1476 |
|
| 1477 | return (Status);
|
| 1478 | }
|
| 1479 |
|
| 1480 | /**
|
| 1481 | Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
|
| 1482 |
|
| 1483 | @param[in] Handle The SHELL_FILE_HANDLE to convert.
|
| 1484 |
|
| 1485 | @return a EFI_FILE_PROTOCOL* representing the same file.
|
| 1486 | **/
|
| 1487 | EFI_FILE_PROTOCOL*
|
| 1488 | EFIAPI
|
| 1489 | ConvertShellHandleToEfiFileProtocol(
|
| 1490 | IN CONST SHELL_FILE_HANDLE Handle
|
| 1491 | )
|
| 1492 | {
|
| 1493 | return ((EFI_FILE_PROTOCOL*)(Handle));
|
| 1494 | }
|
| 1495 |
|
| 1496 | /**
|
| 1497 | Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
|
| 1498 |
|
| 1499 | @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
|
| 1500 | @param[in] Path The path to the file for verification.
|
| 1501 |
|
| 1502 | @return A SHELL_FILE_HANDLE representing the same file.
|
| 1503 | @retval NULL There was not enough memory.
|
| 1504 | **/
|
| 1505 | SHELL_FILE_HANDLE
|
| 1506 | EFIAPI
|
| 1507 | ConvertEfiFileProtocolToShellHandle(
|
| 1508 | IN CONST EFI_FILE_PROTOCOL *Handle,
|
| 1509 | IN CONST CHAR16 *Path
|
| 1510 | )
|
| 1511 | {
|
| 1512 | SHELL_COMMAND_FILE_HANDLE *Buffer;
|
| 1513 | BUFFER_LIST *NewNode;
|
| 1514 |
|
| 1515 | if (Path != NULL) {
|
| 1516 | Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));
|
| 1517 | if (Buffer == NULL) {
|
| 1518 | return (NULL);
|
| 1519 | }
|
| 1520 | NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));
|
| 1521 | if (NewNode == NULL) {
|
| 1522 | SHELL_FREE_NON_NULL(Buffer);
|
| 1523 | return (NULL);
|
| 1524 | }
|
| 1525 | Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;
|
| 1526 | Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);
|
| 1527 | if (Buffer->Path == NULL) {
|
| 1528 | SHELL_FREE_NON_NULL(NewNode);
|
| 1529 | SHELL_FREE_NON_NULL(Buffer);
|
| 1530 | return (NULL);
|
| 1531 | }
|
| 1532 | NewNode->Buffer = Buffer;
|
| 1533 |
|
| 1534 | InsertHeadList(&mFileHandleList.Link, &NewNode->Link);
|
| 1535 | }
|
| 1536 | return ((SHELL_FILE_HANDLE)(Handle));
|
| 1537 | }
|
| 1538 |
|
| 1539 | /**
|
| 1540 | Find the path that was logged with the specified SHELL_FILE_HANDLE.
|
| 1541 |
|
| 1542 | @param[in] Handle The SHELL_FILE_HANDLE to query on.
|
| 1543 |
|
| 1544 | @return A pointer to the path for the file.
|
| 1545 | **/
|
| 1546 | CONST CHAR16*
|
| 1547 | EFIAPI
|
| 1548 | ShellFileHandleGetPath(
|
| 1549 | IN CONST SHELL_FILE_HANDLE Handle
|
| 1550 | )
|
| 1551 | {
|
| 1552 | BUFFER_LIST *Node;
|
| 1553 |
|
| 1554 | for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
|
| 1555 | ; !IsNull(&mFileHandleList.Link, &Node->Link)
|
| 1556 | ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
|
| 1557 | ){
|
| 1558 | if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
|
| 1559 | return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
|
| 1560 | }
|
| 1561 | }
|
| 1562 | return (NULL);
|
| 1563 | }
|
| 1564 |
|
| 1565 | /**
|
| 1566 | Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
|
| 1567 |
|
| 1568 | @param[in] Handle The SHELL_FILE_HANDLE to remove.
|
| 1569 |
|
| 1570 | @retval TRUE The item was removed.
|
| 1571 | @retval FALSE The item was not found.
|
| 1572 | **/
|
| 1573 | BOOLEAN
|
| 1574 | EFIAPI
|
| 1575 | ShellFileHandleRemove(
|
| 1576 | IN CONST SHELL_FILE_HANDLE Handle
|
| 1577 | )
|
| 1578 | {
|
| 1579 | BUFFER_LIST *Node;
|
| 1580 |
|
| 1581 | for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
|
| 1582 | ; !IsNull(&mFileHandleList.Link, &Node->Link)
|
| 1583 | ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
|
| 1584 | ){
|
| 1585 | if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
|
| 1586 | RemoveEntryList(&Node->Link);
|
| 1587 | SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
|
| 1588 | SHELL_FREE_NON_NULL(Node->Buffer);
|
| 1589 | SHELL_FREE_NON_NULL(Node);
|
| 1590 | return (TRUE);
|
| 1591 | }
|
| 1592 | }
|
| 1593 | return (FALSE);
|
| 1594 | }
|
| 1595 |
|
| 1596 | /**
|
| 1597 | Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
|
| 1598 |
|
| 1599 | This will NOT work on directories.
|
| 1600 |
|
| 1601 | If Handle is NULL, then ASSERT.
|
| 1602 |
|
| 1603 | @param[in] Handle the file handle
|
| 1604 |
|
| 1605 | @retval TRUE the position is at the end of the file
|
| 1606 | @retval FALSE the position is not at the end of the file
|
| 1607 | **/
|
| 1608 | BOOLEAN
|
| 1609 | EFIAPI
|
| 1610 | ShellFileHandleEof(
|
| 1611 | IN SHELL_FILE_HANDLE Handle
|
| 1612 | )
|
| 1613 | {
|
| 1614 | EFI_FILE_INFO *Info;
|
| 1615 | UINT64 Pos;
|
| 1616 | BOOLEAN RetVal;
|
| 1617 |
|
| 1618 | //
|
| 1619 | // ASSERT if Handle is NULL
|
| 1620 | //
|
| 1621 | ASSERT(Handle != NULL);
|
| 1622 |
|
| 1623 | gEfiShellProtocol->GetFilePosition(Handle, &Pos);
|
| 1624 | Info = gEfiShellProtocol->GetFileInfo (Handle);
|
| 1625 | ASSERT(Info != NULL);
|
| 1626 | gEfiShellProtocol->SetFilePosition(Handle, Pos);
|
| 1627 |
|
| 1628 | if (Info == NULL) {
|
| 1629 | return (FALSE);
|
| 1630 | }
|
| 1631 |
|
| 1632 | if (Pos == Info->FileSize) {
|
| 1633 | RetVal = TRUE;
|
| 1634 | } else {
|
| 1635 | RetVal = FALSE;
|
| 1636 | }
|
| 1637 |
|
| 1638 | FreePool (Info);
|
| 1639 |
|
| 1640 | return (RetVal);
|
| 1641 | }
|
| 1642 |
|
| 1643 | /**
|
| 1644 | Frees any BUFFER_LIST defined type.
|
| 1645 |
|
| 1646 | @param[in] List The BUFFER_LIST object to free.
|
| 1647 | **/
|
| 1648 | VOID
|
| 1649 | EFIAPI
|
| 1650 | FreeBufferList (
|
| 1651 | IN BUFFER_LIST *List
|
| 1652 | )
|
| 1653 | {
|
| 1654 | BUFFER_LIST *BufferListEntry;
|
| 1655 |
|
| 1656 | if (List == NULL){
|
| 1657 | return;
|
| 1658 | }
|
| 1659 | //
|
| 1660 | // enumerate through the buffer list and free all memory
|
| 1661 | //
|
| 1662 | for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
|
| 1663 | ; !IsListEmpty (&List->Link)
|
| 1664 | ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
|
| 1665 | ){
|
| 1666 | RemoveEntryList(&BufferListEntry->Link);
|
| 1667 | if (BufferListEntry->Buffer != NULL) {
|
| 1668 | FreePool(BufferListEntry->Buffer);
|
| 1669 | }
|
| 1670 | FreePool(BufferListEntry);
|
| 1671 | }
|
| 1672 | }
|
| 1673 |
|