ShellEnvVar.c 16 KB

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