|
@@ -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
|
|
|
|
|