2018-04-11 07:15:03 +01:00
|
|
|
// /***************************************************************************
|
|
|
|
|
// The Disc Image Chef
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// Copyright © 2011-2018 Natalia Portillo
|
|
|
|
|
// ****************************************************************************/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
|
|
|
namespace DiscImageChef.Interop
|
|
|
|
|
{
|
|
|
|
|
public static class DetectOS
|
|
|
|
|
{
|
|
|
|
|
public static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;
|
|
|
|
|
|
2020-02-10 22:44:18 +00:00
|
|
|
/// <summary>Checks if the underlying runtime runs in 64-bit mode</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
public static readonly bool Is64Bit = IntPtr.Size == 8;
|
|
|
|
|
|
2020-02-10 22:44:18 +00:00
|
|
|
/// <summary>Checks if the underlying runtime runs in 32-bit mode</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
public static readonly bool Is32Bit = IntPtr.Size == 4;
|
|
|
|
|
|
|
|
|
|
[DllImport("libc", SetLastError = true)]
|
|
|
|
|
static extern int uname(out utsname name);
|
|
|
|
|
|
|
|
|
|
[DllImport("libc", SetLastError = true, EntryPoint = "sysctlbyname", CharSet = CharSet.Ansi)]
|
|
|
|
|
static extern int OSX_sysctlbyname(string name, IntPtr oldp, IntPtr oldlenp, IntPtr newp, uint newlen);
|
|
|
|
|
|
2020-02-10 22:44:18 +00:00
|
|
|
/// <summary>Gets the real platform ID, not the incomplete .NET framework one</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
/// <returns>Platform ID</returns>
|
|
|
|
|
/// <exception cref="Exception">Unhandled exception</exception>
|
|
|
|
|
public static PlatformID GetRealPlatformID()
|
|
|
|
|
{
|
2020-02-10 22:44:18 +00:00
|
|
|
if((int)Environment.OSVersion.Platform < 4 ||
|
|
|
|
|
(int)Environment.OSVersion.Platform == 5)
|
|
|
|
|
return(PlatformID)(int)Environment.OSVersion.Platform;
|
2018-04-11 07:15:03 +01:00
|
|
|
|
|
|
|
|
int error = uname(out utsname unixname);
|
2020-02-10 22:44:18 +00:00
|
|
|
|
|
|
|
|
if(error != 0)
|
|
|
|
|
throw new Exception($"Unhandled exception calling uname: {Marshal.GetLastWin32Error()}");
|
2018-04-11 07:15:03 +01:00
|
|
|
|
|
|
|
|
switch(unixname.sysname)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Differentiate Linux, Android, Tizen
|
2020-02-10 22:44:18 +00:00
|
|
|
case"Linux":
|
2018-04-11 07:15:03 +01:00
|
|
|
{
|
2020-02-10 22:44:18 +00:00
|
|
|
#if __ANDROID__
|
2018-04-11 07:15:03 +01:00
|
|
|
return PlatformID.Android;
|
2020-02-10 22:44:18 +00:00
|
|
|
#else
|
2018-04-11 07:15:03 +01:00
|
|
|
return PlatformID.Linux;
|
2020-02-10 22:44:18 +00:00
|
|
|
#endif
|
2018-04-11 07:15:03 +01:00
|
|
|
}
|
2020-02-10 22:44:18 +00:00
|
|
|
case"Darwin":
|
2018-04-11 07:15:03 +01:00
|
|
|
{
|
|
|
|
|
int osxError;
|
|
|
|
|
|
|
|
|
|
IntPtr pLen = Marshal.AllocHGlobal(sizeof(int));
|
|
|
|
|
osxError = OSX_sysctlbyname("hw.machine", IntPtr.Zero, pLen, IntPtr.Zero, 0);
|
2020-02-10 22:44:18 +00:00
|
|
|
|
2018-04-11 07:15:03 +01:00
|
|
|
if(osxError != 0)
|
|
|
|
|
{
|
|
|
|
|
Marshal.FreeHGlobal(pLen);
|
|
|
|
|
|
|
|
|
|
throw new Exception($"Unhandled exception calling uname: {Marshal.GetLastWin32Error()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int length = Marshal.ReadInt32(pLen);
|
|
|
|
|
IntPtr pStr = Marshal.AllocHGlobal(length);
|
|
|
|
|
osxError = OSX_sysctlbyname("hw.machine", pStr, pLen, IntPtr.Zero, 0);
|
2020-02-10 22:44:18 +00:00
|
|
|
|
2018-04-11 07:15:03 +01:00
|
|
|
if(osxError != 0)
|
|
|
|
|
{
|
|
|
|
|
Marshal.FreeHGlobal(pStr);
|
|
|
|
|
Marshal.FreeHGlobal(pLen);
|
|
|
|
|
|
|
|
|
|
throw new Exception($"Unhandled exception calling uname: {Marshal.GetLastWin32Error()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string machine = Marshal.PtrToStringAnsi(pStr);
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(pStr);
|
|
|
|
|
Marshal.FreeHGlobal(pLen);
|
|
|
|
|
|
2020-02-10 22:44:18 +00:00
|
|
|
if(machine != null &&
|
|
|
|
|
(machine.StartsWith("iPad", StringComparison.Ordinal) ||
|
|
|
|
|
machine.StartsWith("iPod", StringComparison.Ordinal) ||
|
|
|
|
|
machine.StartsWith("iPhone", StringComparison.Ordinal)))
|
2018-04-11 07:15:03 +01:00
|
|
|
return PlatformID.iOS;
|
|
|
|
|
|
|
|
|
|
return PlatformID.MacOSX;
|
|
|
|
|
}
|
2020-02-10 22:44:18 +00:00
|
|
|
case"GNU": return PlatformID.Hurd;
|
|
|
|
|
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;
|
|
|
|
|
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;
|
|
|
|
|
case"Interix":
|
|
|
|
|
case"UWIN-W7": return PlatformID.Win32NT;
|
2018-04-11 07:15:03 +01:00
|
|
|
default:
|
|
|
|
|
{
|
2020-02-10 22:44:18 +00:00
|
|
|
if(unixname.sysname.StartsWith("CYGWIN_NT", StringComparison.Ordinal) ||
|
2018-04-11 07:15:03 +01:00
|
|
|
unixname.sysname.StartsWith("MINGW32_NT", StringComparison.Ordinal) ||
|
2020-02-10 22:44:18 +00:00
|
|
|
unixname.sysname.StartsWith("MSYS_NT", StringComparison.Ordinal) ||
|
|
|
|
|
unixname.sysname.StartsWith("UWIN", StringComparison.Ordinal))
|
|
|
|
|
return PlatformID.Win32NT;
|
2018-04-11 07:15:03 +01:00
|
|
|
|
|
|
|
|
return PlatformID.Unknown;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-10 22:44:18 +00:00
|
|
|
/// <summary>Gets a string for the current operating system REAL version (handles Darwin 1.4 and Windows 10 falsifying)</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
/// <returns>Current operating system version</returns>
|
|
|
|
|
public static string GetVersion()
|
|
|
|
|
{
|
|
|
|
|
string environ = Environment.OSVersion.Version.ToString();
|
|
|
|
|
|
|
|
|
|
switch(GetRealPlatformID())
|
|
|
|
|
{
|
|
|
|
|
case PlatformID.MacOSX:
|
|
|
|
|
if(Environment.OSVersion.Version.Major != 1)
|
2020-02-10 22:44:18 +00:00
|
|
|
return$"10.{Environment.OSVersion.Version.Major - 4}.{Environment.OSVersion.Version.Minor}";
|
2018-04-11 07:15:03 +01:00
|
|
|
|
|
|
|
|
switch(Environment.OSVersion.Version.Minor)
|
|
|
|
|
{
|
2020-02-10 22:44:18 +00:00
|
|
|
case 3: return"10.0";
|
|
|
|
|
case 4: return"10.1";
|
2018-04-11 07:15:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto default;
|
|
|
|
|
case PlatformID.Win32NT:
|
|
|
|
|
// From Windows 8.1 the reported version is simply falsified...
|
2020-02-10 22:44:18 +00:00
|
|
|
if((Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Major >= 2) ||
|
2018-04-11 07:15:03 +01:00
|
|
|
Environment.OSVersion.Version.Major > 6)
|
2020-02-10 22:44:18 +00:00
|
|
|
return FileVersionInfo.
|
|
|
|
|
GetVersionInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),
|
2018-04-11 07:15:03 +01:00
|
|
|
"KERNEL32.DLL")).ProductVersion;
|
|
|
|
|
|
|
|
|
|
return environ;
|
|
|
|
|
default: return environ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-10 22:44:18 +00:00
|
|
|
/// <summary>From a platform ID and version returns a human-readable version</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
/// <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)
|
|
|
|
|
{
|
2020-02-10 22:44:18 +00:00
|
|
|
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";
|
|
|
|
|
case PlatformID.Linux: return"Linux";
|
2018-04-11 07:15:03 +01:00
|
|
|
case PlatformID.MacOSX:
|
2020-02-10 22:44:18 +00:00
|
|
|
if(string.IsNullOrEmpty(version))
|
|
|
|
|
return"macOS";
|
2018-04-11 07:15:03 +01:00
|
|
|
|
|
|
|
|
string[] pieces = version.Split('.');
|
2020-02-10 22:44:18 +00:00
|
|
|
|
|
|
|
|
if(pieces.Length < 2 ||
|
|
|
|
|
!int.TryParse(pieces[1], out int minor))
|
|
|
|
|
return"macOS";
|
|
|
|
|
|
|
|
|
|
if(minor >= 12)
|
|
|
|
|
return"macOS";
|
|
|
|
|
|
|
|
|
|
if(minor >= 8)
|
|
|
|
|
return"OS X";
|
|
|
|
|
|
|
|
|
|
return"Mac OS X";
|
|
|
|
|
|
|
|
|
|
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";
|
2018-04-11 07:15:03 +01:00
|
|
|
case PlatformID.Win32NT:
|
2020-02-10 22:44:18 +00:00
|
|
|
if(string.IsNullOrEmpty(version))
|
|
|
|
|
return"Windows NT/2000/XP/Vista/7/10";
|
|
|
|
|
|
2018-04-11 07:15:03 +01:00
|
|
|
if(version.StartsWith("3.", StringComparison.Ordinal) ||
|
2020-02-10 22:44:18 +00:00
|
|
|
version.StartsWith("4.", StringComparison.Ordinal))
|
|
|
|
|
return"Windows NT";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("5.0", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 2000";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("5.1", StringComparison.Ordinal))
|
|
|
|
|
return"Windows XP";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("5.2", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 2003";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("6.0", StringComparison.Ordinal))
|
|
|
|
|
return"Windows Vista";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("6.1", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 7";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("6.2", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 8";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("6.3", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 8.1";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("10.0", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 10";
|
|
|
|
|
|
|
|
|
|
return"Windows NT/2000/XP/Vista/7/10";
|
|
|
|
|
case PlatformID.Win32S: return"Windows 3.x with win32s";
|
2018-04-11 07:15:03 +01:00
|
|
|
case PlatformID.Win32Windows:
|
2020-02-10 22:44:18 +00:00
|
|
|
if(string.IsNullOrEmpty(version))
|
|
|
|
|
return"Windows 9x/Me";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("4.0", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 95";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("4.10.2222", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 98 SE";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("4.1", StringComparison.Ordinal))
|
|
|
|
|
return"Windows 98";
|
|
|
|
|
|
|
|
|
|
if(version.StartsWith("4.9", StringComparison.Ordinal))
|
|
|
|
|
return"Windows Me";
|
|
|
|
|
|
|
|
|
|
return"Windows 9x/Me";
|
|
|
|
|
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";
|
2018-04-11 07:15:03 +01:00
|
|
|
default: return id.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-10 22:44:18 +00:00
|
|
|
/// <summary>POSIX uname structure, size from OSX, big enough to handle extra fields</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
|
|
|
|
struct utsname
|
|
|
|
|
{
|
2020-02-10 22:44:18 +00:00
|
|
|
/// <summary>System name</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
2020-02-10 22:44:18 +00:00
|
|
|
public readonly string sysname;
|
|
|
|
|
/// <summary>Node name</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
2020-02-10 22:44:18 +00:00
|
|
|
public readonly string nodename;
|
|
|
|
|
/// <summary>Release level</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
2020-02-10 22:44:18 +00:00
|
|
|
public readonly string release;
|
|
|
|
|
/// <summary>Version level</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
2020-02-10 22:44:18 +00:00
|
|
|
public readonly string version;
|
|
|
|
|
/// <summary>Hardware level</summary>
|
2018-04-11 07:15:03 +01:00
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
2020-02-10 22:44:18 +00:00
|
|
|
public readonly string machine;
|
2018-04-11 07:15:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|