Skip to content

Commit

Permalink
Add Environment.ProcessPath (#42768)
Browse files Browse the repository at this point in the history
Fixes #40862

Co-authored-by: Stephen Toub <stoub@microsoft.com>
Co-authored-by: Ryan Lucia <ryan@luciaonline.net>
  • Loading branch information
3 people authored Oct 1, 2020
1 parent 073edfc commit 2544c74
Show file tree
Hide file tree
Showing 21 changed files with 199 additions and 134 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetLine", SetLastError = true)]
internal static extern string GetLine(IntPtr stream);
/// <summary>
/// Returns the full path to the executable for the current process, resolving symbolic links.
/// </summary>
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetProcessPath", SetLastError = true)]
internal static extern string? GetProcessPath();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;

internal static partial class Interop
{
internal static unsafe partial class Kernel32
{
[DllImport(Libraries.Kernel32, EntryPoint = "GetModuleFileNameW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
internal static extern uint GetModuleFileName(IntPtr hModule, ref char lpFilename, uint nSize);
}
}
4 changes: 0 additions & 4 deletions src/libraries/Native/Unix/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,6 @@ if (CLR_CMAKE_TARGET_LINUX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE")
endif ()

if(CLR_CMAKE_TARGET_FREEBSD)
add_definitions(-D_BSD_SOURCE) # required for getline
endif(CLR_CMAKE_TARGET_FREEBSD)

# CLR_ADDITIONAL_LINKER_FLAGS - used for passing additional arguments to linker
# CLR_ADDITIONAL_COMPILER_OPTIONS - used for passing additional arguments to compiler
#
Expand Down
16 changes: 0 additions & 16 deletions src/libraries/Native/Unix/System.Native/pal_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@
// Somehow, AIX mangles the definition for this behind a C++ def
// Redeclare it here
extern int getpeereid(int, uid_t *__restrict__, gid_t *__restrict__);
// This function declaration is hidden behind `_XOPEN_SOURCE=700`, but we need
// `_ALL_SOURCE` to build the runtime, and that resets that definition to 600.
// Instead of trying to wrangle ifdefs in system headers with more definitions,
// just declare it here.
extern ssize_t getline(char **, size_t *, FILE *);
#endif

#if HAVE_STAT64
Expand Down Expand Up @@ -961,17 +956,6 @@ int32_t SystemNative_PosixFAdvise(intptr_t fd, int64_t offset, int64_t length, i
#endif
}

char* SystemNative_GetLine(FILE* stream)
{
assert(stream != NULL);

char* lineptr = NULL;
size_t n = 0;
ssize_t length = getline(&lineptr, &n, stream);

return length >= 0 ? lineptr : NULL;
}

int32_t SystemNative_Read(intptr_t fd, void* buffer, int32_t bufferSize)
{
return Common_Read(fd, buffer, bufferSize);
Expand Down
7 changes: 0 additions & 7 deletions src/libraries/Native/Unix/System.Native/pal_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,13 +598,6 @@ PALEXPORT int32_t SystemNative_Poll(PollEvent* pollEvents, uint32_t eventCount,
*/
PALEXPORT int32_t SystemNative_PosixFAdvise(intptr_t fd, int64_t offset, int64_t length, int32_t advice);

/**
* Reads a line from the provided stream.
*
* Returns the read line, or null if no line could be read. The caller is responsible for freeing the malloc'd line.
*/
PALEXPORT char* SystemNative_GetLine(FILE* stream);

/**
* Reads the number of bytes specified into the provided buffer from the specified, opened file descriptor.
*
Expand Down
76 changes: 63 additions & 13 deletions src/libraries/Native/Unix/System.Native/pal_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@
#include <sched.h>
#endif

#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif

#ifdef __FreeBSD__
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#endif

// Validate that our SysLogPriority values are correct for the platform
c_static_assert(PAL_LOG_EMERG == LOG_EMERG);
Expand Down Expand Up @@ -516,19 +525,6 @@ done:;
#endif
}

FILE* SystemNative_POpen(const char* command, const char* type)
{
assert(command != NULL);
assert(type != NULL);
return popen(command, type);
}

int32_t SystemNative_PClose(FILE* stream)
{
assert(stream != NULL);
return pclose(stream);
}

// Each platform type has it's own RLIMIT values but the same name, so we need
// to convert our standard types into the platform specific ones.
static int32_t ConvertRLimitResourcesPalToPlatform(RLimitResources value)
Expand Down Expand Up @@ -871,3 +867,57 @@ int32_t SystemNative_SchedGetAffinity(int32_t pid, intptr_t* mask)
return result;
}
#endif

// Returns the full path to the executable for the current process, resolving symbolic links.
// The caller is responsible for releasing the buffer. Returns null on error.
char* SystemNative_GetProcessPath()
{
#if defined(__APPLE__)
uint32_t path_length = 0;
if (_NSGetExecutablePath(NULL, &path_length) != -1)
{
errno = EINVAL;
return NULL;
}

char path_buf[path_length];
if (_NSGetExecutablePath(path_buf, &path_length) != 0)
{
errno = EINVAL;
return NULL;
}

return realpath(path_buf, NULL);
#elif defined(__FreeBSD__)
static const int name[] =
{
CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1
};

char path[PATH_MAX];
size_t len;

len = sizeof(path);
if (sysctl(name, 4, path, &len, NULL, 0) != 0)
{
return NULL;
}

return strdup(path);
#elif defined(__sun)
const char* path = getexecname();
if (path == NULL)
return NULL;
return realpath(path, NULL);
#else

#ifdef __linux__
const char* symlinkEntrypointExecutable = "/proc/self/exe";
#else
const char* symlinkEntrypointExecutable = "/proc/curproc/exe";
#endif

// Resolve the symlink to the executable from /proc
return realpath(symlinkEntrypointExecutable, NULL);
#endif
}
16 changes: 6 additions & 10 deletions src/libraries/Native/Unix/System.Native/pal_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,6 @@ PALEXPORT int32_t SystemNative_ForkAndExecProcess(
int32_t* stdoutFd, // [out] if redirectStdout, the parent's fd for the child's stdout
int32_t* stderrFd); // [out] if redirectStderr, the parent's fd for the child's stderr

/**
* Shim for the popen function.
*/
PALEXPORT FILE* SystemNative_POpen(const char* command, const char* type);

/**
* Shim for the pclose function.
*/
PALEXPORT int32_t SystemNative_PClose(FILE* stream);

/************
* The values below in the header are fixed and correct for managed callers to use forever.
* We must never change them. The implementation must either static_assert that they are equal
Expand Down Expand Up @@ -252,3 +242,9 @@ PALEXPORT int32_t SystemNative_SchedSetAffinity(int32_t pid, intptr_t* mask);
*/
PALEXPORT int32_t SystemNative_SchedGetAffinity(int32_t pid, intptr_t* mask);
#endif

/**
* Returns the path of the executable that started the currently executing process,
* resolving symbolic links. The caller is responsible for releasing the buffer.
*/
PALEXPORT char* SystemNative_GetProcessPath(void);
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,6 @@
Link="Common\Interop\Unix\Interop.ForkAndExecProcess.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetGroupList.cs"
Link="Common\Interop\Unix\Interop.GetGroupList.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetLine.cs"
Link="Common\Interop\Unix\Interop.GetLine.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetPwUid.cs"
Link="Common\Interop\Unix\Interop.GetPwUid.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetSetPriority.cs"
Expand All @@ -264,8 +262,6 @@
Link="Common\Interop\Unix\Interop.ResourceLimits.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.PathConf.cs"
Link="Common\Interop\Unix\Interop.PathConf.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.POpen.cs"
Link="Common\Interop\Unix\Interop.POpen.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.WaitId.cs"
Link="Common\Interop\Unix\Interop.WaitId.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.WaitPid.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,6 @@ private unsafe int ParentProcessId
}
}

/// <summary>Gets the path to the current executable, or null if it could not be retrieved.</summary>
private static string? GetExePath()
{
return Interop.Process.GetProcPath(Environment.ProcessId);
}

// ----------------------------------
// ---- Unix PAL layer ends here ----
// ----------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,6 @@ private int ParentProcessId
}
}

/// <summary>Gets the path to the current executable, or null if it could not be retrieved.</summary>
private static string? GetExePath()
{
try
{
return Interop.libproc.proc_pidpath(Environment.ProcessId);
}
catch (Win32Exception)
{
// It will throw System.ComponentModel.Win32Exception (2): No such file or Directory when
// the executable file is deleted.
return null;
}
}

// ----------------------------------
// ---- Unix PAL layer ends here ----
// ----------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ private static string[] CreateEnvp(ProcessStartInfo psi)
}

// Then check the executable's directory
string? path = GetExePath();
string? path = Environment.ProcessPath;
if (path != null)
{
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,6 @@ private void SetWorkingSetLimitsCore(IntPtr? newMin, IntPtr? newMax, out IntPtr
throw new PlatformNotSupportedException();
}

private static string GetExePath()
{
throw new PlatformNotSupportedException();
}

/// <summary>Gets execution path</summary>
private string GetPathToOpenFile()
{
Expand Down
11 changes: 3 additions & 8 deletions src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -494,15 +494,10 @@ public void TestMainModule()
{
Process p = Process.GetCurrentProcess();

// On UAP casing may not match - we use Path.GetFileName(exePath) instead of kernel32!GetModuleFileNameEx which is not available on UAP
Func<string, string> normalize = PlatformDetection.IsInAppContainer ?
(Func<string, string>)((s) => s.ToLowerInvariant()) :
(s) => s;

Assert.InRange(p.Modules.Count, 1, int.MaxValue);
Assert.Equal(normalize(RemoteExecutor.HostRunnerName), normalize(p.MainModule.ModuleName));
Assert.EndsWith(normalize(RemoteExecutor.HostRunnerName), normalize(p.MainModule.FileName));
Assert.Equal(normalize(string.Format("System.Diagnostics.ProcessModule ({0})", RemoteExecutor.HostRunnerName)), normalize(p.MainModule.ToString()));
Assert.Equal(RemoteExecutor.HostRunnerName, p.MainModule.ModuleName);
Assert.EndsWith(RemoteExecutor.HostRunnerName, p.MainModule.FileName);
Assert.Equal(string.Format("System.Diagnostics.ProcessModule ({0})", RemoteExecutor.HostRunnerName), p.MainModule.ToString());
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,9 @@
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetModuleFileName.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.GetModuleFileName.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetProcessMemoryInfo.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.GetProcessMemoryInfo.cs</Link>
</Compile>
Expand Down Expand Up @@ -1709,6 +1712,9 @@
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetHostName.cs">
<Link>Common\Interop\Unix\System.Native\Interop.GetHostName.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetProcessPath.cs">
<Link>Common\Interop\Unix\System.Native\Interop.GetProcessPath.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetRandomBytes.cs">
<Link>Common\Interop\Unix\System.Native\Interop.GetRandomBytes.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ private static OperatingSystem GetOSVersion()
return new OperatingSystem(PlatformID.Other, new Version(1, 0, 0, 0));
}

private static int GetCurrentProcessId() => 42;
private static int GetProcessId() => 42;

/// <summary>
/// Returns the path of the executable that started the currently executing process. Returns null when the path is not available.
/// </summary>
/// <returns>Path of the executable that started the currently executing process</returns>
private static string? GetProcessPath() => null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -111,6 +112,10 @@ private static unsafe bool TryGetUserNameFromPasswd(byte* buf, int bufLen, out s
throw new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno);
}

private static int GetCurrentProcessId() => Interop.Sys.GetPid();
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Avoid inlining PInvoke frame into the hot path
private static int GetProcessId() => Interop.Sys.GetPid();

[MethodImplAttribute(MethodImplOptions.NoInlining)] // Avoid inlining PInvoke frame into the hot path
private static string? GetProcessPath() => Interop.Sys.GetProcessPath();
}
}
Loading

0 comments on commit 2544c74

Please sign in to comment.