Browse Source

upd to v4.1.1

221V 3 years ago
parent
commit
c66aa4b57a
6 changed files with 70 additions and 47 deletions
  1. 2 0
      LICENSE
  2. 18 38
      README.md
  3. 3 3
      ebin/sh.app
  4. 31 0
      src/exe.erl
  5. 12 3
      src/sh.erl
  6. 4 3
      src/sh_sup.erl

+ 2 - 0
LICENSE

@@ -1,3 +1,5 @@
+ISC License
+
 Copyright (c) 2013 Vladimir Kirillov <proger@hackndev.com>
 Copyright (c) 2013 Vladimir Kirillov <proger@hackndev.com>
 
 
 Permission to use, copy, modify, and/or distribute this software for any
 Permission to use, copy, modify, and/or distribute this software for any

+ 18 - 38
README.md

@@ -1,20 +1,16 @@
-SH Executor - https://github.com/synrc/sh (exe) v1.9 fork
-===========
+# SH Executor - https://github.com/synrc/sh (exe) v1.9 fork (upd to v4.1.1)
 
 
-Family of functions and ports involving interacting with the system shell,
-paths and external programs.
+Family of functions and ports to interact with system shell, paths and external programs.
 
 
-Reason
-------
+## Avoid `os:cmd/1` on user input!
 
 
 ```erlang
 ```erlang
-> Email = "hacker+/somepath&reboot#@example.com". % this is a valid email!
+> Email = "proger+/&reboot%23@hackndev.com". % valid email!
 > os:cmd(["mkdir -p ", Email]).
 > os:cmd(["mkdir -p ", Email]).
 % path clobbering and a reboot may happen here!
 % path clobbering and a reboot may happen here!
 ```
 ```
 
 
-Examples
---------
+## Examples
 
 
 ### Onliners
 ### Onliners
 
 
@@ -22,9 +18,8 @@ Examples
 > sh:oneliner(["touch", filename:join("/tmp/", Path)]).
 > sh:oneliner(["touch", filename:join("/tmp/", Path)]).
 {done,0,<<>>}
 {done,0,<<>>}
 
 
-> sh:oneliner("uname -v"). % oneliner/1,2 funs do not include newlines
-{done,0,
-      <<"Darwin Kernel Version 12.4.0: Wed May  1 17:57:12 PDT 2013; root:xnu-2050.24.15~1/RELEASE_X86_64">>}
+> sh:oneliner("uname -mnprs").
+{done,0,<<"Darwin mac 18.2.0 x86_64 i386">>}
 
 
 > sh:oneliner("git describe --always").
 > sh:oneliner("git describe --always").
 {done,128,<<"fatal: Not a valid object name HEAD">>}
 {done,128,<<"fatal: Not a valid object name HEAD">>}
@@ -77,47 +72,32 @@ p2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304
 >>> {{2013,8,28},{8,39,14}} exit status: 0
 >>> {{2013,8,28},{8,39,14}} exit status: 0
 ```
 ```
 
 
-fdlink Port
------------
+## fdlink: make sure your ports exit when you exit
 
 
 Consider a case of spawning a port that does not actually
 Consider a case of spawning a port that does not actually
 read its standard input (e.g. `socat` that bridges `AF_UNIX` with `AF_INET`):
 read its standard input (e.g. `socat` that bridges `AF_UNIX` with `AF_INET`):
 
 
 ```shell
 ```shell
