@@ -176,52 +176,113 @@ public static bool IsElevatedUser()
176
176
return false ;
177
177
}
178
178
179
- #region Platform argv[0] Utils
179
+ #region Platform Entry Path Utils
180
180
181
- public static string GetNativeArgv0 ( )
181
+ /// <summary>
182
+ /// Get the native entry executable absolute path.
183
+ /// </summary>
184
+ /// <returns>Entry absolute path or null if there was an error.</returns>
185
+ public static string GetNativeEntryPath ( )
182
186
{
183
187
try
184
188
{
185
189
if ( IsWindows ( ) )
186
190
{
187
- return GetWindowsArgv0 ( ) ;
191
+ return GetWindowsEntryPath ( ) ;
188
192
}
189
193
190
194
if ( IsMacOS ( ) )
191
195
{
192
- return GetMacOSArgv0 ( ) ;
196
+ return GetMacOSEntryPath ( ) ;
193
197
}
194
198
195
199
if ( IsLinux ( ) )
196
200
{
197
- return GetLinuxArgv0 ( ) ;
201
+ return GetLinuxEntryPath ( ) ;
198
202
}
199
203
}
200
204
catch
201
205
{
202
- // If there are any issues getting the native argv[0]
206
+ // If there are any issues getting the native entry path
203
207
// we should not throw, and certainly not crash!
204
208
// Just return null instead.
205
209
}
206
210
207
211
return null ;
208
212
}
209
213
210
- private static string GetLinuxArgv0 ( )
214
+ private static string GetLinuxEntryPath ( )
211
215
{
216
+ // Try to extract our native argv[0] from the original cmdline
212
217
string cmdline = File . ReadAllText ( "/proc/self/cmdline" ) ;
213
- return cmdline . Split ( '\0 ' ) [ 0 ] ;
218
+ string argv0 = cmdline . Split ( '\0 ' ) [ 0 ] ;
219
+
220
+ // argv[0] is an absolute file path
221
+ if ( Path . IsPathRooted ( argv0 ) )
222
+ {
223
+ return argv0 ;
224
+ }
225
+
226
+ string path = Path . GetFullPath (
227
+ Path . Combine ( Environment . CurrentDirectory , argv0 )
228
+ ) ;
229
+
230
+ // argv[0] is relative to current directory (./app) or a relative
231
+ // name resolved from the current directory (subdir/app).
232
+ // Note that we do NOT want to consider the case when it is just
233
+ // a simple filename (argv[0] == "app") because that would actually
234
+ // have been resolved from the $PATH instead (handled below)!
235
+ if ( ( argv0 . StartsWith ( "./" ) || argv0 . IndexOf ( '/' ) > 0 ) && File . Exists ( path ) )
236
+ {
237
+ return path ;
238
+ }
239
+
240
+ // argv[0] is a name that was resolved from the $PATH
241
+ string pathVar = Environment . GetEnvironmentVariable ( "PATH" ) ;
242
+ if ( pathVar != null )
243
+ {
244
+ string [ ] paths = pathVar . Split ( ':' ) ;
245
+ foreach ( string pathBase in paths )
246
+ {
247
+ path = Path . Combine ( pathBase , argv0 ) ;
248
+ if ( File . Exists ( path ) )
249
+ {
250
+ return path ;
251
+ }
252
+ }
253
+ }
254
+
255
+ #if NETFRAMEWORK
256
+ return null ;
257
+ #else
258
+ //
259
+ // We cannot determine the absolute file path from argv[0]
260
+ // (how we were launched), so let's now try to extract the
261
+ // fully resolved executable path from /proc/self/exe.
262
+ // Note that this means we may miss if we've been invoked
263
+ // via a symlink, but it's better than nothing at this point!
264
+ //
265
+ FileSystemInfo fsi = File . ResolveLinkTarget ( "/proc/self/exe" , returnFinalTarget : false ) ;
266
+ return fsi ? . FullName ;
267
+ #endif
214
268
}
215
269
216
- private static string GetMacOSArgv0 ( )
270
+ private static string GetMacOSEntryPath ( )
217
271
{
218
- IntPtr ptr = Interop . MacOS . Native . LibC . _NSGetArgv ( ) ;
219
- IntPtr argvPtr = Marshal . ReadIntPtr ( ptr ) ;
220
- IntPtr argv0Ptr = Marshal . ReadIntPtr ( argvPtr ) ;
221
- return Marshal . PtrToStringAnsi ( argv0Ptr ) ;
272
+ // Determine buffer size by passing NULL initially
273
+ Interop . MacOS . Native . LibC . _NSGetExecutablePath ( IntPtr . Zero , out int size ) ;
274
+
275
+ IntPtr bufPtr = Marshal . AllocHGlobal ( size ) ;
276
+ int result = Interop . MacOS . Native . LibC . _NSGetExecutablePath ( bufPtr , out size ) ;
277
+
278
+ // buf is null-byte terminated
279
+ string name = result == 0 ? Marshal . PtrToStringAuto ( bufPtr ) : null ;
280
+ Marshal . FreeHGlobal ( bufPtr ) ;
281
+
282
+ return name ;
222
283
}
223
284
224
- private static string GetWindowsArgv0 ( )
285
+ private static string GetWindowsEntryPath ( )
225
286
{
226
287
IntPtr argvPtr = Interop . Windows . Native . Shell32 . CommandLineToArgvW (
227
288
Interop . Windows . Native . Kernel32 . GetCommandLine ( ) , out _ ) ;
0 commit comments