-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
How to get current process invocation name (argv[0]/$0)? (login shell on *nix) #30212
Comments
Additional output from starting PowerShell as a login shell with the
Note that the process is listed by |
In case anyone else (admittedly not many others writing login shells on .NET) wants a starting point for how to do this: private static void DumpArgv()
{
int pid = getpid();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
string[] argv = System.IO.File.ReadAllText($"/proc/{pid}/cmdline").Split('\0');
for (int i = 0; i < argv.Length; i++)
{
Console.WriteLine($"argv[{i}]: {argv[i]}");
}
return;
}
// Get proc table size
int[] mib = new [] { CTL_KERN, KERN_ARGMAX };
int size = sizeof(int);
int maxargs = 0;
unsafe
{
if (sysctl(mib, mib.Length, &maxargs, &size, IntPtr.Zero, 0) == -1)
{
throw new Exception("argmax");
}
// Now read the proc table
IntPtr procargs = Marshal.AllocHGlobal(maxargs);
try
{
size = maxargs;
mib = new [] { CTL_KERN, KERN_PROCARGS2, pid };
if (sysctl(mib, mib.Length, procargs.ToPointer(), &size, IntPtr.Zero, 0) == -1)
{
throw new Exception("procargs");
}
// Skip over argc
int argc = Marshal.ReadInt32(procargs);
Console.WriteLine($"argc: {argc}");
byte *argvPtr = (byte *)IntPtr.Add(procargs, sizeof(int)).ToPointer();
Console.WriteLine($"exec_path: {Marshal.PtrToStringAnsi((IntPtr)argvPtr)}");
while (*argvPtr != 0) { argvPtr++; }
while (*argvPtr == 0) { argvPtr++; }
for (int i = 0; i < argc; i++)
{
Console.WriteLine($"argv[{i}]: {Marshal.PtrToStringAnsi((IntPtr)argvPtr)}");
while (*argvPtr != 0) { argvPtr++; }
while (*argvPtr == 0) { argvPtr++; }
}
}
finally
{
Marshal.FreeHGlobal(procargs);
}
}
}
[DllImport("libc")]
private static extern int getpid();
[DllImport("libc")]
private static unsafe extern int sysctl(int[] mib, int mibLength, void *oldp, int *oldlenp, IntPtr newp, int newlenp); Based on https://gist.github.com/nonowarn/770696#file-getargv-c. |
Is this possibly related to dotnet/corefx#37294 - I have already expressed my concerns about it: Perhaps we should add ProcessPath now? |
In this case you want to check the We're not using We can probably augment the cmdline reading to specifically support the login shell use-case. That is, A more generic .NET API would expose the |
@tmds I believe until we got 2 APIs it's actually more useful to get argv[0] since you can write additional logic to get it yourself while getting actual argv[0] with current solution requires native call as in above workaround. I agree there should eventually be helper function to get user friendly name (that would be useful even for |
The current implementation of |
Note that another problem with I'm assuming that fixing the issue at hand would also fix the symlink issue - or should I open a separate one? The division of labor would then be:
|
I'm working to enable PowerShell as a login shell on *nix in PowerShell/PowerShell#10050.
When
-Login
or-l
is passed, this works fine (we exec /bin/sh and then exec pwsh again).But the convention in many *nix environments for login shells is to prepend a
-
onto the process name when it is exec'd (e.g.bash
sees its own process name as-bash
and then deduces it must run login shell logic).With PowerShell as a .NET Core 3.0 application, I don't know how to access this information.
I've tried the
args
inpublic static int Main(string[] args)
,Environment.GetCommandLineArgs()
andProcess.GetCurrentProcess()
:Which from PowerShell prints when started as the default login shell on macOS:
Writing a small C program to show the same (compiled with
cc ex.c
):When started as a login shell, prints:
The mechanism for this seems to be the
login
util, which prepends the-
before exec-ing the given executable.My question is: is there a way to detect the name with which a process has been started? Ideally we could do this performantly, since it's a startup time thing and we just want to detect it as fast as possible so we can exec another process.
The text was updated successfully, but these errors were encountered: