diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs index 7132d539f..993275aa9 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs @@ -3,6 +3,7 @@ using System.Security.AccessControl; using System.Security.Principal; using NLog; using NzbDrone.Common.Disk; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; namespace NzbDrone.Common.EnvironmentInfo @@ -33,6 +34,11 @@ namespace NzbDrone.Common.EnvironmentInfo { SetPermissions(); } + + if (!_diskProvider.FolderWritable(_appFolderInfo.AppDataFolder)) + { + throw new SonarrStartupException("AppFolder {0} is not writable", _appFolderInfo.AppDataFolder); + } } private void SetPermissions() diff --git a/src/NzbDrone.Common/Exceptions/SonarrStartupException.cs b/src/NzbDrone.Common/Exceptions/SonarrStartupException.cs new file mode 100644 index 000000000..b61207642 --- /dev/null +++ b/src/NzbDrone.Common/Exceptions/SonarrStartupException.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Common.Exceptions +{ + public class SonarrStartupException : NzbDroneException + { + public SonarrStartupException(string message, params object[] args) + : base("Sonarr failed to start: " + string.Format(message, args)) + { + + } + + public SonarrStartupException(string message) + : base("Sonarr failed to start: " + message) + { + + } + + public SonarrStartupException() + : base("Sonarr failed to start") + { + + } + + public SonarrStartupException(Exception innerException, string message, params object[] args) + : base("Sonarr failed to start: " + string.Format(message, args), innerException) + { + } + + public SonarrStartupException(Exception innerException, string message) + : base("Sonarr failed to start: " + message, innerException) + { + } + + public SonarrStartupException(Exception innerException) + : base("Sonarr failed to start: " + innerException.Message) + { + + } + } +} diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj index 162cd5d36..2e2197f52 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -92,6 +92,7 @@ + diff --git a/src/NzbDrone.Common/Processes/PidFileProvider.cs b/src/NzbDrone.Common/Processes/PidFileProvider.cs index c04ff445f..04cca6527 100644 --- a/src/NzbDrone.Common/Processes/PidFileProvider.cs +++ b/src/NzbDrone.Common/Processes/PidFileProvider.cs @@ -2,6 +2,7 @@ using System.IO; using NLog; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; namespace NzbDrone.Common.Processes { @@ -38,7 +39,7 @@ namespace NzbDrone.Common.Processes catch (Exception ex) { _logger.Error(ex, "Unable to write PID file {0}", filename); - throw; + throw new SonarrStartupException(ex, "Unable to write PID file {0}", filename); } } } diff --git a/src/NzbDrone.Console/ConsoleApp.cs b/src/NzbDrone.Console/ConsoleApp.cs index 6f935887f..d67ee5a5e 100644 --- a/src/NzbDrone.Console/ConsoleApp.cs +++ b/src/NzbDrone.Console/ConsoleApp.cs @@ -2,6 +2,7 @@ using System.Net.Sockets; using NLog; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Host; @@ -11,6 +12,14 @@ namespace NzbDrone.Console { private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(ConsoleApp)); + private enum ExitCodes : int + { + Normal = 0, + UnknownFailure = 1, + RecoverableFailure = 2, + NonRecoverableFailure = 3 + } + public static void Main(string[] args) { try @@ -19,30 +28,61 @@ namespace NzbDrone.Console NzbDroneLogger.Register(startupArgs, false, true); Bootstrap.Start(startupArgs, new ConsoleAlerts()); } - catch (SocketException exception) + catch (SonarrStartupException ex) { System.Console.WriteLine(""); System.Console.WriteLine(""); - Logger.Fatal(exception.Message + ". This can happen if another instance of Sonarr is already running another application is using the same port (default: 8989) or the user has insufficient permissions"); - System.Console.WriteLine("Press enter to exit..."); - System.Console.ReadLine(); - Environment.Exit(1); + Logger.Fatal(ex, "EPIC FAIL!"); + Exit(ExitCodes.NonRecoverableFailure); } - catch (Exception e) + catch (SocketException ex) { System.Console.WriteLine(""); System.Console.WriteLine(""); - Logger.Fatal(e, "EPIC FAIL!"); - System.Console.WriteLine("Press enter to exit..."); - System.Console.ReadLine(); - Environment.Exit(1); + Logger.Fatal(ex.Message + ". This can happen if another instance of Sonarr is already running another application is using the same port (default: 8989) or the user has insufficient permissions"); + Exit(ExitCodes.RecoverableFailure); + } + catch (Exception ex) + { + System.Console.WriteLine(""); + System.Console.WriteLine(""); + Logger.Fatal(ex, "EPIC FAIL!"); + Exit(ExitCodes.UnknownFailure); } Logger.Info("Exiting main."); + Exit(ExitCodes.Normal); + } + + private static void Exit(ExitCodes exitCode) + { + LogManager.Flush(); + + if (exitCode != ExitCodes.Normal) + { + System.Console.WriteLine("Press enter to exit..."); + + System.Threading.Thread.Sleep(1000); + + if (exitCode == ExitCodes.NonRecoverableFailure) + { + System.Console.WriteLine("Non-recoverable failure, waiting for user intervention..."); + for (int i = 0; i < 3600; i++) + { + System.Threading.Thread.Sleep(1000); + + if (System.Console.KeyAvailable) break; + } + } + + // Please note that ReadLine silently succeeds if there is no console, KeyAvailable does not. + System.Console.ReadLine(); + } + //Need this to terminate on mono (thanks nlog) LogManager.Configuration = null; - Environment.Exit(0); + Environment.Exit((int)exitCode); } } } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 99deeef58..39244c28a 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -4,9 +4,11 @@ using System.Threading; using NLog; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Processes; using NzbDrone.Common.Security; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.Instrumentation; @@ -49,9 +51,13 @@ namespace NzbDrone.Host SpinToExit(appMode); } } - catch (TerminateApplicationException e) + catch (InvalidConfigFileException ex) { - Logger.Info(e.Message); + throw new SonarrStartupException(ex); + } + catch (TerminateApplicationException ex) + { + Logger.Info(ex.Message); LogManager.Configuration = null; } }