env.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. env.c
  9. Abstract:
  10. This module implements support for environment variables.
  11. Author:
  12. Evan Green 22-Jun-2013
  13. Environment:
  14. User Mode C Library
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "libcp.h"
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. //
  26. // ---------------------------------------------------------------- Definitions
  27. //
  28. //
  29. // Define the initial capacity of the environments array.
  30. //
  31. #define ENVIRONMENT_ARRAY_INITIAL_CAPACITY 16
  32. //
  33. // ------------------------------------------------------ Data Type Definitions
  34. //
  35. //
  36. // ----------------------------------------------- Internal Function Prototypes
  37. //
  38. PSTR
  39. ClpImGetEnvironmentVariable (
  40. PSTR Variable
  41. );
  42. INT
  43. ClpReallocateEnvironment (
  44. VOID
  45. );
  46. //
  47. // -------------------------------------------------------------------- Globals
  48. //
  49. //
  50. // Define the environment.
  51. //
  52. LIBC_API char **environ;
  53. //
  54. // Store a pointer to the last allocated environment and its size.
  55. //
  56. PSTR *ClAllocatedEnvironment = NULL;
  57. ULONG ClAllocatedEnvironmentCapacity = 0;
  58. //
  59. // ------------------------------------------------------------------ Functions
  60. //
  61. LIBC_API
  62. char *
  63. getenv (
  64. const char *Name
  65. )
  66. /*++
  67. Routine Description:
  68. This routine returns the value for the environment variable with the
  69. given name. This function is neither reentrant nor thread safe.
  70. Arguments:
  71. Name - Supplies a pointer to the null terminated string containing the name
  72. of the environment variable to get.
  73. Return Value:
  74. Returns a pointer to the value of the environment variable on success. This
  75. memory may be destroyed by subsequent calls to getenv, setenv, or
  76. unsetenv. The caller does not own it and must not modify or free this
  77. memory.
  78. --*/
  79. {
  80. ULONG Index;
  81. ULONG NameLength;
  82. if ((Name == NULL) || (*Name == '\0') || (environ == NULL)) {
  83. return NULL;
  84. }
  85. Index = 0;
  86. NameLength = strlen(Name);
  87. while (environ[Index] != NULL) {
  88. if ((strncmp(environ[Index], Name, NameLength) == 0) &&
  89. (environ[Index][NameLength] == '=')) {
  90. return environ[Index] + NameLength + 1;
  91. }
  92. Index += 1;
  93. }
  94. return NULL;
  95. }
  96. LIBC_API
  97. int
  98. setenv (
  99. const char *Name,
  100. const char *Value,
  101. int Overwrite
  102. )
  103. /*++
  104. Routine Description:
  105. This routine sets the value for the given environment variable. This
  106. function is neither reentrant nor thread safe.
  107. Arguments:
  108. Name - Supplies a pointer to the null terminated string containing the name
  109. of the environment variable to set. The routine will fail if this
  110. string has an equal in it.
  111. Value - Supplies a pointer to the null terminated string containing the
  112. value to set for this variable.
  113. Overwrite - Supplies an integer that if non-zero will cause an existing
  114. environment variable with the same name to be overwritten. If this is
  115. zero and the given name exists, the function will return successfully
  116. but the value will not be changed.
  117. Return Value:
  118. 0 on success.
  119. -1 on failure, an errno will be set to contain the error code.
  120. --*/
  121. {
  122. ULONG AllocationSize;
  123. ULONG Index;
  124. ULONG NameLength;
  125. INT Result;
  126. PSTR Variable;
  127. if ((Name == NULL) || (*Name == '\0') || (strchr(Name, '=') != NULL)) {
  128. errno = EINVAL;
  129. return -1;
  130. }
  131. if (Value == NULL) {
  132. return unsetenv(Name);
  133. }
  134. //
  135. // Figure out how big this buffer is going to need to be in the form
  136. // name=value.
  137. //
  138. NameLength = strlen(Name);
  139. AllocationSize = NameLength + strlen(Value) + 2;
  140. //
  141. // Look for the environment variable with the given name first. Compare the
  142. // length of the name and make sure there's an equal coming next in the
  143. // existing environment string (as in name=value).
  144. //
  145. Index = 0;
  146. if (environ != NULL) {
  147. while (environ[Index] != NULL) {
  148. if ((strncmp(environ[Index], Name, NameLength) == 0) &&
  149. (environ[Index][NameLength] == '=')) {
  150. break;
  151. }
  152. Index += 1;
  153. }
  154. }
  155. //
  156. // If the environment is not the same as the allocated environment or the
  157. // allocated one is full, allocate a new environment array.
  158. //
  159. if ((environ != ClAllocatedEnvironment) ||
  160. ((Index + 1) >= ClAllocatedEnvironmentCapacity)) {
  161. Result = ClpReallocateEnvironment();
  162. if (Result != 0) {
  163. errno = Result;
  164. return -1;
  165. }
  166. }
  167. //
  168. // If the variable exists, don't replace it if the user doesn't want to.
  169. //
  170. if ((environ[Index] != NULL) && (Overwrite == 0)) {
  171. return 0;
  172. }
  173. //
  174. // Allocate a new variable string.
  175. //
  176. Variable = malloc(AllocationSize);
  177. if (Variable == NULL) {
  178. errno = ENOMEM;
  179. return -1;
  180. }
  181. snprintf(Variable, AllocationSize, "%s=%s", Name, Value);
  182. //
  183. // Replacing is easy (but leaky, unfortunately by necessity).
  184. //
  185. if (environ[Index] != NULL) {
  186. environ[Index] = Variable;
  187. return 0;
  188. }
  189. assert((Index + 1) < ClAllocatedEnvironmentCapacity);
  190. //
  191. // Expanding when there's room is also easy.
  192. //
  193. environ[Index] = Variable;
  194. environ[Index + 1] = NULL;
  195. return 0;
  196. }
  197. LIBC_API
  198. int
  199. putenv (
  200. char *String
  201. )
  202. /*++
  203. Routine Description:
  204. This routine adds the given string to the environment list.
  205. Arguments:
  206. String - Supplies a pointer to the null terminated string in the form
  207. "name=value". This string will become part of the environment, if it
  208. is modified then that modification will be reflected in the
  209. environment. The memory supplied in this argument is used directly, so
  210. the argument must not be automatically allocated. If the given string
  211. contains no equal sign, then the functionality is equivalent to
  212. unsetenv with the given string.
  213. Return Value:
  214. 0 on success.
  215. -1 on failure, and errno will be set to contain more information.
  216. --*/
  217. {
  218. PSTR Equals;
  219. ULONG Index;
  220. ULONG NameLength;
  221. BOOL Remove;
  222. INT Result;
  223. if (String == NULL) {
  224. errno = EINVAL;
  225. return -1;
  226. }
  227. Remove = FALSE;
  228. //
  229. // This function is pretty sketchy, but at least try to replace an
  230. // existing variable if the input is in the right format.
  231. //
  232. NameLength = 0;
  233. Equals = strchr(String, '=');
  234. if (Equals != NULL) {
  235. NameLength = (UINTN)Equals - (UINTN)String;
  236. if (*(Equals + 1) == '\0') {
  237. Remove = TRUE;
  238. }
  239. }
  240. if (NameLength == 0) {
  241. errno = EINVAL;
  242. return -1;
  243. }
  244. //
  245. // Look for the environment variable with the given name first. Compare the
  246. // length of the name and make sure there's an equal coming next in the
  247. // existing environment string (as in name=value).
  248. //
  249. Index = 0;
  250. if (environ != NULL) {
  251. while (environ[Index] != NULL) {
  252. if ((strncmp(environ[Index], String, NameLength) == 0) &&
  253. (environ[Index][NameLength] == '=')) {
  254. if (Remove != FALSE) {
  255. //
  256. // Move all the other entries down, removing (and leaking)
  257. // this one.
  258. //
  259. while (TRUE) {
  260. environ[Index] = environ[Index + 1];
  261. if (environ[Index] == NULL) {
  262. break;
  263. }
  264. Index += 1;
  265. }
  266. } else {
  267. //
  268. // Replace this entry with the new value. Leak the old value
  269. // intentionally, as it's unknown where it came from.
  270. //
  271. environ[Index] = String;
  272. }
  273. return 0;
  274. }
  275. Index += 1;
  276. }
  277. }
  278. if (Remove != FALSE) {
  279. return 0;
  280. }
  281. //
  282. // If the environment is not the same as the allocated environment or the
  283. // allocated one is full, allocate a new environment array.
  284. //
  285. if ((environ != ClAllocatedEnvironment) ||
  286. ((Index + 1) >= ClAllocatedEnvironmentCapacity)) {
  287. Result = ClpReallocateEnvironment();
  288. if (Result != 0) {
  289. errno = Result;
  290. return -1;
  291. }
  292. }
  293. //
  294. // Add the name of the end.
  295. //
  296. environ[Index] = String;
  297. Index += 1;
  298. environ[Index] = NULL;
  299. return 0;
  300. }
  301. LIBC_API
  302. int
  303. unsetenv (
  304. const char *Name
  305. )
  306. /*++
  307. Routine Description:
  308. This routine removes the environment variable with the given name from
  309. the current environment. This routine is neither re-entrant nor thread safe.
  310. Arguments:
  311. Name - Supplies a pointer to the name of the variable to unset. This
  312. string must not have an equals '=' in it.
  313. Return Value:
  314. 0 on success (whether or not the environment variable previously existed).
  315. -1 on failure, and errno will be set to contain more information. Errno is
  316. commonly set to EINVAL if the argument is a null pointer, an empty string,
  317. or contains an equals.
  318. --*/
  319. {
  320. ULONG Index;
  321. ULONG MoveIndex;
  322. ULONG NameLength;
  323. if ((Name == NULL) || (*Name == '\0') || (strchr(Name, '=') != NULL)) {
  324. errno = EINVAL;
  325. return -1;
  326. }
  327. if (environ == NULL) {
  328. return 0;
  329. }
  330. NameLength = strlen(Name);
  331. //
  332. // Loop through looking for the variable.
  333. //
  334. Index = 0;
  335. while (environ[Index] != NULL) {
  336. if ((strncmp(environ[Index], Name, NameLength) == 0) &&
  337. (environ[Index][NameLength] == '=')) {
  338. //
  339. // Move all other environment variables up one.
  340. //
  341. MoveIndex = Index;
  342. while (environ[MoveIndex] != NULL) {
  343. environ[MoveIndex] = environ[MoveIndex + 1];
  344. MoveIndex += 1;
  345. }
  346. //
  347. // Keep looking for this environment variable name, as the user
  348. // may have edited multiple variables in themselves.
  349. //
  350. continue;
  351. }
  352. Index += 1;
  353. }
  354. return 0;
  355. }
  356. LIBC_API
  357. const char *
  358. getexecname (
  359. void
  360. )
  361. /*++
  362. Routine Description:
  363. This routine returns the path name of the executable.
  364. Arguments:
  365. None.
  366. Return Value:
  367. Returns a pointer to the pathname of the executable on success. The caller
  368. must not alter this memory.
  369. --*/
  370. {
  371. PPROCESS_ENVIRONMENT Environment;
  372. Environment = OsGetCurrentEnvironment();
  373. return Environment->ImageName;
  374. }
  375. VOID
  376. ClpInitializeEnvironment (
  377. VOID
  378. )
  379. /*++
  380. Routine Description:
  381. This routine initializes the environment variable support in the C library.
  382. Arguments:
  383. None.
  384. Return Value:
  385. None.
  386. --*/
  387. {
  388. PPROCESS_ENVIRONMENT Environment;
  389. OsImGetEnvironmentVariable = ClpImGetEnvironmentVariable;
  390. Environment = OsGetCurrentEnvironment();
  391. environ = Environment->Environment;
  392. return;
  393. }
  394. //
  395. // --------------------------------------------------------- Internal Functions
  396. //
  397. PSTR
  398. ClpImGetEnvironmentVariable (
  399. PSTR Variable
  400. )
  401. /*++
  402. Routine Description:
  403. This routine gets an environment variable value for the image library.
  404. Arguments:
  405. Variable - Supplies a pointer to a null terminated string containing the
  406. name of the variable to get.
  407. Return Value:
  408. Returns a pointer to the value of the environment variable. The image
  409. library will not free or modify this value.
  410. NULL if the given environment variable is not set.
  411. --*/
  412. {
  413. return getenv(Variable);
  414. }
  415. INT
  416. ClpReallocateEnvironment (
  417. VOID
  418. )
  419. /*++
  420. Routine Description:
  421. This routine reallocates the environment variables, either copying the
  422. existing allocated variables into an expanded buffer or copying in the
  423. user-supplied variables.
  424. Arguments:
  425. None.
  426. Return Value:
  427. 0 on success.
  428. ENOMEM if insufficient memory was available to add the variable.
  429. --*/
  430. {
  431. ULONG Count;
  432. PSTR *NewEnvironment;
  433. ULONG NewEnvironmentCapacity;
  434. //
  435. // If there is a user environment that has yet to been copied here, then
  436. // base the size off the user environment.
  437. //
  438. Count = 0;
  439. if ((environ != NULL) && (environ != ClAllocatedEnvironment)) {
  440. ASSERT(ClAllocatedEnvironment == NULL);
  441. while (environ[Count] != NULL) {
  442. Count += 1;
  443. }
  444. NewEnvironmentCapacity = Count * 2;
  445. }
  446. //
  447. // If there was no existing environment, or it was empty, use the initial
  448. // capacity or base the new size off of the existing size.
  449. //
  450. if (Count == 0) {
  451. if (ClAllocatedEnvironment == NULL) {
  452. ASSERT(ClAllocatedEnvironmentCapacity == 0);
  453. NewEnvironmentCapacity = ENVIRONMENT_ARRAY_INITIAL_CAPACITY;
  454. } else {
  455. NewEnvironmentCapacity = ClAllocatedEnvironmentCapacity * 2;
  456. }
  457. }
  458. if (NewEnvironmentCapacity < ENVIRONMENT_ARRAY_INITIAL_CAPACITY) {
  459. NewEnvironmentCapacity = ENVIRONMENT_ARRAY_INITIAL_CAPACITY;
  460. }
  461. //
  462. // The capacity does not include room for the NULL terminator, so always
  463. // allocate an extra space.
  464. //
  465. NewEnvironment = realloc(ClAllocatedEnvironment,
  466. (NewEnvironmentCapacity + 1) * sizeof(char *));
  467. if (NewEnvironment == NULL) {
  468. return ENOMEM;
  469. }
  470. //
  471. // If there is a user environment, copy said environment and add the
  472. // null-terminator.
  473. //
  474. if ((environ != NULL) && (environ != ClAllocatedEnvironment)) {
  475. memcpy(NewEnvironment, environ, Count * sizeof(char *));
  476. NewEnvironment[Count] = NULL;
  477. //
  478. // Otherwise, just null terminate if this is the first time the environment
  479. // has been allocated. If realloc copied an existing environment above then
  480. // it should have copied the null-terminator along with it.
  481. //
  482. } else if (environ == NULL) {
  483. NewEnvironment[0] = NULL;
  484. }
  485. //
  486. // Update the global variables.
  487. //
  488. ClAllocatedEnvironmentCapacity = NewEnvironmentCapacity;
  489. ClAllocatedEnvironment = NewEnvironment;
  490. environ = NewEnvironment;
  491. return 0;
  492. }