-# pstree -A -a $(pgrep make)
-make run
-  `-sh -c...
-      `-beam.smp -- -root /usr/lib/erlang -progname erl -- -home /root -- -pa ebin -config run/sys.config -eval[ok = application:
-          |-socat tcp-listen:32133,reuseaddr,bind=127.0.0.1 unix-connect:/var/run/docker.sock
-          `-16*[{beam.smp}]
+# pstree -A -a $(pgrep beam.smp)
+beam.smp -- -root /usr/lib/erlang -progname erl -- -home /root -- -pa ebin -config sys.config
+  |-socat tcp-listen:32133,reuseaddr,bind=127.0.0.1 unix-connect:/var/run/docker.sock
+  `-16*[{beam.smp}]
 ```
 ```
 
 
-If you terminate the node, `beam` will close the port but the process
+If you terminate the node, beam will close the port but the process
 will still remain alive (thus, it will leak). To mitigate this issue,
 will still remain alive (thus, it will leak). To mitigate this issue,
-you can use `fdlink` that will track `stdin` availability for you:
-
-``` shell
-# pstree -A -a $(pgrep make)
-make run
-  `-sh -c...
-      `-beam.smp -- -root /usr/lib/erlang -progname erl -- -home /root -- -pa ebin -config run/sys.config -eval[ok = application:
-          |-fdlink /usr/bin/socat tcp-listen:32133,reuseaddr,bind=127.0.0.1 unix-connect:/var/run/docker.sock
-          |   `-socat tcp-listen:32133,reuseaddr,bind=127.0.0.1 unix-connect:/var/run/docker.sock
-          `-16*[{beam.smp}]
-```
+you can use `fdlink` that tracks `stdin` availability for you:
 
 
-### Using
+### Usage
 
 
 ```erlang
 ```erlang
-> Fdlink = sh:fdlink_executable().               % make sure your app dir is setup correctly
-> Fdlink = filename:join("./priv", "fdlink").    % in case you're running directly from erlsh root
-> erlang:open_port({spawn_executable, Fdlink}, [stream, exit_status, {args, ["/usr/bin/socat"|RestOfArgs]}).
+> Fdlink = sh:fdlink_executable().
+> erlang:open_port({spawn_executable, Fdlink}, [stream, exit_status, {args, ["/usr/bin/socat"|Args]}).
 ```
 ```
 
 
 `fdlink` will also close the standard input of its child process.
 `fdlink` will also close the standard input of its child process.
 
 
-Credits
--------
+## Credits
 
 
 * Vladimir Kirillov
 * Vladimir Kirillov
 
 

+ 3 - 3
ebin/sh.app

@@ -1,9 +1,9 @@
 {application, sh,
 {application, sh,
- [{description, "SH VXZ Executor"},
-  {vsn, "1.9"},
+ [{description, "SH Shell Exec"},
+  {vsn, "4.1.1"},
   {registered, [sh_sup]},
   {registered, [sh_sup]},
   {applications, [kernel,stdlib]},
   {applications, [kernel,stdlib]},
-  {modules, [sh_app, sh_path, sh_sup, sh]},
+  {modules, [exe, sh_app, sh_path, sh_sup, sh]},
   {mod, { sh_app, []}},
   {mod, { sh_app, []}},
   {env, []}
   {env, []}
  ]}.
  ]}.

+ 31 - 0
src/exe.erl

@@ -0,0 +1,31 @@
+-module(exe).
+-export([reduce/0, run/1, sh/1, sh/3]).
+
+
+reduce() ->
+  fun({_, Chunk}, Acc) ->
+    [Chunk|Acc]
+  end.
+
+run(Args) ->
+  erlang:open_port({spawn_executable, os:find_executable("sh")},
+    [stream, in, out, eof, use_stdio, stderr_to_stdout, binary, exit_status,
+     {args, ["-c", Args]}, {cd, erlang:element(2, file:get_cwd())}, {env, []}]).
+
+sh(Port) -> sh(Port, reduce(), []).
+
+sh(Port, Fun, Acc) ->
+  receive
+    {Port, {exit_status, Status}} -> {done, Status, erlang:iolist_to_binary(lists:reverse(Acc))};
+    {Port, {data, {eol, Line}}}   -> sh(Port, Fun, Fun({eol,   Line}, Acc));
+    {Port, {data, {noeol, Line}}} -> sh(Port, Fun, Fun({noeol, Line}, Acc));
+    {Port, {data, Data}} ->
+      case {binary:match(Data, <<"Sign the certificate? [y/n]:">>) =/= nomatch,
+            binary:match(Data, <<"requests certified, commit?">>)  =/= nomatch} of
+        {true,_}   -> Port ! {erlang:self(), {command,<<"y\n">>}};
+        {_,true}   -> Port ! {erlang:self(), {command,<<"y\n">>}};
+        {_,_}      -> skip
+      end,
+      sh(Port, Fun, Fun({data, Data}, Acc))
+  end.
+

+ 12 - 3
src/sh.erl

@@ -1,5 +1,8 @@
 -module(sh).
 -module(sh).
--compile([export_all, nowarn_export_all]).
+-export([fdlink_executable/0, executable/1, oneliner/1, oneliner/2,
+  sh_loop/2, sh_loop/3, sh_loop/4,
+  run/1, run/2, run/3, run/4, run/5]).
+
 
 
 fdlink_executable() -> filename:absname(filename:join(code:priv_dir(sh), "fdlink")).
 fdlink_executable() -> filename:absname(filename:join(code:priv_dir(sh), "fdlink")).
 oneliner(C) -> run(C, ignoreeol, ".").
 oneliner(C) -> run(C, ignoreeol, ".").
@@ -16,7 +19,12 @@ executable(C) ->
     end.
     end.
 
 
 run([C|Args], Log, Cwd) when is_list(C)      -> run(executable(C), Args, Log, Cwd);
 run([C|Args], Log, Cwd) when is_list(C)      -> run(executable(C), Args, Log, Cwd);
-run(Command, Log, Cwd) when is_list(Command) -> run("/bin/sh", ["-c", Command], Log, Cwd).
+run(Command, Log, Cwd) when is_list(Command) ->
+  run(executable("sh"), ["-c", Command], Log, Cwd).
+%  case os:type() of
+%    {win32, _} -> run(executable("cmd"), ["/c", Command], Log, Cwd);
+%    _          -> run(executable("sh"), ["-c", Command], Log, Cwd)
+%  end.
 
 
 run(Command, Args, ignoreeol, Cwd) ->
 run(Command, Args, ignoreeol, Cwd) ->
     Port = erlang:open_port({spawn_executable, Command},
     Port = erlang:open_port({spawn_executable, Command},
@@ -55,5 +63,6 @@ sh_loop(Port, Fun, Acc, Flatten) when is_function(Fun) ->
     end.
     end.
 
 
 ts() ->
 ts() ->
-    Ts = {{_Y,_M,_D},{_H,_Min,_S}} = calendar:now_to_datetime(erlang:timestamp()),
+    Ts = {{_Y, _M, _D}, {_H, _Min, _S}} = calendar:now_to_datetime(os:timestamp()),
     io_lib:format("~p", [Ts]).
     io_lib:format("~p", [Ts]).
+

+ 4 - 3
src/sh_sup.erl

@@ -1,9 +1,10 @@
 -module(sh_sup).
 -module(sh_sup).
 -behaviour(supervisor).
 -behaviour(supervisor).
--export([start_link/0]).
--export([init/1]).
--define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
+
+-export([start_link/0, init/1]).
+
 
 
 start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
 start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
 init([]) -> {ok, { {one_for_one, 5, 10}, []} }.
 init([]) -> {ok, { {one_for_one, 5, 10}, []} }.