Suggestion: make Process.StartInfo a best-effort API
#102 766 ouverte le 28 mai 2024
Métriques du dépôt
- Stars
- (17 886 stars)
- Métriques de merge PR
- (Merge moyen 12j 11h) (661 PRs mergées en 30 j)
Description
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.