diff --git a/LinuxLauncher/README.md b/LinuxLauncher/README.md
index 32f3b5a..7ee2a74 100644
--- a/LinuxLauncher/README.md
+++ b/LinuxLauncher/README.md
@@ -11,7 +11,8 @@ make an AUR package of this script if all goes to plan.
* the first time you start the game, the Wine virtual desktop doesn't
enable properly
-* the story mode intro crashes when it starts to "format" your drive
+* text input boxes are white on white
+* the terminal puts an extra newline after displaying the prompt
* the ShiftOS desktop can go in front of applications
* there is a blue border from the Wine desktop (I want to change that
to black, but I also don't want it showing through while the game is
diff --git a/ShiftOS.WinForms/OobeStory.cs b/ShiftOS.WinForms/OobeStory.cs
index f2a4930..cab1ec8 100644
--- a/ShiftOS.WinForms/OobeStory.cs
+++ b/ShiftOS.WinForms/OobeStory.cs
@@ -85,28 +85,40 @@ namespace ShiftOS.WinForms
ConsoleEx.ForegroundColor = ConsoleColor.White;
Console.WriteLine(@"We'll now begin formatting your drive. Please be patient.");
Console.WriteLine();
- var dinf = new DriveInfo("C:\\");
- decimal bytesFree = ((dinf.AvailableFreeSpace / 1024) / 1024) / 1024;
- decimal totalBytes = ((dinf.TotalSize / 1024) / 1024) / 1024;
- string type = dinf.DriveType.ToString();
- string name = dinf.Name;
- ConsoleEx.Bold = true;
- Console.Write("Drive name: ");
- ConsoleEx.Bold = false;
- Console.WriteLine(name);
- ConsoleEx.Bold = true;
- Console.Write("Drive type: ");
- ConsoleEx.Bold = false;
- Console.WriteLine(type);
- ConsoleEx.Bold = true;
- Console.Write("Total space: ");
- ConsoleEx.Bold = false;
- Console.WriteLine(totalBytes.ToString() + " GB");
- ConsoleEx.Bold = true;
- Console.Write("Free space: ");
- Console.WriteLine(bytesFree.ToString() + " GB");
- Console.WriteLine();
-
+ double bytesFree, totalBytes;
+ string type, name;
+ dynamic dinf;
+ try
+ {
+ if (Lunix.InWine)
+ dinf = new Lunix.DFDriveInfo("/");
+ else
+ dinf = new DriveInfo("C:\\");
+ bytesFree = dinf.AvailableFreeSpace / 1073741824.0;
+ totalBytes = dinf.TotalSize / 1073741824.0;
+ type = dinf.DriveFormat.ToString();
+ name = dinf.Name;
+ ConsoleEx.Bold = true;
+ Console.Write("Drive name: ");
+ ConsoleEx.Bold = false;
+ Console.WriteLine(name);
+ ConsoleEx.Bold = true;
+ Console.Write("Drive type: ");
+ ConsoleEx.Bold = false;
+ Console.WriteLine(type);
+ ConsoleEx.Bold = true;
+ Console.Write("Total space: ");
+ ConsoleEx.Bold = false;
+ Console.WriteLine(String.Format("{0:F1}", totalBytes) + " GB");
+ ConsoleEx.Bold = true;
+ Console.Write("Free space: ");
+ Console.WriteLine(String.Format("{0:F1}", bytesFree) + " GB");
+ Console.WriteLine();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.ToString());
+ }
ConsoleEx.Bold = false;
ConsoleEx.BackgroundColor = ConsoleColor.Black;
diff --git a/ShiftOS_TheReturn/Lunix.cs b/ShiftOS_TheReturn/Lunix.cs
new file mode 100644
index 0000000..529cb71
--- /dev/null
+++ b/ShiftOS_TheReturn/Lunix.cs
@@ -0,0 +1,201 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2017 Michael VanOverbeek and ShiftOS devs
+ *
+ * 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.
+ */
+
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ShiftOS.Engine
+{
+ ///
+ /// Special functions for when we're running under Wine. (Pure Mono is not detected)
+ ///
+ public static class Lunix
+ {
+ ///
+ /// Determines if the game is running under Wine or not.
+ ///
+ public static bool InWine
+ {
+ get
+ {
+ var WineKey = Registry.CurrentUser.OpenSubKey(@"Software\Wine");
+ return WineKey != null;
+ }
+ }
+ ///
+ /// Escape Wine and run shell commands.
+ ///
+ public static class Bash
+ {
+ ///
+ /// Run a command in Bash on the host OS.
+ ///
+ /// The command to run.
+ /// Everything put on STDOUT by the command.
+ public static string RunCommand(string command)
+ {
+ string outfile = Path.GetRandomFileName();
+ string outpath = "Z:\\tmp\\" + outfile;
+ string copypath = Path.GetTempPath() + Path.GetRandomFileName();
+ var p = new Process();
+ p.StartInfo.UseShellExecute = false;
+ p.StartInfo.RedirectStandardOutput = true;
+ p.StartInfo.FileName = "cmd";
+ p.StartInfo.Arguments = "/C start Z:\\bin\\bash -c \"" + command.Replace("\"", "\\\"") + " > /tmp/" + outfile + "\"";
+ p.Start();
+ p.WaitForExit();
+ p.StartInfo.Arguments = "/C move " + outpath + " " + copypath; // Move the file somewhere .NET can see it.
+ p.Start();
+ p.WaitForExit();
+ string output = File.ReadAllText(copypath);
+ File.Delete(copypath); // Get rid of that.
+ return output;
+ }
+ }
+ ///
+ /// Basic, unreliable implementation of DriveInfo using df and lsblk.
+ ///
+ public class DFDriveInfo
+ {
+ private int dfrow, lsblkrow;
+ public string Name;
+ private static string[] rundf(string output)
+ {
+ return Bash.RunCommand("df --output='" + output + "'").Split('\n');
+ }
+
+ private string ourdf(string output)
+ {
+ return rundf(output)[dfrow];
+ }
+
+ private static string[] runlsblk(string output)
+ {
+ return Bash.RunCommand("lsblk -b --output='" + output + "'").Split('\n');
+ }
+
+ private string ourlsblk(string output)
+ {
+ return runlsblk(output)[lsblkrow];
+ }
+
+ public DFDriveInfo(string driveName)
+ {
+ dfrow = Array.IndexOf(rundf("target"), driveName);
+ lsblkrow = Array.IndexOf(runlsblk("MOUNTPOINT"), driveName);
+ Name = driveName;
+ }
+ public long AvailableFreeSpace
+ {
+ get
+ {
+ return Convert.ToInt64(ourdf("avail"));
+ }
+ }
+
+ public string DriveFormat
+ {
+ get
+ {
+ return Bash.RunCommand("df --output='fstype'").Split('\n')[dfrow];
+ }
+ }
+
+ public DriveType DriveType
+ {
+ get
+ {
+ return DriveType.Unknown;
+ }
+ }
+
+ public bool IsReady
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public DirectoryInfo RootDirectory
+ {
+ get
+ {
+ return new DirectoryInfo("Z:" + Name.Replace('/', '\\'));
+ }
+ }
+
+ public long TotalFreeSpace
+ {
+ get
+ {
+ return AvailableFreeSpace;
+ }
+ }
+
+ public long TotalSize
+ {
+ get
+ {
+ return Convert.ToInt64(ourlsblk("SIZE"));
+ }
+ }
+
+ public string VolumeLabel
+ {
+ get
+ {
+ return ourlsblk("LABEL");
+ }
+
+ set
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static DFDriveInfo[] GetDrives()
+ {
+ string[] dnames = rundf("target");
+ var output = new DFDriveInfo[dnames.Length - 1];
+ for (int i = 1; i < dnames.Length; i++)
+ output[i - 1] = new DFDriveInfo(dnames[i]);
+ return output;
+ }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+ }
+ }
+}
diff --git a/ShiftOS_TheReturn/ShiftOS.Engine.csproj b/ShiftOS_TheReturn/ShiftOS.Engine.csproj
index 31f423c..9c9ad0f 100644
--- a/ShiftOS_TheReturn/ShiftOS.Engine.csproj
+++ b/ShiftOS_TheReturn/ShiftOS.Engine.csproj
@@ -138,6 +138,7 @@
+