Home | History | Annotate | Download | only in Shell
      1 /** @file
      2   function declarations for shell environment functions.
      3 
      4   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Shell.h"
     16 
     17 #define INIT_NAME_BUFFER_SIZE  128
     18 #define INIT_DATA_BUFFER_SIZE  1024
     19 
     20 //
     21 // The list is used to cache the environment variables.
     22 //
     23 ENV_VAR_LIST                   gShellEnvVarList;
     24 
     25 /**
     26   Reports whether an environment variable is Volatile or Non-Volatile.
     27 
     28   @param EnvVarName             The name of the environment variable in question
     29   @param Volatile               Return TRUE if the environment variable is volatile
     30 
     31   @retval EFI_SUCCESS           The volatile attribute is returned successfully
     32   @retval others                Some errors happened.
     33 **/
     34 EFI_STATUS
     35 IsVolatileEnv (
     36   IN CONST CHAR16 *EnvVarName,
     37   OUT BOOLEAN     *Volatile
     38   )
     39 {
     40   EFI_STATUS  Status;
     41   UINTN       Size;
     42   VOID        *Buffer;
     43   UINT32      Attribs;
     44 
     45   ASSERT (Volatile != NULL);
     46 
     47   Size = 0;
     48   Buffer = NULL;
     49 
     50   //
     51   // get the variable
     52   //
     53   Status = gRT->GetVariable((CHAR16*)EnvVarName,
     54                             &gShellVariableGuid,
     55                             &Attribs,
     56                             &Size,
     57                             Buffer);
     58   if (Status == EFI_BUFFER_TOO_SMALL) {
     59     Buffer = AllocateZeroPool(Size);
     60     if (Buffer == NULL) {
     61       return EFI_OUT_OF_RESOURCES;
     62     }
     63     Status = gRT->GetVariable((CHAR16*)EnvVarName,
     64                               &gShellVariableGuid,
     65                               &Attribs,
     66                               &Size,
     67                               Buffer);
     68     FreePool(Buffer);
     69   }
     70   //
     71   // not found means volatile
     72   //
     73   if (Status == EFI_NOT_FOUND) {
     74     *Volatile = TRUE;
     75     return EFI_SUCCESS;
     76   }
     77   if (EFI_ERROR (Status)) {
     78     return Status;
     79   }
     80 
     81   //
     82   // check for the Non Volatile bit
     83   //
     84   *Volatile = !(BOOLEAN) ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE);
     85   return EFI_SUCCESS;
     86 }
     87 
     88 /**
     89   free function for ENV_VAR_LIST objects.
     90 
     91   @param[in] List               The pointer to pointer to list.
     92 **/
     93 VOID
     94 FreeEnvironmentVariableList(
     95   IN LIST_ENTRY *List
     96   )
     97 {
     98   ENV_VAR_LIST *Node;
     99 
    100   ASSERT (List != NULL);
    101   if (List == NULL) {
    102     return;
    103   }
    104 
    105   for ( Node = (ENV_VAR_LIST*)GetFirstNode(List)
    106       ; !IsListEmpty(List)
    107       ; Node = (ENV_VAR_LIST*)GetFirstNode(List)
    108      ){
    109     ASSERT(Node != NULL);
    110     RemoveEntryList(&Node->Link);
    111     if (Node->Key != NULL) {
    112       FreePool(Node->Key);
    113     }
    114     if (Node->Val != NULL) {
    115       FreePool(Node->Val);
    116     }
    117     FreePool(Node);
    118   }
    119 }
    120 
    121 /**
    122   Creates a list of all Shell-Guid-based environment variables.
    123 
    124   @param[in, out] ListHead       The pointer to pointer to LIST ENTRY object for
    125                                  storing this list.
    126 
    127   @retval EFI_SUCCESS           the list was created sucessfully.
    128 **/
    129 EFI_STATUS
    130 GetEnvironmentVariableList(
    131   IN OUT LIST_ENTRY *ListHead
    132   )
    133 {
    134   CHAR16            *VariableName;
    135   UINTN             NameSize;
    136   UINTN             NameBufferSize;
    137   EFI_STATUS        Status;
    138   EFI_GUID          Guid;
    139   UINTN             ValSize;
    140   UINTN             ValBufferSize;
    141   ENV_VAR_LIST      *VarList;
    142 
    143   if (ListHead == NULL) {
    144     return (EFI_INVALID_PARAMETER);
    145   }
    146 
    147   Status = EFI_SUCCESS;
    148 
    149   ValBufferSize = INIT_DATA_BUFFER_SIZE;
    150   NameBufferSize = INIT_NAME_BUFFER_SIZE;
    151   VariableName = AllocateZeroPool(NameBufferSize);
    152   if (VariableName == NULL) {
    153     return (EFI_OUT_OF_RESOURCES);
    154   }
    155   *VariableName = CHAR_NULL;
    156 
    157   while (!EFI_ERROR(Status)) {
    158     NameSize = NameBufferSize;
    159     Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);
    160     if (Status == EFI_NOT_FOUND){
    161       Status = EFI_SUCCESS;
    162       break;
    163     } else if (Status == EFI_BUFFER_TOO_SMALL) {
    164       NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;
    165       SHELL_FREE_NON_NULL(VariableName);
    166       VariableName = AllocateZeroPool(NameBufferSize);
    167       if (VariableName == NULL) {
    168         Status = EFI_OUT_OF_RESOURCES;
    169         break;
    170       }
    171       NameSize = NameBufferSize;
    172       Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);
    173     }
    174 
    175     if (!EFI_ERROR(Status) && CompareGuid(&Guid, &gShellVariableGuid)){
    176       VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));
    177       if (VarList == NULL) {
    178         Status = EFI_OUT_OF_RESOURCES;
    179       } else {
    180         ValSize = ValBufferSize;
    181         //
    182         // We need another CHAR16 to save '\0' in VarList->Val.
    183         //
    184         VarList->Val = AllocateZeroPool (ValSize + sizeof (CHAR16));
    185         if (VarList->Val == NULL) {
    186             SHELL_FREE_NON_NULL(VarList);
    187             Status = EFI_OUT_OF_RESOURCES;
    188             break;
    189         }
    190         Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);
    191         if (Status == EFI_BUFFER_TOO_SMALL){
    192           ValBufferSize = ValSize > ValBufferSize * 2 ? ValSize : ValBufferSize * 2;
    193           SHELL_FREE_NON_NULL (VarList->Val);
    194           //
    195           // We need another CHAR16 to save '\0' in VarList->Val.
    196           //
    197           VarList->Val = AllocateZeroPool (ValBufferSize + sizeof (CHAR16));
    198           if (VarList->Val == NULL) {
    199             SHELL_FREE_NON_NULL(VarList);
    200             Status = EFI_OUT_OF_RESOURCES;
    201             break;
    202           }
    203 
    204           ValSize = ValBufferSize;
    205           Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);
    206         }
    207         if (!EFI_ERROR(Status)) {
    208           VarList->Key = AllocateCopyPool(StrSize(VariableName), VariableName);
    209           if (VarList->Key == NULL) {
    210             SHELL_FREE_NON_NULL(VarList->Val);
    211             SHELL_FREE_NON_NULL(VarList);
    212             Status = EFI_OUT_OF_RESOURCES;
    213           } else {
    214             InsertTailList(ListHead, &VarList->Link);
    215           }
    216         } else {
    217           SHELL_FREE_NON_NULL(VarList->Val);
    218           SHELL_FREE_NON_NULL(VarList);
    219         }
    220       } // if (VarList == NULL) ... else ...
    221     } // compare guid
    222   } // while
    223   SHELL_FREE_NON_NULL (VariableName);
    224 
    225   if (EFI_ERROR(Status)) {
    226     FreeEnvironmentVariableList(ListHead);
    227   }
    228 
    229   return (Status);
    230 }
    231 
    232 /**
    233   Sets a list of all Shell-Guid-based environment variables.  this will
    234   also eliminate all existing shell environment variables (even if they
    235   are not on the list).
    236 
    237   This function will also deallocate the memory from List.
    238 
    239   @param[in] ListHead           The pointer to LIST_ENTRY from
    240                                 GetShellEnvVarList().
    241 
    242   @retval EFI_SUCCESS           the list was Set sucessfully.
    243 **/
    244 EFI_STATUS
    245 SetEnvironmentVariableList(
    246   IN LIST_ENTRY *ListHead
    247   )
    248 {
    249   ENV_VAR_LIST      VarList;
    250   ENV_VAR_LIST      *Node;
    251   EFI_STATUS        Status;
    252   UINTN             Size;
    253 
    254   InitializeListHead(&VarList.Link);
    255 
    256   //
    257   // Delete all the current environment variables
    258   //
    259   Status = GetEnvironmentVariableList(&VarList.Link);
    260   ASSERT_EFI_ERROR(Status);
    261 
    262   for ( Node = (ENV_VAR_LIST*)GetFirstNode(&VarList.Link)
    263       ; !IsNull(&VarList.Link, &Node->Link)
    264       ; Node = (ENV_VAR_LIST*)GetNextNode(&VarList.Link, &Node->Link)
    265      ){
    266     if (Node->Key != NULL) {
    267       Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Node->Key);
    268     }
    269     ASSERT_EFI_ERROR(Status);
    270   }
    271 
    272   FreeEnvironmentVariableList(&VarList.Link);
    273 
    274   //
    275   // set all the variables fron the list
    276   //
    277   for ( Node = (ENV_VAR_LIST*)GetFirstNode(ListHead)
    278       ; !IsNull(ListHead, &Node->Link)
    279       ; Node = (ENV_VAR_LIST*)GetNextNode(ListHead, &Node->Link)
    280      ){
    281     Size = StrSize (Node->Val) - sizeof (CHAR16);
    282     if (Node->Atts & EFI_VARIABLE_NON_VOLATILE) {
    283       Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Node->Key, Size, Node->Val);
    284     } else {
    285       Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (Node->Key, Size, Node->Val);
    286     }
    287     ASSERT_EFI_ERROR(Status);
    288   }
    289   FreeEnvironmentVariableList(ListHead);
    290 
    291   return (Status);
    292 }
    293 
    294 /**
    295   sets a list of all Shell-Guid-based environment variables.
    296 
    297   @param Environment        Points to a NULL-terminated array of environment
    298                             variables with the format 'x=y', where x is the
    299                             environment variable name and y is the value.
    300 
    301   @retval EFI_SUCCESS       The command executed successfully.
    302   @retval EFI_INVALID_PARAMETER The parameter is invalid.
    303   @retval EFI_OUT_OF_RESOURCES Out of resources.
    304 
    305   @sa SetEnvironmentVariableList
    306 **/
    307 EFI_STATUS
    308 SetEnvironmentVariables(
    309   IN CONST CHAR16 **Environment
    310   )
    311 {
    312   CONST CHAR16  *CurrentString;
    313   UINTN         CurrentCount;
    314   ENV_VAR_LIST  *VarList;
    315   ENV_VAR_LIST  *Node;
    316 
    317   VarList = NULL;
    318 
    319   if (Environment == NULL) {
    320     return (EFI_INVALID_PARAMETER);
    321   }
    322 
    323   //
    324   // Build a list identical to the ones used for get/set list functions above
    325   //
    326   for ( CurrentCount = 0
    327       ;
    328       ; CurrentCount++
    329      ){
    330     CurrentString = Environment[CurrentCount];
    331     if (CurrentString == NULL) {
    332       break;
    333     }
    334     ASSERT(StrStr(CurrentString, L"=") != NULL);
    335     Node = AllocateZeroPool(sizeof(ENV_VAR_LIST));
    336     if (Node == NULL) {
    337       SetEnvironmentVariableList(&VarList->Link);
    338       return (EFI_OUT_OF_RESOURCES);
    339     }
    340 
    341     Node->Key = AllocateZeroPool((StrStr(CurrentString, L"=") - CurrentString + 1) * sizeof(CHAR16));
    342     if (Node->Key == NULL) {
    343       SHELL_FREE_NON_NULL(Node);
    344       SetEnvironmentVariableList(&VarList->Link);
    345       return (EFI_OUT_OF_RESOURCES);
    346     }
    347 
    348     //
    349     // Copy the string into the Key, leaving the last character allocated as NULL to terminate
    350     //
    351     StrnCpyS( Node->Key,
    352               StrStr(CurrentString, L"=") - CurrentString + 1,
    353               CurrentString,
    354               StrStr(CurrentString, L"=") - CurrentString
    355               );
    356 
    357     //
    358     // ValueSize = TotalSize - already removed size - size for '=' + size for terminator (the last 2 items cancel each other)
    359     //
    360     Node->Val = AllocateCopyPool(StrSize(CurrentString) - StrSize(Node->Key), CurrentString + StrLen(Node->Key) + 1);
    361     if (Node->Val == NULL) {
    362       SHELL_FREE_NON_NULL(Node->Key);
    363       SHELL_FREE_NON_NULL(Node);
    364       SetEnvironmentVariableList(&VarList->Link);
    365       return (EFI_OUT_OF_RESOURCES);
    366     }
    367 
    368     Node->Atts = EFI_VARIABLE_BOOTSERVICE_ACCESS;
    369 
    370     if (VarList == NULL) {
    371       VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));
    372       if (VarList == NULL) {
    373         SHELL_FREE_NON_NULL(Node->Key);
    374         SHELL_FREE_NON_NULL(Node->Val);
    375         SHELL_FREE_NON_NULL(Node);
    376         return (EFI_OUT_OF_RESOURCES);
    377       }
    378       InitializeListHead(&VarList->Link);
    379     }
    380     InsertTailList(&VarList->Link, &Node->Link);
    381 
    382   } // for loop
    383 
    384   //
    385   // set this new list as the set of all environment variables.
    386   // this function also frees the memory and deletes all pre-existing
    387   // shell-guid based environment variables.
    388   //
    389   return (SetEnvironmentVariableList(&VarList->Link));
    390 }
    391 
    392 /**
    393   Find an environment variable in the gShellEnvVarList.
    394 
    395   @param Key        The name of the environment variable.
    396   @param Value      The value of the environment variable, the buffer
    397                     shoule be freed by the caller.
    398   @param ValueSize  The size in bytes of the environment variable
    399                     including the tailing CHAR_NELL.
    400   @param Atts       The attributes of the variable.
    401 
    402   @retval EFI_SUCCESS       The command executed successfully.
    403   @retval EFI_NOT_FOUND     The environment variable is not found in
    404                             gShellEnvVarList.
    405 
    406 **/
    407 EFI_STATUS
    408 ShellFindEnvVarInList (
    409   IN  CONST CHAR16    *Key,
    410   OUT CHAR16          **Value,
    411   OUT UINTN           *ValueSize,
    412   OUT UINT32          *Atts OPTIONAL
    413   )
    414 {
    415   ENV_VAR_LIST      *Node;
    416 
    417   if (Key == NULL || Value == NULL || ValueSize == NULL) {
    418     return SHELL_INVALID_PARAMETER;
    419   }
    420 
    421   for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)
    422       ; !IsNull(&gShellEnvVarList.Link, &Node->Link)
    423       ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)
    424      ){
    425     if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {
    426       *Value      = AllocateCopyPool(StrSize(Node->Val), Node->Val);
    427       *ValueSize  = StrSize(Node->Val);
    428       if (Atts != NULL) {
    429         *Atts = Node->Atts;
    430       }
    431       return EFI_SUCCESS;
    432     }
    433   }
    434 
    435   return EFI_NOT_FOUND;
    436 }
    437 
    438 /**
    439   Add an environment variable into gShellEnvVarList.
    440 
    441   @param Key        The name of the environment variable.
    442   @param Value      The value of environment variable.
    443   @param ValueSize  The size in bytes of the environment variable
    444                     including the tailing CHAR_NULL
    445   @param Atts       The attributes of the variable.
    446 
    447   @retval EFI_SUCCESS  The environment variable was added to list successfully.
    448   @retval others       Some errors happened.
    449 
    450 **/
    451 EFI_STATUS
    452 ShellAddEnvVarToList (
    453   IN CONST CHAR16     *Key,
    454   IN CONST CHAR16     *Value,
    455   IN UINTN            ValueSize,
    456   IN UINT32           Atts
    457   )
    458 {
    459   ENV_VAR_LIST      *Node;
    460   CHAR16            *LocalKey;
    461   CHAR16            *LocalValue;
    462 
    463   if (Key == NULL || Value == NULL || ValueSize == 0) {
    464     return EFI_INVALID_PARAMETER;
    465   }
    466 
    467   LocalValue = AllocateCopyPool (ValueSize, Value);
    468   if (LocalValue == NULL) {
    469     return EFI_OUT_OF_RESOURCES;
    470   }
    471 
    472   //
    473   // Update the variable value if it exists in gShellEnvVarList.
    474   //
    475   for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)
    476       ; !IsNull(&gShellEnvVarList.Link, &Node->Link)
    477       ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)
    478      ){
    479     if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {
    480       Node->Atts = Atts;
    481       SHELL_FREE_NON_NULL(Node->Val);
    482       Node->Val  = LocalValue;
    483       return EFI_SUCCESS;
    484     }
    485   }
    486 
    487   //
    488   // If the environment varialbe key doesn't exist in list just insert
    489   // a new node.
    490   //
    491   LocalKey = AllocateCopyPool (StrSize(Key), Key);
    492   if (LocalKey == NULL) {
    493     FreePool (LocalValue);
    494     return EFI_OUT_OF_RESOURCES;
    495   }
    496   Node = (ENV_VAR_LIST*)AllocateZeroPool (sizeof(ENV_VAR_LIST));
    497   if (Node == NULL) {
    498     FreePool (LocalKey);
    499     FreePool (LocalValue);
    500     return EFI_OUT_OF_RESOURCES;
    501   }
    502   Node->Key = LocalKey;
    503   Node->Val = LocalValue;
    504   Node->Atts = Atts;
    505   InsertTailList(&gShellEnvVarList.Link, &Node->Link);
    506 
    507   return EFI_SUCCESS;
    508 }
    509 
    510 /**
    511   Remove a specified environment variable in gShellEnvVarList.
    512 
    513   @param Key        The name of the environment variable.
    514 
    515   @retval EFI_SUCCESS       The command executed successfully.
    516   @retval EFI_NOT_FOUND     The environment variable is not found in
    517                             gShellEnvVarList.
    518 **/
    519 EFI_STATUS
    520 ShellRemvoeEnvVarFromList (
    521   IN CONST CHAR16           *Key
    522   )
    523 {
    524   ENV_VAR_LIST      *Node;
    525 
    526   if (Key == NULL) {
    527     return EFI_INVALID_PARAMETER;
    528   }
    529 
    530   for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)
    531       ; !IsNull(&gShellEnvVarList.Link, &Node->Link)
    532       ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)
    533      ){
    534     if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {
    535       SHELL_FREE_NON_NULL(Node->Key);
    536       SHELL_FREE_NON_NULL(Node->Val);
    537       RemoveEntryList(&Node->Link);
    538       SHELL_FREE_NON_NULL(Node);
    539       return EFI_SUCCESS;
    540     }
    541   }
    542 
    543   return EFI_NOT_FOUND;
    544 }
    545 
    546 /**
    547   Initialize the gShellEnvVarList and cache all Shell-Guid-based environment
    548   variables.
    549 
    550 **/
    551 EFI_STATUS
    552 ShellInitEnvVarList (
    553   VOID
    554   )
    555 {
    556   EFI_STATUS    Status;
    557 
    558   InitializeListHead(&gShellEnvVarList.Link);
    559   Status = GetEnvironmentVariableList (&gShellEnvVarList.Link);
    560 
    561   return Status;
    562 }
    563 
    564 /**
    565   Destructe the gShellEnvVarList.
    566 
    567 **/
    568 VOID
    569 ShellFreeEnvVarList (
    570   VOID
    571   )
    572 {
    573   FreeEnvironmentVariableList (&gShellEnvVarList.Link);
    574   InitializeListHead(&gShellEnvVarList.Link);
    575 
    576   return;
    577 }
    578 
    579