/// <summary> /// Writes information about a single service to the database. /// </summary> /// <param name="obj">A ServiceObject to write.</param> public void Write(ServiceObject obj) { _numCollected++; var cmd = new SqliteCommand(INSERT_SQL, DatabaseManager.Connection, DatabaseManager.Transaction); cmd.Parameters.AddWithValue("@run_id", this.runId); cmd.Parameters.AddWithValue("@row_key", obj.GetUniqueHash()); cmd.Parameters.AddWithValue("@service_name", obj.ServiceName); cmd.Parameters.AddWithValue("@display_name", obj.DisplayName); cmd.Parameters.AddWithValue("@start_type", obj.StartType); cmd.Parameters.AddWithValue("@current_state", obj.CurrentState); cmd.Parameters.AddWithValue("@serialized", JsonConvert.SerializeObject(obj)); cmd.ExecuteNonQuery(); }
/// <summary> /// Executes the ServiceCollector (main entrypoint). /// </summary> public override void Execute() { Start(); if (!this.CanRunOnPlatform()) { Log.Information("ServiceCollector cannot run on this platform."); return; } Truncate(runId); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // This gathers official "services" on Windows, but perhaps neglects other startup items foreach (ServiceController service in ServiceController.GetServices()) { if (this.filter != null && !this.filter(service)) { Log.Information("Service [{0}] did not pass filter, ignoring.", service.ToString()); continue; } var obj = new ServiceObject() { DisplayName = service.DisplayName, ServiceName = service.ServiceName, StartType = service.StartType.ToString(), CurrentState = service.Status.ToString() }; this.Write(obj); } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { var runner = new ExternalCommandRunner(); // Get the user processes // run "launchtl dumpstate" for the super detailed view // However, dumpstate is difficult to parse var result = runner.RunExternalCommand("launchctl", "list"); Dictionary <string, ServiceObject> outDict = new Dictionary <string, ServiceObject>(); foreach (var _line in result.Split('\n')) { // Lines are formatted like this: // PID Exit Name //1015 0 com.apple.appstoreagent var _fields = _line.Split('\t'); if (_fields.Length < 3 || _fields[0].Contains("PID")) { continue; } var obj = new ServiceObject() { DisplayName = _fields[2], ServiceName = _fields[2], StartType = "Unknown", // If we have a current PID then it is running. CurrentState = (_fields[0].Equals("-"))?"Stopped":"Running" }; if (!outDict.ContainsKey(obj.GetUniqueHash())) { this.Write(obj); outDict.Add(obj.GetUniqueHash(), obj); } } // Then get the system processes result = runner.RunExternalCommand("sudo", "launchctl list"); foreach (var _line in result.Split('\n')) { // Lines are formatted like this, with single tab separation: // PID Exit Name // 1015 0 com.apple.appstoreagent var _fields = _line.Split('\t'); if (_fields.Length < 3 || _fields[0].Contains("PID")) { continue; } var obj = new ServiceObject() { DisplayName = _fields[2], ServiceName = _fields[2], StartType = "Unknown", // If we have a current PID then it is running. CurrentState = (_fields[0].Equals("-")) ? "Stopped" : "Running" }; if (!outDict.ContainsKey(obj.GetUniqueHash())) { this.Write(obj); outDict.Add(obj.GetUniqueHash(), obj); } } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { var runner = new ExternalCommandRunner(); var result = runner.RunExternalCommand("systemctl", "list-units --type service"); //Split lines and remove header var lines = result.Split('\n'); lines.ToList().RemoveAt(0); foreach (var _line in lines) { var _fields = _line.Split('\t'); if (_fields.Count() == 5) { var obj = new ServiceObject() { DisplayName = _fields[4], ServiceName = _fields[0], StartType = "Unknown", CurrentState = _fields[3], }; Write(obj); } } result = runner.RunExternalCommand("ls", "/etc/init.d/ -l"); lines = result.Split('\n'); String pattern = @".*\s(.*)"; foreach (var _line in lines) { Match match = Regex.Match(_line, pattern); GroupCollection groups = match.Groups; var serviceName = groups[1].ToString(); var obj = new ServiceObject() { DisplayName = serviceName, ServiceName = serviceName, StartType = "Unknown", CurrentState = "Unknown" }; Write(obj); } // without systemd (maybe just CentOS) // chkconfig --list // BSD // service -l // this provides very minor amount of info } Stop(); }