129 lines
5.0 KiB
C#
129 lines
5.0 KiB
C#
using Microsoft.Win32;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace TWASys_App.Models.ServerInfo
|
|
{
|
|
public record OsInfo(string Platform, string Name, string Version, string Kernel, string Architecture);
|
|
|
|
public class OsInfoReader
|
|
{
|
|
public static OsInfo Get()
|
|
{
|
|
var arch = RuntimeInformation.OSArchitecture.ToString();
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
return GetWindows(arch);
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
return GetLinux(arch);
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
return GetMac(arch);
|
|
|
|
return new OsInfo(RuntimeInformation.OSDescription, "Unknown", "Unknown", "Unknown", arch);
|
|
}
|
|
|
|
// ---------- Windows ----------
|
|
static OsInfo GetWindows(string arch)
|
|
{
|
|
string name = "Windows";
|
|
string version = "Unknown";
|
|
try
|
|
{
|
|
using var k = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
|
|
var productName = k?.GetValue("ProductName")?.ToString();
|
|
var displayVer = k?.GetValue("DisplayVersion")?.ToString() ?? k?.GetValue("ReleaseId")?.ToString();
|
|
var build = k?.GetValue("CurrentBuildNumber")?.ToString();
|
|
var ubrObj = k?.GetValue("UBR");
|
|
var ubr = ubrObj is int i ? i.ToString() : ubrObj?.ToString();
|
|
|
|
name = productName ?? "Windows";
|
|
if (!string.IsNullOrWhiteSpace(build))
|
|
version = $"{(displayVer ?? "")}".Trim();
|
|
if (!string.IsNullOrWhiteSpace(build))
|
|
version = string.IsNullOrWhiteSpace(version) ? $"Build {build}.{ubr}" : $"{version} (Build {build}.{ubr})";
|
|
}
|
|
catch { /* fallback below */ }
|
|
|
|
var kernel = RuntimeInformation.OSDescription; // e.g. "Microsoft Windows 10.0.19045"
|
|
return new OsInfo("Windows", name, version, kernel, arch);
|
|
}
|
|
|
|
// ---------- Linux ----------
|
|
static OsInfo GetLinux(string arch)
|
|
{
|
|
string name = "Linux";
|
|
string version = "Unknown";
|
|
|
|
try
|
|
{
|
|
var dict = ParseKeyValueFile("/etc/os-release"); // NAME, PRETTY_NAME, VERSION_ID...
|
|
if (dict.TryGetValue("NAME", out var n)) name = TrimQuotes(n);
|
|
if (dict.TryGetValue("PRETTY_NAME", out var pretty)) version = TrimQuotes(pretty);
|
|
else if (dict.TryGetValue("VERSION", out var v)) version = TrimQuotes(v);
|
|
else if (dict.TryGetValue("VERSION_ID", out var vid)) version = TrimQuotes(vid);
|
|
}
|
|
catch { /* ignore */ }
|
|
|
|
var kernel = Run("uname", "-sr"); // e.g. "Linux 6.8.0-40-generic"
|
|
if (string.IsNullOrWhiteSpace(kernel)) kernel = RuntimeInformation.OSDescription;
|
|
|
|
return new OsInfo("Linux", name, version, kernel, arch);
|
|
}
|
|
|
|
// ---------- macOS ----------
|
|
static OsInfo GetMac(string arch)
|
|
{
|
|
var name = Run("sw_vers", "-productName"); // "macOS"
|
|
var version = Run("sw_vers", "-productVersion"); // "14.6.1"
|
|
if (string.IsNullOrWhiteSpace(name)) name = "macOS";
|
|
if (string.IsNullOrWhiteSpace(version)) version = "Unknown";
|
|
|
|
var kernel = Run("uname", "-sr"); // "Darwin 23.6.0"
|
|
if (string.IsNullOrWhiteSpace(kernel)) kernel = RuntimeInformation.OSDescription;
|
|
|
|
return new OsInfo("macOS", name.Trim(), version.Trim(), kernel.Trim(), arch);
|
|
}
|
|
|
|
// ---------- helpers ----------
|
|
static Dictionary<string, string> ParseKeyValueFile(string path)
|
|
{
|
|
var d = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
if (!File.Exists(path)) return d;
|
|
foreach (var raw in File.ReadAllLines(path))
|
|
{
|
|
var line = raw.Trim();
|
|
if (line.Length == 0 || line.StartsWith("#")) continue;
|
|
var i = line.IndexOf('=');
|
|
if (i <= 0) continue;
|
|
d[line[..i]] = line[(i + 1)..];
|
|
}
|
|
return d;
|
|
}
|
|
static string TrimQuotes(string s) => s.Trim().Trim('"');
|
|
|
|
static string Run(string file, string args)
|
|
{
|
|
try
|
|
{
|
|
var p = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = file,
|
|
Arguments = args,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true
|
|
}
|
|
};
|
|
p.Start();
|
|
var s = p.StandardOutput.ReadToEnd().Trim();
|
|
p.WaitForExit(1500);
|
|
return s;
|
|
}
|
|
catch { return ""; }
|
|
}
|
|
}
|
|
}
|