diff options
Diffstat (limited to 'Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs')
| -rw-r--r-- | Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs | 477 |
1 files changed, 149 insertions, 328 deletions
diff --git a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs index 2f0003be8..48cb2e1d5 100644 --- a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs +++ b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs @@ -1,9 +1,10 @@ using System; +using System.Diagnostics; +using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; @@ -11,441 +12,274 @@ using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace IsoMounter { + /// <summary> + /// The ISO manager implementation for Linux. + /// </summary> public class LinuxIsoManager : IIsoMounter { - [DllImport("libc", SetLastError = true)] - static extern uint getuid(); + private const string MountCommand = "mount"; + private const string UnmountCommand = "umount"; + private const string SudoCommand = "sudo"; - #region Private Fields - - private readonly bool ExecutablesAvailable; 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 + private readonly string _mountPointRoot; - #region Constructor(s) - - public LinuxIsoManager(ILogger logger, IProcessFactory processFactory) + /// <summary> + /// Initializes a new instance of the <see cref="LinuxIsoManager" /> class. + /// </summary> + /// <param name="logger">The logger.</param> + public LinuxIsoManager(ILogger logger) { _logger = logger; - ProcessFactory = processFactory; - MountPointRoot = Path.DirectorySeparatorChar + "tmp" + Path.DirectorySeparatorChar + "Emby"; + _mountPointRoot = Path.DirectorySeparatorChar + "tmp" + Path.DirectorySeparatorChar + "Emby"; _logger.LogDebug( "[{0}] System PATH is currently set to [{1}].", Name, - Environment.GetEnvironmentVariable("PATH") ?? "" - ); + Environment.GetEnvironmentVariable("PATH") ?? string.Empty); _logger.LogDebug( "[{0}] System path separator is [{1}].", Name, - Path.PathSeparator - ); + Path.PathSeparator); _logger.LogDebug( "[{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.LogInformation( - "[{0}] Using version of [sudo] located at [{1}].", - Name, - SudoCommand - ); - - MountCommand = GetFullPathForExecutable("mount"); - - _logger.LogInformation( - "[{0}] Using version of [mount] located at [{1}].", - Name, - MountCommand - ); - - UmountCommand = GetFullPathForExecutable("umount"); - - _logger.LogInformation( - "[{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; - } - + _mountPointRoot); } - #endregion - - #region Interface Implementation for IIsoMounter - - public bool IsInstalled => true; - + /// <inheritdoc /> public string Name => "LinuxMount"; - public bool RequiresInstallation => false; +#pragma warning disable SA1300 +#pragma warning disable SA1400 + [DllImport("libc", SetLastError = true)] + static extern uint getuid(); + +#pragma warning restore SA1300 +#pragma warning restore SA1400 + /// <inheritdoc /> public bool CanMount(string path) { - if (OperatingSystem.Id != OperatingSystemId.Linux) { return false; } + _logger.LogInformation( - "[{0}] Checking we can attempt to mount [{1}], Extension = [{2}], Operating System = [{3}], Executables Available = [{4}].", + "[{0}] Checking we can attempt to mount [{1}], Extension = [{2}], Operating System = [{3}].", Name, path, Path.GetExtension(path), - OperatingSystem.Name, - ExecutablesAvailable - ); + OperatingSystem.Name); - if (ExecutablesAvailable) - { - return string.Equals(Path.GetExtension(path), ".iso", StringComparison.OrdinalIgnoreCase); - } - else - { - return false; - } - } - - public Task Install(CancellationToken cancellationToken) - { - return Task.FromResult(false); + return string.Equals(Path.GetExtension(path), ".iso", StringComparison.OrdinalIgnoreCase); } + /// <inheritdoc /> public Task<IIsoMount> Mount(string isoPath, CancellationToken cancellationToken) { - if (MountISO(isoPath, out LinuxMount mountedISO)) - { - return Task.FromResult<IIsoMount>(mountedISO); - } - else + string cmdArguments; + string cmdFilename; + string mountPoint = Path.Combine(_mountPointRoot, Guid.NewGuid().ToString()); + + if (string.IsNullOrEmpty(isoPath)) { - throw new IOException(string.Format( - "An error occurred trying to mount image [$0].", - isoPath - )); + throw new ArgumentNullException(nameof(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); + _logger.LogInformation( + "[{Name}] Attempting to mount [{Path}].", + Name, + isoPath); - } + _logger.LogDebug( + "[{Name}] ISO will be mounted at [{Path}].", + Name, + mountPoint); - protected virtual void Dispose(bool disposing) - { + try + { + Directory.CreateDirectory(mountPoint); + } + catch (UnauthorizedAccessException ex) + { + throw new IOException("Unable to create mount point(Permission denied) for " + isoPath, ex); + } + catch (Exception ex) + { + throw new IOException("Unable to create mount point for " + isoPath, ex); + } - if (disposed) + if (GetUID() == 0) + { + cmdFilename = MountCommand; + cmdArguments = string.Format( + CultureInfo.InvariantCulture, + "\"{0}\" \"{1}\"", + isoPath, + mountPoint); + } + else { - return; + cmdFilename = SudoCommand; + cmdArguments = string.Format( + CultureInfo.InvariantCulture, + "\"{0}\" \"{1}\" \"{2}\"", + MountCommand, + isoPath, + mountPoint); } - _logger.LogInformation( - "[{0}] Disposing [{1}].", + _logger.LogDebug( + "[{0}] Mount command [{1}], mount arguments [{2}].", Name, - disposing - ); + cmdFilename, + cmdArguments); - if (disposing) + int exitcode = ExecuteCommand(cmdFilename, cmdArguments); + if (exitcode == 0) { + _logger.LogInformation( + "[{0}] ISO mount completed successfully.", + Name); - // - // Free managed objects here. - // - + return Task.FromResult<IIsoMount>(new LinuxMount(this, isoPath, mountPoint)); } - // - // Free any unmanaged objects here. - // - - disposed = true; - - } - - #endregion - - #region Private Methods - - private string GetFullPathForExecutable(string name) - { + _logger.LogInformation( + "[{0}] ISO mount completed with errors.", + Name); - foreach (string test in (Environment.GetEnvironmentVariable("PATH") ?? "").Split(Path.PathSeparator)) + try { - string path = test.Trim(); - - if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, name))) - { - return Path.GetFullPath(path); - } + Directory.Delete(mountPoint, false); + } + catch (Exception ex) + { + _logger.LogError(ex, "[{Name}] Unhandled exception removing mount point.", Name); + throw; } - return string.Empty; + throw new ExternalException("Mount command failed", exitcode); } private uint GetUID() { - var uid = getuid(); _logger.LogDebug( "[{0}] GetUserId() returned [{2}].", Name, - uid - ); + uid); return uid; - } - private bool ExecuteCommand(string cmdFilename, string cmdArguments) + private int 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 - } - ); + var startInfo = new ProcessStartInfo + { + FileName = cmdFilename, + Arguments = cmdArguments, + UseShellExecute = false, + CreateNoWindow = true, + ErrorDialog = false, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + + var process = new Process() + { + StartInfo = startInfo + }; try { process.Start(); - //StreamReader outputReader = process.StandardOutput.; - //StreamReader errorReader = process.StandardError; - _logger.LogDebug( "[{Name}] Standard output from process is [{Error}].", Name, - process.StandardOutput.ReadToEnd() - ); + process.StandardOutput.ReadToEnd()); _logger.LogDebug( "[{Name}] Standard error from process is [{Error}].", Name, - process.StandardError.ReadToEnd() - ); + process.StandardError.ReadToEnd()); + + return process.ExitCode; } catch (Exception ex) { - processFailed = true; _logger.LogDebug(ex, "[{Name}] Unhandled exception executing command.", Name); + throw; } - - if (!processFailed && process.ExitCode == 0) + finally { - return true; + process?.Dispose(); } - else - { - return false; - } - } - private bool MountISO(string isoPath, out LinuxMount mountedISO) + /// <summary> + /// Unmounts the specified mount. + /// </summary> + /// <param name="mount">The mount.</param> + internal void OnUnmount(LinuxMount mount) { - - string cmdArguments; - string cmdFilename; - string mountPoint = Path.Combine(MountPointRoot, Guid.NewGuid().ToString()); - - if (!string.IsNullOrEmpty(isoPath)) - { - - _logger.LogInformation( - "[{Name}] Attempting to mount [{Path}].", - Name, - isoPath - ); - - _logger.LogDebug( - "[{Name}] ISO will be mounted at [{Path}].", - Name, - mountPoint - ); - - } - else + if (mount == null) { - - throw new ArgumentNullException(nameof(isoPath)); - - } - - try - { - Directory.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); + throw new ArgumentNullException(nameof(mount)); } - _logger.LogDebug( - "[{0}] Mount command [{1}], mount arguments [{2}].", + _logger.LogInformation( + "[{0}] Attempting to unmount ISO [{1}] mounted on [{2}].", Name, - cmdFilename, - cmdArguments - ); - - if (ExecuteCommand(cmdFilename, cmdArguments)) - { - - _logger.LogInformation( - "[{0}] ISO mount completed successfully.", - Name - ); - - mountedISO = new LinuxMount(this, isoPath, mountPoint); - - } - else - { - - _logger.LogInformation( - "[{0}] ISO mount completed with errors.", - Name - ); - - try - { - Directory.Delete(mountPoint, false); - } - catch (Exception ex) - { - _logger.LogInformation(ex, "[{Name}] Unhandled exception removing mount point.", Name); - } - - mountedISO = null; - - } - - return mountedISO != null; - - } - - private void UnmountISO(LinuxMount mount) - { + mount.IsoPath, + mount.MountedPath); string cmdArguments; string cmdFilename; - if (mount != null) - { - - _logger.LogInformation( - "[{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); + cmdFilename = UnmountCommand; + cmdArguments = string.Format( + CultureInfo.InvariantCulture, + "\"{0}\"", + mount.MountedPath); } else { cmdFilename = SudoCommand; - cmdArguments = string.Format("\"{0}\" \"{1}\"", UmountCommand, mount.MountedPath); + cmdArguments = string.Format( + CultureInfo.InvariantCulture, + "\"{0}\" \"{1}\"", + UnmountCommand, + mount.MountedPath); } _logger.LogDebug( "[{0}] Umount command [{1}], umount arguments [{2}].", Name, cmdFilename, - cmdArguments - ); + cmdArguments); - if (ExecuteCommand(cmdFilename, cmdArguments)) + int exitcode = ExecuteCommand(cmdFilename, cmdArguments); + if (exitcode == 0) { - _logger.LogInformation( "[{0}] ISO unmount completed successfully.", - Name - ); - + Name); } else { - _logger.LogInformation( "[{0}] ISO unmount completed with errors.", - Name - ); - + Name); } try @@ -454,24 +288,11 @@ namespace IsoMounter } catch (Exception ex) { - _logger.LogInformation(ex, "[{Name}] Unhandled exception removing mount point.", Name); + _logger.LogError(ex, "[{Name}] Unhandled exception removing mount point.", Name); + throw; } - } - - #endregion - - #region Internal Methods - - internal void OnUnmount(LinuxMount mount) - { - - UnmountISO(mount); + throw new ExternalException("Mount command failed", exitcode); } - - #endregion - } - } - |
