dotnet/runtime

Suggestion: make Process.StartInfo a best-effort API

Open

#102.766 aperta il 28 mag 2024

Vedi su GitHub
 (9 commenti) (0 reazioni) (0 assegnatari)C# (5445 fork)batch import
area-System.Diagnostics.Processhelp wanted

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.

Guida contributor