diff --git a/src/Core/ServiceWrapper/Logging/WrapperServiceEventLogProvider.cs b/src/Core/ServiceWrapper/Logging/WrapperServiceEventLogProvider.cs index 4f44952..f051d32 100644 --- a/src/Core/ServiceWrapper/Logging/WrapperServiceEventLogProvider.cs +++ b/src/Core/ServiceWrapper/Logging/WrapperServiceEventLogProvider.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using winsw.Logging; +using System.Diagnostics; namespace winsw.Logging { @@ -11,7 +7,7 @@ namespace winsw.Logging /// public class WrapperServiceEventLogProvider : IServiceEventLogProvider { - public WrapperService service {get; set;} + public WrapperService service { get; set; } public EventLog locate() { diff --git a/src/Core/ServiceWrapper/Main.cs b/src/Core/ServiceWrapper/Main.cs index 1d08e3c..93465fd 100644 --- a/src/Core/ServiceWrapper/Main.cs +++ b/src/Core/ServiceWrapper/Main.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Management; +using System.Reflection; using System.Runtime.InteropServices; using System.ServiceProcess; using System.Text; @@ -12,15 +12,13 @@ using log4net.Appender; using log4net.Config; using log4net.Core; using log4net.Layout; -using log4net.Repository.Hierarchy; using Microsoft.Win32; using winsw.Extensions; +using winsw.Logging; +using winsw.Native; using winsw.Util; using WMI; using ServiceType = WMI.ServiceType; -using winsw.Native; -using System.Reflection; -using winsw.Logging; namespace winsw { @@ -32,7 +30,7 @@ namespace winsw private readonly ServiceDescriptor _descriptor; private Dictionary _envs; - internal WinSWExtensionManager ExtensionManager { private set; get; } + internal WinSWExtensionManager ExtensionManager { get; private set; } private static readonly ILog Log = LogManager.GetLogger("WinSW"); private static readonly WrapperServiceEventLogProvider eventLogProvider = new WrapperServiceEventLogProvider(); @@ -50,17 +48,12 @@ namespace winsw /// /// The version will be taken from /// - public static Version Version - { - get { return Assembly.GetExecutingAssembly().GetName().Version; } - } + public static Version Version => Assembly.GetExecutingAssembly().GetName().Version; /// /// Indicates that the system is shutting down. /// - public bool IsShuttingDown { - get { return _systemShuttingdown; } - } + public bool IsShuttingDown => _systemShuttingdown; public WrapperService(ServiceDescriptor descriptor) { @@ -77,8 +70,8 @@ namespace winsw eventLogProvider.service = this; } - public WrapperService() : this (new ServiceDescriptor()) - { + public WrapperService() : this(new ServiceDescriptor()) + { } /// @@ -93,7 +86,7 @@ namespace winsw try { - using (var tr = new StreamReader(file,Encoding.UTF8)) + using (var tr = new StreamReader(file, Encoding.UTF8)) { string line; while ((line = tr.ReadLine()) != null) @@ -114,7 +107,6 @@ namespace winsw { File.Delete(file); } - } /// @@ -151,7 +143,7 @@ namespace winsw return logAppender; } - public void LogEvent(String message) + public void LogEvent(string message) { if (_systemShuttingdown) { @@ -170,7 +162,7 @@ namespace winsw } } - public void LogEvent(String message, EventLogEntryType type) + public void LogEvent(string message, EventLogEntryType type) { if (_systemShuttingdown) { @@ -199,13 +191,12 @@ namespace winsw { LogEvent("envar " + key + '=' + _envs[key]); }*/ - HandleFileCopies(); // handle downloads foreach (Download d in _descriptor.Downloads) { - String downloadMsg = "Downloading: " + d.From + " to " + d.To + ". failOnError=" + d.FailOnError; + string downloadMsg = "Downloading: " + d.From + " to " + d.To + ". failOnError=" + d.FailOnError; LogEvent(downloadMsg); Log.Info(downloadMsg); try @@ -217,12 +208,13 @@ namespace winsw string errorMessage = "Failed to download " + d.From + " to " + d.To; LogEvent(errorMessage + ". " + e.Message); Log.Error(errorMessage, e); + // TODO: move this code into the download logic if (d.FailOnError) { throw new IOException(errorMessage, e); } - + // Else just keep going } } @@ -254,7 +246,7 @@ namespace winsw protected override void OnShutdown() { -// WriteEvent("OnShutdown"); + // WriteEvent("OnShutdown"); try { @@ -269,7 +261,7 @@ namespace winsw protected override void OnStop() { -// WriteEvent("OnStop"); + // WriteEvent("OnStop"); try { @@ -311,14 +303,14 @@ namespace winsw stoparguments += " " + _descriptor.Arguments; Process stopProcess = new Process(); - String executable = _descriptor.StopExecutable; + string executable = _descriptor.StopExecutable; if (executable == null) { executable = _descriptor.Executable; } - // TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated + // TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated StartProcess(stopProcess, stoparguments, executable, null, false); Log.Debug("WaitForProcessToExit " + _process.Id + "+" + stopProcess.Id); @@ -327,10 +319,10 @@ namespace winsw SignalShutdownComplete(); } - // Stop extensions + // Stop extensions ExtensionManager.FireBeforeWrapperStopped(); - if (_systemShuttingdown && _descriptor.BeepOnShutdown) + if (_systemShuttingdown && _descriptor.BeepOnShutdown) { Console.Beep(); } @@ -341,13 +333,13 @@ namespace winsw private void WaitForProcessToExit(Process processoWait) { SignalShutdownPending(); - + int effectiveProcessWaitSleepTime; - if (_descriptor.SleepTime.TotalMilliseconds > Int32.MaxValue) + if (_descriptor.SleepTime.TotalMilliseconds > int.MaxValue) { - Log.Warn("The requested sleep time " + _descriptor.SleepTime.TotalMilliseconds + "is greater that the max value " + - Int32.MaxValue + ". The value will be truncated"); - effectiveProcessWaitSleepTime = Int32.MaxValue; + Log.Warn("The requested sleep time " + _descriptor.SleepTime.TotalMilliseconds + "is greater that the max value " + + int.MaxValue + ". The value will be truncated"); + effectiveProcessWaitSleepTime = int.MaxValue; } else { @@ -356,12 +348,12 @@ namespace winsw try { -// WriteEvent("WaitForProcessToExit [start]"); + // WriteEvent("WaitForProcessToExit [start]"); while (!processoWait.WaitForExit(effectiveProcessWaitSleepTime)) { SignalShutdownPending(); -// WriteEvent("WaitForProcessToExit [repeat]"); + // WriteEvent("WaitForProcessToExit [repeat]"); } } catch (InvalidOperationException) @@ -369,28 +361,27 @@ namespace winsw // already terminated } -// WriteEvent("WaitForProcessToExit [finished]"); + // WriteEvent("WaitForProcessToExit [finished]"); } private void SignalShutdownPending() { int effectiveWaitHint; - if (_descriptor.WaitHint.TotalMilliseconds > Int32.MaxValue) + if (_descriptor.WaitHint.TotalMilliseconds > int.MaxValue) { - Log.Warn("The requested WaitHint value (" + _descriptor.WaitHint.TotalMilliseconds + " ms) is greater that the max value " + - Int32.MaxValue + ". The value will be truncated"); - effectiveWaitHint = Int32.MaxValue; + Log.Warn("The requested WaitHint value (" + _descriptor.WaitHint.TotalMilliseconds + " ms) is greater that the max value " + + int.MaxValue + ". The value will be truncated"); + effectiveWaitHint = int.MaxValue; } else { effectiveWaitHint = (int)_descriptor.WaitHint.TotalMilliseconds; } - IntPtr handle = ServiceHandle; _wrapperServiceStatus.checkPoint++; _wrapperServiceStatus.waitHint = effectiveWaitHint; -// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint); + // WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint); _wrapperServiceStatus.currentState = (int)State.SERVICE_STOP_PENDING; Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus); } @@ -399,16 +390,15 @@ namespace winsw { IntPtr handle = ServiceHandle; _wrapperServiceStatus.checkPoint++; -// WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint); + // WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint); _wrapperServiceStatus.currentState = (int)State.SERVICE_STOPPED; Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus); } - private void StartProcess(Process processToStart, string arguments, String executable, LogHandler logHandler, bool redirectStdin) + private void StartProcess(Process processToStart, string arguments, string executable, LogHandler logHandler, bool redirectStdin) { - // Define handler of the completed process - ProcessCompletionCallback processCompletionCallback = delegate(Process proc) + ProcessCompletionCallback processCompletionCallback = proc => { string msg = processToStart.Id + " - " + processToStart.StartInfo.FileName + " " + processToStart.StartInfo.Arguments; try @@ -425,6 +415,7 @@ namespace winsw // restart the service automatically if (proc.ExitCode == 0) SignalShutdownComplete(); + Environment.Exit(proc.ExitCode); } } @@ -485,30 +476,27 @@ namespace winsw throw new WmiException(ReturnValue.NoSuchService); } - // ReSharper disable once InconsistentNaming /// /// Runs the wrapper. /// /// Arguments. If empty, WinSW will behave in the service mode. Otherwise - CLI mode - /// Service descriptor. If null, it will be initialized within the method. + /// Service descriptor. If null, it will be initialized within the method. /// In such case configs will be loaded from the XML Configuration File. /// Any unhandled exception public static void Run(string[] _args, ServiceDescriptor descriptor = null) { bool isCLIMode = _args.Length > 0; - - + // If descriptor is not specified, initialize the new one (and load configs from there) var d = descriptor ?? new ServiceDescriptor(); - + // Configure the wrapper-internal logging. // STDIN and STDOUT of the child process will be handled independently. InitLoggers(d, isCLIMode); - if (isCLIMode) // CLI mode, in-service mode otherwise - { + { Log.Debug("Starting ServiceWrapper in the CLI mode"); // Get service info for the future use @@ -519,7 +507,7 @@ namespace winsw if (args[0] == "/redirect") { // Redirect output - // One might ask why we support this when the caller + // One might ask why we support this when the caller // can redirect the output easily. The answer is for supporting UAC. // On UAC-enabled Windows such as Vista, SCM operation requires // elevated privileges, thus winsw.exe needs to be launched @@ -527,7 +515,7 @@ namespace winsw // and among other things it makes it difficult for the caller // to read stdout/stderr. Thus redirection becomes handy. var f = new FileStream(args[1], FileMode.Create); - var w = new StreamWriter(f) {AutoFlush = true}; + var w = new StreamWriter(f) { AutoFlush = true }; Console.SetOut(w); Console.SetError(w); @@ -551,7 +539,7 @@ namespace winsw throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists"); } - string username=null, password=null; + string username = null, password = null; bool setallowlogonasaserviceright = false; if (args.Count > 1 && args[1] == "/p") { @@ -578,13 +566,13 @@ namespace winsw setallowlogonasaserviceright = d.AllowServiceAcountLogonRight; } } - + if (setallowlogonasaserviceright) { LogonAsAService.AddLogonAsAServiceRight(username); } - svc.Create ( + svc.Create( d.Id, d.Caption, "\"" + d.ExecutablePath + "\"", @@ -616,7 +604,7 @@ namespace winsw using (Service sc = scm.Open(d.Id)) { // Delayed auto start - if (isDelayedAutoStart) + if (isDelayedAutoStart) { sc.SetDelayedAutoStart(true); } @@ -629,8 +617,10 @@ namespace winsw } } } + return; } + if (args[0] == "uninstall") { Log.Info("Uninstalling the service with id '" + d.Id + "'"); @@ -639,6 +629,7 @@ namespace winsw Log.Warn("The service with id '" + d.Id + "' does not exist. Nothing to uninstall"); return; // there's no such service, so consider it already uninstalled } + if (s.Started) { // We could fail the opeartion here, but it would be an incompatible change. @@ -654,9 +645,9 @@ namespace winsw { if (e.ErrorCode == ReturnValue.ServiceMarkedForDeletion) { - Log.Error("Failed to uninstall the service with id '" + d.Id + "'" + Log.Error("Failed to uninstall the service with id '" + d.Id + "'" + ". It has been marked for deletion."); - + // TODO: change the default behavior to Error? return; // it's already uninstalled, so consider it a success } @@ -664,31 +655,40 @@ namespace winsw { Log.Fatal("Failed to uninstall the service with id '" + d.Id + "'. WMI Error code is '" + e.ErrorCode + "'"); } + throw e; } + return; } + if (args[0] == "start") { Log.Info("Starting the service with id '" + d.Id + "'"); - if (s == null) ThrowNoSuchService(); + if (s == null) + ThrowNoSuchService(); + s.StartService(); return; } + if (args[0] == "stop") { Log.Info("Stopping the service with id '" + d.Id + "'"); - if (s == null) ThrowNoSuchService(); + if (s == null) + ThrowNoSuchService(); + s.StopService(); return; } + if (args[0] == "restart") { Log.Info("Restarting the service with id '" + d.Id + "'"); - if (s == null) + if (s == null) ThrowNoSuchService(); - if(s.Started) + if (s.Started) s.StopService(); while (s.Started) @@ -700,22 +700,24 @@ namespace winsw s.StartService(); return; } + if (args[0] == "restart!") { Log.Info("Restarting the service with id '" + d.Id + "'"); // run restart from another process group. see README.md for why this is useful. - STARTUPINFO si = new STARTUPINFO(); - PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); + STARTUPINFO si = default; - bool result = Kernel32.CreateProcess(null, d.ExecutablePath+" restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out pi); + bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out PROCESS_INFORMATION pi); if (!result) { - throw new Exception("Failed to invoke restart: "+Marshal.GetLastWin32Error()); + throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error()); } + return; } + if (args[0] == "status") { Log.Debug("User requested the status of the process with id '" + d.Id + "'"); @@ -727,6 +729,7 @@ namespace winsw Console.WriteLine("Stopped"); return; } + if (args[0] == "test") { WrapperService wsvc = new WrapperService(d); @@ -735,6 +738,7 @@ namespace winsw wsvc.OnStop(); return; } + if (args[0] == "testwait") { WrapperService wsvc = new WrapperService(d); @@ -744,27 +748,29 @@ namespace winsw wsvc.OnStop(); return; } - if (args[0] == "help" || args[0] == "--help" || args[0] == "-h" + + if (args[0] == "help" || args[0] == "--help" || args[0] == "-h" || args[0] == "-?" || args[0] == "/?") { printHelp(); return; } + if (args[0] == "version") { printVersion(); return; } - + Console.WriteLine("Unknown command: " + args[0]); printAvailableCommandsInfo(); throw new Exception("Unknown command: " + args[0]); - } else { Log.Info("Starting ServiceWrapper in the service mode"); } + Run(new WrapperService(d)); } @@ -774,7 +780,7 @@ namespace winsw Level logLevel = Level.Debug; // TODO: Debug should not be printed to console by default. Otherwise commands like 'status' will be pollutted // This is a workaround till there is a better command line parsing, which will allow determining - Level consoleLogLevel = Level.Info; + Level consoleLogLevel = Level.Info; Level eventLogLevel = Level.Warn; // Legacy format from winsw-1.x: (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " - " + message); @@ -784,7 +790,7 @@ namespace winsw List appenders = new List(); // wrapper.log - String wrapperLogPath = Path.Combine(d.LogDirectory, d.BaseName + ".wrapper.log"); + string wrapperLogPath = Path.Combine(d.LogDirectory, d.BaseName + ".wrapper.log"); var wrapperLog = new FileAppender { AppendToFile = true, @@ -812,11 +818,11 @@ namespace winsw } // System log - var systemEventLogger = new ServiceEventLogAppender + var systemEventLogger = new ServiceEventLogAppender { Name = "System event log", Threshold = eventLogLevel, - provider = eventLogProvider + provider = eventLogProvider }; systemEventLogger.ActivateOptions(); appenders.Add(systemEventLogger); @@ -851,21 +857,21 @@ namespace winsw private static void printHelp() { Console.WriteLine("A wrapper binary that can be used to host executables as Windows services"); - Console.WriteLine(""); + Console.WriteLine(); Console.WriteLine("Usage: winsw [/redirect file] []"); Console.WriteLine(" Missing arguments trigger the service mode"); - Console.WriteLine(""); + Console.WriteLine(); printAvailableCommandsInfo(); - Console.WriteLine(""); + Console.WriteLine(); Console.WriteLine("Extra options:"); Console.WriteLine("- '/redirect' - redirect the wrapper's STDOUT and STDERR to the specified file"); - Console.WriteLine(""); + Console.WriteLine(); printVersion(); Console.WriteLine("More info: https://github.com/kohsuke/winsw"); Console.WriteLine("Bug tracker: https://github.com/kohsuke/winsw/issues"); } - //TODO: Rework to enum in winsw-2.0 + // TODO: Rework to enum in winsw-2.0 private static void printAvailableCommandsInfo() { Console.WriteLine("Available commands:"); diff --git a/src/Core/ServiceWrapper/SigIntHelper.cs b/src/Core/ServiceWrapper/SigIntHelper.cs index 64fc12e..7dfabe6 100644 --- a/src/Core/ServiceWrapper/SigIntHelper.cs +++ b/src/Core/ServiceWrapper/SigIntHelper.cs @@ -16,8 +16,9 @@ namespace winsw [DllImport(KERNEL32)] private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); + // Delegate type to be used as the Handler Routine for SCCH - private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType); + private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType); // Enumerated type for the control messages sent to the handler routine private enum CtrlTypes : uint @@ -43,15 +44,15 @@ namespace winsw { if (AttachConsole((uint)process.Id)) { - //Disable Ctrl-C handling for our program + // Disable Ctrl-C handling for our program SetConsoleCtrlHandler(null, true); GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); process.WaitForExit((int)shutdownTimeout.TotalMilliseconds); - return process.HasExited; + return process.HasExited; } - + return false; } } diff --git a/src/Core/WinSWCore/Configuration/DefaultSettings.cs b/src/Core/WinSWCore/Configuration/DefaultSettings.cs index 9a1d924..fedbd6b 100644 --- a/src/Core/WinSWCore/Configuration/DefaultSettings.cs +++ b/src/Core/WinSWCore/Configuration/DefaultSettings.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; -using System.Text; using System.Xml; using WMI; @@ -14,11 +13,11 @@ namespace winsw.Configuration /// public sealed class DefaultWinSWSettings : IWinSWConfiguration { - public string Id { get { return null; } } - public string Caption { get { return null; } } - public string Description { get { return null; } } - public string Executable { get { return null; } } - public bool HideWindow { get { return false; } } + public string Id => null; + public string Caption => null; + public string Description => null; + public string Executable => null; + public bool HideWindow => false; public string ExecutablePath { @@ -32,47 +31,47 @@ namespace winsw.Configuration } // Installation - public bool AllowServiceAcountLogonRight { get { return false; } } - public string ServiceAccountPassword { get { return null; } } - public string ServiceAccountUser { get { return "NULL\\NULL"; } } - public List FailureActions { get { return new List(); } } - public TimeSpan ResetFailureAfter { get { return TimeSpan.FromDays(1); } } + public bool AllowServiceAcountLogonRight => false; + public string ServiceAccountPassword => null; + public string ServiceAccountUser => "NULL\\NULL"; + public List FailureActions => new List(); + public TimeSpan ResetFailureAfter => TimeSpan.FromDays(1); // Executable management - public string Arguments { get { return ""; } } - public string Startarguments { get { return null; } } - public string StopExecutable { get { return null; } } - public string Stoparguments { get { return null; } } - public string WorkingDirectory { get { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } } - public ProcessPriorityClass Priority { get { return ProcessPriorityClass.Normal; } } - public TimeSpan StopTimeout { get { return TimeSpan.FromSeconds(15); } } - public bool StopParentProcessFirst { get { return false; } } + public string Arguments => string.Empty; + public string Startarguments => null; + public string StopExecutable => null; + public string Stoparguments => null; + public string WorkingDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + public ProcessPriorityClass Priority => ProcessPriorityClass.Normal; + public TimeSpan StopTimeout => TimeSpan.FromSeconds(15); + public bool StopParentProcessFirst => false; // Service management - public StartMode StartMode { get { return StartMode.Automatic; } } - public bool DelayedAutoStart { get { return false; } } - public string[] ServiceDependencies { get { return new string[0]; } } - public TimeSpan WaitHint { get { return TimeSpan.FromSeconds(15); } } - public TimeSpan SleepTime { get { return TimeSpan.FromSeconds(1); } } - public bool Interactive { get { return false; } } + public StartMode StartMode => StartMode.Automatic; + public bool DelayedAutoStart => false; + public string[] ServiceDependencies => new string[0]; + public TimeSpan WaitHint => TimeSpan.FromSeconds(15); + public TimeSpan SleepTime => TimeSpan.FromSeconds(1); + public bool Interactive => false; // Logging - public string LogDirectory { get { return Path.GetDirectoryName(ExecutablePath); } } - public string LogMode { get { return "append"; } } + public string LogDirectory => Path.GetDirectoryName(ExecutablePath); + public string LogMode => "append"; - public bool OutFileDisabled { get { return false; } } - public bool ErrFileDisabled { get { return false; } } - public string OutFilePattern { get { return ".out.log"; } } - public string ErrFilePattern { get { return ".err.log"; } } + public bool OutFileDisabled => false; + public bool ErrFileDisabled => false; + public string OutFilePattern => ".out.log"; + public string ErrFilePattern => ".err.log"; // Environment - public List Downloads { get { return new List(); } } - public Dictionary EnvironmentVariables { get { return new Dictionary(); } } + public List Downloads => new List(); + public Dictionary EnvironmentVariables => new Dictionary(); // Misc - public bool BeepOnShutdown { get { return false; } } + public bool BeepOnShutdown => false; // Extensions - public XmlNode ExtensionsConfiguration { get {return null; } } + public XmlNode ExtensionsConfiguration => null; } } diff --git a/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs b/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs index e6b6d75..be222d5 100644 --- a/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs +++ b/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs @@ -7,7 +7,7 @@ namespace winsw.Configuration { public interface IWinSWConfiguration { - //TODO: Document the parameters && refactor + // TODO: Document the parameters && refactor string Id { get; } string Caption { get; } @@ -20,7 +20,7 @@ namespace winsw.Configuration bool AllowServiceAcountLogonRight { get; } string ServiceAccountPassword { get; } string ServiceAccountUser { get; } - List FailureActions { get; } + List FailureActions { get; } TimeSpan ResetFailureAfter { get; } // Executable management @@ -39,16 +39,16 @@ namespace winsw.Configuration TimeSpan WaitHint { get; } TimeSpan SleepTime { get; } bool Interactive { get; } - + // Logging string LogDirectory { get; } - //TODO: replace by enum + // TODO: replace by enum string LogMode { get; } - + // Environment List Downloads { get; } Dictionary EnvironmentVariables { get; } - + // Misc bool BeepOnShutdown { get; } diff --git a/src/Core/WinSWCore/Download.cs b/src/Core/WinSWCore/Download.cs index f41e499..b6fe87b 100755 --- a/src/Core/WinSWCore/Download.cs +++ b/src/Core/WinSWCore/Download.cs @@ -13,7 +13,12 @@ namespace winsw /// public class Download { - public enum AuthType { none = 0, sspi, basic } + public enum AuthType + { + none = 0, + sspi, + basic + } public readonly string From; public readonly string To; @@ -23,10 +28,16 @@ namespace winsw public readonly bool UnsecureAuth; public readonly bool FailOnError; - public string ShortId { get { return String.Format("(download from {0})", From); } } + public string ShortId => $"(download from {From})"; - public Download(string from, string to, bool failOnError = false, AuthType auth = AuthType.none, - string username = null, string password = null, bool unsecureAuth = false) + public Download( + string from, + string to, + bool failOnError = false, + AuthType auth = AuthType.none, + string username = null, + string password = null, + bool unsecureAuth = false) { From = from; To = to; @@ -44,23 +55,23 @@ namespace winsw /// The required attribute is missing or the configuration is invalid internal Download(XmlElement n) { - From = XmlHelper.SingleAttribute(n, "from"); - To = XmlHelper.SingleAttribute(n, "to"); + From = XmlHelper.SingleAttribute(n, "from"); + To = XmlHelper.SingleAttribute(n, "to"); // All arguments below are optional - FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false); + FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false); - Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.none); - Username = XmlHelper.SingleAttribute(n, "user", null); - Password = XmlHelper.SingleAttribute(n, "password", null); - UnsecureAuth = XmlHelper.SingleAttribute(n, "unsecureAuth", false); + Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.none); + Username = XmlHelper.SingleAttribute(n, "user", null); + Password = XmlHelper.SingleAttribute(n, "password", null); + UnsecureAuth = XmlHelper.SingleAttribute(n, "unsecureAuth", false); if (Auth == AuthType.basic) { - // Allow it only for HTTPS or for UnsecureAuth + // Allow it only for HTTPS or for UnsecureAuth if (!From.StartsWith("https:") && !UnsecureAuth) { - throw new InvalidDataException("Warning: you're sending your credentials in clear text to the server " + ShortId + + throw new InvalidDataException("Warning: you're sending your credentials in clear text to the server " + ShortId + "If you really want this you must enable 'unsecureAuth' in the configuration"); } @@ -69,6 +80,7 @@ namespace winsw { throw new InvalidDataException("Basic Auth is enabled, but username is not specified " + ShortId); } + if (Password == null) { throw new InvalidDataException("Basic Auth is enabled, but password is not specified " + ShortId); @@ -77,7 +89,7 @@ namespace winsw } // Source: http://stackoverflow.com/questions/2764577/forcing-basic-authentication-in-webrequest - private void SetBasicAuthHeader(WebRequest request, String username, String password) + private void SetBasicAuthHeader(WebRequest request, string username, string password) { string authInfo = username + ":" + password; authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo)); @@ -87,7 +99,7 @@ namespace winsw /// /// Downloads the requested file and puts it to the specified target. /// - /// + /// /// Download failure. FailOnError flag should be processed outside. /// public void Perform() @@ -120,6 +132,7 @@ namespace winsw // only after we successfully downloaded a file, overwrite the existing one if (File.Exists(To)) File.Delete(To); + File.Move(To + ".tmp", To); } @@ -129,9 +142,12 @@ namespace winsw while (true) { int len = i.Read(buf, 0, buf.Length); - if (len <= 0) break; + if (len <= 0) + break; + o.Write(buf, 0, len); } + i.Close(); o.Close(); } diff --git a/src/Core/WinSWCore/DynamicProxy.cs b/src/Core/WinSWCore/DynamicProxy.cs index 910c54a..dcda669 100644 --- a/src/Core/WinSWCore/DynamicProxy.cs +++ b/src/Core/WinSWCore/DynamicProxy.cs @@ -7,8 +7,8 @@ using System.Threading; namespace DynamicProxy { /// - /// Interface that a user defined proxy handler needs to implement. This interface - /// defines one method that gets invoked by the generated proxy. + /// Interface that a user defined proxy handler needs to implement. This interface + /// defines one method that gets invoked by the generated proxy. /// public interface IProxyInvocationHandler { @@ -86,7 +86,7 @@ namespace DynamicProxy public class ProxyFactory { private static ProxyFactory _instance; - private static readonly Object LockObj = new Object(); + private static readonly object LockObj = new object(); private readonly Hashtable _typeMap = Hashtable.Synchronized(new Hashtable()); private static readonly Hashtable OpCodeTypeMapper = new Hashtable(); @@ -96,18 +96,18 @@ namespace DynamicProxy private const string MODULE_NAME = "ProxyModule"; private const string HANDLER_NAME = "handler"; - // Initialize the value type mapper. This is needed for methods with intrinsic + // Initialize the value type mapper. This is needed for methods with intrinsic // return types, used in the Emit process. static ProxyFactory() { - OpCodeTypeMapper.Add(typeof(Boolean), OpCodes.Ldind_I1); - OpCodeTypeMapper.Add(typeof(Int16), OpCodes.Ldind_I2); - OpCodeTypeMapper.Add(typeof(Int32), OpCodes.Ldind_I4); - OpCodeTypeMapper.Add(typeof(Int64), OpCodes.Ldind_I8); - OpCodeTypeMapper.Add(typeof(Double), OpCodes.Ldind_R8); - OpCodeTypeMapper.Add(typeof(Single), OpCodes.Ldind_R4); - OpCodeTypeMapper.Add(typeof(UInt16), OpCodes.Ldind_U2); - OpCodeTypeMapper.Add(typeof(UInt32), OpCodes.Ldind_U4); + OpCodeTypeMapper.Add(typeof(bool), OpCodes.Ldind_I1); + OpCodeTypeMapper.Add(typeof(short), OpCodes.Ldind_I2); + OpCodeTypeMapper.Add(typeof(int), OpCodes.Ldind_I4); + OpCodeTypeMapper.Add(typeof(long), OpCodes.Ldind_I8); + OpCodeTypeMapper.Add(typeof(double), OpCodes.Ldind_R8); + OpCodeTypeMapper.Add(typeof(float), OpCodes.Ldind_R4); + OpCodeTypeMapper.Add(typeof(ushort), OpCodes.Ldind_U2); + OpCodeTypeMapper.Add(typeof(uint), OpCodes.Ldind_U4); } private ProxyFactory() @@ -135,7 +135,7 @@ namespace DynamicProxy } } - public Object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface) + public object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface) { string typeName = objType.FullName + PROXY_SUFFIX; Type type = (Type)_typeMap[typeName]; @@ -160,7 +160,7 @@ namespace DynamicProxy return Activator.CreateInstance(type, new object[] { handler }); } - public Object Create(IProxyInvocationHandler handler, Type objType) + public object Create(IProxyInvocationHandler handler, Type objType) { return Create(handler, objType, false); } @@ -171,7 +171,7 @@ namespace DynamicProxy if (handler != null && interfaces != null) { - Type objType = typeof(Object); + Type objType = typeof(object); Type handlerType = typeof(IProxyInvocationHandler); AppDomain domain = Thread.GetDomain(); @@ -182,7 +182,7 @@ namespace DynamicProxy // create a new assembly for this proxy, one that isn't presisted on the file system AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Run); - // assemblyName, AssemblyBuilderAccess.RunAndSave,"."); // to save it to the disk + // assemblyName, AssemblyBuilderAccess.RunAndSave,"."); // to save it to the disk // create a new module for this proxy ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(MODULE_NAME); @@ -200,9 +200,8 @@ namespace DynamicProxy FieldBuilder handlerField = typeBuilder.DefineField( HANDLER_NAME, handlerType, FieldAttributes.Private); - // build a constructor that takes the delegate object as the only argument - //ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] ); + // ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] ); ConstructorInfo superConstructor = objType.GetConstructor(new Type[0]); ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType }); @@ -224,8 +223,8 @@ namespace DynamicProxy constructorIL.Emit(OpCodes.Ret); #endregion - // for every method that the interfaces define, build a corresponding - // method in the dynamic type that calls the handlers invoke method. + // for every method that the interfaces define, build a corresponding + // method in the dynamic type that calls the handlers invoke method. foreach (Type interfaceType in interfaces) { GenerateMethod(interfaceType, handlerField, typeBuilder); @@ -242,106 +241,122 @@ namespace DynamicProxy private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod("Invoke"); private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod("GetMethod", new Type[] { typeof(string), typeof(int) }); - private void GenerateMethod( Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder ) { - MetaDataFactory.Add( interfaceType ); + private void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder) + { + MetaDataFactory.Add(interfaceType); MethodInfo[] interfaceMethods = interfaceType.GetMethods(); PropertyInfo[] props = interfaceType.GetProperties(); - for ( int i = 0; i < interfaceMethods.Length; i++ ) { + for (int i = 0; i < interfaceMethods.Length; i++) + { MethodInfo methodInfo = interfaceMethods[i]; // Get the method parameters since we need to create an array // of parameter types ParameterInfo[] methodParams = methodInfo.GetParameters(); int numOfParams = methodParams.Length; - Type[] methodParameters = new Type[ numOfParams ]; + Type[] methodParameters = new Type[numOfParams]; // convert the ParameterInfo objects into Type - for ( int j = 0; j < numOfParams; j++ ) { + for (int j = 0; j < numOfParams; j++) + { methodParameters[j] = methodParams[j].ParameterType; } // create a new builder for the method in the interface MethodBuilder methodBuilder = typeBuilder.DefineMethod( - methodInfo.Name, - /*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes&~MethodAttributes.Abstract, + methodInfo.Name, + /*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes & ~MethodAttributes.Abstract, CallingConventions.Standard, - methodInfo.ReturnType, methodParameters ); + methodInfo.ReturnType, methodParameters); #region( "Handler Method IL Code" ) ILGenerator methodIL = methodBuilder.GetILGenerator(); - + // load "this" - methodIL.Emit( OpCodes.Ldarg_0 ); + methodIL.Emit(OpCodes.Ldarg_0); // load the handler - methodIL.Emit( OpCodes.Ldfld, handlerField ); + methodIL.Emit(OpCodes.Ldfld, handlerField); // load "this" since its needed for the call to invoke - methodIL.Emit( OpCodes.Ldarg_0 ); + methodIL.Emit(OpCodes.Ldarg_0); // load the name of the interface, used to get the MethodInfo object // from MetaDataFactory - methodIL.Emit( OpCodes.Ldstr, interfaceType.FullName ); - // load the index, used to get the MethodInfo object - // from MetaDataFactory - methodIL.Emit( OpCodes.Ldc_I4, i ); + methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName); + // load the index, used to get the MethodInfo object + // from MetaDataFactory + methodIL.Emit(OpCodes.Ldc_I4, i); // invoke GetMethod in MetaDataFactory - methodIL.Emit( OpCodes.Call, GET_METHODINFO_METHOD); + methodIL.Emit(OpCodes.Call, GET_METHODINFO_METHOD); // load the number of parameters onto the stack - methodIL.Emit( OpCodes.Ldc_I4, numOfParams ); + methodIL.Emit(OpCodes.Ldc_I4, numOfParams); // create a new array, using the size that was just pused on the stack - methodIL.Emit( OpCodes.Newarr, typeof(object) ); - + methodIL.Emit(OpCodes.Newarr, typeof(object)); + // if we have any parameters, then iterate through and set the values // of each element to the corresponding arguments - for ( int j = 0; j < numOfParams; j++ ) { - methodIL.Emit( OpCodes.Dup ); // this copies the array - methodIL.Emit( OpCodes.Ldc_I4, j ); - methodIL.Emit( OpCodes.Ldarg, j + 1 ); - if ( methodParameters[j].IsValueType ) { - methodIL.Emit( OpCodes.Box, methodParameters[j] ); + for (int j = 0; j < numOfParams; j++) + { + methodIL.Emit(OpCodes.Dup); // this copies the array + methodIL.Emit(OpCodes.Ldc_I4, j); + methodIL.Emit(OpCodes.Ldarg, j + 1); + if (methodParameters[j].IsValueType) + { + methodIL.Emit(OpCodes.Box, methodParameters[j]); } - methodIL.Emit( OpCodes.Stelem_Ref ); + + methodIL.Emit(OpCodes.Stelem_Ref); } // call the Invoke method - methodIL.Emit( OpCodes.Callvirt, INVOKE_METHOD ); - - if ( methodInfo.ReturnType != typeof(void) ) { + methodIL.Emit(OpCodes.Callvirt, INVOKE_METHOD); + + if (methodInfo.ReturnType != typeof(void)) + { // if the return type if a value type, then unbox the return value // so that we don't get junk. - if ( methodInfo.ReturnType.IsValueType ) { - methodIL.Emit( OpCodes.Unbox, methodInfo.ReturnType ); - if ( methodInfo.ReturnType.IsEnum ) { - methodIL.Emit( OpCodes.Ldind_I4 ); - } else if ( !methodInfo.ReturnType.IsPrimitive ) { - methodIL.Emit( OpCodes.Ldobj, methodInfo.ReturnType ); - } else { - methodIL.Emit( (OpCode) OpCodeTypeMapper[ methodInfo.ReturnType ] ); + if (methodInfo.ReturnType.IsValueType) + { + methodIL.Emit(OpCodes.Unbox, methodInfo.ReturnType); + if (methodInfo.ReturnType.IsEnum) + { + methodIL.Emit(OpCodes.Ldind_I4); } - } - } else { - // pop the return value that Invoke returned from the stack since - // the method's return type is void. - methodIL.Emit( OpCodes.Pop ); + else if (!methodInfo.ReturnType.IsPrimitive) + { + methodIL.Emit(OpCodes.Ldobj, methodInfo.ReturnType); + } + else + { + methodIL.Emit((OpCode)OpCodeTypeMapper[methodInfo.ReturnType]); + } + } } - + else + { + // pop the return value that Invoke returned from the stack since + // the method's return type is void. + methodIL.Emit(OpCodes.Pop); + } + // Return - methodIL.Emit( OpCodes.Ret ); + methodIL.Emit(OpCodes.Ret); #endregion } - //for (int i = 0; i < props.Length; i++) - //{ - // PropertyInfo p = props[i]; + // for (int i = 0; i < props.Length; i++) + // { + // PropertyInfo p = props[i]; - // PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType }); - // pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]); - // pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]); - //} + // PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType }); + // pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]); + // pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]); + // } // Iterate through the parent interfaces and recursively call this method - foreach ( Type parentType in interfaceType.GetInterfaces() ) { - GenerateMethod( parentType, handlerField, typeBuilder ); + foreach (Type parentType in interfaceType.GetInterfaces()) + { + GenerateMethod(parentType, handlerField, typeBuilder); } } } diff --git a/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs b/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs index ba1f8cf..d665a2c 100644 --- a/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs +++ b/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs @@ -1,12 +1,12 @@ using System; using System.Xml; -using winsw.Util; namespace winsw.Extensions { - public abstract class AbstractWinSWExtension : IWinSWExtension + public abstract class AbstractWinSWExtension : IWinSWExtension { - public abstract String DisplayName { get; } + public abstract string DisplayName { get; } + public WinSWExtensionDescriptor Descriptor { get; set; } public virtual void Configure(ServiceDescriptor descriptor, XmlNode node) diff --git a/src/Core/WinSWCore/Extensions/ExtensionException.cs b/src/Core/WinSWCore/Extensions/ExtensionException.cs index 5ac682a..48a5ae2 100644 --- a/src/Core/WinSWCore/Extensions/ExtensionException.cs +++ b/src/Core/WinSWCore/Extensions/ExtensionException.cs @@ -4,26 +4,20 @@ namespace winsw.Extensions { public class ExtensionException : WinSWException { - public String ExtensionId { get; private set; } + public string ExtensionId { get; private set; } - public ExtensionException(String extensionName, String message) + public ExtensionException(string extensionName, string message) : base(message) { ExtensionId = extensionName; } - public ExtensionException(String extensionName, String message, Exception innerException) + public ExtensionException(string extensionName, string message, Exception innerException) : base(message, innerException) { ExtensionId = extensionName; } - public override string Message - { - get - { - return ExtensionId + ": " + base.Message; - } - } + public override string Message => ExtensionId + ": " + base.Message; } } diff --git a/src/Core/WinSWCore/Extensions/ExtensionPointAttribute.cs b/src/Core/WinSWCore/Extensions/ExtensionPointAttribute.cs index 61a4e11..fd51b4d 100644 --- a/src/Core/WinSWCore/Extensions/ExtensionPointAttribute.cs +++ b/src/Core/WinSWCore/Extensions/ExtensionPointAttribute.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace winsw.Extensions +namespace winsw.Extensions { /// /// This attribute is used to identify extension points within the code diff --git a/src/Core/WinSWCore/Extensions/IWinSWExtension.cs b/src/Core/WinSWCore/Extensions/IWinSWExtension.cs index 0f11987..4562c4f 100644 --- a/src/Core/WinSWCore/Extensions/IWinSWExtension.cs +++ b/src/Core/WinSWCore/Extensions/IWinSWExtension.cs @@ -1,6 +1,5 @@ using System; using System.Xml; -using winsw.Util; namespace winsw.Extensions { @@ -8,7 +7,7 @@ namespace winsw.Extensions /// Interface for Win Service Wrapper Extension /// /// - /// All implementations should provide the default empty constructor. + /// All implementations should provide the default empty constructor. /// The initialization will be performed by Init methods. /// Binary comparibility of the class is not guaranteed in WinSW 2. /// @@ -17,7 +16,7 @@ namespace winsw.Extensions /// /// Extension name to be displayed in logs /// - String DisplayName { get; } + string DisplayName { get; } /// /// Extension descriptor diff --git a/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs index 3d58c73..004560c 100644 --- a/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs +++ b/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs @@ -15,7 +15,7 @@ namespace winsw.Extensions /// /// Unique extension ID /// - public String Id { get; private set; } + public string Id { get; private set; } /// /// Exception is enabled @@ -25,7 +25,7 @@ namespace winsw.Extensions /// /// Extension classname /// - public String ClassName { get; private set; } + public string ClassName { get; private set; } private WinSWExtensionDescriptor(string id, string className, bool enabled) { diff --git a/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs index 51cfd1a..9c6ffb7 100644 --- a/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs +++ b/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs @@ -1,17 +1,16 @@ using System; using System.Collections.Generic; -using System.Xml; using System.Reflection; -using System.Diagnostics; -using winsw.Util; +using System.Xml; using log4net; namespace winsw.Extensions { public class WinSWExtensionManager { - public Dictionary Extensions { private set; get; } - public ServiceDescriptor ServiceDescriptor { private set; get; } + public Dictionary Extensions { get; private set; } + + public ServiceDescriptor ServiceDescriptor { get; private set; } private static readonly ILog Log = LogManager.GetLogger(typeof(WinSWExtensionManager)); @@ -27,7 +26,7 @@ namespace winsw.Extensions /// If any extensions fails, WinSW startup should be interrupted. /// /// Start failure - public void FireOnWrapperStarted() + public void FireOnWrapperStarted() { foreach (var ext in Extensions) { @@ -50,7 +49,7 @@ namespace winsw.Extensions public void FireBeforeWrapperStopped() { foreach (var ext in Extensions) - { + { try { ext.Value.BeforeWrapperStopped(); @@ -100,10 +99,9 @@ namespace winsw.Extensions } } - //TODO: Implement loading of external extensions. Current version supports internal hack + // TODO: Implement loading of external extensions. Current version supports internal hack #region Extension load management - /// Loads extensions according to the configuration file. /// /// Logger @@ -111,7 +109,7 @@ namespace winsw.Extensions public void LoadExtensions() { var extensionIds = ServiceDescriptor.ExtensionIds; - foreach (String extensionId in extensionIds) + foreach (string extensionId in extensionIds) { LoadExtension(extensionId); } @@ -131,7 +129,7 @@ namespace winsw.Extensions } var extensionsConfig = ServiceDescriptor.ExtensionsConfiguration; - XmlElement configNode =(extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='"+id+"'][1]") as XmlElement : null; + XmlElement configNode = (extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement : null; if (configNode == null) { throw new ExtensionException(id, "Cannot get the configuration entry"); @@ -151,6 +149,7 @@ namespace winsw.Extensions Log.Fatal("Failed to configure the extension " + id, ex); throw ex; } + Extensions.Add(id, extension); Log.Info("Extension loaded: " + id); } @@ -158,37 +157,35 @@ namespace winsw.Extensions { Log.Warn("Extension is disabled: " + id); } - } private IWinSWExtension CreateExtensionInstance(string id, string className) { - ActivationContext ac = AppDomain.CurrentDomain.ActivationContext; - Assembly assembly = Assembly.GetCallingAssembly(); - Object created; - + object created; + try { Type t = Type.GetType(className); if (t == null) { - throw new ExtensionException(id, "Class "+className+" does not exist"); + throw new ExtensionException(id, "Class " + className + " does not exist"); } + created = Activator.CreateInstance(t); - } + } catch (Exception ex) { - throw new ExtensionException(id, "Cannot load the class by name: "+className, ex); + throw new ExtensionException(id, "Cannot load the class by name: " + className, ex); } - - var extension = created as IWinSWExtension; - if (extension == null) + + if (!(created is IWinSWExtension extension)) { throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType()); } + return extension; } - #endregion + #endregion } } diff --git a/src/Core/WinSWCore/LogAppenders.cs b/src/Core/WinSWCore/LogAppenders.cs index d9d7e30..7df463f 100644 --- a/src/Core/WinSWCore/LogAppenders.cs +++ b/src/Core/WinSWCore/LogAppenders.cs @@ -2,7 +2,6 @@ using System; using System.Diagnostics; using System.IO; using System.Threading; -using System.Timers; using ICSharpCode.SharpZipLib.Zip; namespace winsw @@ -11,6 +10,7 @@ namespace winsw public interface EventLogger { void LogEvent(string message); + void LogEvent(string message, EventLogEntryType type); } @@ -25,7 +25,7 @@ namespace winsw /// /// Error and information about logging should be reported here. /// - public EventLogger EventLogger { set; get; } + public EventLogger EventLogger { get; set; } /// /// Convenience method to copy stuff from StreamReader to StreamWriter @@ -36,10 +36,13 @@ namespace winsw while (true) { int sz = i.Read(buf, 0, buf.Length); - if (sz == 0) break; + if (sz == 0) + break; + o.Write(buf, 0, sz); o.Flush(); } + i.Close(); o.Close(); } @@ -66,11 +69,11 @@ namespace winsw /// public abstract class AbstractFileLogAppender : LogHandler { - protected string BaseLogFileName { private set; get; } - protected bool OutFileDisabled { private set; get; } - protected bool ErrFileDisabled { private set; get; } - protected string OutFilePattern { private set; get; } - protected string ErrFilePattern { private set; get; } + protected string BaseLogFileName { get; private set; } + protected bool OutFileDisabled { get; private set; } + protected bool ErrFileDisabled { get; private set; } + protected string OutFilePattern { get; private set; } + protected string ErrFilePattern { get; private set; } protected AbstractFileLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern) { @@ -84,9 +87,9 @@ namespace winsw public abstract class SimpleLogAppender : AbstractFileLogAppender { - public FileMode FileMode { private set; get; } - public string OutputLogFileName { private set; get; } - public string ErrorLogFileName { private set; get; } + public FileMode FileMode { get; private set; } + public string OutputLogFileName { get; private set; } + public string ErrorLogFileName { get; private set; } protected SimpleLogAppender(string logDirectory, string baseName, FileMode fileMode, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern) : base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern) @@ -98,8 +101,11 @@ namespace winsw public override void log(Stream outputStream, Stream errorStream) { - if (!OutFileDisabled) new Thread(delegate() { CopyStream(outputStream, new FileStream(OutputLogFileName, FileMode)); }).Start(); - if (!ErrFileDisabled) new Thread(delegate() { CopyStream(errorStream, new FileStream(ErrorLogFileName, FileMode)); }).Start(); + if (!OutFileDisabled) + new Thread(() => CopyStream(outputStream, new FileStream(OutputLogFileName, FileMode))).Start(); + + if (!ErrFileDisabled) + new Thread(() => CopyStream(errorStream, new FileStream(ErrorLogFileName, FileMode))).Start(); } } @@ -118,7 +124,7 @@ namespace winsw { } } - + /// /// LogHandler that throws away output /// @@ -126,8 +132,8 @@ namespace winsw { public override void log(Stream outputStream, Stream errorStream) { - new Thread(delegate() { CopyStream(outputStream, Stream.Null); }).Start(); - new Thread(delegate() { CopyStream(errorStream, Stream.Null); }).Start(); + new Thread(() => CopyStream(outputStream, Stream.Null)).Start(); + new Thread(() => CopyStream(errorStream, Stream.Null)).Start(); } } @@ -145,8 +151,11 @@ namespace winsw public override void log(Stream outputStream, Stream errorStream) { - if (!OutFileDisabled) new Thread(delegate() { CopyStreamWithDateRotation(outputStream, OutFilePattern); }).Start(); - if (!ErrFileDisabled) new Thread(delegate() { CopyStreamWithDateRotation(errorStream, ErrFilePattern); }).Start(); + if (!OutFileDisabled) + new Thread(() => CopyStreamWithDateRotation(outputStream, OutFilePattern)).Start(); + + if (!ErrFileDisabled) + new Thread(() => CopyStreamWithDateRotation(errorStream, ErrFilePattern)).Start(); } /// @@ -162,16 +171,19 @@ namespace winsw while (true) { int len = data.Read(buf, 0, buf.Length); - if (len == 0) break; // EOF + if (len == 0) + break; // EOF if (periodicRollingCalendar.shouldRoll) - {// rotate at the line boundary + { + // rotate at the line boundary int offset = 0; bool rolled = false; for (int i = 0; i < len; i++) { if (buf[i] == 0x0A) - {// at the line boundary. + { + // at the line boundary. // time to rotate. w.Write(buf, offset, i + 1); w.Close(); @@ -189,24 +201,25 @@ namespace winsw } if (!rolled) - {// we didn't roll - most likely as we didnt find a line boundary, so we should log what we read and roll anyway. + { + // we didn't roll - most likely as we didnt find a line boundary, so we should log what we read and roll anyway. w.Write(buf, 0, len); w.Close(); w = new FileStream(BaseLogFileName + "_" + periodicRollingCalendar.format + ext, FileMode.Create); } - } else - {// typical case. write the whole thing into the current file + { + // typical case. write the whole thing into the current file w.Write(buf, 0, len); } w.Flush(); } + data.Close(); w.Close(); } - } public class SizeBasedRollingLogAppender : AbstractFileLogAppender @@ -220,9 +233,9 @@ namespace winsw // ReSharper disable once InconsistentNaming public static int DEFAULT_FILES_TO_KEEP = 8; - public int SizeTheshold { private set; get; } + public int SizeTheshold { get; private set; } - public int FilesToKeep { private set; get; } + public int FilesToKeep { get; private set; } public SizeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, int filesToKeep) : base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern) @@ -236,8 +249,11 @@ namespace winsw public override void log(Stream outputStream, Stream errorStream) { - if (!OutFileDisabled) new Thread(delegate() { CopyStreamWithRotation(outputStream, OutFilePattern); }).Start(); - if (!ErrFileDisabled) new Thread(delegate() { CopyStreamWithRotation(errorStream, ErrFilePattern); }).Start(); + if (!OutFileDisabled) + new Thread(() => CopyStreamWithRotation(outputStream, OutFilePattern)).Start(); + + if (!ErrFileDisabled) + new Thread(() => CopyStreamWithRotation(errorStream, ErrFilePattern)).Start(); } /// @@ -252,9 +268,12 @@ namespace winsw while (true) { int len = data.Read(buf, 0, buf.Length); - if (len == 0) break; // EOF + if (len == 0) + break; // EOF + if (sz + len < SizeTheshold) - {// typical case. write the whole thing into the current file + { + // typical case. write the whole thing into the current file w.Write(buf, 0, len); sz += len; } @@ -264,8 +283,11 @@ namespace winsw int s = 0; for (int i = 0; i < len; i++) { - if (buf[i] != 0x0A) continue; - if (sz + i < SizeTheshold) continue; + if (buf[i] != 0x0A) + continue; + + if (sz + i < SizeTheshold) + continue; // at the line boundary and exceeded the rotation unit. // time to rotate. @@ -281,9 +303,11 @@ namespace winsw string src = BaseLogFileName + "." + (j - 2) + ext; if (File.Exists(dst)) File.Delete(dst); + if (File.Exists(src)) File.Move(src, dst); } + File.Move(BaseLogFileName + ext, BaseLogFileName + ".0" + ext); } catch (IOException e) @@ -300,6 +324,7 @@ namespace winsw w.Flush(); } + data.Close(); w.Close(); } @@ -317,8 +342,12 @@ namespace winsw public override void log(Stream outputStream, Stream errorStream) { - if (!OutFileDisabled) CopyFile(OutputLogFileName, OutputLogFileName + ".old"); - if (!ErrFileDisabled) CopyFile(ErrorLogFileName, ErrorLogFileName + ".old"); + if (!OutFileDisabled) + CopyFile(OutputLogFileName, OutputLogFileName + ".old"); + + if (!ErrFileDisabled) + CopyFile(ErrorLogFileName, ErrorLogFileName + ".old"); + base.log(outputStream, errorStream); } } @@ -326,11 +355,11 @@ namespace winsw public class RollingSizeTimeLogAppender : AbstractFileLogAppender { public static int BYTES_PER_KB = 1024; - public int SizeTheshold { private set; get; } - public string FilePattern { private set; get; } - public TimeSpan? AutoRollAtTime { private set; get; } - public int? ZipOlderThanNumDays { private set; get; } - public string ZipDateFormat { private set; get; } + public int SizeTheshold { get; private set; } + public string FilePattern { get; private set; } + public TimeSpan? AutoRollAtTime { get; private set; } + public int? ZipOlderThanNumDays { get; private set; } + public string ZipDateFormat { get; private set; } public RollingSizeTimeLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, string filePattern, TimeSpan? autoRollAtTime, int? zipolderthannumdays, string zipdateformat) : base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern) @@ -344,8 +373,11 @@ namespace winsw public override void log(Stream outputStream, Stream errorStream) { - if (!OutFileDisabled) new Thread(delegate () { CopyStreamWithRotation(outputStream, OutFilePattern); }).Start(); - if (!ErrFileDisabled) new Thread(delegate () { CopyStreamWithRotation(errorStream, ErrFilePattern); }).Start(); + if (!OutFileDisabled) + new Thread(() => CopyStreamWithRotation(outputStream, OutFilePattern)).Start(); + + if (!ErrFileDisabled) + new Thread(() => CopyStreamWithRotation(errorStream, ErrFilePattern)).Start(); } private void CopyStreamWithRotation(Stream data, string ext) @@ -379,7 +411,7 @@ namespace winsw var now = DateTime.Now.AddDays(-1); var nextFileNumber = GetNextFileNumber(ext, baseDirectory, baseFileName, now); - var nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(FilePattern), nextFileNumber, ext)); + var nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(FilePattern), nextFileNumber, ext)); File.Move(logFile, nextFileName); w = new FileStream(logFile, FileMode.Create); @@ -402,10 +434,13 @@ namespace winsw }; timer.Start(); } + while (true) { var len = data.Read(buf, 0, buf.Length); - if (len == 0) break; // EOF + if (len == 0) + break; // EOF + lock (fileLock) { if (sz + len < SizeTheshold) @@ -422,8 +457,11 @@ namespace winsw int s = 0; for (int i = 0; i < len; i++) { - if (buf[i] != 0x0A) continue; - if (sz + i < SizeTheshold) continue; + if (buf[i] != 0x0A) + continue; + + if (sz + i < SizeTheshold) + continue; // at the line boundary and exceeded the rotation unit. // time to rotate. @@ -450,16 +488,19 @@ namespace winsw EventLogger.LogEvent(string.Format("Failed to roll size time log: {0}", e.Message)); } } + w.Flush(); } } + data.Close(); w.Close(); } private void ZipFiles(string path, string fileExt, string baseZipfilename) { - if (ZipOlderThanNumDays == null || !(ZipOlderThanNumDays > 0)) return; + if (ZipOlderThanNumDays == null || !(ZipOlderThanNumDays > 0)) + return; try { @@ -467,7 +508,8 @@ namespace winsw foreach (var file in files) { var fi = new FileInfo(file); - if (fi.LastWriteTimeUtc >= DateTime.UtcNow.AddDays(-ZipOlderThanNumDays.Value)) continue; + if (fi.LastWriteTimeUtc >= DateTime.UtcNow.AddDays(-ZipOlderThanNumDays.Value)) + continue; // lets archive this bugger ZipTheFile(file, path, fi.LastWriteTimeUtc.ToString(ZipDateFormat), baseZipfilename); @@ -487,7 +529,6 @@ namespace winsw bool commited = false; try { - if (File.Exists(zipfilename)) { zipFile = new ZipFile(zipfilename); @@ -539,18 +580,18 @@ namespace winsw { var nowTime = DateTime.Now; var scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, AutoRollAtTime.Value.Hours, - AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); //Specify your time HH,MM,SS + AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); // Specify your time HH,MM,SS if (nowTime > scheduledTime) scheduledTime = scheduledTime.AddDays(1); - double tickTime = (double) (scheduledTime - DateTime.Now).TotalMilliseconds; + double tickTime = (scheduledTime - DateTime.Now).TotalMilliseconds; return tickTime; } private int GetNextFileNumber(string ext, string baseDirectory, string baseFileName, DateTime now) { var nextFileNumber = 0; - var files = Directory.GetFiles(baseDirectory, String.Format("{0}.{1}.#*{2}", baseFileName, now.ToString(FilePattern), ext)); + var files = Directory.GetFiles(baseDirectory, string.Format("{0}.{1}.#*{2}", baseFileName, now.ToString(FilePattern), ext)); if (files.Length == 0) { nextFileNumber = 1; @@ -564,24 +605,29 @@ namespace winsw var filenameOnly = Path.GetFileNameWithoutExtension(f); var hashIndex = filenameOnly.IndexOf('#'); var lastNumberAsString = filenameOnly.Substring(hashIndex + 1, 4); - //var lastNumberAsString = filenameOnly.Substring(filenameOnly.Length - 4, 4); - int lastNumber = 0; - if (int.TryParse(lastNumberAsString, out lastNumber)) + // var lastNumberAsString = filenameOnly.Substring(filenameOnly.Length - 4, 4); + if (int.TryParse(lastNumberAsString, out int lastNumber)) { if (lastNumber > nextFileNumber) nextFileNumber = lastNumber; } else - throw new IOException(string.Format("File {0} does not follow the pattern provided",f)); + { + throw new IOException(string.Format("File {0} does not follow the pattern provided", f)); + } } catch (Exception e) { - throw new IOException(string.Format("Failed to process file {0} due to error {1}",f, e.Message), e); + throw new IOException(string.Format("Failed to process file {0} due to error {1}", f, e.Message), e); } } - if (nextFileNumber == 0) throw new IOException("Cannot roll the file because matching pattern not found"); + + if (nextFileNumber == 0) + throw new IOException("Cannot roll the file because matching pattern not found"); + nextFileNumber++; } + return nextFileNumber; } } diff --git a/src/Core/WinSWCore/Logging/IServiceEventLogProvider.cs b/src/Core/WinSWCore/Logging/IServiceEventLogProvider.cs index 2c66d03..c590b47 100644 --- a/src/Core/WinSWCore/Logging/IServiceEventLogProvider.cs +++ b/src/Core/WinSWCore/Logging/IServiceEventLogProvider.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; +using System.Diagnostics; namespace winsw.Logging { diff --git a/src/Core/WinSWCore/Logging/ServiceEventLogAppender.cs b/src/Core/WinSWCore/Logging/ServiceEventLogAppender.cs index a1b864a..0c4f939 100644 --- a/src/Core/WinSWCore/Logging/ServiceEventLogAppender.cs +++ b/src/Core/WinSWCore/Logging/ServiceEventLogAppender.cs @@ -1,9 +1,6 @@ -using log4net.Appender; +using System.Diagnostics; +using log4net.Appender; using log4net.Core; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; namespace winsw.Logging { @@ -31,6 +28,7 @@ namespace winsw.Logging { return EventLogEntryType.Error; } + if (level.Value >= Level.Warn.Value) { return EventLogEntryType.Warning; diff --git a/src/Core/WinSWCore/Native/Advapi32.cs b/src/Core/WinSWCore/Native/Advapi32.cs index 9d77b74..99f23ba 100755 --- a/src/Core/WinSWCore/Native/Advapi32.cs +++ b/src/Core/WinSWCore/Native/Advapi32.cs @@ -17,7 +17,7 @@ namespace winsw.Native _handle = Advapi32.OpenSCManager(null, null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS); if (_handle == IntPtr.Zero) { - throw new Exception(String.Format("Error connecting to Service Control Manager. Error provided was: 0x{0:X}", Marshal.GetLastWin32Error())); + throw new Exception(string.Format("Error connecting to Service Control Manager. Error provided was: 0x{0:X}", Marshal.GetLastWin32Error())); } } @@ -26,8 +26,9 @@ namespace winsw.Native IntPtr svcHandle = Advapi32.OpenService(_handle, serviceName, (int)SERVICE_ACCESS.SERVICE_ALL_ACCESS); if (svcHandle == IntPtr.Zero) { - throw new Exception(String.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error())); + throw new Exception(string.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error())); } + return new Service(svcHandle); } @@ -52,9 +53,9 @@ namespace winsw.Native { SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS { - dwResetPeriod = (int) failureResetPeriod.TotalSeconds, - lpRebootMsg = "", - lpCommand = "" + dwResetPeriod = (int)failureResetPeriod.TotalSeconds, + lpRebootMsg = string.Empty, + lpCommand = string.Empty }; // delete message // delete the command to run @@ -101,7 +102,7 @@ namespace winsw.Native public void Dispose() { - if (Handle!=IntPtr.Zero) + if (Handle != IntPtr.Zero) Advapi32.CloseServiceHandle(Handle); Handle = IntPtr.Zero; } @@ -111,14 +112,14 @@ namespace winsw.Native { public static void AddLogonAsAServiceRight(string username) { - //Needs to be at least XP or 2003 server - //https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx + // Needs to be at least XP or 2003 server + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx OperatingSystem osInfo = Environment.OSVersion; if (osInfo.Version.Major >= 5 && osInfo.Version.Minor >= 1) { var newuser = GetLocalAccountIfLocalAccount(username); - //Trace.WriteLine("Username for Logon as A Service: " + newuser); + // Trace.WriteLine("Username for Logon as A Service: " + newuser); long rightexitcode = SetRight(newuser, PrivlegeRights.SeServiceLogonRight.ToString()); if (rightexitcode != 0) { @@ -155,6 +156,7 @@ namespace winsw.Native { return GetLogin(username); } + return username; } @@ -162,34 +164,34 @@ namespace winsw.Native /// Name of an account - "domain\account" or only "account" /// Name ofthe privilege /// The windows error code returned by LsaAddAccountRights - private static long SetRight(String accountName, String privilegeName) + private static long SetRight(string accountName, string privilegeName) { - long winErrorCode = 0; //contains the last error + long winErrorCode; // contains the last error - //pointer an size for the SID + // pointer an size for the SID IntPtr sid = IntPtr.Zero; int sidSize = 0; - //StringBuilder and size for the domain name + // StringBuilder and size for the domain name StringBuilder domainName = new StringBuilder(); int nameSize = 0; - //account-type variable for lookup + // account-type variable for lookup int accountType = 0; - //get required buffer size - Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType); + // get required buffer size + Advapi32.LookupAccountName(string.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType); - //allocate buffers + // allocate buffers domainName = new StringBuilder(nameSize); sid = Marshal.AllocHGlobal(sidSize); - //lookup the SID for the account - bool result = Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, + // lookup the SID for the account + bool result = Advapi32.LookupAccountName(string.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType); - //say what you're doing - //Console.WriteLine("LookupAccountName result = " + result); - //Console.WriteLine("IsValidSid: " + Advapi32.IsValidSid(sid)); - //Console.WriteLine("LookupAccountName domainName: " + domainName.ToString()); + // say what you're doing + // Console.WriteLine("LookupAccountName result = " + result); + // Console.WriteLine("IsValidSid: " + Advapi32.IsValidSid(sid)); + // Console.WriteLine("LookupAccountName domainName: " + domainName.ToString()); if (!result) { @@ -198,10 +200,9 @@ namespace winsw.Native } else { - - //initialize an empty unicode-string - LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING(); - //combine all policies + // initialize an empty unicode-string + LSA_UNICODE_STRING systemName = default; + // combine all policies const int access = (int)( LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN | LSA_AccessPolicy.POLICY_CREATE_ACCOUNT | @@ -217,10 +218,9 @@ namespace winsw.Native LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION | LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION ); - //initialize a pointer for the policy handle - IntPtr policyHandle = IntPtr.Zero; + // initialize a pointer for the policy handle - //these attributes are not used, but LsaOpenPolicy wants them to exists + // these attributes are not used, but LsaOpenPolicy wants them to exists LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES { Length = 0, @@ -230,8 +230,8 @@ namespace winsw.Native SecurityQualityOfService = IntPtr.Zero }; - //get a policy handle - uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref objectAttributes, access, out policyHandle); + // get a policy handle + uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref objectAttributes, access, out IntPtr policyHandle); winErrorCode = Advapi32.LsaNtStatusToWinError(resultPolicy); if (winErrorCode != 0) @@ -240,17 +240,17 @@ namespace winsw.Native } else { - //Now that we have the SID an the policy, - //we can add rights to the account. + // Now that we have the SID an the policy, + // we can add rights to the account. - //initialize an unicode-string for the privilege name + // initialize an unicode-string for the privilege name LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1]; - userRights[0] = new LSA_UNICODE_STRING(); + userRights[0] = default; userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName); - userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize); - userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize); + userRights[0].Length = (ushort)(privilegeName.Length * UnicodeEncoding.CharSize); + userRights[0].MaximumLength = (ushort)((privilegeName.Length + 1) * UnicodeEncoding.CharSize); - //add the right to the account + // add the right to the account uint res = Advapi32.LsaAddAccountRights(policyHandle, sid, userRights, 1); winErrorCode = Advapi32.LsaNtStatusToWinError(res); if (winErrorCode != 0) @@ -260,6 +260,7 @@ namespace winsw.Native Advapi32.LsaClose(policyHandle); } + Advapi32.FreeSid(sid); } @@ -290,7 +291,7 @@ namespace winsw.Native [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); - + [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseServiceHandle(IntPtr hSCObject); @@ -299,7 +300,7 @@ namespace winsw.Native public static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", PreserveSig = true)] - internal static extern UInt32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, + internal static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, int DesiredAccess, out IntPtr PolicyHandle); [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] @@ -309,7 +310,7 @@ namespace winsw.Native internal static extern void FreeSid(IntPtr pSid); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)] - internal static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName, + internal static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName, ref int cbdomainLength, ref int use); [DllImport("advapi32.dll")] @@ -320,29 +321,28 @@ namespace winsw.Native [DllImport("advapi32.dll", SetLastError = false)] internal static extern uint LsaNtStatusToWinError(uint status); - } - //http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx internal enum PrivlegeRights { - SeServiceLogonRight, //Required for an account to log on using the service logon type. - SeRemoteInteractiveLogonRight, //Required for an account to log on remotely using the interactive logon type. - SeNetworkLogonRight, //Required for an account to log on using the network logon type. - SeInteractiveLogonRight, //Required for an account to log on using the interactive logon type. - SeDenyServiceLogonRight, //Explicitly denies an account the right to log on using the service logon type. - SeDenyRemoteInteractiveLogonRight, //Explicitly denies an account the right to log on remotely using the interactive logon type. - SeDenyNetworkLogonRight, //Explicitly denies an account the right to log on using the network logon type. - SeDenyInteractiveLogonRight, //Explicitly denies an account the right to log on using the interactive logon type. - SeDenyBatchLogonRight, //Explicitly denies an account the right to log on using the batch logon type. - SeBatchLogonRight //Required for an account to log on using the batch logon type. + SeServiceLogonRight, // Required for an account to log on using the service logon type. + SeRemoteInteractiveLogonRight, // Required for an account to log on remotely using the interactive logon type. + SeNetworkLogonRight, // Required for an account to log on using the network logon type. + SeInteractiveLogonRight, // Required for an account to log on using the interactive logon type. + SeDenyServiceLogonRight, // Explicitly denies an account the right to log on using the service logon type. + SeDenyRemoteInteractiveLogonRight, // Explicitly denies an account the right to log on remotely using the interactive logon type. + SeDenyNetworkLogonRight, // Explicitly denies an account the right to log on using the network logon type. + SeDenyInteractiveLogonRight, // Explicitly denies an account the right to log on using the interactive logon type. + SeDenyBatchLogonRight, // Explicitly denies an account the right to log on using the batch logon type. + SeBatchLogonRight // Required for an account to log on using the batch logon type. } [StructLayout(LayoutKind.Sequential)] struct LSA_UNICODE_STRING { - public UInt16 Length; - public UInt16 MaximumLength; + public ushort Length; + public ushort MaximumLength; public IntPtr Buffer; } @@ -352,7 +352,7 @@ namespace winsw.Native public int Length; public IntPtr RootDirectory; public LSA_UNICODE_STRING ObjectName; - public UInt32 Attributes; + public uint Attributes; public IntPtr SecurityDescriptor; public IntPtr SecurityQualityOfService; } @@ -381,7 +381,7 @@ namespace winsw.Native /// /// Required to connect to the service control manager. /// - + SC_MANAGER_CONNECT = 0x00001, /// @@ -391,19 +391,19 @@ namespace winsw.Native SC_MANAGER_CREATE_SERVICE = 0x00002, /// - /// Required to call the EnumServicesStatusEx function to list the + /// Required to call the EnumServicesStatusEx function to list the /// services that are in the database. /// SC_MANAGER_ENUMERATE_SERVICE = 0x00004, /// - /// Required to call the LockServiceDatabase function to acquire a + /// Required to call the LockServiceDatabase function to acquire a /// lock on the database. /// SC_MANAGER_LOCK = 0x00008, /// - /// Required to call the QueryServiceLockStatus function to retrieve + /// Required to call the QueryServiceLockStatus function to retrieve /// the lock status information for the database. /// SC_MANAGER_QUERY_LOCK_STATUS = 0x00010, @@ -414,7 +414,7 @@ namespace winsw.Native SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020, /// - /// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access + /// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access /// rights in this table. /// SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED | @@ -452,7 +452,7 @@ namespace winsw.Native SERVICE_PAUSE_CONTINUE = 0x00040, SERVICE_INTERROGATE = 0x00080, SERVICE_USER_DEFINED_CONTROL = 0x00100, - SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | + SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | @@ -461,7 +461,7 @@ namespace winsw.Native SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | - SERVICE_USER_DEFINED_CONTROL) + SERVICE_USER_DEFINED_CONTROL } [Flags] @@ -536,7 +536,6 @@ namespace winsw.Native SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSED = 0x00000007, } - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685126(v=vs.85).aspx [StructLayout(LayoutKind.Sequential)] @@ -577,7 +576,7 @@ namespace winsw.Native } // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685939(v=vs.85).aspx - [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct SERVICE_FAILURE_ACTIONS { /// diff --git a/src/Core/WinSWCore/Native/Kernel32.cs b/src/Core/WinSWCore/Native/Kernel32.cs index c91ceb8..abc7c85 100755 --- a/src/Core/WinSWCore/Native/Kernel32.cs +++ b/src/Core/WinSWCore/Native/Kernel32.cs @@ -1,6 +1,6 @@ -using Microsoft.Win32.SafeHandles; -using System; +using System; using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; namespace winsw.Native { @@ -8,7 +8,7 @@ namespace winsw.Native /// kernel32.dll P/Invoke wrappers /// public class Kernel32 - { + { [DllImport("kernel32.dll", SetLastError = true)] public static extern bool SetStdHandle(int nStdHandle, SafeFileHandle handle); @@ -36,20 +36,20 @@ namespace winsw.Native [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct STARTUPINFO { - public Int32 cb; + public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; - public Int32 dwX; - public Int32 dwY; - public Int32 dwXSize; - public Int32 dwYSize; - public Int32 dwXCountChars; - public Int32 dwYCountChars; - public Int32 dwFillAttribute; - public Int32 dwFlags; - public Int16 wShowWindow; - public Int16 cbReserved2; + public int dwX; + public int dwY; + public int dwXSize; + public int dwYSize; + public int dwXCountChars; + public int dwYCountChars; + public int dwFillAttribute; + public int dwFlags; + public short wShowWindow; + public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; diff --git a/src/Core/WinSWCore/PeriodicRollingCalendar.cs b/src/Core/WinSWCore/PeriodicRollingCalendar.cs index 9801566..3a77d7c 100644 --- a/src/Core/WinSWCore/PeriodicRollingCalendar.cs +++ b/src/Core/WinSWCore/PeriodicRollingCalendar.cs @@ -29,10 +29,16 @@ namespace winsw public enum PeriodicityType { - ERRONEOUS, TOP_OF_MILLISECOND, TOP_OF_SECOND, TOP_OF_MINUTE, TOP_OF_HOUR, TOP_OF_DAY + ERRONEOUS, + TOP_OF_MILLISECOND, + TOP_OF_SECOND, + TOP_OF_MINUTE, + TOP_OF_HOUR, + TOP_OF_DAY } - private static readonly PeriodicityType[] VALID_ORDERED_LIST = { + private static readonly PeriodicityType[] VALID_ORDERED_LIST = + { PeriodicityType.TOP_OF_MILLISECOND, PeriodicityType.TOP_OF_SECOND, PeriodicityType.TOP_OF_MINUTE, PeriodicityType.TOP_OF_HOUR, PeriodicityType.TOP_OF_DAY }; @@ -54,6 +60,7 @@ namespace winsw return i; } } + return PeriodicityType.ERRONEOUS; } @@ -89,7 +96,7 @@ namespace winsw public PeriodicityType periodicityType { get; set; } - public Boolean shouldRoll + public bool shouldRoll { get { @@ -100,17 +107,11 @@ namespace winsw _nextRoll = nextTriggeringTime(now, _period); return true; } + return false; } } - public string format - { - get - { - return _currentRoll.ToString(_format); - } - } - + public string format => _currentRoll.ToString(_format); } } diff --git a/src/Core/WinSWCore/ServiceDescriptor.cs b/src/Core/WinSWCore/ServiceDescriptor.cs index 08d33c6..510206e 100755 --- a/src/Core/WinSWCore/ServiceDescriptor.cs +++ b/src/Core/WinSWCore/ServiceDescriptor.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Reflection; using System.Xml; using winsw.Configuration; using winsw.Native; @@ -20,40 +19,35 @@ namespace winsw // ReSharper disable once InconsistentNaming protected readonly XmlDocument dom = new XmlDocument(); - private static readonly DefaultWinSWSettings defaults = new DefaultWinSWSettings(); - public static DefaultWinSWSettings Defaults { get { return defaults; } } + public static DefaultWinSWSettings Defaults { get; } = new DefaultWinSWSettings(); /// /// Where did we find the configuration file? - /// + /// /// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml" /// public string BasePath { get; set; } /// /// The file name portion of the configuration file. - /// + /// /// In the above example, this would be "ghi". /// public string BaseName { get; set; } - public virtual string ExecutablePath - { - get - { - // Currently there is no opportunity to alter the executable path - return Defaults.ExecutablePath; - } - } + // Currently there is no opportunity to alter the executable path + public virtual string ExecutablePath => Defaults.ExecutablePath; public ServiceDescriptor() { // find co-located configuration xml. We search up to the ancestor directories to simplify debugging, // as well as trimming off ".vshost" suffix (which is used during debugging) - //Get the first parent to go into the recursive loop + // Get the first parent to go into the recursive loop string p = ExecutablePath; string baseName = Path.GetFileNameWithoutExtension(p); - if (baseName.EndsWith(".vshost")) baseName = baseName.Substring(0, baseName.Length - 7); + if (baseName.EndsWith(".vshost")) + baseName = baseName.Substring(0, baseName.Length - 7); + DirectoryInfo d = new DirectoryInfo(Path.GetDirectoryName(p)); while (true) { @@ -61,7 +55,7 @@ namespace winsw break; if (d.Parent == null) - throw new FileNotFoundException("Unable to locate "+baseName+".xml file within executable directory or any parents"); + throw new FileNotFoundException("Unable to locate " + baseName + ".xml file within executable directory or any parents"); d = d.Parent; } @@ -73,11 +67,13 @@ namespace winsw // register the base directory as environment variable so that future expansions can refer to this. Environment.SetEnvironmentVariable("BASE", d.FullName); + // ditto for ID Environment.SetEnvironmentVariable("SERVICE_ID", Id); // New name Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_EXECUTABLE_PATH, ExecutablePath); + // Also inject system environment variables Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_SERVICE_ID, Id); } @@ -106,7 +102,9 @@ namespace winsw private string SingleElement(string tagName, bool optional) { var n = dom.SelectSingleNode("//" + tagName); - if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + if (n == null && !optional) + throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText); } @@ -147,51 +145,36 @@ namespace winsw return TimeSpan.FromMilliseconds(int.Parse(v.Substring(0, v.Length - s.Key.Length).Trim()) * s.Value); } } + return TimeSpan.FromMilliseconds(int.Parse(v)); } - private static readonly Dictionary Suffix = new Dictionary { - { "ms", 1 }, + private static readonly Dictionary Suffix = new Dictionary + { + { "ms", 1 }, { "sec", 1000L }, { "secs", 1000L }, - { "min", 1000L*60L }, - { "mins", 1000L*60L }, - { "hr", 1000L*60L*60L }, - { "hrs", 1000L*60L*60L }, - { "hour", 1000L*60L*60L }, - { "hours", 1000L*60L*60L }, - { "day", 1000L*60L*60L*24L }, - { "days", 1000L*60L*60L*24L } + { "min", 1000L * 60L }, + { "mins", 1000L * 60L }, + { "hr", 1000L * 60L * 60L }, + { "hrs", 1000L * 60L * 60L }, + { "hour", 1000L * 60L * 60L }, + { "hours", 1000L * 60L * 60L }, + { "day", 1000L * 60L * 60L * 24L }, + { "days", 1000L * 60L * 60L * 24L } }; /// /// Path to the executable. /// - public string Executable - { - get - { - return SingleElement("executable"); - } - } + public string Executable => SingleElement("executable"); - public bool HideWindow - { - get { - return SingleBoolElement("hidewindow", Defaults.HideWindow); - } - } + public bool HideWindow => SingleBoolElement("hidewindow", Defaults.HideWindow); /// /// Optionally specify a different Path to an executable to shutdown the service. /// - public string StopExecutable - { - get - { - return SingleElement("stopexecutable", true); - } - } + public string StopExecutable => SingleElement("stopexecutable", true); /// /// Arguments or multiple optional argument elements which overrule the arguments element. @@ -223,30 +206,19 @@ namespace winsw /// /// Multiple optional startargument elements. /// - public string Startarguments - { - get - { - return AppendTags("startargument", Defaults.Startarguments); - } - } + public string Startarguments => AppendTags("startargument", Defaults.Startarguments); /// /// Multiple optional stopargument elements. /// - public string Stoparguments + public string Stoparguments => AppendTags("stopargument", Defaults.Stoparguments); + + public string WorkingDirectory { get { - return AppendTags("stopargument", Defaults.Stoparguments); - } - } - - - public string WorkingDirectory { - get { var wd = SingleElement("workingdirectory", true); - return String.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd; + return string.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd; } } @@ -257,13 +229,13 @@ namespace winsw List res = new List(); XmlNode argumentNode = ExtensionsConfiguration; - XmlNodeList extensions = argumentNode != null ? argumentNode.SelectNodes("extension") : null; - if ( extensions != null) + XmlNodeList extensions = argumentNode?.SelectNodes("extension"); + if (extensions != null) { foreach (XmlNode e in extensions) { XmlElement extension = (XmlElement)e; - String extensionId = XmlHelper.SingleAttribute(extension, "id"); + string extensionId = XmlHelper.SingleAttribute(extension, "id"); res.Add(extensionId); } } @@ -272,14 +244,7 @@ namespace winsw } } - public XmlNode ExtensionsConfiguration - { - get - { - XmlNode argumentNode = dom.SelectSingleNode("//extensions"); - return argumentNode; - } - } + public XmlNode ExtensionsConfiguration => dom.SelectSingleNode("//extensions"); /// /// Combines the contents of all the elements of the given name, @@ -295,7 +260,7 @@ namespace winsw } else { - string arguments = ""; + string arguments = string.Empty; foreach (XmlElement argument in dom.SelectNodes("//" + tagName)) { @@ -314,6 +279,7 @@ namespace winsw token = '"' + token + '"'; } } + arguments += " " + token; } @@ -365,6 +331,7 @@ namespace winsw { mode = Defaults.LogMode; } + return mode; } } @@ -379,18 +346,9 @@ namespace winsw } } - public bool OutFileDisabled - { - get { return SingleBoolElement("outfiledisabled", Defaults.OutFileDisabled); } - } + public bool OutFileDisabled => SingleBoolElement("outfiledisabled", Defaults.OutFileDisabled); - public bool ErrFileDisabled - { - get - { - return SingleBoolElement("errfiledisabled", Defaults.ErrFileDisabled); - } - } + public bool ErrFileDisabled => SingleBoolElement("errfiledisabled", Defaults.ErrFileDisabled); public string OutFilePattern { @@ -414,7 +372,6 @@ namespace winsw public LogHandler LogHandler { - get { XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode"); @@ -423,6 +380,7 @@ namespace winsw // this is more modern way, to support nested elements as configuration e = (XmlElement)dom.SelectSingleNode("//log"); } + int sizeThreshold; switch (LogMode) { @@ -444,13 +402,14 @@ namespace winsw { throw new InvalidDataException("Time Based rolling policy is specified but no pattern can be found in configuration XML."); } + var pattern = patternNode.InnerText; - int period = SingleIntElement(e,"period",1); + int period = SingleIntElement(e, "period", 1); return new TimeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, pattern, period); case "roll-by-size": - sizeThreshold = SingleIntElement(e,"sizeThreshold",10*1024) * SizeBasedRollingLogAppender.BYTES_PER_KB; - int keepFiles = SingleIntElement(e,"keepFiles",SizeBasedRollingLogAppender.DEFAULT_FILES_TO_KEEP); + sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * SizeBasedRollingLogAppender.BYTES_PER_KB; + int keepFiles = SingleIntElement(e, "keepFiles", SizeBasedRollingLogAppender.DEFAULT_FILES_TO_KEEP); return new SizeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, sizeThreshold, keepFiles); case "append": @@ -463,29 +422,29 @@ namespace winsw { throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but no pattern can be found in configuration XML."); } + XmlNode autoRollAtTimeNode = e.SelectSingleNode("autoRollAtTime"); TimeSpan? autoRollAtTime = null; if (autoRollAtTimeNode != null) { - TimeSpan autoRollAtTimeValue; // validate it - if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out autoRollAtTimeValue)) + if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out TimeSpan autoRollAtTimeValue)) throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but autoRollAtTime does not match the TimeSpan format HH:mm:ss found in configuration XML."); autoRollAtTime = autoRollAtTimeValue; } + XmlNode zipolderthannumdaysNode = e.SelectSingleNode("zipOlderThanNumDays"); int? zipolderthannumdays = null; if (zipolderthannumdaysNode != null) { - int zipolderthannumdaysValue; // validate it - if (!int.TryParse(zipolderthannumdaysNode.InnerText, out zipolderthannumdaysValue)) + if (!int.TryParse(zipolderthannumdaysNode.InnerText, out int zipolderthannumdaysValue)) throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but zipOlderThanNumDays does not match the int format found in configuration XML."); zipolderthannumdays = zipolderthannumdaysValue; } XmlNode zipdateformatNode = e.SelectSingleNode("zipDateFormat"); - string zipdateformat = null; + string zipdateformat; if (zipdateformatNode == null) { zipdateformat = "yyyyMM"; @@ -501,7 +460,6 @@ namespace winsw throw new InvalidDataException("Undefined logging mode: " + LogMode); } } - } /// @@ -519,35 +477,19 @@ namespace winsw { serviceDependencies.Add(depend.InnerText); } + return (string[])serviceDependencies.ToArray(typeof(string)); } + return Defaults.ServiceDependencies; } } - public string Id - { - get - { - return SingleElement("id"); - } - } + public string Id => SingleElement("id"); - public string Caption - { - get - { - return SingleElement("name"); - } - } + public string Caption => SingleElement("name"); - public string Description - { - get - { - return SingleElement("description"); - } - } + public string Description => SingleElement("description"); /// /// Start mode of the Service @@ -557,7 +499,9 @@ namespace winsw get { var p = SingleElement("startmode", true); - if (p == null) return Defaults.StartMode; + if (p == null) + return Defaults.StartMode; + try { return (StartMode)Enum.Parse(typeof(StartMode), p, true); @@ -569,6 +513,7 @@ namespace winsw { Console.WriteLine(sm); } + throw; } } @@ -578,64 +523,32 @@ namespace winsw /// True if the service should be installed with the DelayedAutoStart flag. /// This setting will be applyed only during the install command and only when the Automatic start mode is configured. /// - public bool DelayedAutoStart - { - get - { - return dom.SelectSingleNode("//delayedAutoStart") != null; - } - } + public bool DelayedAutoStart => dom.SelectSingleNode("//delayedAutoStart") != null; /// /// True if the service should beep when finished on shutdown. /// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx /// - public bool BeepOnShutdown - { - get - { - return dom.SelectSingleNode("//beeponshutdown") != null; - } - } - + public bool BeepOnShutdown => dom.SelectSingleNode("//beeponshutdown") != null; /// /// The estimated time required for a pending stop operation (default 15 secs). - /// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function + /// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function /// with either an incremented checkPoint value or a change in currentState. (see http://msdn.microsoft.com/en-us/library/ms685996.aspx) /// - public TimeSpan WaitHint - { - get - { - return SingleTimeSpanElement(dom, "waithint", Defaults.WaitHint); - } - } - + public TimeSpan WaitHint => SingleTimeSpanElement(dom, "waithint", Defaults.WaitHint); /// - /// The time before the service should make its next call to the SetServiceStatus function + /// The time before the service should make its next call to the SetServiceStatus function /// with an incremented checkPoint value (default 1 sec). /// Do not wait longer than the wait hint. A good interval is one-tenth of the wait hint but not less than 1 second and not more than 10 seconds. /// - public TimeSpan SleepTime - { - get - { - return SingleTimeSpanElement(dom, "sleeptime", Defaults.SleepTime); - } - } + public TimeSpan SleepTime => SingleTimeSpanElement(dom, "sleeptime", Defaults.SleepTime); /// /// True if the service can interact with the desktop. /// - public bool Interactive - { - get - { - return dom.SelectSingleNode("//interactive") != null; - } - } + public bool Interactive => dom.SelectSingleNode("//interactive") != null; /// /// Environment variable overrides @@ -653,6 +566,7 @@ namespace winsw Environment.SetEnvironmentVariable(key, value); } + return map; } } @@ -666,7 +580,7 @@ namespace winsw get { var xmlNodeList = dom.SelectNodes("//download"); - if (xmlNodeList == null) + if (xmlNodeList == null) { return Defaults.Downloads; } @@ -674,12 +588,12 @@ namespace winsw List r = new List(); foreach (XmlNode n in xmlNodeList) { - XmlElement el = n as XmlElement; - if (el != null) + if (n is XmlElement el) { r.Add(new Download(el)); } } + return r; } } @@ -710,25 +624,21 @@ namespace winsw default: throw new Exception("Invalid failure action: " + action); } + XmlAttribute delay = n.Attributes["delay"]; r.Add(new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero)); } } + return r; } } - public TimeSpan ResetFailureAfter - { - get - { - return SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter); - } - } + public TimeSpan ResetFailureAfter => SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter); protected string GetServiceAccountPart(string subNodeName) - { - var node = dom.SelectSingleNode("//serviceaccount"); + { + var node = dom.SelectSingleNode("//serviceaccount"); if (node != null) { @@ -736,56 +646,28 @@ namespace winsw if (subNode != null) { return subNode.InnerText; - } + } } - return null; - - } - - protected string AllowServiceLogon - { - get - { - return GetServiceAccountPart("allowservicelogon"); - } + return null; } - // ReSharper disable once InconsistentNaming - protected string serviceAccountDomain - { - get - { - return GetServiceAccountPart("domain"); - } - } + protected string AllowServiceLogon => GetServiceAccountPart("allowservicelogon"); // ReSharper disable once InconsistentNaming - protected string serviceAccountName - { - get - { - return GetServiceAccountPart("user"); - } - } + protected string serviceAccountDomain => GetServiceAccountPart("domain"); - public string ServiceAccountPassword - { - get - { - return GetServiceAccountPart("password"); - } - } + // ReSharper disable once InconsistentNaming + protected string serviceAccountName => GetServiceAccountPart("user"); - public string ServiceAccountUser - { - get { return (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL"); } - } + public string ServiceAccountPassword => GetServiceAccountPart("password"); - public bool HasServiceAccount() - { - return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName); - } + public string ServiceAccountUser => (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL"); + + public bool HasServiceAccount() + { + return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName); + } public bool AllowServiceAcountLogonRight { @@ -793,37 +675,31 @@ namespace winsw { if (AllowServiceLogon != null) { - bool parsedvalue; - if (Boolean.TryParse(AllowServiceLogon, out parsedvalue)) + if (bool.TryParse(AllowServiceLogon, out bool parsedvalue)) { return parsedvalue; } } + return false; } } - /// - /// Time to wait for the service to gracefully shutdown the executable before we forcibly kill it - /// - public TimeSpan StopTimeout - { - get - { - return SingleTimeSpanElement(dom, "stoptimeout", Defaults.StopTimeout); - } - } + /// + /// Time to wait for the service to gracefully shutdown the executable before we forcibly kill it + /// + public TimeSpan StopTimeout => SingleTimeSpanElement(dom, "stoptimeout", Defaults.StopTimeout); public bool StopParentProcessFirst { get { var value = SingleElement("stopparentprocessfirst", true); - bool result; - if (bool.TryParse(value, out result)) + if (bool.TryParse(value, out bool result)) { return result; } + return Defaults.StopParentProcessFirst; } } @@ -835,8 +711,9 @@ namespace winsw { get { - var p = SingleElement("priority",true); - if (p == null) return Defaults.Priority; + var p = SingleElement("priority", true); + if (p == null) + return Defaults.Priority; return (ProcessPriorityClass)Enum.Parse(typeof(ProcessPriorityClass), p, true); } diff --git a/src/Core/WinSWCore/Util/ProcessHelper.cs b/src/Core/WinSWCore/Util/ProcessHelper.cs index b67d457..c8d6e77 100644 --- a/src/Core/WinSWCore/Util/ProcessHelper.cs +++ b/src/Core/WinSWCore/Util/ProcessHelper.cs @@ -1,10 +1,9 @@ -using log4net; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Management; -using System.Text; using System.Threading; +using log4net; namespace winsw.Util { @@ -24,8 +23,9 @@ namespace winsw.Util public static List GetChildPids(int pid) { var childPids = new List(); - - try { + + try + { var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid); foreach (var mo in searcher.Get()) { @@ -38,7 +38,7 @@ namespace winsw.Util { Logger.Warn("Failed to locate children of the process with PID=" + pid + ". Child processes won't be terminated", ex); } - + return childPids; } @@ -87,7 +87,7 @@ namespace winsw.Util } } - //TODO: Propagate error if process kill fails? Currently we use the legacy behavior + // TODO: Propagate error if process kill fails? Currently we use the legacy behavior } /// @@ -100,7 +100,7 @@ namespace winsw.Util public static void StopProcessAndChildren(int pid, TimeSpan stopTimeout, bool stopParentProcessFirst) { if (!stopParentProcessFirst) - { + { foreach (var childPid in GetChildPids(pid)) { StopProcessAndChildren(childPid, stopTimeout, stopParentProcessFirst); @@ -131,7 +131,7 @@ namespace winsw.Util /// Completion callback. If null, the completion won't be monitored /// Log handler. If enabled, logs will be redirected to the process and then reported /// Redirect standard input - public static void StartProcessAndCallbackForExit(Process processToStart, String executable = null, string arguments = null, Dictionary envVars = null, + public static void StartProcessAndCallbackForExit(Process processToStart, string executable = null, string arguments = null, Dictionary envVars = null, string workingDirectory = null, ProcessPriorityClass? priority = null, ProcessCompletionCallback callback = null, bool redirectStdin = true, LogHandler logHandler = null, bool hideWindow = false) { var ps = processToStart.StartInfo; @@ -149,7 +149,7 @@ namespace winsw.Util foreach (string key in envVars.Keys) { Environment.SetEnvironmentVariable(key, envVars[key]); - // DONTDO: ps.EnvironmentVariables[key] = envs[key]; + // DONTDO: ps.EnvironmentVariables[key] = envs[key]; // bugged (lower cases all variable names due to StringDictionary being used, see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=326163) } } @@ -157,8 +157,8 @@ namespace winsw.Util processToStart.Start(); Logger.Info("Started process " + processToStart.Id); - if (priority != null && priority.Value != ProcessPriorityClass.Normal) - { + if (priority != null && priority.Value != ProcessPriorityClass.Normal) + { processToStart.PriorityClass = priority.Value; } @@ -172,7 +172,7 @@ namespace winsw.Util // monitor the completion of the process if (callback != null) { - StartThread(delegate + StartThread(() => { processToStart.WaitForExit(); callback(processToStart); @@ -187,7 +187,7 @@ namespace winsw.Util /// public static void StartThread(ThreadStart main) { - new Thread(delegate() + new Thread(() => { try { diff --git a/src/Core/WinSWCore/Util/SigIntHelper.cs b/src/Core/WinSWCore/Util/SigIntHelper.cs index f7c5e0b..d6e639c 100644 --- a/src/Core/WinSWCore/Util/SigIntHelper.cs +++ b/src/Core/WinSWCore/Util/SigIntHelper.cs @@ -1,7 +1,7 @@ -using log4net; -using System; +using System; using System.Diagnostics; using System.Runtime.InteropServices; +using log4net; using winsw.Native; namespace winsw.Util @@ -20,8 +20,9 @@ namespace winsw.Util [DllImport(KERNEL32)] private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); + // Delegate type to be used as the Handler Routine for SCCH - private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType); + private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType); // Enumerated type for the control messages sent to the handler routine private enum CtrlTypes : uint @@ -47,7 +48,7 @@ namespace winsw.Util { if (AttachConsole((uint)process.Id)) { - //Disable Ctrl-C handling for our program + // Disable Ctrl-C handling for our program SetConsoleCtrlHandler(null, true); GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); @@ -61,9 +62,9 @@ namespace winsw.Util Logger.Warn("Failed to detach from console. Error code: " + errorCode); } - return process.HasExited; + return process.HasExited; } - + return false; } } diff --git a/src/Core/WinSWCore/Util/XmlHelper.cs b/src/Core/WinSWCore/Util/XmlHelper.cs index af64773..e5c98e5 100644 --- a/src/Core/WinSWCore/Util/XmlHelper.cs +++ b/src/Core/WinSWCore/Util/XmlHelper.cs @@ -1,25 +1,25 @@ using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; using System.IO; +using System.Xml; namespace winsw.Util { public class XmlHelper { /// - /// Retrieves a single string element + /// Retrieves a single string element /// /// Parent node /// Element name /// If optional, don't throw an exception if the elemen is missing /// String value or null /// The required element is missing - public static string SingleElement(XmlNode node, string tagName, Boolean optional) + public static string SingleElement(XmlNode node, string tagName, bool optional) { var n = node.SelectSingleNode(tagName); - if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + if (n == null && !optional) + throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText); } @@ -31,10 +31,12 @@ namespace winsw.Util /// If otional, don't throw an exception if the elemen is missing /// String value or null /// The required element is missing - public static XmlNode SingleNode(XmlNode node, string tagName, Boolean optional) + public static XmlNode SingleNode(XmlNode node, string tagName, bool optional) { var n = node.SelectSingleNode(tagName); - if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + if (n == null && !optional) + throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return n; } @@ -45,14 +47,14 @@ namespace winsw.Util /// Attribute name /// Attribute value /// The required attribute is missing - public static TAttributeType SingleAttribute (XmlElement node, string attributeName) + public static TAttributeType SingleAttribute(XmlElement node, string attributeName) { if (!node.HasAttribute(attributeName)) { throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML"); } - return SingleAttribute(node, attributeName, default(TAttributeType)); + return SingleAttribute(node, attributeName, default(TAttributeType)); } /// @@ -64,12 +66,13 @@ namespace winsw.Util /// Attribute value (or default) public static TAttributeType SingleAttribute(XmlElement node, string attributeName, TAttributeType defaultValue) { - if (!node.HasAttribute(attributeName)) return defaultValue; + if (!node.HasAttribute(attributeName)) + return defaultValue; - string rawValue = node.GetAttribute(attributeName); - string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue); - var value = (TAttributeType)Convert.ChangeType(substitutedValue, typeof(TAttributeType)); - return value; + string rawValue = node.GetAttribute(attributeName); + string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue); + var value = (TAttributeType)Convert.ChangeType(substitutedValue, typeof(TAttributeType)); + return value; } /// @@ -83,7 +86,8 @@ namespace winsw.Util /// Wrong enum value public static TAttributeType EnumAttribute(XmlElement node, string attributeName, TAttributeType defaultValue) { - if (!node.HasAttribute(attributeName)) return defaultValue; + if (!node.HasAttribute(attributeName)) + return defaultValue; string rawValue = node.GetAttribute(attributeName); string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue); @@ -94,7 +98,7 @@ namespace winsw.Util } catch (Exception ex) // Most likely ArgumentException { - throw new InvalidDataException("Cannot parse <" + attributeName + "> Enum value from string '" + substitutedValue + + throw new InvalidDataException("Cannot parse <" + attributeName + "> Enum value from string '" + substitutedValue + "'. Enum type: " + typeof(TAttributeType), ex); } } diff --git a/src/Core/WinSWCore/WinSWException.cs b/src/Core/WinSWCore/WinSWException.cs index 870660e..6fed7b7 100644 --- a/src/Core/WinSWCore/WinSWException.cs +++ b/src/Core/WinSWCore/WinSWException.cs @@ -1,16 +1,14 @@ using System; -using System.Collections.Generic; -using System.Text; namespace winsw { public class WinSWException : Exception { - public WinSWException(String message) + public WinSWException(string message) : base(message) { } - public WinSWException(String message, Exception innerException) + public WinSWException(string message, Exception innerException) : base(message, innerException) { } } diff --git a/src/Core/WinSWCore/WinSWSystem.cs b/src/Core/WinSWCore/WinSWSystem.cs index 2e853f3..b1739db 100644 --- a/src/Core/WinSWCore/WinSWSystem.cs +++ b/src/Core/WinSWCore/WinSWSystem.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace winsw +namespace winsw { /// /// Class, which contains generic information about WinSW runtime. @@ -19,11 +15,11 @@ namespace winsw /// Variable, which points to the service ID. /// It may be used to determine runaway processes. /// - public static string ENVVAR_NAME_SERVICE_ID { get { return SYSTEM_EVNVVAR_PREFIX + "SERVICE_ID"; } } + public static string ENVVAR_NAME_SERVICE_ID => SYSTEM_EVNVVAR_PREFIX + "SERVICE_ID"; /// /// Variable, which specifies path to the executable being launched by WinSW. /// - public static string ENVVAR_NAME_EXECUTABLE_PATH { get { return SYSTEM_EVNVVAR_PREFIX + "EXECUTABLE"; } } + public static string ENVVAR_NAME_EXECUTABLE_PATH => SYSTEM_EVNVVAR_PREFIX + "EXECUTABLE"; } } diff --git a/src/Core/WinSWCore/Wmi.cs b/src/Core/WinSWCore/Wmi.cs index 976ee53..d8837ba 100755 --- a/src/Core/WinSWCore/Wmi.cs +++ b/src/Core/WinSWCore/Wmi.cs @@ -5,7 +5,7 @@ using DynamicProxy; namespace WMI { - //Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx + // Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx public enum ReturnValue { @@ -63,13 +63,14 @@ namespace WMI public class WmiClassName : Attribute { public readonly string Name; - public WmiClassName(string name) { Name = name; } + + public WmiClassName(string name) => Name = name; } /// /// Marker interface to denote a collection in WMI. /// - public interface IWmiCollection {} + public interface IWmiCollection { } /// /// Marker interface to denote an individual managed object @@ -98,7 +99,7 @@ namespace WMI string path; if (machineName != null) - path = String.Format(@"\\{0}\root\cimv2", machineName); + path = string.Format(@"\\{0}\root\cimv2", machineName); else path = @"\root\cimv2"; scope = new ManagementScope(path, options); @@ -141,6 +142,7 @@ namespace WMI _mo[method.Name.Substring(4)] = args[0]; return null; } + if (method.Name.StartsWith("get_")) { return _mo[method.Name.Substring(4)]; @@ -180,7 +182,9 @@ namespace WMI string query = "SELECT * FROM " + _wmiClass + " WHERE "; for (int i = 0; i < args.Length; i++) { - if (i != 0) query += " AND "; + if (i != 0) + query += " AND "; + query += ' ' + Capitalize(methodArgs[i].Name) + " = '" + args[i] + "'"; } diff --git a/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs b/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs index f025d72..974cfa3 100644 --- a/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs +++ b/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs @@ -1,12 +1,12 @@ using System; -using System.Collections.Generic; -using System.Xml; +using System.Collections.Specialized; using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; +using log4net; using winsw.Extensions; using winsw.Util; -using log4net; -using System.Collections.Specialized; -using System.Text; namespace winsw.Plugins.RunawayProcessKiller { @@ -15,7 +15,7 @@ namespace winsw.Plugins.RunawayProcessKiller /// /// Absolute path to the PID file, which stores ID of the previously launched process. /// - public String Pidfile { get; private set; } + public string Pidfile { get; private set; } /// /// Defines the process termination timeout in milliseconds. @@ -34,9 +34,9 @@ namespace winsw.Plugins.RunawayProcessKiller /// public bool CheckWinSWEnvironmentVariable { get; private set; } - public override String DisplayName { get { return "Runaway Process Killer"; } } + public override string DisplayName => "Runaway Process Killer"; - private String ServiceId { get; set; } + private string ServiceId { get; set; } private static readonly ILog Logger = LogManager.GetLogger(typeof(RunawayProcessKillerExtension)); @@ -45,7 +45,7 @@ namespace winsw.Plugins.RunawayProcessKiller // Default initializer } - public RunawayProcessKillerExtension(String pidfile, int stopTimeoutMs = 5000, bool stopParentFirst = false, bool checkWinSWEnvironmentVariable = true) + public RunawayProcessKillerExtension(string pidfile, int stopTimeoutMs = 5000, bool stopParentFirst = false, bool checkWinSWEnvironmentVariable = true) { this.Pidfile = pidfile; this.StopTimeout = TimeSpan.FromMilliseconds(stopTimeoutMs); @@ -58,12 +58,12 @@ namespace winsw.Plugins.RunawayProcessKiller // We expect the upper logic to process any errors // TODO: a better parser API for types would be useful Pidfile = XmlHelper.SingleElement(node, "pidfile", false); - StopTimeout = TimeSpan.FromMilliseconds(Int32.Parse(XmlHelper.SingleElement(node, "stopTimeout", false))); - StopParentProcessFirst = Boolean.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false)); + StopTimeout = TimeSpan.FromMilliseconds(int.Parse(XmlHelper.SingleElement(node, "stopTimeout", false))); + StopParentProcessFirst = bool.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false)); ServiceId = descriptor.Id; - //TODO: Consider making it documented + // TODO: Consider making it documented var checkWinSWEnvironmentVariable = XmlHelper.SingleElement(node, "checkWinSWEnvironmentVariable", true); - CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable != null ? Boolean.Parse(checkWinSWEnvironmentVariable) : true; + CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable != null ? bool.Parse(checkWinSWEnvironmentVariable) : true; } /// @@ -74,20 +74,22 @@ namespace winsw.Plugins.RunawayProcessKiller { // Read PID file from the disk int pid; - if (System.IO.File.Exists(Pidfile)) { + if (File.Exists(Pidfile)) + { string pidstring; try { - pidstring = System.IO.File.ReadAllText(Pidfile); + pidstring = File.ReadAllText(Pidfile); } catch (Exception ex) { Logger.Error("Cannot read PID file from " + Pidfile, ex); return; } + try { - pid = Int32.Parse(pidstring); + pid = int.Parse(pidstring); } catch (FormatException e) { @@ -108,18 +110,18 @@ namespace winsw.Plugins.RunawayProcessKiller { proc = Process.GetProcessById(pid); } - catch (ArgumentException ex) + catch (ArgumentException) { Logger.Debug("No runaway process with PID=" + pid + ". The process has been already stopped."); return; } // Ensure the process references the service - String affiliatedServiceId; + string affiliatedServiceId; // TODO: This method is not ideal since it works only for vars explicitly mentioned in the start info // No Windows 10- compatible solution for EnvVars retrieval, see https://blog.gapotchenko.com/eazfuscator.net/reading-environment-variables StringDictionary previousProcessEnvVars = proc.StartInfo.EnvironmentVariables; - String expectedEnvVarName = WinSWSystem.ENVVAR_NAME_SERVICE_ID; + string expectedEnvVarName = WinSWSystem.ENVVAR_NAME_SERVICE_ID; if (previousProcessEnvVars.ContainsKey(expectedEnvVarName)) { // StringDictionary is case-insensitive, hence it will fetch variable definitions in any case @@ -127,14 +129,16 @@ namespace winsw.Plugins.RunawayProcessKiller } else if (CheckWinSWEnvironmentVariable) { - Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. " + Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. " + "The process has not been started by WinSW, hence it won't be terminated."); - if (Logger.IsDebugEnabled) { - //TODO replace by String.Join() in .NET 4 - String[] keys = new String[previousProcessEnvVars.Count]; + if (Logger.IsDebugEnabled) + { + // TODO replace by String.Join() in .NET 4 + string[] keys = new string[previousProcessEnvVars.Count]; previousProcessEnvVars.Keys.CopyTo(keys, 0); - Logger.DebugFormat("Env vars of the process with PID={0}: {1}", new Object[] {pid, String.Join(",", keys)}); + Logger.DebugFormat("Env vars of the process with PID={0}: {1}", new object[] { pid, string.Join(",", keys) }); } + return; } else @@ -155,11 +159,13 @@ namespace winsw.Plugins.RunawayProcessKiller StringBuilder bldr = new StringBuilder("Stopping the runaway process (pid="); bldr.Append(pid); bldr.Append(") and its children. Environment was "); - if (!CheckWinSWEnvironmentVariable) { + if (!CheckWinSWEnvironmentVariable) + { bldr.Append("not "); } + bldr.Append("checked, affiliated service ID: "); - bldr.Append(affiliatedServiceId != null ? affiliatedServiceId : "undefined"); + bldr.Append(affiliatedServiceId ?? "undefined"); bldr.Append(", process to kill: "); bldr.Append(proc); @@ -171,12 +177,12 @@ namespace winsw.Plugins.RunawayProcessKiller /// Records the started process PID for the future use in OnStart() after the restart. /// /// - public override void OnProcessStarted(System.Diagnostics.Process process) + public override void OnProcessStarted(Process process) { Logger.Info("Recording PID of the started process:" + process.Id + ". PID file destination is " + Pidfile); try { - System.IO.File.WriteAllText(Pidfile, process.Id.ToString()); + File.WriteAllText(Pidfile, process.Id.ToString()); } catch (Exception ex) { diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs index c5cf9e9..27d6f74 100644 --- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; using System.Xml; -using System.Diagnostics; +using log4net; using winsw.Extensions; using winsw.Util; -using log4net; namespace winsw.Plugins.SharedDirectoryMapper { @@ -13,7 +12,7 @@ namespace winsw.Plugins.SharedDirectoryMapper private readonly SharedDirectoryMappingHelper _mapper = new SharedDirectoryMappingHelper(); private readonly List _entries = new List(); - public override String DisplayName { get { return "Shared Directory Mapper"; } } + public override string DisplayName => "Shared Directory Mapper"; private static readonly ILog Logger = LogManager.GetLogger(typeof(SharedDirectoryMapper)); @@ -34,8 +33,7 @@ namespace winsw.Plugins.SharedDirectoryMapper { foreach (XmlNode mapNode in nodes) { - var mapElement = mapNode as XmlElement; - if (mapElement != null) + if (mapNode is XmlElement mapElement) { var config = SharedDirectoryMapperConfig.FromXml(mapElement); _entries.Add(config); @@ -85,8 +83,9 @@ namespace winsw.Plugins.SharedDirectoryMapper } } - private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex) { - Logger.Error("Mapping of " + config.Label + " failed. STDOUT: " + ex.Process.StandardOutput.ReadToEnd() + private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex) + { + Logger.Error("Mapping of " + config.Label + " failed. STDOUT: " + ex.Process.StandardOutput.ReadToEnd() + " \r\nSTDERR: " + ex.Process.StandardError.ReadToEnd(), ex); throw new ExtensionException(Descriptor.Id, DisplayName + ": Mapping of " + config.Label + "failed", ex); } diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs index 59276e8..68f7335 100644 --- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs @@ -10,8 +10,8 @@ namespace winsw.Plugins.SharedDirectoryMapper public class SharedDirectoryMapperConfig { public bool EnableMapping { get; set; } - public String Label { get; set; } - public String UNCPath { get; set; } + public string Label { get; set; } + public string UNCPath { get; set; } public SharedDirectoryMapperConfig(bool enableMapping, string label, string uncPath) { diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs index 8016a93..8647a5c 100644 --- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using winsw.Util; namespace winsw.Plugins.SharedDirectoryMapper { @@ -13,7 +12,7 @@ namespace winsw.Plugins.SharedDirectoryMapper /// Command to be executed /// Command arguments /// Operation failure - private void InvokeCommand(String command, String args) + private void InvokeCommand(string command, string args) { Process p = new Process { @@ -42,7 +41,7 @@ namespace winsw.Plugins.SharedDirectoryMapper /// Disk label /// UNC path to the directory /// Operation failure - public void MapDirectory(String label, String uncPath) + public void MapDirectory(string label, string uncPath) { InvokeCommand("net.exe", " use " + label + " " + uncPath); } @@ -52,7 +51,7 @@ namespace winsw.Plugins.SharedDirectoryMapper /// /// Disk label /// Operation failure - public void UnmapDirectory(String label) + public void UnmapDirectory(string label) { InvokeCommand("net.exe", " use /DELETE /YES " + label); } @@ -60,7 +59,7 @@ namespace winsw.Plugins.SharedDirectoryMapper class MapperException : WinSWException { - public String Call { get; private set; } + public string Call { get; private set; } public Process Process { get; private set; } public MapperException(Process process, string command, string args) diff --git a/src/Test/winswTests/Configuration/ExamplesTest.cs b/src/Test/winswTests/Configuration/ExamplesTest.cs index 454239b..40c0ccb 100644 --- a/src/Test/winswTests/Configuration/ExamplesTest.cs +++ b/src/Test/winswTests/Configuration/ExamplesTest.cs @@ -1,9 +1,6 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; +using System.IO; using System.Xml; +using NUnit.Framework; using winsw; using winswTests.Util; @@ -16,11 +13,10 @@ namespace winswTests.Configuration [TestFixture] class ExamplesTest { - [Test] - public void allOptionsConfigShouldDeclareDefaults() + public void AllOptionsConfigShouldDeclareDefaults() { - ServiceDescriptor d = doLoad("allOptions"); + ServiceDescriptor d = DoLoad("allOptions"); Assert.AreEqual("myapp", d.Id); Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption); @@ -31,9 +27,9 @@ namespace winswTests.Configuration } [Test] - public void minimalConfigShouldDeclareDefaults() + public void MinimalConfigShouldDeclareDefaults() { - ServiceDescriptor d = doLoad("minimal"); + ServiceDescriptor d = DoLoad("minimal"); Assert.AreEqual("myapp", d.Id); Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption); @@ -43,13 +39,15 @@ namespace winswTests.Configuration ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(d); } - private ServiceDescriptor doLoad(string exampleName) { + private ServiceDescriptor DoLoad(string exampleName) + { var dir = Directory.GetCurrentDirectory(); string path = Path.GetFullPath(dir + "\\..\\..\\..\\..\\..\\..\\examples\\sample-" + exampleName + ".xml"); if (!File.Exists(path)) { throw new FileNotFoundException("Cannot find the XML file " + path, path); } + XmlDocument dom = new XmlDocument(); dom.Load(path); return new ServiceDescriptor(dom); diff --git a/src/Test/winswTests/DownloadTest.cs b/src/Test/winswTests/DownloadTest.cs index 7d9f906..7a4452f 100644 --- a/src/Test/winswTests/DownloadTest.cs +++ b/src/Test/winswTests/DownloadTest.cs @@ -1,8 +1,6 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; +using System; using System.IO; -using System.Text; +using NUnit.Framework; using winsw; using winswTests.Util; @@ -22,7 +20,7 @@ namespace winswTests var sd = ConfigXmlBuilder.create() .WithDownload(d) .ToServiceDescriptor(true); - var loaded = getSingleEntry(sd); + var loaded = GetSingleEntry(sd); // Check default values Assert.That(loaded.FailOnError, Is.EqualTo(false)); @@ -40,7 +38,7 @@ namespace winswTests var sd = ConfigXmlBuilder.create() .WithDownload(d) .ToServiceDescriptor(true); - var loaded = getSingleEntry(sd); + var loaded = GetSingleEntry(sd); // Check default values Assert.That(loaded.FailOnError, Is.EqualTo(true)); @@ -58,7 +56,7 @@ namespace winswTests var sd = ConfigXmlBuilder.create() .WithDownload(d) .ToServiceDescriptor(true); - var loaded = getSingleEntry(sd); + var loaded = GetSingleEntry(sd); // Check default values Assert.That(loaded.FailOnError, Is.EqualTo(false)); @@ -67,29 +65,29 @@ namespace winswTests Assert.That(loaded.Password, Is.Null); Assert.That(loaded.UnsecureAuth, Is.EqualTo(false)); } - + [TestCase("http://")] [TestCase("ftp://")] [TestCase("file:///")] [TestCase("jar://")] [TestCase("\\\\")] // UNC - public void ShouldReject_BasicAuth_with_UnsecureProtocol(String protocolPrefix) + public void ShouldReject_BasicAuth_with_UnsecureProtocol(string protocolPrefix) { var d = new Download(protocolPrefix + "myServer.com:8080/file.txt", To, auth: Download.AuthType.basic, username: "aUser", password: "aPassword"); - assertInitializationFails(d, "you're sending your credentials in clear text to the server"); + AssertInitializationFails(d, "you're sending your credentials in clear text to the server"); } public void ShouldRejectBasicAuth_without_username() { var d = new Download(From, To, auth: Download.AuthType.basic, username: null, password: "aPassword"); - assertInitializationFails(d, "Basic Auth is enabled, but username is not specified"); + AssertInitializationFails(d, "Basic Auth is enabled, but username is not specified"); } public void ShouldRejectBasicAuth_without_password() { var d = new Download(From, To, auth: Download.AuthType.basic, username: "aUser", password: null); - assertInitializationFails(d, "Basic Auth is enabled, but password is not specified"); + AssertInitializationFails(d, "Basic Auth is enabled, but password is not specified"); } /// @@ -105,7 +103,7 @@ namespace winswTests .WithDownload(d) .ToServiceDescriptor(true); - var loaded = getSingleEntry(sd); + var loaded = GetSingleEntry(sd); Assert.That(loaded.From, Is.EqualTo(From)); Assert.That(loaded.To, Is.EqualTo(To)); Assert.That(loaded.FailOnError, Is.EqualTo(failOnError), "Unexpected FailOnError value"); @@ -121,7 +119,7 @@ namespace winswTests .WithRawEntry("") .ToServiceDescriptor(true); - var loaded = getSingleEntry(sd); + var loaded = GetSingleEntry(sd); Assert.That(loaded.FailOnError, Is.False); } @@ -129,12 +127,12 @@ namespace winswTests [TestCase("SSPI")] [TestCase("SsPI")] [TestCase("Sspi")] - public void AuthType_Is_CaseInsensitive(String authType) + public void AuthType_Is_CaseInsensitive(string authType) { var sd = ConfigXmlBuilder.create() .WithRawEntry("") .ToServiceDescriptor(true); - var loaded = getSingleEntry(sd); + var loaded = GetSingleEntry(sd); Assert.That(loaded.Auth, Is.EqualTo(Download.AuthType.sspi)); } @@ -146,27 +144,28 @@ namespace winswTests .WithRawEntry("") .ToServiceDescriptor(true); - ExceptionHelper.assertFails("Cannot parse Enum value from string 'digest'", typeof(InvalidDataException), delegate { - var d = getSingleEntry(sd); + ExceptionHelper.assertFails("Cannot parse Enum value from string 'digest'", typeof(InvalidDataException), () => + { + var d = GetSingleEntry(sd); }); } - private Download getSingleEntry(ServiceDescriptor sd) + private Download GetSingleEntry(ServiceDescriptor sd) { var downloads = sd.Downloads.ToArray(); Assert.That(downloads.Length, Is.EqualTo(1), "Service Descriptor is expected to have only one entry"); return downloads[0]; } - private void assertInitializationFails(Download download, String expectedMessagePart = null, Type expectedExceptionType = null) + private void AssertInitializationFails(Download download, string expectedMessagePart = null, Type expectedExceptionType = null) { var sd = ConfigXmlBuilder.create() .WithDownload(download) .ToServiceDescriptor(true); - ExceptionHelper.assertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), delegate + ExceptionHelper.assertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), () => { - var d = getSingleEntry(sd); + var d = GetSingleEntry(sd); }); } } diff --git a/src/Test/winswTests/Extensions/ExtensionTestBase.cs b/src/Test/winswTests/Extensions/ExtensionTestBase.cs index bd1543e..74f85cc 100644 --- a/src/Test/winswTests/Extensions/ExtensionTestBase.cs +++ b/src/Test/winswTests/Extensions/ExtensionTestBase.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace winswTests.Extensions { @@ -15,7 +13,7 @@ namespace winswTests.Extensions /// /// Type of the extension /// String for Type locator, which includes class and assembly names - public static String getExtensionClassNameWithAssembly(Type type) + public static string GetExtensionClassNameWithAssembly(Type type) { return type.ToString() + ", " + type.Assembly; } diff --git a/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs b/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs index db11f44..e9b1972 100644 --- a/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs +++ b/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs @@ -1,14 +1,13 @@ -using winsw; -using NUnit.Framework; -using winsw.Extensions; -using winsw.Plugins.SharedDirectoryMapper; -using winsw.Plugins.RunawayProcessKiller; -using winswTests.Util; -using System.IO; -using System.Diagnostics; -using winsw.Util; -using System; +using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using NUnit.Framework; +using winsw; +using winsw.Extensions; +using winsw.Plugins.RunawayProcessKiller; +using winsw.Util; +using winswTests.Util; namespace winswTests.Extensions { @@ -17,8 +16,8 @@ namespace winswTests.Extensions { ServiceDescriptor _testServiceDescriptor; - string testExtension = getExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension)); - + string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension)); + [SetUp] public void SetUp() { @@ -71,9 +70,9 @@ namespace winswTests.Extensions var winswId = "myAppWithRunaway"; var extensionId = "runawayProcessKiller"; var tmpDir = FilesystemTestHelper.CreateTmpDirectory(); - + // Prepare the env var - String varName = WinSWSystem.ENVVAR_NAME_SERVICE_ID; + string varName = WinSWSystem.ENVVAR_NAME_SERVICE_ID; var env = new Dictionary(); env.Add(varName, winswId); @@ -99,7 +98,7 @@ namespace winswTests.Extensions Assert.IsNotNull(extension, "RunawayProcessKillerExtension should be loaded"); Assert.AreEqual(pidfile, extension.Pidfile, "PidFile should have been retained during the config roundtrip"); - // Inject PID + // Inject PID File.WriteAllText(pidfile, proc.Id.ToString()); // Try to terminate @@ -119,7 +118,7 @@ namespace winswTests.Extensions Console.Error.WriteLine("Test: ProcessHelper failed to properly terminate process with ID=" + proc.Id); } } - } + } } } } diff --git a/src/Test/winswTests/Extensions/SharedDirectoryMapperTest.cs b/src/Test/winswTests/Extensions/SharedDirectoryMapperTest.cs index 5aa60c0..ec91028 100644 --- a/src/Test/winswTests/Extensions/SharedDirectoryMapperTest.cs +++ b/src/Test/winswTests/Extensions/SharedDirectoryMapperTest.cs @@ -1,5 +1,5 @@ -using winsw; -using NUnit.Framework; +using NUnit.Framework; +using winsw; using winsw.Extensions; using winsw.Plugins.SharedDirectoryMapper; @@ -10,12 +10,11 @@ namespace winswTests.Extensions { ServiceDescriptor _testServiceDescriptor; - string testExtension = getExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper)); + string testExtension = GetExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper)); [SetUp] public void SetUp() { - string seedXml = "" + " " + " SERVICE_NAME " diff --git a/src/Test/winswTests/MainTest.cs b/src/Test/winswTests/MainTest.cs index 0622f82..90eb7f9 100644 --- a/src/Test/winswTests/MainTest.cs +++ b/src/Test/winswTests/MainTest.cs @@ -7,7 +7,6 @@ namespace winswTests [TestFixture] class MainTest { - [Test] public void PrintVersion() { @@ -21,12 +20,12 @@ namespace winswTests { string expectedVersion = WrapperService.Version.ToString(); string cliOut = CLITestHelper.CLITest(new[] { "help" }); - + StringAssert.Contains(expectedVersion, cliOut, "Expected that help contains " + expectedVersion); StringAssert.Contains("start", cliOut, "Expected that help refers start command"); StringAssert.Contains("help", cliOut, "Expected that help refers help command"); StringAssert.Contains("version", cliOut, "Expected that help refers version command"); - //TODO: check all commands after the migration of ccommands to enum + // TODO: check all commands after the migration of ccommands to enum // Extra options StringAssert.Contains("/redirect", cliOut, "Expected that help message refers the redirect message"); @@ -37,8 +36,8 @@ namespace winswTests { const string commandName = "nonExistentCommand"; string expectedMessage = "Unknown command: " + commandName.ToLower(); - CLITestResult res = CLITestHelper.CLIErrorTest(new[] {commandName}); - + CLITestResult res = CLITestHelper.CLIErrorTest(new[] { commandName }); + Assert.True(res.HasException, "Expected an exception due to the wrong command"); StringAssert.Contains(expectedMessage, res.Out, "Expected the message about unknown command"); // ReSharper disable once PossibleNullReferenceException diff --git a/src/Test/winswTests/ServiceDescriptorTests.cs b/src/Test/winswTests/ServiceDescriptorTests.cs index 6dc33ce..35313e4 100644 --- a/src/Test/winswTests/ServiceDescriptorTests.cs +++ b/src/Test/winswTests/ServiceDescriptorTests.cs @@ -1,18 +1,16 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using NUnit.Framework; using winsw; namespace winswTests { using System; - using WMI; using winswTests.Util; + using WMI; [TestFixture] public class ServiceDescriptorTests { - private ServiceDescriptor _extendedServiceDescriptor; private const string ExpectedWorkingDirectory = @"Z:\Path\SubPath"; @@ -32,9 +30,9 @@ namespace winswTests + "My Arguments" + "rotate" + "" - + "" + Domain + "" - + "" + Username + "" - + "" + Password + "" + + "" + Domain + "" + + "" + Username + "" + + "" + Password + "" + "" + AllowServiceAccountLogonRight + "" + "" + "" @@ -52,7 +50,7 @@ namespace winswTests } [Test] - [ExpectedException(typeof(System.ArgumentException))] + [ExpectedException(typeof(ArgumentException))] public void IncorrectStartMode() { const string SeedXml = "" @@ -105,6 +103,7 @@ namespace winswTests _extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml); Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Manual)); } + [Test] public void VerifyWorkingDirectory() { @@ -154,8 +153,8 @@ namespace winswTests [Test] public void CanParseStopParentProcessFirst() { - const string seedXml = "" - + "true" + const string seedXml = "" + + "true" + ""; var serviceDescriptor = ServiceDescriptor.FromXML(seedXml); @@ -165,8 +164,8 @@ namespace winswTests [Test] public void CanParseStopTimeout() { - const string seedXml = "" - + "60sec" + const string seedXml = "" + + "60sec" + ""; var serviceDescriptor = ServiceDescriptor.FromXML(seedXml); @@ -176,8 +175,8 @@ namespace winswTests [Test] public void CanParseStopTimeoutFromMinutes() { - const string seedXml = "" - + "10min" + const string seedXml = "" + + "10min" + ""; var serviceDescriptor = ServiceDescriptor.FromXML(seedXml); @@ -242,14 +241,14 @@ namespace winswTests [Test] public void LogModeRollBySize() { - const string seedXml = "" + const string seedXml = "" + "c:\\" + "" - + "112" - + "113" + + "112" + + "113" + "" + ""; - + var serviceDescriptor = ServiceDescriptor.FromXML(seedXml); serviceDescriptor.BaseName = "service"; @@ -265,8 +264,8 @@ namespace winswTests const string seedXml = "" + "c:\\" + "" - + "7" - + "log pattern" + + "7" + + "log pattern" + "" + ""; @@ -298,23 +297,24 @@ namespace winswTests Assert.NotNull(logHandler); Assert.That(logHandler.SizeTheshold, Is.EqualTo(10240 * 1024)); Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd")); - Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0,0,0))); + Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0, 0, 0))); } [Test] public void VerifyServiceLogonRightGraceful() { - const string seedXml="" + const string seedXml = "" + "" - + "" + Domain + "" - + "" + Username + "" - + "" + Password + "" + + "" + Domain + "" + + "" + Username + "" + + "" + Password + "" + "true1" - + "" + + "" + ""; var serviceDescriptor = ServiceDescriptor.FromXML(seedXml); Assert.That(serviceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(false)); } + [Test] public void VerifyServiceLogonRightOmitted() { @@ -358,7 +358,7 @@ namespace winswTests .ToServiceDescriptor(true); Assert.That(sd.WaitHint, Is.EqualTo(TimeSpan.FromMinutes(22))); } - + [Test] public void VerifyWaitHint_XMLWithoutVersionAndComment() { @@ -438,10 +438,12 @@ namespace winswTests public void DelayedStart_RoundTrip(bool enabled) { var bldr = ConfigXmlBuilder.create(); - if (enabled) { + if (enabled) + { bldr = bldr.WithDelayedAutoStart(); } - var sd = bldr.ToServiceDescriptor(); + + var sd = bldr.ToServiceDescriptor(); Assert.That(sd.DelayedAutoStart, Is.EqualTo(enabled)); } } diff --git a/src/Test/winswTests/Util/CLITestHelper.cs b/src/Test/winswTests/Util/CLITestHelper.cs index 193c6b7..9dddb3f 100644 --- a/src/Test/winswTests/Util/CLITestHelper.cs +++ b/src/Test/winswTests/Util/CLITestHelper.cs @@ -22,6 +22,7 @@ namespace winswTests.Util + "" + @"C:\winsw\logs" + ""; + private static readonly ServiceDescriptor DefaultServiceDescriptor = ServiceDescriptor.FromXML(SeedXml); /// @@ -32,7 +33,7 @@ namespace winswTests.Util /// STDOUT if there's no exceptions /// Command failure [NotNull] - public static string CLITest(String[] args, ServiceDescriptor descriptor = null) + public static string CLITest(string[] args, ServiceDescriptor descriptor = null) { using (StringWriter sw = new StringWriter()) { @@ -52,7 +53,7 @@ namespace winswTests.Util /// Optional Service descriptor (will be used for initializationpurposes) /// Test results [NotNull] - public static CLITestResult CLIErrorTest(String[] args, ServiceDescriptor descriptor = null) + public static CLITestResult CLIErrorTest(string[] args, ServiceDescriptor descriptor = null) { StringWriter swOut, swErr; Exception testEx = null; @@ -61,8 +62,9 @@ namespace winswTests.Util using (swOut = new StringWriter()) using (swErr = new StringWriter()) + { try - { + { Console.SetOut(swOut); Console.SetError(swErr); WrapperService.Run(args, descriptor ?? DefaultServiceDescriptor); @@ -85,7 +87,8 @@ namespace winswTests.Util Console.WriteLine(testEx); } } - + } + return new CLITestResult(swOut.ToString(), swErr.ToString(), testEx); } } @@ -96,17 +99,17 @@ namespace winswTests.Util public class CLITestResult { [NotNull] - public String Out { get; private set; } - + public string Out { get; private set; } + [NotNull] - public String Err { get; private set; } - + public string Err { get; private set; } + [CanBeNull] public Exception Exception { get; private set; } - public bool HasException { get { return Exception != null; } } + public bool HasException => Exception != null; - public CLITestResult(String output, String err, Exception exception = null) + public CLITestResult(string output, string err, Exception exception = null) { Out = output; Err = err; diff --git a/src/Test/winswTests/Util/ConfigXmlBuilder.cs b/src/Test/winswTests/Util/ConfigXmlBuilder.cs index e6d4653..fce4951 100644 --- a/src/Test/winswTests/Util/ConfigXmlBuilder.cs +++ b/src/Test/winswTests/Util/ConfigXmlBuilder.cs @@ -17,10 +17,10 @@ namespace winswTests.Util public string Description { get; set; } public string Executable { get; set; } public bool PrintXMLVersion { get; set; } - public string XMLComment { get; set; } + public string XMLComment { get; set; } public List ExtensionXmls { get; private set; } - private List configEntries; + private List configEntries; // TODO: Switch to the initializer? private ConfigXmlBuilder() @@ -29,9 +29,9 @@ namespace winswTests.Util ExtensionXmls = new List(); } - public static ConfigXmlBuilder create(string id = null, string name = null, - string description = null, string executable = null, bool printXMLVersion = true, - string xmlComment = "") + public static ConfigXmlBuilder create(string id = null, string name = null, + string description = null, string executable = null, bool printXMLVersion = true, + string xmlComment = "") { var config = new ConfigXmlBuilder(); config.Id = id ?? "myapp"; @@ -39,8 +39,8 @@ namespace winswTests.Util config.Description = description ?? "MyApp Service (powered by WinSW)"; config.Executable = executable ?? "%BASE%\\myExecutable.exe"; config.PrintXMLVersion = printXMLVersion; - config.XMLComment = (xmlComment != null && xmlComment.Length == 0) - ? "Just a sample configuration file generated by the test suite" + config.XMLComment = (xmlComment != null && xmlComment.Length == 0) + ? "Just a sample configuration file generated by the test suite" : xmlComment; return config; } @@ -53,29 +53,32 @@ namespace winswTests.Util // TODO: The encoding is generally wrong str.Append("\n"); } + if (XMLComment != null) { str.AppendFormat("\n", XMLComment); } + str.Append("\n"); str.AppendFormat(" {0}\n", Id); str.AppendFormat(" {0}\n", Name); str.AppendFormat(" {0}\n", Description); str.AppendFormat(" {0}\n", Executable); - foreach (String entry in configEntries) + foreach (string entry in configEntries) { // We do not care much about pretty formatting here str.AppendFormat(" {0}\n", entry); } // Extensions - if (ExtensionXmls.Count > 0) + if (ExtensionXmls.Count > 0) { str.Append(" \n"); - foreach (string xml in ExtensionXmls) + foreach (string xml in ExtensionXmls) { str.Append(xml); } + str.Append(" \n"); } @@ -86,13 +89,14 @@ namespace winswTests.Util Console.Out.WriteLine("Produced config:"); Console.Out.WriteLine(res); } + return res; } public ServiceDescriptor ToServiceDescriptor(bool dumpConfig = false) { return ServiceDescriptor.FromXML(ToXMLString(dumpConfig)); - } + } public ConfigXmlBuilder WithRawEntry(string entry) { @@ -101,20 +105,20 @@ namespace winswTests.Util } public ConfigXmlBuilder WithTag(string tagName, string value) - { - return WithRawEntry(String.Format("<{0}>{1}", tagName, value)); + { + return WithRawEntry(string.Format("<{0}>{1}", tagName, value)); } public ConfigXmlBuilder WithRunawayProcessKiller(RunawayProcessKillerExtension ext, string extensionId = "killRunawayProcess", bool enabled = true) { - var fullyQualifiedExtensionName = ExtensionTestBase.getExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension)); + var fullyQualifiedExtensionName = ExtensionTestBase.GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension)); StringBuilder str = new StringBuilder(); - str.AppendFormat(" \n", new Object[] { enabled, fullyQualifiedExtensionName, extensionId}); + str.AppendFormat(" \n", new object[] { enabled, fullyQualifiedExtensionName, extensionId }); str.AppendFormat(" {0}\n", ext.Pidfile); str.AppendFormat(" {0}\n", ext.StopTimeout.TotalMilliseconds); str.AppendFormat(" {0}\n", ext.StopParentProcessFirst); str.AppendFormat(" {0}\n", ext.CheckWinSWEnvironmentVariable); - str.Append( " \n"); + str.Append(" \n"); ExtensionXmls.Add(str.ToString()); return this; @@ -123,15 +127,15 @@ namespace winswTests.Util public ConfigXmlBuilder WithDownload(Download download) { StringBuilder str = new StringBuilder(); - str.AppendFormat(" /// tmp Dir - public static string CreateTmpDirectory(String testName = null) + public static string CreateTmpDirectory(string testName = null) { - string tempDirectory = Path.Combine(Path.GetTempPath(), "winswTests_" + (testName ?? "") + Path.GetRandomFileName()); + string tempDirectory = Path.Combine(Path.GetTempPath(), "winswTests_" + (testName ?? string.Empty) + Path.GetRandomFileName()); Directory.CreateDirectory(tempDirectory); Console.Out.WriteLine("Created the temporary directory: {0}", tempDirectory); return tempDirectory; @@ -29,7 +28,8 @@ namespace winswTests.Util { Dictionary res = new Dictionary(); var lines = File.ReadAllLines(filePath); - foreach(var line in lines) { + foreach (var line in lines) + { var parsed = line.Split("=".ToCharArray(), 2); if (parsed.Length == 2) { @@ -40,6 +40,7 @@ namespace winswTests.Util Assert.Fail("Wrong line in the parsed Set output file: " + line); } } + return res; } } diff --git a/src/Test/winswTests/Util/ProcessHelperTest.cs b/src/Test/winswTests/Util/ProcessHelperTest.cs index 44b5b80..499aca3 100644 --- a/src/Test/winswTests/Util/ProcessHelperTest.cs +++ b/src/Test/winswTests/Util/ProcessHelperTest.cs @@ -1,14 +1,12 @@ using System; +using System.Collections.Generic; using System.Diagnostics; -using NUnit.Framework; -using winsw; using System.IO; +using NUnit.Framework; using winsw.Util; -using System.Collections.Generic; - -namespace winswTests.Util -{ +namespace winswTests.Util +{ [TestFixture] class ProcessHelperTest { @@ -21,11 +19,10 @@ namespace winswTests.Util Environment.SetEnvironmentVariable("TEST_KEY", "TEST_VALUE"); var tmpDir = FilesystemTestHelper.CreateTmpDirectory(); - String envFile = Path.Combine(tmpDir, "env.properties"); - String scriptFile = Path.Combine(tmpDir, "printenv.bat"); + string envFile = Path.Combine(tmpDir, "env.properties"); + string scriptFile = Path.Combine(tmpDir, "printenv.bat"); File.WriteAllText(scriptFile, "set > " + envFile); - Process proc = new Process(); var ps = proc.StartInfo; ps.FileName = scriptFile; @@ -39,44 +36,45 @@ namespace winswTests.Util // Check several veriables, which are expected to be in Uppercase var envVars = FilesystemTestHelper.parseSetOutput(envFile); - String[] keys = new String[envVars.Count]; + string[] keys = new string[envVars.Count]; envVars.Keys.CopyTo(keys, 0); - String availableVars = "[" + String.Join(",", keys) + "]"; + String availableVars = "[" + string.Join(",", keys) + "]"; Assert.That(envVars.ContainsKey("TEST_KEY"), "No TEST_KEY in the injected vars: " + availableVars); - + // And just ensure that the parsing logic is case-sensitive Assert.That(!envVars.ContainsKey("test_key"), "Test error: the environment parsing logic is case-insensitive"); } - - [Test] - public void ShouldNotHangWhenWritingLargeStringToStdOut() - { - var tmpDir = FilesystemTestHelper.CreateTmpDirectory(); - String scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat"); - var lotsOfStdOut = string.Join("", _Range(1,1000)); - File.WriteAllText(scriptFile, string.Format("echo \"{0}\"", lotsOfStdOut)); - - Process proc = new Process(); - var ps = proc.StartInfo; - ps.FileName = scriptFile; - - ProcessHelper.StartProcessAndCallbackForExit(proc); - var exited = proc.WaitForExit(5000); - if (!exited) - { - Assert.Fail("Process " + proc + " didn't exit after 5 seconds"); - } - } - - private string[] _Range(int start, int limit) - { - var range = new List(); - for(var i = start; i(); + for (var i = start; i < limit; i++) + { + range.Add(i.ToString()); + } + + return range.ToArray(); + } + } +} diff --git a/src/Test/winswTests/Util/ServiceDescriptorAssert.cs b/src/Test/winswTests/Util/ServiceDescriptorAssert.cs index d66f2d4..516dcfd 100644 --- a/src/Test/winswTests/Util/ServiceDescriptorAssert.cs +++ b/src/Test/winswTests/Util/ServiceDescriptorAssert.cs @@ -1,8 +1,6 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Reflection; -using System.Text; +using NUnit.Framework; using winsw; using winsw.Configuration; @@ -13,7 +11,7 @@ namespace winswTests.Util // TODO: convert to Extension attributes once the .NET dependency is upgraded // BTW there is a way to get them working in .NET2, but KISS - public static void AssertPropertyIsDefault(ServiceDescriptor d, string property) + public static void AssertPropertyIsDefault(ServiceDescriptor d, string property) { PropertyInfo actualProperty = typeof(ServiceDescriptor).GetProperty(property); Assert.IsNotNull(actualProperty, "Cannot find property " + property + " in the service descriptor" + d); @@ -37,14 +35,17 @@ namespace winswTests.Util AssertPropertyIsDefault(d, AllOptionalProperties); } - private static List AllProperties { - get { + private static List AllProperties + { + get + { var res = new List(); var properties = typeof(IWinSWConfiguration).GetProperties(); foreach (var prop in properties) { res.Add(prop.Name); } + return res; } } @@ -62,6 +63,4 @@ namespace winswTests.Util } } } - - }