Skip to content

Commit

Permalink
added winsz message to call TIOCSWINSZ on pty master
Browse files Browse the repository at this point in the history
  • Loading branch information
noelbk committed Mar 29, 2017
1 parent da46fad commit da27b25
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 3 deletions.
24 changes: 22 additions & 2 deletions c_src/exec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ bool process_command()
return false;
}

enum CmdTypeT { MANAGE, RUN, STOP, KILL, LIST, SHUTDOWN, STDIN, DEBUG } cmd;
const char* cmds[] = { "manage","run","stop","kill","list","shutdown","stdin","debug" };
enum CmdTypeT { MANAGE, RUN, STOP, KILL, LIST, SHUTDOWN, STDIN, DEBUG, WINSZ } cmd;
const char* cmds[] = { "manage","run","stop","kill","list","shutdown","stdin","debug", "winsz" };

/* Determine the command */
if ((int)(cmd = (CmdTypeT) eis.decodeAtomIndex(cmds, command)) < 0) {
Expand Down Expand Up @@ -395,6 +395,26 @@ bool process_command()
send_pid_list(transId, children);
break;
}
case WINSZ: {
// {winsz, OsPid::integer(), rows::integer(), cols::integer()}
long pid, rows, cols;
if (arity != 4
|| eis.decodeInt(pid) < 0
|| eis.decodeInt(rows) < 0
|| eis.decodeInt(cols) < 0) {
send_error_str(transId, true, "badarg");
break;
}
MapChildrenT::iterator it = children.find(pid);
if (it == children.end()) {
if (debug)
fprintf(stderr, "pid %ld doesn't exist\r\n", pid);
break;
}
set_pid_winsz(it->second, rows, cols);
break;
}

case STDIN: {
// {stdin, OsPid::integer(), Data::binary()}
long pid;
Expand Down
1 change: 1 addition & 0 deletions c_src/exec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ int read_sigchld(pid_t& child);
void check_child_exit(pid_t pid);
int set_nice(pid_t pid,int nice, std::string& error);
bool process_sigchld();
bool set_pid_winsz(CmdInfo& ci, int rows, int cols);
bool process_pid_input(CmdInfo& ci);
void process_pid_output(CmdInfo& ci, int maxsize = 4096);
int send_ok(int transId, long value = -1);
Expand Down
15 changes: 15 additions & 0 deletions c_src/exec_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,21 @@ int set_nice(pid_t pid,int nice, std::string& error)
return 0;
}

//------------------------------------------------------------------------------
bool set_pid_winsz(CmdInfo& ci, int rows, int cols)
{
int& fd = ci.stream_fd[STDIN_FILENO];
int r;
struct winsize ws;
ws.ws_row = rows;
ws.ws_col = cols;
r = ioctl(fd, TIOCSWINSZ, &ws);
if (debug)
fprintf(stderr, "TIOCSWINSZ rows=%d cols=%d ret=%d\n", rows, cols, r);

return true;
}

//------------------------------------------------------------------------------
bool process_pid_input(CmdInfo& ci)
{
Expand Down
34 changes: 33 additions & 1 deletion src/exec.erl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

%% External exports
-export([
start/0, start/1, start_link/1, run/2, run_link/2, manage/2, send/2,
start/0, start/1, start_link/1, run/2, run_link/2, manage/2, send/2, winsz/3,
which_children/0, kill/2, setpgid/2, stop/1, stop_and_wait/2,
ospid/1, pid/1, status/1, signal/1, debug/1
]).
Expand Down Expand Up @@ -467,6 +467,20 @@ send(OsPid, Data)
(is_binary(Data) orelse Data =:= eof) ->
gen_server:call(?MODULE, {port, {send, OsPid, Data}}).

%%-------------------------------------------------------------------------
%% @doc Set the pty terminal `Rows' and `Cols' of the OS process identified by `OsPid'.
%%
%% The process must have been created with the `pty' option.
%%
%% @end
%%-------------------------------------------------------------------------
-spec winsz(OsPid :: ospid() | pid(), integer(), integer()) -> ok.
winsz(OsPid, Rows, Cols)
when (is_integer(OsPid) orelse is_pid(OsPid)),
is_integer(Rows),
is_integer(Cols) ->
gen_server:call(?MODULE, {port, {winsz, OsPid, Rows, Cols}}).

%%-------------------------------------------------------------------------
%% @doc Set debug level of the port process.
%% @end
Expand Down Expand Up @@ -986,6 +1000,15 @@ is_port_command({send, Pid, Data}, _Pid, _State)
is_port_command({send, OsPid, Data}, _Pid, _State)
when is_integer(OsPid), is_binary(Data) orelse Data =:= eof ->
{ok, {stdin, OsPid, Data}};
is_port_command({winsz, Pid, Rows, Cols}, _Pid, _State)
when is_pid(Pid), is_integer(Rows), is_integer(Cols) ->
case ets:lookup(exec_mon, Pid) of
[{Pid, OsPid}] -> {ok, {winsz, OsPid, Rows, Cols}};
[] -> throw({error, no_process})
end;
is_port_command({winsz, OsPid, Rows, Cols}, _Pid, _State)
when is_integer(OsPid), is_integer(Rows), is_integer(Cols) ->
{ok, {winsz, OsPid, Rows, Cols}};
is_port_command({kill, OsPid, Sig}=T, _Pid, _State) when is_integer(OsPid),is_integer(Sig) ->
{ok, T, undefined, undefined, []};
is_port_command({setpgid, OsPid, Gid}=T, _Pid, _State) when is_integer(OsPid),is_integer(Gid) ->
Expand Down Expand Up @@ -1112,6 +1135,7 @@ exec_test_() ->
[
?tt(test_monitor()),
?tt(test_sync()),
?tt(test_winsz()),
?tt(test_stdin()),
?tt(test_stdin_eof()),
?tt(test_std(stdout)),
Expand Down Expand Up @@ -1140,6 +1164,14 @@ test_sync() ->
exec:run(["/bin/echo", ""], [sync, stdout])).


test_winsz() ->
{ok, P, I} = exec:run(["/bin/bash", "-i", "-c", "echo started; read x; echo LINES=$(tput lines) COLUMNS=$(tput cols)"], [stdin, stdout, stderr, monitor, pty]),
?receiveMatch({stdout, I, <<"started\r\n">>}, 3000),
ok = exec:winsz(I, 99, 88),
ok = exec:send(I, <<"\n">>),
?receiveMatch({stdout, I, <<"LINES=99 COLUMNS=88\r\n">>}, 3000),
?receiveMatch({'DOWN', _, process, P, normal}, 5000).

test_stdin() ->
{ok, P, I} = exec:run("read x; echo \"Got: $x\"", [stdin, stdout, monitor]),
ok = exec:send(I, <<"Test data\n">>),
Expand Down

0 comments on commit da27b25

Please sign in to comment.