1 // 2 // Copyright (c) 2010-2021 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 #if !PLATFORM_WINDOWS 8 using System; 9 using System.ComponentModel; 10 using System.Diagnostics; 11 using System.Threading; 12 using AntShell.Terminal; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.UI 17 { 18 public abstract class ProcessBasedProvider : IConsoleBackendAnalyzerProvider 19 { 20 // isMonitorWindows is not used for ProcessBasedProvider TryOpen(string consoleName, out IIOSource io, bool isMonitorWindow = false)21 public bool TryOpen(string consoleName, out IIOSource io, bool isMonitorWindow = false) 22 { 23 var ptyUnixStream = new PtyUnixStream(); 24 io = new StreamIOSource(ptyUnixStream); 25 26 if(!CheckScreenTool()) 27 { 28 process = null; 29 return false; 30 } 31 32 var commandString = $"{ScreenTool} {(ptyUnixStream.SlaveName)}"; 33 process = CreateProcess(consoleName, commandString); 34 if(!RunProcess(process)) 35 { 36 process = null; 37 return false; 38 } 39 40 // here we give 1s time for screen to start; otherwise some initial data (e.g. banner could be lost) 41 Thread.Sleep(1000); 42 return true; 43 } 44 Close()45 public void Close() 46 { 47 var p = process; 48 if(p == null) 49 { 50 return; 51 } 52 53 try 54 { 55 p.CloseMainWindow(); 56 } 57 catch(InvalidOperationException e) 58 { 59 // do not report an exception if the process has already exited 60 if(!e.Message.Contains("finished") && !e.Message.Contains("exited")) 61 { 62 throw; 63 } 64 } 65 process = null; 66 } 67 68 public event Action OnClose; 69 CreateProcess(string consoleName, string command)70 protected abstract Process CreateProcess(string consoleName, string command); 71 LogError(string source, string arguments, int exitCode)72 protected void LogError(string source, string arguments, int exitCode) 73 { 74 Logger.LogAs(this, LogLevel.Error, "There was an error while starting {0} with arguments: {1}. It exited with code: {2}. In order to use different terminal, change preferences in configuration file.", source, arguments, exitCode); 75 } 76 InnerOnClose()77 protected void InnerOnClose() 78 { 79 OnClose?.Invoke(); 80 } 81 RunProcess(Process p)82 private bool RunProcess(Process p) 83 { 84 try 85 { 86 p.Start(); 87 return true; 88 } 89 catch(Win32Exception e) 90 { 91 if(e.NativeErrorCode == 2) 92 { 93 Logger.LogAs(this, LogLevel.Warning, "Could not find binary: {0}", p.StartInfo.FileName); 94 } 95 else 96 { 97 Logger.LogAs(this, LogLevel.Error, "There was an error when starting process: {0}", e.Message); 98 } 99 } 100 101 return false; 102 } 103 CheckScreenTool()104 private bool CheckScreenTool() 105 { 106 var p = new Process(); 107 p.StartInfo = new ProcessStartInfo(ScreenTool, "--help") 108 { 109 UseShellExecute = false, 110 RedirectStandardError = true, 111 RedirectStandardOutput = true, 112 RedirectStandardInput = true, 113 }; 114 return RunProcess(p); 115 } 116 117 private Process process; 118 119 private const string ScreenTool = "screen"; 120 } 121 } 122 123 #endif 124