123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- /*++
- Copyright (c) 2013 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- env.c
- Abstract:
- This module implements support for environment variables.
- Author:
- Evan Green 22-Jun-2013
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "libcp.h"
- #include <assert.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the initial capacity of the environments array.
- //
- #define ENVIRONMENT_ARRAY_INITIAL_CAPACITY 16
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- PSTR
- ClpImGetEnvironmentVariable (
- PSTR Variable
- );
- INT
- ClpReallocateEnvironment (
- VOID
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Define the environment.
- //
- LIBC_API char **environ;
- //
- // Store a pointer to the last allocated environment and its size.
- //
- PSTR *ClAllocatedEnvironment = NULL;
- ULONG ClAllocatedEnvironmentCapacity = 0;
- //
- // ------------------------------------------------------------------ Functions
- //
- LIBC_API
- char *
- getenv (
- const char *Name
- )
- /*++
- Routine Description:
- This routine returns the value for the environment variable with the
- given name. This function is neither reentrant nor thread safe.
- Arguments:
- Name - Supplies a pointer to the null terminated string containing the name
- of the environment variable to get.
- Return Value:
- Returns a pointer to the value of the environment variable on success. This
- memory may be destroyed by subsequent calls to getenv, setenv, or
- unsetenv. The caller does not own it and must not modify or free this
- memory.
- --*/
- {
- ULONG Index;
- ULONG NameLength;
- if ((Name == NULL) || (*Name == '\0') || (environ == NULL)) {
- return NULL;
- }
- Index = 0;
- NameLength = strlen(Name);
- while (environ[Index] != NULL) {
- if ((strncmp(environ[Index], Name, NameLength) == 0) &&
- (environ[Index][NameLength] == '=')) {
- return environ[Index] + NameLength + 1;
- }
- Index += 1;
- }
- return NULL;
- }
- LIBC_API
- int
- setenv (
- const char *Name,
- const char *Value,
- int Overwrite
- )
- /*++
- Routine Description:
- This routine sets the value for the given environment variable. This
- function is neither reentrant nor thread safe.
- Arguments:
- Name - Supplies a pointer to the null terminated string containing the name
- of the environment variable to set. The routine will fail if this
- string has an equal in it.
- Value - Supplies a pointer to the null terminated string containing the
- value to set for this variable.
- Overwrite - Supplies an integer that if non-zero will cause an existing
- environment variable with the same name to be overwritten. If this is
- zero and the given name exists, the function will return successfully
- but the value will not be changed.
- Return Value:
- 0 on success.
- -1 on failure, an errno will be set to contain the error code.
- --*/
- {
- ULONG AllocationSize;
- ULONG Index;
- ULONG NameLength;
- INT Result;
- PSTR Variable;
- if ((Name == NULL) || (*Name == '\0') || (strchr(Name, '=') != NULL)) {
- errno = EINVAL;
- return -1;
- }
- if (Value == NULL) {
- return unsetenv(Name);
- }
- //
- // Figure out how big this buffer is going to need to be in the form
- // name=value.
- //
- NameLength = strlen(Name);
- AllocationSize = NameLength + strlen(Value) + 2;
- //
- // Look for the environment variable with the given name first. Compare the
- // length of the name and make sure there's an equal coming next in the
- // existing environment string (as in name=value).
- //
- Index = 0;
- if (environ != NULL) {
- while (environ[Index] != NULL) {
- if ((strncmp(environ[Index], Name, NameLength) == 0) &&
- (environ[Index][NameLength] == '=')) {
- break;
- }
- Index += 1;
- }
- }
- //
- // If the environment is not the same as the allocated environment or the
- // allocated one is full, allocate a new environment array.
- //
- if ((environ != ClAllocatedEnvironment) ||
- ((Index + 1) >= ClAllocatedEnvironmentCapacity)) {
- Result = ClpReallocateEnvironment();
- if (Result != 0) {
- errno = Result;
- return -1;
- }
- }
- //
- // If the variable exists, don't replace it if the user doesn't want to.
- //
- if ((environ[Index] != NULL) && (Overwrite == 0)) {
- return 0;
- }
- //
- // Allocate a new variable string.
- //
- Variable = malloc(AllocationSize);
- if (Variable == NULL) {
- errno = ENOMEM;
- return -1;
- }
- snprintf(Variable, AllocationSize, "%s=%s", Name, Value);
- //
- // Replacing is easy (but leaky, unfortunately by necessity).
- //
- if (environ[Index] != NULL) {
- environ[Index] = Variable;
- return 0;
- }
- assert((Index + 1) < ClAllocatedEnvironmentCapacity);
- //
- // Expanding when there's room is also easy.
- //
- environ[Index] = Variable;
- environ[Index + 1] = NULL;
- return 0;
- }
- LIBC_API
- int
- putenv (
- char *String
- )
- /*++
- Routine Description:
- This routine adds the given string to the environment list.
- Arguments:
- String - Supplies a pointer to the null terminated string in the form
- "name=value". This string will become part of the environment, if it
- is modified then that modification will be reflected in the
- environment. The memory supplied in this argument is used directly, so
- the argument must not be automatically allocated. If the given string
- contains no equal sign, then the functionality is equivalent to
- unsetenv with the given string.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- PSTR Equals;
- ULONG Index;
- ULONG NameLength;
- BOOL Remove;
- INT Result;
- if (String == NULL) {
- errno = EINVAL;
- return -1;
- }
- Remove = FALSE;
- //
- // This function is pretty sketchy, but at least try to replace an
- // existing variable if the input is in the right format.
- //
- NameLength = 0;
- Equals = strchr(String, '=');
- if (Equals != NULL) {
- NameLength = (UINTN)Equals - (UINTN)String;
- if (*(Equals + 1) == '\0') {
- Remove = TRUE;
- }
- }
- if (NameLength == 0) {
- errno = EINVAL;
- return -1;
- }
- //
- // Look for the environment variable with the given name first. Compare the
- // length of the name and make sure there's an equal coming next in the
- // existing environment string (as in name=value).
- //
- Index = 0;
- if (environ != NULL) {
- while (environ[Index] != NULL) {
- if ((strncmp(environ[Index], String, NameLength) == 0) &&
- (environ[Index][NameLength] == '=')) {
- if (Remove != FALSE) {
- //
- // Move all the other entries down, removing (and leaking)
- // this one.
- //
- while (TRUE) {
- environ[Index] = environ[Index + 1];
- if (environ[Index] == NULL) {
- break;
- }
- Index += 1;
- }
- } else {
- //
- // Replace this entry with the new value. Leak the old value
- // intentionally, as it's unknown where it came from.
- //
- environ[Index] = String;
- }
- return 0;
- }
- Index += 1;
- }
- }
- if (Remove != FALSE) {
- return 0;
- }
- //
- // If the environment is not the same as the allocated environment or the
- // allocated one is full, allocate a new environment array.
- //
- if ((environ != ClAllocatedEnvironment) ||
- ((Index + 1) >= ClAllocatedEnvironmentCapacity)) {
- Result = ClpReallocateEnvironment();
- if (Result != 0) {
- errno = Result;
- return -1;
- }
- }
- //
- // Add the name of the end.
- //
- environ[Index] = String;
- Index += 1;
- environ[Index] = NULL;
- return 0;
- }
- LIBC_API
- int
- unsetenv (
- const char *Name
- )
- /*++
- Routine Description:
- This routine removes the environment variable with the given name from
- the current environment. This routine is neither re-entrant nor thread safe.
- Arguments:
- Name - Supplies a pointer to the name of the variable to unset. This
- string must not have an equals '=' in it.
- Return Value:
- 0 on success (whether or not the environment variable previously existed).
- -1 on failure, and errno will be set to contain more information. Errno is
- commonly set to EINVAL if the argument is a null pointer, an empty string,
- or contains an equals.
- --*/
- {
- ULONG Index;
- ULONG MoveIndex;
- ULONG NameLength;
- if ((Name == NULL) || (*Name == '\0') || (strchr(Name, '=') != NULL)) {
- errno = EINVAL;
- return -1;
- }
- if (environ == NULL) {
- return 0;
- }
- NameLength = strlen(Name);
- //
- // Loop through looking for the variable.
- //
- Index = 0;
- while (environ[Index] != NULL) {
- if ((strncmp(environ[Index], Name, NameLength) == 0) &&
- (environ[Index][NameLength] == '=')) {
- //
- // Move all other environment variables up one.
- //
- MoveIndex = Index;
- while (environ[MoveIndex] != NULL) {
- environ[MoveIndex] = environ[MoveIndex + 1];
- MoveIndex += 1;
- }
- //
- // Keep looking for this environment variable name, as the user
- // may have edited multiple variables in themselves.
- //
- continue;
- }
- Index += 1;
- }
- return 0;
- }
- LIBC_API
- const char *
- getexecname (
- void
- )
- /*++
- Routine Description:
- This routine returns the path name of the executable.
- Arguments:
- None.
- Return Value:
- Returns a pointer to the pathname of the executable on success. The caller
- must not alter this memory.
- --*/
- {
- PPROCESS_ENVIRONMENT Environment;
- Environment = OsGetCurrentEnvironment();
- return Environment->ImageName;
- }
- VOID
- ClpInitializeEnvironment (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes the environment variable support in the C library.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PPROCESS_ENVIRONMENT Environment;
- OsImGetEnvironmentVariable = ClpImGetEnvironmentVariable;
- Environment = OsGetCurrentEnvironment();
- environ = Environment->Environment;
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- PSTR
- ClpImGetEnvironmentVariable (
- PSTR Variable
- )
- /*++
- Routine Description:
- This routine gets an environment variable value for the image library.
- Arguments:
- Variable - Supplies a pointer to a null terminated string containing the
- name of the variable to get.
- Return Value:
- Returns a pointer to the value of the environment variable. The image
- library will not free or modify this value.
- NULL if the given environment variable is not set.
- --*/
- {
- return getenv(Variable);
- }
- INT
- ClpReallocateEnvironment (
- VOID
- )
- /*++
- Routine Description:
- This routine reallocates the environment variables, either copying the
- existing allocated variables into an expanded buffer or copying in the
- user-supplied variables.
- Arguments:
- None.
- Return Value:
- 0 on success.
- ENOMEM if insufficient memory was available to add the variable.
- --*/
- {
- ULONG Count;
- PSTR *NewEnvironment;
- ULONG NewEnvironmentCapacity;
- //
- // If there is a user environment that has yet to been copied here, then
- // base the size off the user environment.
- //
- Count = 0;
- if ((environ != NULL) && (environ != ClAllocatedEnvironment)) {
- ASSERT(ClAllocatedEnvironment == NULL);
- while (environ[Count] != NULL) {
- Count += 1;
- }
- NewEnvironmentCapacity = Count * 2;
- }
- //
- // If there was no existing environment, or it was empty, use the initial
- // capacity or base the new size off of the existing size.
- //
- if (Count == 0) {
- if (ClAllocatedEnvironment == NULL) {
- ASSERT(ClAllocatedEnvironmentCapacity == 0);
- NewEnvironmentCapacity = ENVIRONMENT_ARRAY_INITIAL_CAPACITY;
- } else {
- NewEnvironmentCapacity = ClAllocatedEnvironmentCapacity * 2;
- }
- }
- if (NewEnvironmentCapacity < ENVIRONMENT_ARRAY_INITIAL_CAPACITY) {
- NewEnvironmentCapacity = ENVIRONMENT_ARRAY_INITIAL_CAPACITY;
- }
- //
- // The capacity does not include room for the NULL terminator, so always
- // allocate an extra space.
- //
- NewEnvironment = realloc(ClAllocatedEnvironment,
- (NewEnvironmentCapacity + 1) * sizeof(char *));
- if (NewEnvironment == NULL) {
- return ENOMEM;
- }
- //
- // If there is a user environment, copy said environment and add the
- // null-terminator.
- //
- if ((environ != NULL) && (environ != ClAllocatedEnvironment)) {
- memcpy(NewEnvironment, environ, Count * sizeof(char *));
- NewEnvironment[Count] = NULL;
- //
- // Otherwise, just null terminate if this is the first time the environment
- // has been allocated. If realloc copied an existing environment above then
- // it should have copied the null-terminator along with it.
- //
- } else if (environ == NULL) {
- NewEnvironment[0] = NULL;
- }
- //
- // Update the global variables.
- //
- ClAllocatedEnvironmentCapacity = NewEnvironmentCapacity;
- ClAllocatedEnvironment = NewEnvironment;
- environ = NewEnvironment;
- return 0;
- }
|