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