public async Task <bool> PerformBackgroundScan(ITracer _tracer, AllSafeLinuxLock _scanLock, String folderPath, CancellationToken token, String scanId, String mainScanDirPath) { var successfulScan = true; await Task.Run(() => { _scanLock.LockOperation(() => { _scanLock.SetLockMsg(Resources.ScanUnderwayMsg); String statusFilePath = Path.Combine(folderPath, Constants.ScanStatusFile); String logFilePath = Path.Combine(folderPath, Constants.ScanLogFile); _tracer.Trace("Starting Scan {0}, ScanCommand: {1}, LogFile: {2}", scanId, Constants.ScanCommand, logFilePath); UpdateScanStatus(folderPath, ScanStatus.Executing, null); var escapedArgs = Constants.ScanCommand + " " + logFilePath; Process _executingProcess = new Process() { StartInfo = new ProcessStartInfo { FileName = "/bin/bash", Arguments = "-c \"" + escapedArgs + "\"", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true, } }; _executingProcess.Start(); string tempScanFilePath = GetTempScanFilePath(mainScanDirPath); //Check if process is completing before timeout while (!_executingProcess.HasExited) { //Process still running, but timeout is done //Or Process is still running but scan has been stopped by user if (token.IsCancellationRequested || (tempScanFilePath != null && !FileSystemHelpers.FileExists(tempScanFilePath))) { //Kill process _executingProcess.Kill(true, _tracer); //Wait for process to be completely killed _executingProcess.WaitForExit(); successfulScan = false; if (token.IsCancellationRequested) { _tracer.Trace("Scan {0} has timed out at {1}", scanId, DateTime.UtcNow.ToString("yyy-MM-dd_HH-mm-ssZ")); //Update status file UpdateScanStatus(folderPath, ScanStatus.TimeoutFailure, null); } else { _tracer.Trace("Scan {0} has been force stopped at {1}", scanId, DateTime.UtcNow.ToString("yyy-MM-dd_HH-mm-ssZ")); //Update status file UpdateScanStatus(folderPath, ScanStatus.ForceStopped, null); } break; } } //Clean up the temp file StopScan(mainScanDirPath); //Update status file with success if (successfulScan) { //Check if process terminated with errors if (_executingProcess.ExitCode != 0) { UpdateScanStatus(folderPath, ScanStatus.Failed, null); _tracer.Trace("Scan {0} has terminated with exit code {1}. More info found in {2}", scanId, _executingProcess.ExitCode, logFilePath); } else { UpdateScanStatus(folderPath, ScanStatus.Success, null); _tracer.Trace("Scan {0} is Successful", scanId); } } }, "Performing continuous scan", TimeSpan.Zero); _scanLock.SetLockMsg(""); }); return(successfulScan); }
public async Task <ScanRequestResult> StartScan(String timeout, String mainScanDirPath, String id, String host, Boolean checkModified) { using (_tracer.Step("Start scan in the background")) { String folderPath = Path.Combine(mainScanDirPath, Constants.ScanFolderName + id); String filePath = Path.Combine(folderPath, Constants.ScanStatusFile); Boolean hasFileModifcations = true; if (_scanLock.IsHeld) { return(ScanRequestResult.ScanAlreadyInProgress); } //Create unique scan folder and scan status file _scanLock.LockOperation(() => { //This means user wants to start a scan without checking for file changes after previous scan //Delete the manifest file containing last updated timestamps of files //This will force a scan to start irrespective of changes made to files if (!checkModified) { String manifestPath = Path.Combine(mainScanDirPath, Constants.ScanManifest); if (FileSystemHelpers.FileExists(manifestPath)) { FileSystemHelpers.DeleteFileSafe(manifestPath); } } //Check if files are modified if (CheckModifications(mainScanDirPath)) { //Create unique scan directory for current scan FileSystemHelpers.CreateDirectory(folderPath); _tracer.Trace("Unique scan directory created for scan {0}", id); //Create scan status file inside folder FileSystemHelpers.CreateFile(filePath).Close(); //Create temp file to check if scan is still running string tempScanFilePath = GetTempScanFilePath(mainScanDirPath); tempScanFilePath = Path.Combine(mainScanDirPath, Constants.TempScanFile); FileSystemHelpers.CreateFile(tempScanFilePath).Close(); UpdateScanStatus(folderPath, ScanStatus.Starting, id); } else { hasFileModifcations = false; } }, "Creating unique scan folder", TimeSpan.Zero); if (!hasFileModifcations) { return(ScanRequestResult.NoFileModifications); } //Start Backgorund Scan using (var timeoutCancellationTokenSource = new CancellationTokenSource()) { var successfullyScanned = PerformBackgroundScan(_tracer, _scanLock, folderPath, timeoutCancellationTokenSource.Token, id, mainScanDirPath); //Wait till scan task completes or the timeout goes off if (await Task.WhenAny(successfullyScanned, Task.Delay(Int32.Parse(timeout), timeoutCancellationTokenSource.Token)) == successfullyScanned) { //If scan task completes before timeout //Delete excess scan folders, just keep the maximum number allowed await DeletePastScans(mainScanDirPath, _tracer); //Create new Manifest file containing the modified timestamps String manifestPath = Path.Combine(mainScanDirPath, Constants.ScanManifest); if (FileSystemHelpers.FileExists(manifestPath)) { FileSystemHelpers.DeleteFileSafe(manifestPath); } JObject manifestObj = new JObject(); //Write to the manifest with new timestamps of the modified file ModifyManifestFile(manifestObj, Constants.ScanDir); File.WriteAllText(manifestPath, JsonConvert.SerializeObject(manifestObj)); //Path to common log file for azure monitor String aggrLogPath = Path.Combine(mainScanDirPath, Constants.AggregrateScanResults); //This checks if result scan log is formed //If yes, it will append necessary logs to the aggregrate log file //Current appended logs will be "Scanned files","Infected files", and details of infected files String currLogPath = Path.Combine(folderPath, Constants.ScanLogFile); if (FileSystemHelpers.FileExists(currLogPath)) { StreamReader file = new StreamReader(currLogPath); string line; while ((line = file.ReadLine()) != null) { if (line.Contains("FOUND") || line.Contains("Infected files") || line.Contains("Scanned files")) { //logType "Infected" means this log line represents details of infected files String logType = "Infected"; if (line.Contains("Infected files") || line.Contains("Scanned files")) { //logType "Info" means this log line represents total number of scanned or infected files logType = "Info"; } FileSystemHelpers.AppendAllTextToFile(aggrLogPath, DateTime.UtcNow.ToString(@"M/d/yyyy hh:mm:ss tt") + "," + id + "," + logType + "," + host + "," + line + '\n'); } } } return(successfullyScanned.Result ? ScanRequestResult.RunningAynschronously : ScanRequestResult.AsyncScanFailed); } else { //Timeout went off before scan task completion //Cancel scan task timeoutCancellationTokenSource.Cancel(); //Scan process will be cancelled //wait till scan status file is appropriately updated await successfullyScanned; //Delete excess scan folders, just keep the maximum number allowed await DeletePastScans(mainScanDirPath, _tracer); return(ScanRequestResult.AsyncScanFailed); } } } }