Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Environment.ProcessPath #42768

Merged
merged 16 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

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

using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
/// <summary>
/// Takes a path containing relative subpaths or links and returns the absolute path.
/// This function works on both files and folders and returns a null-terminated string.
jkotas marked this conversation as resolved.
Show resolved Hide resolved
/// </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
52 changes: 39 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,9 @@
#include <sched.h>
#endif

#ifdef __APPLE__
#include <mach-o/dyld.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 +519,6 @@ done:;
#endif
}

FILE* SystemNative_POpen(const char* command, const char* type)
jkotas marked this conversation as resolved.
Show resolved Hide resolved
{
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 +861,39 @@ 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.
jkotas marked this conversation as resolved.
Show resolved Hide resolved
// The caller is responsible for releasing the buffer. Returns null on error.
char* SystemNative_GetProcessPath()
{
// Get path to the executable for the current process using
jkotas marked this conversation as resolved.
Show resolved Hide resolved
jkotas marked this conversation as resolved.
Show resolved Hide resolved
// platform specific means.
jkotas marked this conversation as resolved.
Show resolved Hide resolved
#ifdef __APPLE__
// On Mac, we ask the OS for the absolute path to the entrypoint executable
jkotas marked this conversation as resolved.
Show resolved Hide resolved
uint32_t path_length = 0;
if (_NSGetExecutablePath(nullptr, &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);
jkotas marked this conversation as resolved.
Show resolved Hide resolved
#else

#ifdef __linux__
#define symlinkEntrypointExecutable "/proc/self/exe"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think a normal variable is more appropriate here than a mid-function define, unless there's a good reason for this to be using the preprocessor that I'm missing. Codegen should be identical.

#else
#define symlinkEntrypointExecutable "/proc/curproc/exe"
#endif

// Resove 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 @@ -240,8 +240,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 @@ -262,8 +260,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
13 changes: 5 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,12 @@ 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());

Assert.Equal(Environment.ProcessPath, p.MainModule.FileName);
jkotas marked this conversation as resolved.
Show resolved Hide resolved
}

[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 @@ -26,5 +26,11 @@ private static OperatingSystem GetOSVersion()
}

private static int GetCurrentProcessId() => 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>
public static string? ProcessPath => null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,11 @@ private static unsafe bool TryGetUserNameFromPasswd(byte* buf, int bufLen, out s
}

private static int GetCurrentProcessId() => Interop.Sys.GetPid();

/// <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>
public static string? ProcessPath => Interop.Sys.GetProcessPath();
jkotas marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ private static string ExpandEnvironmentVariablesCore(string name)
}

if (length == 0)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
throw Win32Marshal.GetExceptionForLastWin32Error();

// length includes the null terminator
builder.Length = (int)length - 1;
Expand All @@ -88,6 +88,30 @@ private static string ExpandEnvironmentVariablesCore(string name)

private static int GetCurrentProcessId() => unchecked((int)Interop.Kernel32.GetCurrentProcessId());

/// <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>
public static string? ProcessPath
{
get
{
var builder = new ValueStringBuilder(stackalloc char[Interop.Kernel32.MAX_PATH]);

uint length;
while ((length = Interop.Kernel32.GetModuleFileName(IntPtr.Zero, ref builder.GetPinnableReference(), (uint)builder.Capacity)) >= builder.Capacity)
{
builder.EnsureCapacity((int)length);
}

if (length == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();

builder.Length = (int)length;
return builder.ToString();
}
}

private static unsafe OperatingSystem GetOSVersion()
{
if (Interop.NtDll.RtlGetVersionEx(out Interop.NtDll.RTL_OSVERSIONINFOEX osvi) != 0)
Expand Down
Loading