diff options
6 files changed, 87 insertions, 3 deletions
diff --git a/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.GetEnviron.cs b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.GetEnviron.cs new file mode 100644 index 000000000..539cdb3cf --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.GetEnviron.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal unsafe partial class Sys + { + [DllImport(Interop.Libraries.CoreLibNative, EntryPoint = "CoreLibNative_GetEnviron")] + internal static extern unsafe IntPtr GetEnviron(); + } +} diff --git a/src/Native/System.Private.CoreLib.Native/config.h.in b/src/Native/System.Private.CoreLib.Native/config.h.in index c7c3aafd9..3c3f11298 100644 --- a/src/Native/System.Private.CoreLib.Native/config.h.in +++ b/src/Native/System.Private.CoreLib.Native/config.h.in @@ -6,3 +6,4 @@ #cmakedefine01 HAVE_MACH_ABSOLUTE_TIME #cmakedefine01 HAVE_SCHED_GETCPU #cmakedefine01 HAVE_GNU_LIBNAMES_H +#cmakedefine01 HAVE__NSGETENVIRON
\ No newline at end of file diff --git a/src/Native/System.Private.CoreLib.Native/configure.cmake b/src/Native/System.Private.CoreLib.Native/configure.cmake index aaabb387c..1fbbf9c5e 100644 --- a/src/Native/System.Private.CoreLib.Native/configure.cmake +++ b/src/Native/System.Private.CoreLib.Native/configure.cmake @@ -1,6 +1,7 @@ include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) include(CheckLibraryExists) +include(CheckFunctionExists) check_library_exists(pthread pthread_condattr_setclock "" HAVE_PTHREAD_CONDATTR_SETCLOCK) @@ -62,6 +63,8 @@ set(CMAKE_REQUIRED_LIBRARIES) check_include_files(gnu/lib-names.h HAVE_GNU_LIBNAMES_H) +check_function_exists(_NSGetEnviron HAVE__NSGETENVIRON) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) diff --git a/src/Native/System.Private.CoreLib.Native/pal_environment.cpp b/src/Native/System.Private.CoreLib.Native/pal_environment.cpp index 94660baba..15ef90c34 100644 --- a/src/Native/System.Private.CoreLib.Native/pal_environment.cpp +++ b/src/Native/System.Private.CoreLib.Native/pal_environment.cpp @@ -10,6 +10,9 @@ #if HAVE_SCHED_GETCPU #include <sched.h> #endif +#if HAVE__NSGETENVIRON +#include <crt_externs.h> +#endif extern "C" char* CoreLibNative_GetEnv(const char* variable) @@ -30,3 +33,17 @@ extern "C" void CoreLibNative_Exit(int32_t exitCode) { exit(exitCode); } + +extern "C" char** CoreLibNative_GetEnviron() +{ + char** sysEnviron; + +#if HAVE__NSGETENVIRON + sysEnviron = *(_NSGetEnviron()); +#else // HAVE__NSGETENVIRON + extern char **environ; + sysEnviron = environ; +#endif // HAVE__NSGETENVIRON + + return sysEnviron; +}
\ No newline at end of file diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Unix.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Unix.cs index 6d28d393b..76ead8cb7 100644 --- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Unix.cs +++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Unix.cs @@ -27,10 +27,55 @@ namespace Internal.Runtime.Augments public static IEnumerable<KeyValuePair<string,string>> EnumerateEnvironmentVariables() { - if ("".Length != 0) - throw new NotImplementedException(); // Need to return something better than an empty environment block. + IntPtr block = Interop.Sys.GetEnviron(); + if (block == IntPtr.Zero) + yield break; - return Array.Empty<KeyValuePair<string,string>>(); + // Per man page, environment variables come back as an array of pointers to strings + // Parse each pointer of strings individually + while (ParseEntry(block, out string key, out string value)) + { + if (key != null && value != null) + yield return new KeyValuePair<string, string>(key, value); + + // Increment to next environment variable entry + block += IntPtr.Size; + } + + // Use a local, unsafe function since we cannot use `yield return` inside of an `unsafe` block + unsafe bool ParseEntry(IntPtr current, out string key, out string value) + { + // Setup + key = null; + value = null; + + // Point to current entry + byte* entry = *(byte**)current; + + // Per man page, "The last pointer in this array has the value NULL" + // Therefore, if entry is null then we're at the end and can bail + if (entry == null) + return false; + + // Parse each byte of the entry until we hit either the separator '=' or '\0'. + // This finds the split point for creating key/value strings below. + // On some old OS, the environment block can be corrupted. + // Some will not have '=', so we need to check for '\0'. + byte* splitpoint = entry; + while (*splitpoint != '=' && *splitpoint != '\0') + splitpoint++; + + // Skip over entries starting with '=' and entries with no value (just a null-terminating char '\0') + if (splitpoint == entry || *splitpoint == '\0') + return true; + + // The key is the bytes from start (0) until our splitpoint + key = new string((sbyte*)entry, 0, checked((int)(splitpoint - entry))); + // The value is the rest of the bytes starting after the splitpoint + value = new string((sbyte*)(splitpoint + 1)); + + return true; + } } private static void ExitRaw() diff --git a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj index f830beb82..c865aa858 100644 --- a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -601,6 +601,9 @@ <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.ErrNo.cs"> <Link>Interop\Unix\System.Private.CoreLib.Native\Interop.ErrNo.cs</Link> </Compile> + <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.GetEnviron.cs"> + <Link>Interop\Unix\System.Private.CoreLib.Native\Interop.GetEnviron.cs</Link> + </Compile> </ItemGroup> <ItemGroup> <Compile Include="..\..\Common\src\TypeSystem\Common\Utilities\LockFreeReaderHashtable.cs"> |