aboutsummaryrefslogtreecommitdiff
path: root/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs')
-rw-r--r--Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs481
1 files changed, 481 insertions, 0 deletions
diff --git a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
new file mode 100644
index 000000000..12669d05d
--- /dev/null
+++ b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
@@ -0,0 +1,481 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Diagnostics;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.System;
+using System.Runtime.InteropServices;
+
+namespace IsoMounter
+{
+ public class LinuxIsoManager : IIsoMounter
+ {
+ [DllImport("libc", SetLastError = true)]
+ public static extern uint getuid();
+
+ #region Private Fields
+
+ private readonly IEnvironmentInfo EnvironmentInfo;
+ private readonly bool ExecutablesAvailable;
+ private readonly IFileSystem FileSystem;
+ private readonly ILogger Logger;
+ private readonly string MountCommand;
+ private readonly string MountPointRoot;
+ private readonly IProcessFactory ProcessFactory;
+ private readonly string SudoCommand;
+ private readonly string UmountCommand;
+
+ #endregion
+
+ #region Constructor(s)
+
+ public LinuxIsoManager(ILogger logger, IFileSystem fileSystem, IEnvironmentInfo environment, IProcessFactory processFactory)
+ {
+
+ EnvironmentInfo = environment;
+ FileSystem = fileSystem;
+ Logger = logger;
+ ProcessFactory = processFactory;
+
+ MountPointRoot = FileSystem.DirectorySeparatorChar + "tmp" + FileSystem.DirectorySeparatorChar + "Emby";
+
+ Logger.Debug(
+ "[{0}] System PATH is currently set to [{1}].",
+ Name,
+ EnvironmentInfo.GetEnvironmentVariable("PATH") ?? ""
+ );
+
+ Logger.Debug(
+ "[{0}] System path separator is [{1}].",
+ Name,
+ EnvironmentInfo.PathSeparator
+ );
+
+ Logger.Debug(
+ "[{0}] Mount point root is [{1}].",
+ Name,
+ MountPointRoot
+ );
+
+ //
+ // Get the location of the executables we need to support mounting/unmounting ISO images.
+ //
+
+ SudoCommand = GetFullPathForExecutable("sudo");
+
+ Logger.Info(
+ "[{0}] Using version of [sudo] located at [{1}].",
+ Name,
+ SudoCommand
+ );
+
+ MountCommand = GetFullPathForExecutable("mount");
+
+ Logger.Info(
+ "[{0}] Using version of [mount] located at [{1}].",
+ Name,
+ MountCommand
+ );
+
+ UmountCommand = GetFullPathForExecutable("umount");
+
+ Logger.Info(
+ "[{0}] Using version of [umount] located at [{1}].",
+ Name,
+ UmountCommand
+ );
+
+ if (!String.IsNullOrEmpty(SudoCommand) && !String.IsNullOrEmpty(MountCommand) && !String.IsNullOrEmpty(UmountCommand)) {
+ ExecutablesAvailable = true;
+ } else {
+ ExecutablesAvailable = false;
+ }
+
+ }
+
+ #endregion
+
+ #region Interface Implementation for IIsoMounter
+
+ public bool IsInstalled {
+ get {
+ return true;
+ }
+ }
+
+ public string Name {
+ get { return "LinuxMount"; }
+ }
+
+ public bool RequiresInstallation {
+ get {
+ return false;
+ }
+ }
+
+ public bool CanMount(string path)
+ {
+
+ if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux) {
+ Logger.Info(
+ "[{0}] Checking we can attempt to mount [{1}], Extension = [{2}], Operating System = [{3}], Executables Available = [{4}].",
+ Name,
+ path,
+ Path.GetExtension(path),
+ EnvironmentInfo.OperatingSystem,
+ ExecutablesAvailable.ToString()
+ );
+
+ if (ExecutablesAvailable) {
+ return string.Equals(Path.GetExtension(path), ".iso", StringComparison.OrdinalIgnoreCase);
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ }
+
+ public Task Install(CancellationToken cancellationToken)
+ {
+ return Task.FromResult(false);
+ }
+
+ public async Task<IIsoMount> Mount(string isoPath, CancellationToken cancellationToken)
+ {
+
+ LinuxMount mountedISO;
+
+ if (MountISO(isoPath, out mountedISO)) {
+
+ return mountedISO;
+
+ }else{
+
+ throw new IOException(String.Format(
+ "An error occurred trying to mount image [$0].",
+ isoPath
+ ));
+
+ }
+
+ }
+
+ #endregion
+
+ #region Interface Implementation for IDisposable
+
+ // Flag: Has Dispose already been called?
+ private bool disposed = false;
+
+ public void Dispose()
+ {
+
+ // Dispose of unmanaged resources.
+ Dispose(true);
+
+ // Suppress finalization.
+ GC.SuppressFinalize(this);
+
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+
+ if (disposed) {
+ return;
+ }
+
+ Logger.Info(
+ "[{0}] Disposing [{1}].",
+ Name,
+ disposing.ToString()
+ );
+
+ if (disposing) {
+
+ //
+ // Free managed objects here.
+ //
+
+ }
+
+ //
+ // Free any unmanaged objects here.
+ //
+
+ disposed = true;
+
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private string GetFullPathForExecutable(string name)
+ {
+
+ foreach (string test in (EnvironmentInfo.GetEnvironmentVariable("PATH") ?? "").Split(EnvironmentInfo.PathSeparator)) {
+
+ string path = test.Trim();
+
+ if (!String.IsNullOrEmpty(path) && FileSystem.FileExists(path = Path.Combine(path, name))) {
+ return FileSystem.GetFullPath(path);
+ }
+
+ }
+
+ return String.Empty;
+
+ }
+
+ private uint GetUID()
+ {
+
+ var uid = getuid();
+
+ Logger.Debug(
+ "[{0}] Our current UID is [{1}], GetUserId() returned [{2}].",
+ Name,
+ uid.ToString(),
+ uid
+ );
+
+ return uid;
+
+ }
+
+ private bool ExecuteCommand(string cmdFilename, string cmdArguments)
+ {
+
+ bool processFailed = false;
+
+ var process = ProcessFactory.Create(
+ new ProcessOptions {
+ CreateNoWindow = true,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ FileName = cmdFilename,
+ Arguments = cmdArguments,
+ IsHidden = true,
+ ErrorDialog = false,
+ EnableRaisingEvents = true
+ }
+ );
+
+ try {
+
+ process.Start();
+
+ //StreamReader outputReader = process.StandardOutput.;
+ //StreamReader errorReader = process.StandardError;
+
+ Logger.Debug(
+ "[{0}] Standard output from process is [{1}].",
+ Name,
+ process.StandardOutput.ReadToEnd()
+ );
+
+ Logger.Debug(
+ "[{0}] Standard error from process is [{1}].",
+ Name,
+ process.StandardError.ReadToEnd()
+ );
+
+ } catch (Exception ex) {
+
+ processFailed = true;
+
+ Logger.Debug(
+ "[{0}] Unhandled exception executing command, exception is [{1}].",
+ Name,
+ ex.Message
+ );
+
+ }
+
+ if (!processFailed && process.ExitCode == 0) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ private bool MountISO(string isoPath, out LinuxMount mountedISO)
+ {
+
+ string cmdArguments;
+ string cmdFilename;
+ string mountPoint = Path.Combine(MountPointRoot, Guid.NewGuid().ToString());
+
+ if (!string.IsNullOrEmpty(isoPath)) {
+
+ Logger.Info(
+ "[{0}] Attempting to mount [{1}].",
+ Name,
+ isoPath
+ );
+
+ Logger.Debug(
+ "[{0}] ISO will be mounted at [{1}].",
+ Name,
+ mountPoint
+ );
+
+ } else {
+
+ throw new ArgumentNullException(nameof(isoPath));
+
+ }
+
+ try {
+ FileSystem.CreateDirectory(mountPoint);
+ } catch (UnauthorizedAccessException) {
+ throw new IOException("Unable to create mount point(Permission denied) for " + isoPath);
+ } catch (Exception) {
+ throw new IOException("Unable to create mount point for " + isoPath);
+ }
+
+ if (GetUID() == 0) {
+ cmdFilename = MountCommand;
+ cmdArguments = string.Format("\"{0}\" \"{1}\"", isoPath, mountPoint);
+ } else {
+ cmdFilename = SudoCommand;
+ cmdArguments = string.Format("\"{0}\" \"{1}\" \"{2}\"", MountCommand, isoPath, mountPoint);
+ }
+
+ Logger.Debug(
+ "[{0}] Mount command [{1}], mount arguments [{2}].",
+ Name,
+ cmdFilename,
+ cmdArguments
+ );
+
+ if (ExecuteCommand(cmdFilename, cmdArguments)) {
+
+ Logger.Info(
+ "[{0}] ISO mount completed successfully.",
+ Name
+ );
+
+ mountedISO = new LinuxMount(this, isoPath, mountPoint);
+
+ } else {
+
+ Logger.Info(
+ "[{0}] ISO mount completed with errors.",
+ Name
+ );
+
+ try {
+
+ FileSystem.DeleteDirectory(mountPoint, false);
+
+ } catch (Exception ex) {
+
+ Logger.Info(
+ "[{0}] Unhandled exception removing mount point, exception is [{1}].",
+ Name,
+ ex.Message
+ );
+
+ }
+
+ mountedISO = null;
+
+ }
+
+ return mountedISO != null;
+
+ }
+
+ private void UnmountISO(LinuxMount mount)
+ {
+
+ string cmdArguments;
+ string cmdFilename;
+
+ if (mount != null) {
+
+ Logger.Info(
+ "[{0}] Attempting to unmount ISO [{1}] mounted on [{2}].",
+ Name,
+ mount.IsoPath,
+ mount.MountedPath
+ );
+
+ } else {
+
+ throw new ArgumentNullException(nameof(mount));
+
+ }
+
+ if (GetUID() == 0) {
+ cmdFilename = UmountCommand;
+ cmdArguments = string.Format("\"{0}\"", mount.MountedPath);
+ } else {
+ cmdFilename = SudoCommand;
+ cmdArguments = string.Format("\"{0}\" \"{1}\"", UmountCommand, mount.MountedPath);
+ }
+
+ Logger.Debug(
+ "[{0}] Umount command [{1}], umount arguments [{2}].",
+ Name,
+ cmdFilename,
+ cmdArguments
+ );
+
+ if (ExecuteCommand(cmdFilename, cmdArguments)) {
+
+ Logger.Info(
+ "[{0}] ISO unmount completed successfully.",
+ Name
+ );
+
+ } else {
+
+ Logger.Info(
+ "[{0}] ISO unmount completed with errors.",
+ Name
+ );
+
+ }
+
+ try {
+
+ FileSystem.DeleteDirectory(mount.MountedPath, false);
+
+ } catch (Exception ex) {
+
+ Logger.Info(
+ "[{0}] Unhandled exception removing mount point, exception is [{1}].",
+ Name,
+ ex.Message
+ );
+
+ }
+
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ internal void OnUnmount(LinuxMount mount)
+ {
+
+ UnmountISO(mount);
+
+ }
+
+ #endregion
+
+ }
+
+}
+