using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Text.Json; using System.Threading; namespace Barsik { /// /// Monitors configured RAID array status via /proc/mdstat /// Will fill registers info starting from baseAddress with /// disk status (0 - fail, 1 - up) in following order: /// raid #0 disk #0 /// raid #0 disk #1 /// ... /// raid #0 disk #N /// raid #1 disk #0 /// ... /// etc /// class MDStatMonitoringUnit : BaseMonitoringUnit { List knownRaids; public MDStatMonitoringUnit(JsonElement config, RegistersContainer registers) : base(config, registers) { knownRaids = new List(); int currentAddress = baseAddress; // the file is not so big, so read it completely var lines = File.ReadAllLines("/proc/mdstat"); for (int i = 0; i < lines.Length;) { if (lines[i].StartsWith("md") && i < lines.Length - 1) { // we found device description // second line of it is as follows: // 2930264896 blocks super 1.0 [2/2] [UU] // we need last characters in brackets [] int last_pos = lines[i + 1].LastIndexOf(']'); int pos; for (pos = last_pos; pos > 0 && lines[i + 1][pos] != '['; pos--) ; if (lines[i + 1][pos] != '[') knownRaids.Add(0); else knownRaids.Add(last_pos - pos - 1); i += 2; } else i++; } } public override void GenerateItemsConfig(string name, StringBuilder config) { for (int i = 0; i < knownRaids.Count; i++) { for (int j = 0; j < knownRaids[i]; j++) { config.Append(string.Format("Switch {0}_RAID{1}Disk{2} \"{0} RAID{1} Disk{2} status\" ", name, i, j)); config.Append(" {channel=\""); config.AppendFormat("modbus:data:{0}:{1}:", name, unitName); config.AppendFormat("RAID{0}Disk{1}:switch", i, j); config.Append("\"}\n"); } } } public override void GenerateThingsConfig(StringBuilder config) { int diskAmount = 0; foreach (var size in knownRaids) diskAmount += size; config.Append("\tBridge poller "); config.Append(unitName); config.AppendFormat("[start = {0}, length = {1}, type = \"holding\", refresh = 500] {{\n", baseAddress, diskAmount); int currentAddress = baseAddress; for (int i = 0; i < knownRaids.Count; i++) { for (int j = 0; j < knownRaids[i]; j++) { string name = string.Format("RAID{0}Disk{1}", i, j); config.Append("\t\tThing data "); config.Append(name); config.AppendFormat("[readStart = \"{0}\", readValueType = \"int16\"]\n", currentAddress); currentAddress++; } } config.Append("\t}\n"); } public override void Run() { while (true) { int currentAddress = baseAddress; // the file is not so big, so read it completely var lines = File.ReadAllLines("/proc/mdstat"); for (int i = 0; i < lines.Length;) { if (lines[i].StartsWith("md") && i < lines.Length - 1) { // we found device description // second line of it is as follows: // 2930264896 blocks super 1.0 [2/2] [UU] // we need last characters in brackets [] currentAddress += FillDiskStatus(currentAddress, lines[i + 1]); i += 2; } else i++; } Thread.Sleep(2000); } } private int FillDiskStatus(int address, string v) { int last_pos = v.LastIndexOf(']'); int pos; for (pos = last_pos; pos > 0 && v[pos] != '['; pos--) ; if (v[pos] != '[') return 0; for (int i = pos + 1; i < last_pos; i++) { if (v[i] == 'U') registers[address + i - (pos + 1)] = 1; else registers[address + i - (pos + 1)] = 1; } return last_pos - pos - 1; } } }