diff --git a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs
index 7c9a3188..9005e8d6 100644
--- a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs
+++ b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs
@@ -1,142 +1,98 @@
using System.Runtime.Versioning;
using GeneralUpdate.Common.Shared;
using GeneralUpdate.Drivelution.Abstractions;
+using GeneralUpdate.Drivelution.Abstractions.Configuration;
using GeneralUpdate.Drivelution.Abstractions.Exceptions;
using GeneralUpdate.Drivelution.Abstractions.Models;
+using GeneralUpdate.Drivelution.Core.Pipeline;
using GeneralUpdate.Drivelution.Core.Utilities;
using GeneralUpdate.Drivelution.Linux.Helpers;
namespace GeneralUpdate.Drivelution.Linux.Implementation;
///
-/// Linux驱动更新器实现
-/// Linux driver updater implementation
+/// Linux driver updater implementation.
+/// Inherits the unified pipeline from and adds Linux-specific
+/// sudo permission check, kernel module / .deb / .rpm installation, and module parsing.
///
[SupportedOSPlatform("linux")]
-public class LinuxGeneralDrivelution : IGeneralDrivelution
+public class LinuxGeneralDrivelution : BaseDriverUpdater
{
- private readonly IDriverValidator _validator;
- private readonly IDriverBackup _backup;
-
- public LinuxGeneralDrivelution(IDriverValidator validator, IDriverBackup backup)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Driver validator.
+ /// Driver backup manager.
+ /// Configuration options (optional).
+ public LinuxGeneralDrivelution(
+ IDriverValidator validator,
+ IDriverBackup backup,
+ DrivelutionOptions? options = null)
+ : base(validator, backup, options)
{
- _validator = validator ?? throw new ArgumentNullException(nameof(validator));
- _backup = backup ?? throw new ArgumentNullException(nameof(backup));
}
+ // ─── Pipeline overrides ────────────────────────────────────────────
+
///
- public async Task UpdateAsync(
- DriverInfo driverInfo,
- UpdateStrategy strategy,
- CancellationToken cancellationToken = default)
+ protected override IEnumerable GetPipelineSteps(UpdateStrategy strategy)
{
- var result = new UpdateResult
- {
- StartTime = DateTime.UtcNow,
- Status = UpdateStatus.NotStarted
- };
+ yield return CreateSudoCheckStep();
- try
- {
- GeneralTracer.Info($"Starting driver update for: {driverInfo.Name} v{driverInfo.Version}");
-
- // Permission check
- await LinuxPermissionHelper.EnsureSudoAsync();
-
- // Validation
- result.Status = UpdateStatus.Validating;
- if (!await ValidateAsync(driverInfo, cancellationToken))
- {
- throw new DriverValidationException("Driver validation failed", "General");
- }
-
- // Backup if required
- if (strategy.RequireBackup)
- {
- result.Status = UpdateStatus.BackingUp;
- var backupPath = GenerateBackupPath(driverInfo, strategy.BackupPath);
- if (await BackupAsync(driverInfo, backupPath, cancellationToken))
- {
- result.BackupPath = backupPath;
- }
- }
-
- // Execute update
- result.Status = UpdateStatus.Updating;
- await ExecuteDriverInstallationAsync(driverInfo, cancellationToken);
-
- result.Success = true;
- result.Status = UpdateStatus.Succeeded;
- result.Message = "Driver update completed successfully";
- }
- catch (Exception ex)
- {
- GeneralTracer.Error("Driver update failed", ex);
- result.Success = false;
- result.Status = UpdateStatus.Failed;
- result.Error = new ErrorInfo
- {
- Type = ErrorType.InstallationFailed,
- Message = ex.Message,
- Details = ex.ToString()
- };
- }
- finally
- {
- result.EndTime = DateTime.UtcNow;
- }
-
- return result;
+ foreach (var step in base.GetPipelineSteps(strategy))
+ yield return step;
}
///
- public async Task ValidateAsync(DriverInfo driverInfo, CancellationToken cancellationToken = default)
+ protected override async Task InstallCoreAsync(
+ DriverInfo driverInfo,
+ UpdateStrategy strategy,
+ CancellationToken cancellationToken)
{
- if (!File.Exists(driverInfo.FilePath))
- {
- return false;
- }
+ GeneralTracer.Info($"Installing Linux driver: {driverInfo.FilePath}");
+
+ var extension = Path.GetExtension(driverInfo.FilePath).ToLowerInvariant();
- // Validate hash if provided
- if (!string.IsNullOrEmpty(driverInfo.Hash))
+ switch (extension)
{
- if (!await _validator.ValidateIntegrityAsync(
- driverInfo.FilePath,
- driverInfo.Hash,
- driverInfo.HashAlgorithm,
- cancellationToken))
- {
- return false;
- }
+ case ".ko":
+ await InstallKernelModuleAsync(driverInfo.FilePath, cancellationToken);
+ break;
+ case ".deb":
+ await InstallDebPackageAsync(driverInfo.FilePath, cancellationToken);
+ break;
+ case ".rpm":
+ await InstallRpmPackageAsync(driverInfo.FilePath, cancellationToken);
+ break;
+ default:
+ GeneralTracer.Warn($"Unknown driver format: {extension}. Attempting generic installation.");
+ await InstallKernelModuleAsync(driverInfo.FilePath, cancellationToken);
+ break;
}
- // Validate compatibility
- return await _validator.ValidateCompatibilityAsync(driverInfo, cancellationToken);
+ GeneralTracer.Info("Linux driver installation completed");
}
- ///
- public Task BackupAsync(DriverInfo driverInfo, string backupPath, CancellationToken cancellationToken = default)
- {
- return _backup.BackupAsync(driverInfo.FilePath, backupPath, cancellationToken);
- }
+ // ─── Rollback override ─────────────────────────────────────────────
///
- public async Task RollbackAsync(string backupPath, CancellationToken cancellationToken = default)
+ public override async Task RollbackAsync(
+ string backupPath,
+ CancellationToken cancellationToken = default)
{
try
{
- GeneralTracer.Info($"Rolling back driver from backup: {backupPath}");
-
+ GeneralTracer.Info($"Rolling back Linux driver from backup: {backupPath}");
+
if (!Directory.Exists(backupPath))
{
GeneralTracer.Error($"Backup directory not found: {backupPath}");
return false;
}
- // Find backed up kernel modules (.ko files)
var koFiles = Directory.GetFiles(backupPath, "*.ko", SearchOption.AllDirectories);
-
- if (!koFiles.Any())
+
+ if (koFiles.Length == 0)
{
GeneralTracer.Warn($"No kernel module backups found in: {backupPath}");
return false;
@@ -146,15 +102,21 @@ public async Task RollbackAsync(string backupPath, CancellationToken cance
{
try
{
- GeneralTracer.Info($"Attempting to restore kernel module: {koFile}");
-
- // Copy back to /lib/modules or appropriate location
var moduleName = Path.GetFileNameWithoutExtension(koFile);
-
- // Try to unload current module first
- await ExecuteCommandAsync("modprobe", $"-r {moduleName}", cancellationToken);
-
- // Try to reload the backed-up module (if system supports it)
+ GeneralTracer.Info($"Restoring kernel module: {moduleName}");
+
+ // Unload current module first
+ try
+ {
+ await ExecuteCommandAsync("modprobe", $"-r {moduleName}", cancellationToken);
+ }
+ catch
+ {
+ // Module might not be loaded — ignore
+ }
+
+ // Reload the backed-up module
+ await ExecuteCommandAsync("insmod", koFile, cancellationToken);
GeneralTracer.Info($"Restored module: {moduleName}");
}
catch (Exception ex)
@@ -167,223 +129,48 @@ public async Task RollbackAsync(string backupPath, CancellationToken cance
}
catch (Exception ex)
{
- GeneralTracer.Error("Failed to rollback driver", ex);
+ GeneralTracer.Error("Linux driver rollback failed", ex);
return false;
}
}
- private async Task ExecuteDriverInstallationAsync(DriverInfo driverInfo, CancellationToken cancellationToken)
- {
- GeneralTracer.Info($"Installing Linux driver: {driverInfo.FilePath}");
-
- var filePath = driverInfo.FilePath;
- var extension = Path.GetExtension(filePath).ToLowerInvariant();
-
- try
- {
- // Handle different Linux driver formats
- if (extension == ".ko")
- {
- // Kernel module installation
- await InstallKernelModuleAsync(filePath, cancellationToken);
- }
- else if (extension == ".deb")
- {
- // Debian package installation
- await InstallDebPackageAsync(filePath, cancellationToken);
- }
- else if (extension == ".rpm")
- {
- // RPM package installation
- await InstallRpmPackageAsync(filePath, cancellationToken);
- }
- else
- {
- GeneralTracer.Warn($"Unknown driver format: {extension}. Attempting generic installation.");
- // Try to detect and install generically
- await InstallKernelModuleAsync(filePath, cancellationToken);
- }
-
- GeneralTracer.Info("Driver installation completed successfully");
- }
- catch (Exception ex)
- {
- GeneralTracer.Error("Failed to install Linux driver", ex);
- throw new DriverInstallationException(
- $"Failed to install Linux driver: {ex.Message}", ex);
- }
- }
-
- private async Task InstallKernelModuleAsync(string modulePath, CancellationToken cancellationToken)
- {
- GeneralTracer.Info($"Installing kernel module: {modulePath}");
-
- var moduleName = Path.GetFileNameWithoutExtension(modulePath);
-
- try
- {
- // Try to use insmod (direct installation)
- GeneralTracer.Info("Attempting to load module using insmod");
- await ExecuteCommandAsync("insmod", modulePath, cancellationToken);
- GeneralTracer.Info("Module loaded successfully using insmod");
- }
- catch
- {
- try
- {
- // Fallback to modprobe if insmod fails
- GeneralTracer.Info("Attempting to load module using modprobe");
-
- // Copy to modules directory first (may require permissions)
- var kernelVersion = await GetKernelVersionAsync(cancellationToken);
- var targetDir = $"/lib/modules/{kernelVersion}/extra";
-
- GeneralTracer.Info($"Target module directory: {targetDir}");
-
- // Note: This would typically require root permissions
- // In a real scenario, you'd use sudo or elevated permissions
-
- await ExecuteCommandAsync("modprobe", moduleName, cancellationToken);
- GeneralTracer.Info("Module loaded successfully using modprobe");
- }
- catch (Exception ex)
- {
- GeneralTracer.Error("Failed to load kernel module", ex);
- throw;
- }
- }
- }
+ // ─── Driver discovery overrides ────────────────────────────────────
- private async Task InstallDebPackageAsync(string packagePath, CancellationToken cancellationToken)
- {
- GeneralTracer.Info($"Installing Debian package: {packagePath}");
-
- try
- {
- // Use dpkg to install the package
- await ExecuteCommandAsync("dpkg", $"-i {packagePath}", cancellationToken);
- GeneralTracer.Info("Debian package installed successfully");
- }
- catch (Exception ex)
- {
- GeneralTracer.Error("Failed to install Debian package", ex);
- throw;
- }
- }
-
- private async Task InstallRpmPackageAsync(string packagePath, CancellationToken cancellationToken)
- {
- GeneralTracer.Info($"Installing RPM package: {packagePath}");
-
- try
- {
- // Try rpm command first
- try
- {
- await ExecuteCommandAsync("rpm", $"-ivh {packagePath}", cancellationToken);
- }
- catch
- {
- // Fallback to dnf/yum
- await ExecuteCommandAsync("dnf", $"install -y {packagePath}", cancellationToken);
- }
-
- GeneralTracer.Info("RPM package installed successfully");
- }
- catch (Exception ex)
- {
- GeneralTracer.Error("Failed to install RPM package", ex);
- throw;
- }
- }
-
- private async Task GetKernelVersionAsync(CancellationToken cancellationToken)
- {
- try
- {
- var output = await ExecuteCommandAsync("uname", "-r", cancellationToken);
- return output.Trim();
- }
- catch
- {
- return "current";
- }
- }
-
- private async Task ExecuteCommandAsync(string command, string arguments, CancellationToken cancellationToken)
- {
- var startInfo = new System.Diagnostics.ProcessStartInfo
- {
- FileName = command,
- Arguments = arguments,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- UseShellExecute = false,
- CreateNoWindow = true
- };
-
- using var process = System.Diagnostics.Process.Start(startInfo);
- if (process == null)
- {
- throw new InvalidOperationException($"Failed to start process: {command}");
- }
-
- var output = await process.StandardOutput.ReadToEndAsync(cancellationToken);
- var error = await process.StandardError.ReadToEndAsync(cancellationToken);
-
- await process.WaitForExitAsync(cancellationToken);
-
- if (process.ExitCode != 0)
- {
- GeneralTracer.Warn($"Command {command} {arguments} exited with code {process.ExitCode}. Error: {error}");
- throw new InvalidOperationException($"Command failed with exit code {process.ExitCode}: {error}");
- }
-
- return output;
- }
-
- private string GenerateBackupPath(DriverInfo driverInfo, string baseBackupPath)
- {
- if (string.IsNullOrEmpty(baseBackupPath))
- {
- baseBackupPath = "/var/backup/drivers";
- }
-
- var fileName = Path.GetFileName(driverInfo.FilePath);
- return Path.Combine(baseBackupPath, fileName);
- }
+ ///
+ protected override string GetDefaultSearchPattern() => "*.ko";
///
- public async Task> GetDriversFromDirectoryAsync(
+ public override async Task> GetDriversFromDirectoryAsync(
string directoryPath,
string? searchPattern = null,
CancellationToken cancellationToken = default)
{
- var driverInfoList = new List();
+ var drivers = new List();
try
{
- GeneralTracer.Info($"Reading driver information from directory: {directoryPath}");
+ GeneralTracer.Info($"Reading Linux drivers from directory: {directoryPath}");
if (!Directory.Exists(directoryPath))
{
GeneralTracer.Warn($"Directory not found: {directoryPath}");
- return driverInfoList;
+ return drivers;
}
- // Default to kernel modules for Linux
- var pattern = searchPattern ?? "*.ko";
- var driverFiles = Directory.GetFiles(directoryPath, pattern, SearchOption.AllDirectories);
+ // Search for kernel modules, .deb, and .rpm packages
+ var driverFiles = new List();
+ driverFiles.AddRange(Directory.GetFiles(directoryPath, searchPattern ?? "*.ko",
+ SearchOption.AllDirectories));
- // Also look for .deb and .rpm packages if no specific pattern was provided
- if (searchPattern == null)
+ if (searchPattern is null)
{
- var debFiles = Directory.GetFiles(directoryPath, "*.deb", SearchOption.AllDirectories);
- var rpmFiles = Directory.GetFiles(directoryPath, "*.rpm", SearchOption.AllDirectories);
- driverFiles = driverFiles.Concat(debFiles).Concat(rpmFiles).ToArray();
+ driverFiles.AddRange(Directory.GetFiles(directoryPath, "*.deb",
+ SearchOption.AllDirectories));
+ driverFiles.AddRange(Directory.GetFiles(directoryPath, "*.rpm",
+ SearchOption.AllDirectories));
}
- GeneralTracer.Info($"Found {driverFiles.Length} driver files matching pattern: {pattern}");
+ GeneralTracer.Info($"Found {driverFiles.Count} Linux driver file(s)");
foreach (var filePath in driverFiles)
{
@@ -392,12 +179,9 @@ public async Task> GetDriversFromDirectoryAsync(
try
{
- var driverInfo = await ParseDriverFileAsync(filePath, cancellationToken);
- if (driverInfo != null)
- {
- driverInfoList.Add(driverInfo);
- GeneralTracer.Info($"Parsed driver: {driverInfo.Name} v{driverInfo.Version}");
- }
+ var driverInfo = await ParseLinuxDriverFileAsync(filePath, cancellationToken);
+ if (driverInfo is not null)
+ drivers.Add(driverInfo);
}
catch (Exception ex)
{
@@ -405,51 +189,126 @@ public async Task> GetDriversFromDirectoryAsync(
}
}
- GeneralTracer.Info($"Successfully loaded {driverInfoList.Count} driver(s) from directory");
+ GeneralTracer.Info($"Loaded {drivers.Count} Linux driver(s) from directory");
}
catch (Exception ex)
{
GeneralTracer.Error($"Error reading drivers from directory: {directoryPath}", ex);
}
- return driverInfoList;
+ return drivers;
}
+ // ─── Private: Pipeline steps ────────────────────────────────────────
+
///
- /// Parses driver file information
+ /// Creates a sudo privilege check as the first pipeline step.
///
- private async Task ParseDriverFileAsync(string filePath, CancellationToken cancellationToken)
+ private static IPipelineStep CreateSudoCheckStep()
{
+ return new DelegateStep("CheckSudo",
+ execute: async (context, ct) =>
+ {
+ context.Result.StepLogs.Add($"[{DateTime.Now:HH:mm:ss}] Checking Linux root privileges");
+
+ try
+ {
+ await LinuxPermissionHelper.EnsureSudoAsync();
+ return PipelineResult.Ok();
+ }
+ catch (Exception ex)
+ {
+ return PipelineResult.Fail(
+ $"Root privileges are required for driver updates. {ex.Message}");
+ }
+ });
+ }
+
+ // ─── Private: Format-specific installers ───────────────────────────
+
+ private static async Task InstallKernelModuleAsync(
+ string modulePath,
+ CancellationToken cancellationToken)
+ {
+ GeneralTracer.Info($"Installing kernel module: {modulePath}");
+
try
{
- var fileInfo = new FileInfo(filePath);
- var fileName = Path.GetFileNameWithoutExtension(filePath);
- var extension = Path.GetExtension(filePath).ToLowerInvariant();
+ await ExecuteCommandAsync("insmod", modulePath, cancellationToken);
+ GeneralTracer.Info("Module loaded via insmod");
+ }
+ catch
+ {
+ // Fallback: modprobe with the module name
+ GeneralTracer.Info("insmod failed, trying modprobe...");
+ var moduleName = Path.GetFileNameWithoutExtension(modulePath);
+ await ExecuteCommandAsync("modprobe", moduleName, cancellationToken);
+ GeneralTracer.Info("Module loaded via modprobe");
+ }
+ }
+
+ private static async Task InstallDebPackageAsync(
+ string packagePath,
+ CancellationToken cancellationToken)
+ {
+ GeneralTracer.Info($"Installing Debian package: {packagePath}");
+ await ExecuteCommandAsync("dpkg", $"-i {packagePath}", cancellationToken);
+ GeneralTracer.Info("Debian package installed");
+ }
+
+ private static async Task InstallRpmPackageAsync(
+ string packagePath,
+ CancellationToken cancellationToken)
+ {
+ GeneralTracer.Info($"Installing RPM package: {packagePath}");
+
+ try
+ {
+ await ExecuteCommandAsync("rpm", $"-ivh {packagePath}", cancellationToken);
+ }
+ catch
+ {
+ // Fallback to dnf/yum
+ await ExecuteCommandAsync("dnf", $"install -y {packagePath}", cancellationToken);
+ }
+
+ GeneralTracer.Info("RPM package installed");
+ }
+ // ─── Private: File parsing ─────────────────────────────────────────
+
+ private static async Task ParseLinuxDriverFileAsync(
+ string filePath,
+ CancellationToken cancellationToken)
+ {
+ try
+ {
var driverInfo = new DriverInfo
{
- Name = fileName,
+ Name = Path.GetFileNameWithoutExtension(filePath),
FilePath = filePath,
TargetOS = "Linux",
Architecture = Environment.Is64BitOperatingSystem ? "x64" : "x86"
};
- // Parse based on file type
- if (extension == ".ko")
- {
- await ParseKernelModuleAsync(filePath, driverInfo, cancellationToken);
- }
- else if (extension == ".deb")
- {
- await ParseDebPackageAsync(filePath, driverInfo, cancellationToken);
- }
- else if (extension == ".rpm")
+ var extension = Path.GetExtension(filePath).ToLowerInvariant();
+
+ switch (extension)
{
- await ParseRpmPackageAsync(filePath, driverInfo, cancellationToken);
+ case ".ko":
+ await ParseKernelModuleAsync(filePath, driverInfo, cancellationToken);
+ break;
+ case ".deb":
+ await ParseDebPackageAsync(filePath, driverInfo, cancellationToken);
+ break;
+ case ".rpm":
+ await ParseRpmPackageAsync(filePath, driverInfo, cancellationToken);
+ break;
}
- // Get file hash for integrity validation
- driverInfo.Hash = await HashValidator.ComputeHashAsync(filePath, "SHA256", cancellationToken);
+ // Compute file hash for integrity validation
+ driverInfo.Hash = await HashValidator.ComputeHashAsync(
+ filePath, "SHA256", cancellationToken);
driverInfo.HashAlgorithm = "SHA256";
return driverInfo;
@@ -461,134 +320,167 @@ public async Task> GetDriversFromDirectoryAsync(
}
}
- ///
- /// Parses kernel module
- ///
- private async Task ParseKernelModuleAsync(string koPath, DriverInfo driverInfo, CancellationToken cancellationToken)
+ private static async Task ParseKernelModuleAsync(
+ string koPath,
+ DriverInfo driverInfo,
+ CancellationToken cancellationToken)
{
try
{
- // Try to get module info using modinfo command
var output = await ExecuteCommandAsync("modinfo", koPath, cancellationToken);
var lines = output.Split('\n');
foreach (var line in lines)
{
- var trimmedLine = line.Trim();
+ var trimmed = line.Trim();
- if (trimmedLine.StartsWith("version:", StringComparison.OrdinalIgnoreCase))
+ if (trimmed.StartsWith("version:", StringComparison.OrdinalIgnoreCase))
+ driverInfo.Version = trimmed[8..].Trim();
+ else if (trimmed.StartsWith("description:", StringComparison.OrdinalIgnoreCase))
+ driverInfo.Description = trimmed[12..].Trim();
+ else if (trimmed.StartsWith("alias:", StringComparison.OrdinalIgnoreCase))
{
- driverInfo.Version = trimmedLine.Substring(8).Trim();
- }
- else if (trimmedLine.StartsWith("description:", StringComparison.OrdinalIgnoreCase))
- {
- driverInfo.Description = trimmedLine.Substring(12).Trim();
- }
- else if (trimmedLine.StartsWith("alias:", StringComparison.OrdinalIgnoreCase))
- {
- var alias = trimmedLine.Substring(6).Trim();
if (string.IsNullOrEmpty(driverInfo.HardwareId))
- {
- driverInfo.HardwareId = alias;
- }
+ driverInfo.HardwareId = trimmed[6..].Trim();
}
}
if (string.IsNullOrEmpty(driverInfo.Version))
- {
driverInfo.Version = "1.0.0";
- }
}
catch (Exception ex)
{
- GeneralTracer.Debug($"Could not get module info for: {koPath} - {ex.Message}");
+ GeneralTracer.Debug($"Could not get module info for {koPath}: {ex.Message}");
driverInfo.Version = "1.0.0";
}
}
- ///
- /// Parses Debian package
- ///
- private async Task ParseDebPackageAsync(string debPath, DriverInfo driverInfo, CancellationToken cancellationToken)
+ private static async Task ParseDebPackageAsync(
+ string debPath,
+ DriverInfo driverInfo,
+ CancellationToken cancellationToken)
{
try
{
- // Try to get package info using dpkg-deb command
- // Use proper argument passing to avoid injection issues
var escapedPath = debPath.Replace("'", "'\\''");
var output = await ExecuteCommandAsync("dpkg-deb", $"-I '{escapedPath}'", cancellationToken);
- var lines = output.Split('\n');
- foreach (var line in lines)
+ foreach (var line in output.Split('\n'))
{
- var trimmedLine = line.Trim();
+ var trimmed = line.Trim();
- if (trimmedLine.StartsWith("Version:", StringComparison.OrdinalIgnoreCase))
- {
- driverInfo.Version = trimmedLine.Substring(8).Trim();
- }
- else if (trimmedLine.StartsWith("Description:", StringComparison.OrdinalIgnoreCase))
- {
- driverInfo.Description = trimmedLine.Substring(12).Trim();
- }
+ if (trimmed.StartsWith("Version:", StringComparison.OrdinalIgnoreCase))
+ driverInfo.Version = trimmed[8..].Trim();
+ else if (trimmed.StartsWith("Description:", StringComparison.OrdinalIgnoreCase))
+ driverInfo.Description = trimmed[12..].Trim();
}
if (string.IsNullOrEmpty(driverInfo.Version))
- {
driverInfo.Version = "1.0.0";
- }
}
catch (Exception ex)
{
- GeneralTracer.Debug($"Could not get package info for: {debPath} - {ex.Message}");
+ GeneralTracer.Debug($"Could not get package info for {debPath}: {ex.Message}");
driverInfo.Version = "1.0.0";
}
}
- ///
- /// Parses RPM package
- ///
- private async Task ParseRpmPackageAsync(string rpmPath, DriverInfo driverInfo, CancellationToken cancellationToken)
+ private static async Task ParseRpmPackageAsync(
+ string rpmPath,
+ DriverInfo driverInfo,
+ CancellationToken cancellationToken)
{
try
{
- // Try to get package info using rpm command
- // Use proper argument passing to avoid injection issues
var escapedPath = rpmPath.Replace("'", "'\\''");
var output = await ExecuteCommandAsync("rpm", $"-qip '{escapedPath}'", cancellationToken);
- var lines = output.Split('\n');
- foreach (var line in lines)
+ foreach (var line in output.Split('\n'))
{
- var trimmedLine = line.Trim();
+ var trimmed = line.Trim();
- if (trimmedLine.StartsWith("Version", StringComparison.OrdinalIgnoreCase))
+ if (trimmed.StartsWith("Version", StringComparison.OrdinalIgnoreCase))
{
- var parts = trimmedLine.Split(':');
+ var parts = trimmed.Split(':');
if (parts.Length > 1)
- {
driverInfo.Version = parts[1].Trim();
- }
}
- else if (trimmedLine.StartsWith("Summary", StringComparison.OrdinalIgnoreCase))
+ else if (trimmed.StartsWith("Summary", StringComparison.OrdinalIgnoreCase))
{
- var parts = trimmedLine.Split(':');
+ var parts = trimmed.Split(':');
if (parts.Length > 1)
- {
driverInfo.Description = parts[1].Trim();
- }
}
}
if (string.IsNullOrEmpty(driverInfo.Version))
- {
driverInfo.Version = "1.0.0";
- }
}
catch (Exception ex)
{
- GeneralTracer.Debug($"Could not get package info for: {rpmPath} - {ex.Message}");
+ GeneralTracer.Debug($"Could not get package info for {rpmPath}: {ex.Message}");
driverInfo.Version = "1.0.0";
}
}
+
+ // ─── Private: Command execution ────────────────────────────────────
+
+ private static async Task ExecuteCommandAsync(
+ string command,
+ string arguments,
+ CancellationToken cancellationToken)
+ {
+ var psi = new System.Diagnostics.ProcessStartInfo
+ {
+ FileName = command,
+ Arguments = arguments,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+
+ using var process = System.Diagnostics.Process.Start(psi)
+ ?? throw new InvalidOperationException($"Failed to start process: {command}");
+
+ var output = await process.StandardOutput.ReadToEndAsync(cancellationToken);
+ var error = await process.StandardError.ReadToEndAsync(cancellationToken);
+ await process.WaitForExitAsync(cancellationToken);
+
+ if (process.ExitCode != 0)
+ {
+ GeneralTracer.Warn($"Command {command} {arguments} exited with code {process.ExitCode}. Error: {error}");
+ throw new InvalidOperationException(
+ $"Command '{command}' failed with exit code {process.ExitCode}: {error}");
+ }
+
+ return output;
+ }
+
+ // ─── Nested type ──────────────────────────────────────────────────
+
+ ///
+ /// A lightweight pipeline step backed by delegates.
+ ///
+ private sealed class DelegateStep : IPipelineStep
+ {
+ private readonly Func> _execute;
+
+ public string StepName { get; }
+
+ public DelegateStep(
+ string stepName,
+ Func> execute)
+ {
+ StepName = stepName;
+ _execute = execute;
+ }
+
+ public bool ShouldExecute(PipelineContext context) => true;
+
+ public Task ExecuteAsync(
+ PipelineContext context,
+ CancellationToken cancellationToken)
+ => _execute(context, cancellationToken);
+ }
}