--- src/powershell/Program.cs.orig 2024-03-30 20:39:17 UTC
+++ src/powershell/Program.cs
@@ -56,6 +56,13 @@ namespace Microsoft.PowerShell
private const int MACOS_KERN_ARGMAX = 8;
private const int MACOS_KERN_PROCARGS2 = 49;
private const int MACOS_PROC_PIDPATHINFO_MAXSIZE = 4096;
+
+ // FreeBSD p/Invoke constants
+ private const int FREEBSD_CTL_KERN = 1;
+ private const int FREEBSD_KERN_PROC = 14;
+ private const int FREEBSD_KERN_PROC_ARGS = 7;
+ private const int FREEBSD_KERN_PROC_PATHNAME = 12;
+ private const int FREEBSD_ENOMEM = 12;
#endif
///
@@ -125,7 +132,62 @@ namespace Microsoft.PowerShell
ThrowOnFailure("exec", ExecPwshLogin(args, pwshPath, isMacOS: false));
return;
}
+ else if (OperatingSystem.IsFreeBSD())
+ {
+ Span fmib = stackalloc int[4];
+ int fmibLength = 4;
+ fmib[0] = FREEBSD_CTL_KERN;
+ fmib[1] = FREEBSD_KERN_PROC;
+ fmib[2] = FREEBSD_KERN_PROC_ARGS;
+ fmib[3] = -1;
+ int sz = 1;
+ unsafe
+ {
+ fixed (int *mibptr = fmib)
+ {
+ ThrowOnFailure(nameof(procNameFirstByte), SysCtl(mibptr, fmibLength, &procNameFirstByte, &sz, IntPtr.Zero, 0), FREEBSD_ENOMEM);
+ }
+ }
+
+ if (!IsLogin(procNameFirstByte, args))
+ {
+ return;
+ }
+
+ fmib[2] = FREEBSD_KERN_PROC_PATHNAME;
+ int pathsz = 0;
+
+ unsafe
+ {
+ fixed (int *mibptr = fmib)
+ {
+ ThrowOnFailure(nameof(pathsz), SysCtl(mibptr, fmibLength, (void *)null, &pathsz, IntPtr.Zero, 0));
+ }
+ }
+
+ IntPtr execPathPtr = Marshal.AllocHGlobal(pathsz);
+ try
+ {
+ unsafe
+ {
+ fixed (int *mibptr = fmib)
+ {
+ ThrowOnFailure(nameof(execPathPtr), SysCtl(mibptr, fmibLength, execPathPtr.ToPointer(), &pathsz, IntPtr.Zero, 0));
+ }
+ }
+ string? execPath = Marshal.PtrToStringAnsi(execPathPtr);
+ ArgumentNullException.ThrowIfNull(execPath);
+ ThrowOnFailure("exec", ExecPwshLogin(args, execPath, isMacOS: false));
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(execPathPtr);
+ }
+
+ return;
+ }
+
// At this point, we are on macOS
// Set up the mib array and the query for process maximum args size
@@ -417,11 +479,13 @@ namespace Microsoft.PowerShell
///
/// The native call that was attempted.
/// The exit code it returned.
- private static void ThrowOnFailure(string call, int code)
+ /// Ignore this error, consider it success.
+ private static void ThrowOnFailure(string call, int code, int ignore = 0)
{
if (code < 0)
{
code = Marshal.GetLastWin32Error();
+ if (code == ignore) return;
Console.Error.WriteLine($"Call to '{call}' failed with errno {code}");
throw new StartupException(call, code);
}