Skip to content

Commit

Permalink
print: default output based on parent process name (#338)
Browse files Browse the repository at this point in the history
### Why

We can do better about choosing the output than just checking the OS.
There's a chance someone could be using bash on windows or powershell on
mac

### How

Use Windows API and for linux / mac use some shell code to climb up the
process tree and get the proper name

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: DotNet Format Bot <[email protected]>
  • Loading branch information
3 people authored Jun 26, 2023
1 parent a0bd992 commit 51d4caa
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/D2L.Bmx/D2L.Bmx.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<InvariantGlobalization>true</InvariantGlobalization>
<RootNamespace>D2L.Bmx</RootNamespace>
<LangVersion>preview</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Expand Down
26 changes: 23 additions & 3 deletions src/D2L.Bmx/PrintHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,30 @@ public async Task HandleAsync(
} else if( string.Equals( output, "json", StringComparison.OrdinalIgnoreCase ) ) {
PrintJson( awsCreds );
} else {
string? procName = null;
if( OperatingSystem.IsWindows() ) {
PrintPowershell( awsCreds );
} else if( OperatingSystem.IsMacOS() || OperatingSystem.IsLinux() ) {
PrintBash( awsCreds );
procName = WindowsParentProcess.GetParentProcessName().ToLower();
} else if( OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() ) {
procName = UnixParentProcess.GetParentProcessName().ToLower();
}

switch( procName ) {
case "pwsh":
case "powershell":
PrintPowershell( awsCreds );
break;
case "zsh":
case "bash":
case "sh":
PrintBash( awsCreds );
break;
default:
if( OperatingSystem.IsWindows() ) {
PrintPowershell( awsCreds );
} else if( OperatingSystem.IsMacOS() || OperatingSystem.IsLinux() ) {
PrintBash( awsCreds );
}
break;
}
}
}
Expand Down
36 changes: 36 additions & 0 deletions src/D2L.Bmx/UnixParentProcess.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Diagnostics;

namespace D2L.Bmx;

/**
This file may eventually be replaced if the following dotnet runtime api proposals are implemented:
- https://github.com/dotnet/runtime/issues/21941
- https://github.com/dotnet/runtime/issues/24423
*/
internal class UnixParentProcess {

public static string GetParentProcessName() {
int parentPid = GetParentProcessId( Environment.ProcessId );
return Process.GetProcessById( parentPid ).ProcessName;
}

private static int GetParentProcessId( int pid ) {
var proccessStartInfo = new ProcessStartInfo {
FileName = "ps",
ArgumentList = { "-p", $"{pid}", "-o", "ppid=" },
RedirectStandardOutput = true,
};

using var proc = Process.Start( proccessStartInfo );
if( proc is null ) {
return -1;
}

string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
if( int.TryParse( output.Trim(), out int parentPid ) ) {
return parentPid;
}
return -1;
}
}
53 changes: 53 additions & 0 deletions src/D2L.Bmx/WindowsParentProcess.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace D2L.Bmx;
/**
This file may eventually be replaced if the following dotnet runtime api proposals are implemented:
- https://github.com/dotnet/runtime/issues/21941
- https://github.com/dotnet/runtime/issues/24423
Uses the same approach of calling NtQueryInformationProcess as in the PowerShell library
https://github.com/PowerShell/PowerShell/blob/26f621952910e33840efb0c539fbef1e2a467a0d/src/System.Management.Automation/engine/ProcessCodeMethods.cs
*/
internal partial class WindowsParentProcess {

[LibraryImport( "ntdll.dll", EntryPoint = "NtQueryInformationProcess" )]
internal static partial int NtQueryInformationProcess(
IntPtr processHandle,
int processInformationClass,
ref PROCESS_BASIC_INFORMATION processInformation,
int processInformationLength,
out int returnLength
);

internal struct PROCESS_BASIC_INFORMATION {
public IntPtr ExitStatus;
public IntPtr PebBaseAddress;
public IntPtr AffinityMask;
public IntPtr BasePriority;
public UIntPtr UniqueProcessId;
public UIntPtr InheritedFromUniqueProcessId;
}

private static int GetParentProcessId() {
var proc = Process.GetCurrentProcess();
var pbi = new PROCESS_BASIC_INFORMATION();
int status = NtQueryInformationProcess(
proc.Handle,
0,
ref pbi,
Marshal.SizeOf<PROCESS_BASIC_INFORMATION>(),
out int infoLen
);

if( status != 0 ) {
return -1;
}
return (int)pbi.InheritedFromUniqueProcessId;
}

public static string GetParentProcessName() {
return Process.GetProcessById( GetParentProcessId() ).ProcessName;
}
}

0 comments on commit 51d4caa

Please sign in to comment.