Files
Aaru/Aaru.CommonTypes/Interop/DetectOS.cs

435 lines
17 KiB
C#
Raw Normal View History

// /***************************************************************************
2020-02-27 12:31:21 +00:00
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : DetectOS.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Interop services.
//
// --[ Description ] ----------------------------------------------------------
//
// Detects underlying operating system.
//
// --[ License ] --------------------------------------------------------------
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ----------------------------------------------------------------------------
2024-12-19 10:45:18 +00:00
// Copyright © 2011-2025 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Security.Principal;
namespace Aaru.CommonTypes.Interop;
2022-03-06 13:29:30 +00:00
/// <summary>Detects the underlying execution framework and operating system</summary>
public static partial class DetectOS
{
2022-03-06 13:29:30 +00:00
/// <summary>Are we running under Mono?</summary>
public static readonly bool IsMono =
RuntimeInformation.FrameworkDescription.StartsWith("Mono", StringComparison.Ordinal);
/// <summary>Are we running under .NET Core?</summary>
public static readonly bool IsNetCore =
RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.Ordinal);
/// <summary>Checks if the underlying runtime runs in 64-bit mode</summary>
public static readonly bool Is64Bit = IntPtr.Size == 8;
/// <summary>Are we running under Windows?</summary>
public static bool IsWindows => GetRealPlatformID() == PlatformID.Win32NT ||
GetRealPlatformID() == PlatformID.Win32S ||
GetRealPlatformID() == PlatformID.Win32Windows ||
GetRealPlatformID() == PlatformID.WinCE ||
GetRealPlatformID() == PlatformID.WindowsPhone ||
GetRealPlatformID() == PlatformID.Xbox;
/// <summary>Are we running with administrative (root) privileges?</summary>
public static bool IsAdmin
{
2022-03-06 13:29:30 +00:00
get
2018-12-31 13:17:27 +00:00
{
2024-05-01 04:05:22 +01:00
if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return Environment.UserName == "root";
2019-11-03 01:41:48 +00:00
2022-03-06 13:29:30 +00:00
bool isAdmin;
WindowsIdentity user = null;
2018-12-31 13:17:27 +00:00
2022-03-06 13:29:30 +00:00
try
{
user = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(user);
isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch(UnauthorizedAccessException)
{
isAdmin = false;
}
catch(Exception)
{
isAdmin = false;
}
finally
{
user?.Dispose();
2018-12-31 13:17:27 +00:00
}
2022-03-06 13:29:30 +00:00
return isAdmin;
2018-12-31 13:17:27 +00:00
}
2022-03-06 13:29:30 +00:00
}
2018-12-31 13:17:27 +00:00
[DllImport("libc", SetLastError = true)]
static extern int uname(out UtsName name);
[LibraryImport("libc",
EntryPoint = "sysctlbyname",
SetLastError = true,
StringMarshalling = StringMarshalling.Custom,
StringMarshallingCustomType = typeof(AnsiStringMarshaller))]
private static partial int OSX_sysctlbyname(string name, IntPtr oldp, IntPtr oldlenp, IntPtr newp, uint newlen);
2022-03-06 13:29:30 +00:00
/// <summary>Gets the real platform ID, not the incomplete .NET framework one</summary>
/// <returns>Platform ID</returns>
/// <exception cref="Exception">Unhandled exception</exception>
public static PlatformID GetRealPlatformID()
{
if((int)Environment.OSVersion.Platform < 4 || (int)Environment.OSVersion.Platform == 5)
2022-03-06 13:29:30 +00:00
return (PlatformID)(int)Environment.OSVersion.Platform;
2023-10-05 02:31:57 +01:00
int error = uname(out UtsName unixname);
2019-11-03 01:41:48 +00:00
2022-03-06 13:29:30 +00:00
if(error != 0)
{
throw new Exception(string.Format(Localization.Unhandled_exception_calling_uname_0,
Marshal.GetLastWin32Error()));
}
2022-03-06 13:29:30 +00:00
switch(unixname.sysname)
{
// TODO: Differentiate Linux, Android, Tizen
case "Linux":
{
2024-05-01 04:05:22 +01:00
#if __ANDROID__
return PlatformID.Android;
#else
2022-03-06 13:29:30 +00:00
return PlatformID.Linux;
2024-05-01 04:05:22 +01:00
#endif
2022-03-06 13:29:30 +00:00
}
2019-07-15 15:33:46 +01:00
2022-03-06 13:29:30 +00:00
case "Darwin":
{
IntPtr pLen = Marshal.AllocHGlobal(sizeof(int));
int osxError = OSX_sysctlbyname("hw.machine", IntPtr.Zero, pLen, IntPtr.Zero, 0);
if(osxError != 0)
{
2022-03-06 13:29:30 +00:00
Marshal.FreeHGlobal(pLen);
2019-11-03 01:41:48 +00:00
throw new Exception(string.Format(Localization.Unhandled_exception_calling_uname_0,
Marshal.GetLastWin32Error()));
2022-03-06 13:29:30 +00:00
}
2022-03-06 13:29:30 +00:00
int length = Marshal.ReadInt32(pLen);
IntPtr pStr = Marshal.AllocHGlobal(length);
osxError = OSX_sysctlbyname("hw.machine", pStr, pLen, IntPtr.Zero, 0);
2022-03-06 13:29:30 +00:00
if(osxError != 0)
{
Marshal.FreeHGlobal(pStr);
Marshal.FreeHGlobal(pLen);
2019-11-03 01:41:48 +00:00
throw new Exception(string.Format(Localization.Unhandled_exception_calling_uname_0,
Marshal.GetLastWin32Error()));
2022-03-06 13:29:30 +00:00
}
2022-03-06 13:29:30 +00:00
string machine = Marshal.PtrToStringAnsi(pStr);
2022-03-06 13:29:30 +00:00
Marshal.FreeHGlobal(pStr);
Marshal.FreeHGlobal(pLen);
2022-03-06 13:29:30 +00:00
if(machine != null &&
(machine.StartsWith("iPad", StringComparison.Ordinal) ||
machine.StartsWith("iPod", StringComparison.Ordinal) ||
2022-03-06 13:29:30 +00:00
machine.StartsWith("iPhone", StringComparison.Ordinal)))
return PlatformID.iOS;
2022-03-06 13:29:30 +00:00
return PlatformID.MacOSX;
}
2019-07-15 15:33:46 +01:00
case "GNU":
return PlatformID.Hurd;
2022-03-06 13:29:30 +00:00
case "FreeBSD":
case "GNU/kFreeBSD":
return PlatformID.FreeBSD;
case "DragonFly":
return PlatformID.DragonFly;
case "Haiku":
return PlatformID.Haiku;
case "HP-UX":
return PlatformID.HPUX;
case "AIX":
return PlatformID.AIX;
case "OS400":
return PlatformID.OS400;
2022-03-06 13:29:30 +00:00
case "IRIX":
case "IRIX64":
return PlatformID.IRIX;
case "Minix":
return PlatformID.Minix;
case "NetBSD":
return PlatformID.NetBSD;
case "NONSTOP_KERNEL":
return PlatformID.NonStop;
case "OpenBSD":
return PlatformID.OpenBSD;
case "QNX":
return PlatformID.QNX;
case "SINIX-Y":
return PlatformID.SINIX;
case "SunOS":
return PlatformID.Solaris;
case "OSF1":
return PlatformID.Tru64;
case "ULTRIX":
return PlatformID.Ultrix;
case "SCO_SV":
return PlatformID.OpenServer;
case "UnixWare":
return PlatformID.UnixWare;
2022-03-06 13:29:30 +00:00
case "Interix":
case "UWIN-W7":
return PlatformID.Win32NT;
2022-03-06 13:29:30 +00:00
default:
{
if(unixname.sysname.StartsWith("CYGWIN_NT", StringComparison.Ordinal) ||
2022-03-06 13:29:30 +00:00
unixname.sysname.StartsWith("MINGW32_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("MSYS_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("UWIN", StringComparison.Ordinal))
2022-03-06 13:29:30 +00:00
return PlatformID.Win32NT;
2022-03-06 13:29:30 +00:00
return PlatformID.Unknown;
}
}
2022-03-06 13:29:30 +00:00
}
2022-03-06 13:29:30 +00:00
/// <summary>Gets a string for the current operating system REAL version (handles Darwin 1.4 and Windows 10 falsifying)</summary>
/// <returns>Current operating system version</returns>
public static string GetVersion()
{
2022-03-07 07:36:32 +00:00
var environ = Environment.OSVersion.Version.ToString();
2022-03-06 13:29:30 +00:00
switch(GetRealPlatformID())
{
2022-03-06 13:29:30 +00:00
case PlatformID.MacOSX:
2024-05-01 04:05:22 +01:00
if(Environment.OSVersion.Version.Major >= 11) return environ;
2022-03-06 13:29:30 +00:00
if(Environment.OSVersion.Version.Major != 1)
return $"10.{Environment.OSVersion.Version.Major - 4}.{Environment.OSVersion.Version.Minor}";
2022-03-06 13:29:30 +00:00
switch(Environment.OSVersion.Version.Minor)
{
case 3:
return "10.0";
case 4:
return "10.1";
2022-03-06 13:29:30 +00:00
}
goto default;
case PlatformID.Win32NT:
// From Windows 8.1 the reported version is simply falsified...
2023-10-04 09:37:47 +01:00
if(Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2 ||
Environment.OSVersion.Version.Major > 6)
{
2024-05-01 04:05:22 +01:00
return FileVersionInfo
.GetVersionInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),
"KERNEL32.DLL"))
.ProductVersion;
}
2022-03-06 13:29:30 +00:00
return environ;
default:
return environ;
}
2022-03-06 13:29:30 +00:00
}
2022-03-06 13:29:30 +00:00
/// <summary>From a platform ID and version returns a human-readable version</summary>
/// <param name="id">Platform ID</param>
/// <param name="version">Version number</param>
/// <returns>Operating system name</returns>
public static string GetPlatformName(PlatformID id, string version = null)
{
switch(id)
{
case PlatformID.AIX:
return "AIX";
case PlatformID.Android:
return "Android";
case PlatformID.DragonFly:
return "DragonFly BSD";
case PlatformID.FreeBSD:
return "FreeBSD";
case PlatformID.Haiku:
return "Haiku";
case PlatformID.HPUX:
return "HP/UX";
case PlatformID.Hurd:
return "Hurd";
case PlatformID.iOS:
return "iOS";
case PlatformID.IRIX:
return "IRIX";
2022-03-06 13:29:30 +00:00
case PlatformID.Linux:
2024-05-01 04:05:22 +01:00
if(!File.Exists("/proc/version")) return "Linux";
2022-03-06 13:29:30 +00:00
string s = File.ReadAllText("/proc/version");
return s.Contains("Microsoft") || s.Contains("WSL") ? "Windows Subsystem for Linux" : "Linux";
case PlatformID.MacOSX:
2024-05-01 04:05:22 +01:00
if(string.IsNullOrEmpty(version)) return "macOS";
2022-03-06 13:29:30 +00:00
string[] pieces = version.Split('.');
2024-05-01 04:05:22 +01:00
if(pieces.Length < 2 || !int.TryParse(pieces[1], out int minor)) return "macOS";
2022-03-06 13:29:30 +00:00
int.TryParse(pieces[0], out int major);
2022-03-06 13:29:30 +00:00
2024-05-01 04:05:22 +01:00
if(minor >= 12 || major >= 11) return "macOS";
2022-03-06 13:29:30 +00:00
return minor >= 8 ? "OS X" : "Mac OS X";
2022-03-06 13:29:30 +00:00
case PlatformID.Minix:
return "MINIX";
case PlatformID.NetBSD:
return "NetBSD";
case PlatformID.NonStop:
return "NonStop OS";
case PlatformID.OpenBSD:
return "OpenBSD";
case PlatformID.OpenServer:
return "SCO OpenServer";
case PlatformID.OS400:
return "OS/400";
case PlatformID.PlayStation3:
return "Sony CellOS";
case PlatformID.PlayStation4:
return "Sony Orbis OS";
case PlatformID.QNX:
return "QNX";
case PlatformID.SINIX:
return "SINIX";
case PlatformID.Solaris:
return "Sun Solaris";
case PlatformID.Tizen:
return "Samsung Tizen";
case PlatformID.Tru64:
return "Tru64 UNIX";
case PlatformID.Ultrix:
return "Ultrix";
case PlatformID.Unix:
return "UNIX";
case PlatformID.UnixWare:
return "SCO UnixWare";
case PlatformID.Wii:
return "Nintendo Wii";
case PlatformID.WiiU:
return "Nintendo Wii U";
2022-03-06 13:29:30 +00:00
case PlatformID.Win32NT:
2024-05-01 04:05:22 +01:00
if(string.IsNullOrEmpty(version)) return "Windows NT/2000/XP/Vista/7/10";
2019-11-03 01:41:48 +00:00
2022-03-06 13:29:30 +00:00
if(version.StartsWith("3.", StringComparison.Ordinal) ||
version.StartsWith("4.", StringComparison.Ordinal))
return "Windows NT";
2024-05-01 04:05:22 +01:00
if(version.StartsWith("5.0", StringComparison.Ordinal)) return "Windows 2000";
2022-03-06 13:29:30 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("5.1", StringComparison.Ordinal)) return "Windows XP";
2022-03-06 13:29:30 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("5.2", StringComparison.Ordinal)) return "Windows 2003";
2019-11-03 01:41:48 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("6.0", StringComparison.Ordinal)) return "Windows Vista";
2019-11-03 01:41:48 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("6.1", StringComparison.Ordinal)) return "Windows 7";
2019-11-03 01:41:48 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("6.2", StringComparison.Ordinal)) return "Windows 8";
2019-11-03 01:41:48 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("6.3", StringComparison.Ordinal)) return "Windows 8.1";
2022-03-06 13:29:30 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("10.0", StringComparison.Ordinal)) return "Windows 10";
2022-03-06 13:29:30 +00:00
return version.StartsWith("11.0", StringComparison.Ordinal)
? "Windows 11"
2022-11-13 20:54:01 +00:00
: "Windows NT/2000/XP/Vista/7/10/11";
2022-04-10 10:17:48 +01:00
case PlatformID.Win32S:
return "Windows 3.x with win32s";
2022-03-06 13:29:30 +00:00
case PlatformID.Win32Windows:
2024-05-01 04:05:22 +01:00
if(string.IsNullOrEmpty(version)) return "Windows 9x/Me";
2024-05-01 04:05:22 +01:00
if(version.StartsWith("4.0", StringComparison.Ordinal)) return "Windows 95";
2022-03-06 13:29:30 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("4.10.2222", StringComparison.Ordinal)) return "Windows 98 SE";
2022-03-06 13:29:30 +00:00
2024-05-01 04:05:22 +01:00
if(version.StartsWith("4.1", StringComparison.Ordinal)) return "Windows 98";
2022-03-06 13:29:30 +00:00
2022-11-13 20:54:01 +00:00
return version.StartsWith("4.9", StringComparison.Ordinal) ? "Windows Me" : "Windows 9x/Me";
2022-03-06 13:29:30 +00:00
case PlatformID.WinCE:
return "Windows CE/Mobile";
case PlatformID.WindowsPhone:
return "Windows Phone";
case PlatformID.Xbox:
return "Xbox OS";
case PlatformID.zOS:
return "z/OS";
default:
return id.ToString();
}
}
2022-03-06 13:29:30 +00:00
2023-10-05 02:31:57 +01:00
#region Nested type: UtsName
2022-03-06 13:29:30 +00:00
/// <summary>POSIX uname structure, size from OSX, big enough to handle extra fields</summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
2023-10-05 02:31:57 +01:00
struct UtsName
2022-03-06 13:29:30 +00:00
{
/// <summary>System name</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string sysname;
/// <summary>Node name</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string nodename;
/// <summary>Release level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string release;
/// <summary>Version level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string version;
/// <summary>Hardware level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string machine;
}
#endregion
}