1 module socat;
2 
3 version (Posix) {}
4 else static assert(0, "support only posix platform");
5 
6 import std.process;
7 import std.string;
8 import std.exception;
9 
10 import core.sys.posix.unistd : getuid;
11 
12 auto runSocat(uint bufferSize=1024)
13 {
14     struct Result
15     {
16         ProcessPipes pipe;
17         string port1, port2;
18 
19         string[2] ports() const @property
20         { return [port1, port2]; }
21 
22         this(int bufsz)
23         {
24             enforce(getuid() == 0, "you must be a root");
25             auto cmd = ("socat -d -d -b%d pty,raw,"~
26                    "echo=0 pty,raw,echo=0").format(bufsz);
27             import std.stdio;
28             writeln(cmd);
29             pipe = pipeShell(cmd);
30             
31             port1 = parsePort(pipe.stderr.readln.strip);
32             port2 = parsePort(pipe.stderr.readln.strip);
33         }
34 
35         string parsePort(string ln)
36         {
37             import std.file : exists;
38             auto p = parseSocatPort(ln);
39             enforce(p.exists, "%s doesn't exists".format(p));
40             return p;
41         }
42 
43         ~this() { kill(pipe.pid); }
44     }
45 
46     return Result(bufferSize);
47 }
48 
49 string parseSocatPort(string ln)
50 {
51     // 
52     auto ret = ln.split[$-1];
53     enforce(ret.startsWith("/dev/pts/"),
54     "unexpected last word in output line '%s'".format(ln));
55     return ret;
56 }
57 
58 unittest
59 {
60     assert("2018/03/08 02:56:58 socat[30331] N PTY is /dev/pts/1"
61                 .parseSocatPort == "/dev/pts/1");
62 
63     assertThrown("some string".parseSocatPort);
64 }