using System.Text.RegularExpressions; using System.Diagnostics; using Microsoft.Extensions.Logging; namespace GSS2.Core.Hardware; public class UsbService : IDisposable { private bool _disposedValue; private readonly ILogger _logger; public UsbService(ILogger logger) { _logger = logger; } public List<(string id, string name, bool mounted, string? mountPath)> GetDevices() { var devices = new List<(string name, string id, bool mounted, string? mountPath)>(); try { _logger.LogInformation("Получаем список дисков"); var (exitCode, output, error) = RunCommand("lsblk", "-P -o NAME,PATH,RM,TYPE,MOUNTPOINT,LABEL,MODEL"); if (exitCode != 0) { _logger.LogWarning("Не удалось получить список дисков: {} {}", exitCode, error.Trim()); return devices; } var lines = output.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var model = string.Empty; foreach (var line in lines) { var dict = new Dictionary(); var matches = Regex.Matches(line, @"(\w+)=""([^""]*)"""); foreach (Match m in matches) dict[m.Groups[1].Value] = m.Groups[2].Value; if (dict.TryGetValue("RM", out var rm) && dict.TryGetValue("TYPE", out var type) && rm == "1" && type == "disk") { model = dict.GetValueOrDefault("MODEL", "").Trim(); } if (dict.TryGetValue("RM", out rm) && dict.TryGetValue("TYPE", out type) && rm == "1" && type == "part") { var id = dict.GetValueOrDefault("PATH", ""); var mountpoint = dict.GetValueOrDefault("MOUNTPOINT", ""); var label = dict.GetValueOrDefault("LABEL", "").Trim(); var rawName = dict.GetValueOrDefault("NAME", "").Trim(); string displayName = string.Empty; if (!string.IsNullOrWhiteSpace(label)) displayName = label; if (!string.IsNullOrWhiteSpace(model)) displayName = displayName + (!string.IsNullOrWhiteSpace(displayName) ? " " : "") + model; else displayName = displayName + (!string.IsNullOrWhiteSpace(displayName) ? " " : "") + rawName; if (!string.IsNullOrWhiteSpace(id)) devices.Add((id, displayName, !string.IsNullOrWhiteSpace(mountpoint), string.IsNullOrWhiteSpace(mountpoint) ? null : mountpoint)); } } } catch (Exception ex) { _logger.LogError(ex, "Исключение при попытке получить список дисков"); } _logger.LogInformation("Список дисков: \n\t{}", string.Join("\n\t", devices.Select(d => $"{d.name} {d.mounted} {d.id}"))); return devices; } public string? MountDevice(string id) { try { _logger.LogInformation("Монтируем диск: {}", id); var (exitCode, output, error) = RunCommand("udisksctl", $"mount -b {id} --no-user-interaction"); if (exitCode != 0) { _logger.LogWarning("Не удалось смонтировать диск {}: {} {}", id, exitCode, error.Trim()); return null; } _logger.LogInformation("Диск смонтирован {}: {}", id, output.Trim()); var result = output.Trim().Split("\n").Last(); if (result.StartsWith($"Mounted {id} at ")) { var path = result.Substring($"Mounted {id} at ".Count()); return path; } return null; } catch (Exception ex) { _logger.LogError(ex, "Исключение при попытке смонтировать диск {}", id); return null; } } public string? GetMountPath(string id) { try { _logger.LogInformation("Получаем информацию о диске: {}", id); var (exitCode, output, error) = RunCommand("udisksctl", $"info -b {id}"); if (exitCode != 0) { _logger.LogWarning("Не удалось получить информацию о дисе {}: {} {}", id, exitCode, error.Trim()); return null; } _logger.LogInformation("Информация о диске {}: {}", id, output.Trim()); var result = output.Split("\n").FirstOrDefault(l => l.Trim().StartsWith("MountPoints:")); if (result is null) return null; result = result.Trim().Substring("MountPoints:".Count()).Trim(); if (string.IsNullOrEmpty(result)) return null; return result; } catch (Exception ex) { _logger.LogError(ex, "Исключение при получении информации о диске {}", id); return null; } } public bool UnmountDevice(string id) { try { _logger.LogInformation("Размонтируем диск {}", id); var (exitCode, output, error) = RunCommand("udisksctl", $"unmount -b {id} --no-user-interaction"); if (exitCode != 0) { _logger.LogError("Не удалось размонтировать диск {}: {} {}", id, exitCode, error.Trim()); return false; } _logger.LogInformation("Диск размонтирован {}", id); return true; } catch (Exception ex) { _logger.LogError(ex, "Исключение при попытке размонтировать диск {}", id); return false; } } public void UnmountAllDevices() { _logger.LogInformation("Размонтируем все диски"); var mountedDevices = GetDevices().Where(d => d.mounted).ToList(); foreach (var device in mountedDevices){ Console.WriteLine(device.id); UnmountDevice(device.id);} } private (int exitCode, string output, string error) RunCommand(string fileName, string arguments) { using var process = new Process { StartInfo = new ProcessStartInfo { FileName = fileName, Arguments = arguments, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true } }; process.Start(); string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); process.WaitForExit(); return (process.ExitCode, output, error); } protected virtual void Dispose(bool disposing) { if (!_disposedValue) { if (disposing) UnmountAllDevices(); _disposedValue = true; } } void IDisposable.Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } }