Suggestion: make Process.StartInfo a best-effort API
#102.766 aperta il 28 mag 2024
Metriche repository
- Star
- (17.886 star)
- Metriche merge PR
- (Merge medio 12g 11h) (661 PR mergiate in 30 g)
Descrizione
Currently, this API throws if the process is not self or a child of current process.
System.InvalidOperationException: Process was not started by this object, so requested information cannot be determined.
Other tools, such as ps(1), provide information about the process in a "best effort" manner, e.g.
#!/bin/sh
ps ax -o pid,comm,args | while read pid comm args; do
if [ "$pid" = 1 ]; then
printf '%s\t%s\t%s\n' "$pid" "$comm" "$args"
fi
done
gives info about the init process on Linux, macOS and FreeBSD alike, regardless of the current user privileges. In contrast, while this program will output the process name of the non-self, non-children processes:
Process process = Process.GetProcessById(1);
Console.WriteLine(process.ProcessName);
we cannot get the process path or arguments which ps(1) offers.
ps: there is a macOS-sepcific quirk that we can use process.MainModule.FullName to find the path, but MainModule is null for "not owned by us" process on Linux and FreeBSD
FWIW, I was trying to make this implementation of UnixInitSystem detection robust for case where multiple init systems are installed (and one of them is active); using Process:
using System;
using System.IO;
UnixInitSystem initSystem = InitSystemDetector.Detect();
Console.WriteLine($"Init system detected: {initSystem}");
/// <summary>
/// Represents the different types of Unix initialization (init) systems.
/// </summary>
public enum UnixInitSystem
{
/// <summary>
/// Init system could not be determined, possibly in a container environment.
/// </summary>
Unknown,
/// <summary>
/// BSD-style init system.
/// </summary>
BSD,
/// <summary>
/// BusyBox init system.
/// </summary>
BusyBox,
/// <summary>
/// EInit init system.
/// </summary>
EInit,
/// <summary>
/// Launchd init system (macOS).
/// </summary>
Launchd,
/// <summary>
/// Monit process supervision.
/// </summary>
Monit,
/// <summary>
/// Mudar init system.
/// </summary>
Mudar,
/// <summary>
/// OpenRC init system.
/// </summary>
OpenRC,
/// <summary>
/// Runit init system.
/// </summary>
Runit,
/// <summary>
/// Service Management Facility, Solaris.
/// </summary>
SMF,
/// <summary>
/// Systemd init system.
/// </summary>
Systemd,
/// <summary>
/// System V init system.
/// </summary>
SystemV,
/// <summary>
/// Upstart init system.
/// </summary>
Upstart
}
/// <summary>
/// Provides functionality to detect the Unix initialization (init) system.
/// </summary>
public static class InitSystemDetector
{
/// <summary>
/// Detects the Unix init system currently in use.
/// </summary>
/// <returns>
/// A <see cref="UnixInitSystem"/> value representing the detected init system.
/// </returns>
public static UnixInitSystem Detect()
{
if (File.Exists("/sbin/einit") || File.Exists("/etc/einit/einit.conf"))
{
return UnixInitSystem.EInit;
}
if (File.Exists("/etc/rc") && File.Exists("/etc/rc.subr"))
{
return UnixInitSystem.BSD;
}
if (File.Exists("/sbin/init") && new FileInfo("/sbin/init").LinkTarget == "/bin/busybox")
{
return UnixInitSystem.BusyBox;
}
if (File.Exists("/sbin/launchd") && Directory.Exists("/Library/LaunchDaemons"))
{
return UnixInitSystem.Launchd;
}
if (File.Exists("/etc/monitrc") || Directory.Exists("/etc/monit.d"))
{
return UnixInitSystem.Monit;
}
if (File.Exists("/sbin/mudar"))
{
return UnixInitSystem.Mudar;
}
if (Directory.Exists("/etc/init.d") && File.Exists("/sbin/openrc-init"))
{
return UnixInitSystem.OpenRC;
}
if (Directory.Exists("/etc/sv") && Directory.Exists("/etc/service") && File.Exists("/sbin/runsvdir"))
{
return UnixInitSystem.Runit;
}
if (Directory.Exists("/lib/svc") && File.Exists("/usr/sbin/svcadm"))
{
return UnixInitSystem.SMF;
}
if (Directory.Exists("/run/systemd/system") && File.Exists("/sbin/init") && File.ReadAllText("/proc/1/comm").Trim() == "systemd")
{
return UnixInitSystem.Systemd;
}
if (File.Exists("/sbin/init") && File.Exists("/etc/inittab"))
{
return UnixInitSystem.SystemV;
}
if (File.Exists("/sbin/initctl") && Directory.Exists("/etc/init"))
{
return UnixInitSystem.Upstart;
}
return UnixInitSystem.Unknown;
}
}
guess I can shell out to ps(1) directly for this.