1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using Antmicro.Renode.Core; 8 using Antmicro.Renode.Exceptions; 9 #if !PLATFORM_WINDOWS 10 using System; 11 using Antmicro.Renode.Peripherals.UART; 12 using Antmicro.Renode.Utilities; 13 using AntShell.Terminal; 14 using Antmicro.Migrant; 15 using Mono.Unix; 16 using System.IO; 17 #endif 18 19 namespace Antmicro.Renode.Backends.Terminals 20 { 21 public static class UartPtyTerminalExtensions 22 { CreateUartPtyTerminal(this Emulation emulation, string name, string fileName, bool forceCreate = false)23 public static void CreateUartPtyTerminal(this Emulation emulation, string name, string fileName, bool forceCreate = false) 24 { 25 #if !PLATFORM_WINDOWS 26 emulation.ExternalsManager.AddExternal(new UartPtyTerminal(fileName, forceCreate), name); 27 #else 28 throw new RecoverableException("Creating UartPtyTerminal is not supported on Windows."); 29 #endif 30 } 31 } 32 33 #if !PLATFORM_WINDOWS 34 public class UartPtyTerminal : BackendTerminal, IDisposable 35 { UartPtyTerminal(string linkName, bool forceCreate = false)36 public UartPtyTerminal(string linkName, bool forceCreate = false) 37 { 38 39 this.linkName = linkName; 40 this.forceCreate = forceCreate; 41 42 Initialize(); 43 } 44 Dispose()45 public void Dispose() 46 { 47 io.Dispose(); 48 try 49 { 50 symlink.Delete(); 51 } 52 catch(FileNotFoundException e) 53 { 54 throw new RecoverableException(string.Format("There was an error when removing symlink `{0}': {1}", symlink.FullName, e.Message)); 55 } 56 } 57 WriteChar(byte value)58 public override void WriteChar(byte value) 59 { 60 io.Write(value); 61 } 62 BufferStateChanged(BufferState state)63 public override void BufferStateChanged(BufferState state) 64 { 65 base.BufferStateChanged(state); 66 if(state == BufferState.Full) 67 { 68 io.Pause(); 69 } 70 else if(state == BufferState.Empty) 71 { 72 io.Resume(); 73 } 74 } 75 76 [Migrant.Hooks.PostDeserialization] Initialize()77 private void Initialize() 78 { 79 ptyStream = new PtyUnixStream(); 80 io = new IOProvider { Backend = new StreamIOSource(ptyStream) }; 81 io.ByteRead += b => CallCharReceived((byte)b); 82 83 CreateSymlink(); 84 } 85 CreateSymlink()86 private void CreateSymlink() 87 { 88 if(File.Exists(linkName)) 89 { 90 if(!forceCreate) 91 { 92 throw new RecoverableException(string.Format("File `{0}' already exists. Use forceCreate to overwrite it.", linkName)); 93 } 94 95 try 96 { 97 File.Delete(linkName); 98 } 99 catch(Exception e) 100 { 101 throw new RecoverableException(string.Format("There was an error when removing existing `{0}' symlink: {1}", linkName, e.Message)); 102 } 103 } 104 try 105 { 106 var slavePtyFile = new UnixFileInfo(ptyStream.SlaveName); 107 symlink = slavePtyFile.CreateSymbolicLink(linkName); 108 } 109 catch(Exception e) 110 { 111 throw new RecoverableException(string.Format("There was an error when when creating a symlink `{0}': {1}", linkName, e.Message)); 112 } 113 } 114 115 private UnixSymbolicLinkInfo symlink; 116 117 private readonly bool forceCreate; 118 private readonly string linkName; 119 [Transient] 120 private PtyUnixStream ptyStream; 121 [Transient] 122 private IOProvider io; 123 } 124 #endif 125 } 126 127