модуль PTY
Создаёт и управляет псевдотерминалами (PTY). См. также en.wikipedia.org/wiki/Pseudo_terminal
PTY позволяет вам выделять новые терминалы, используя ::open или ::spawn для запуска нового терминала со специфической командой.
Пример
В этом примере мы изменим тип буферизации в команде factor, предполагая, что фактор использует stdio для буферизации stdout.
Если IO.pipe используется вместо ::open, этот код зависает, так как stdout фактора полностью буферизован.
# start by requiring the standard library PTY
require 'pty'
master, slave = PTY.open
read, write = IO.pipe
pid = spawn("factor", :in=>read, :out=>slave)
read.close # we dont need the read
slave.close # or the slave
# pipe "42" to the factor command
write.puts "42"
# output the response from factor
p master.gets #=> "42: 2 3 7\n"
# pipe "144" to factor and print out the response
write.puts "144"
p master.gets #=> "144: 2 2 2 2 3 3\n"
write.close # close the pipe
# The result of read operation when pty slave is closed is platform
# dependent.
ret = begin
master.gets # FreeBSD returns nil.
rescue Errno::EIO # GNU/Linux raises EIO.
nil
end
p ret #=> nil
Лицензия
C) Copyright 1998 by Akinori Ito. This software may be redistributed freely for this purpose, in full or in part, provided that this entire copyright notice is included on any copies of this software and applications and derivations thereof. This software is provided on an "as is" basis, without warranty of any kind, either expressed or implied, as to any matter including, but not limited to warranty of fitness of purpose, or merchantability, or results obtained from use of this software.
Методы публичного класса
static VALUE
pty_check(int argc, VALUE *argv, VALUE self)
{
VALUE pid, exc;
rb_pid_t cpid;
int status;
const int flag =
#ifdef WNOHANG
WNOHANG|
#endif
#ifdef WUNTRACED
WUNTRACED|
#endif
0;
rb_scan_args(argc, argv, "11", &pid, &exc);
cpid = rb_waitpid(NUM2PIDT(pid), &status, flag);
if (cpid == -1 || cpid == 0) return Qnil;
if (!RTEST(exc)) return rb_last_status_get();
raise_from_check(cpid, status);
UNREACHABLE;
} Проверяет состояние дочернего процесса, указанного pid. Возвращает nil, если процесс всё ещё жив.
Если процесс не жив, и raise было true, будет вызвано исключение PTY::ChildExited. В противном случае будет возвращён объект Process::Status.
-
pid -
Идентификатор процесса для проверки
-
raise -
Если
trueи процесс, идентифицированный какpid, больше не жив, то вызывается исключение PTY::ChildExited.
static VALUE
pty_getpty(int argc, VALUE *argv, VALUE self)
{
VALUE res;
struct pty_info info;
rb_io_t *wfptr,*rfptr;
VALUE rport = rb_obj_alloc(rb_cFile);
VALUE wport = rb_obj_alloc(rb_cFile);
char SlaveName[DEVICELEN];
MakeOpenFile(rport, rfptr);
MakeOpenFile(wport, wfptr);
establishShell(argc, argv, &info, SlaveName);
rfptr->mode = rb_io_modestr_fmode("r");
rfptr->fd = info.fd;
rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
wfptr->mode = rb_io_modestr_fmode("w") | FMODE_SYNC;
wfptr->fd = rb_cloexec_dup(info.fd);
if (wfptr->fd == -1)
rb_sys_fail("dup()");
rb_update_max_fd(wfptr->fd);
wfptr->pathv = rfptr->pathv;
res = rb_ary_new2(3);
rb_ary_store(res,0,(VALUE)rport);
rb_ary_store(res,1,(VALUE)wport);
rb_ary_store(res,2,PIDT2NUM(info.child_pid));
if (rb_block_given_p()) {
rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
return Qnil;
}
return res;
} Запускает указанную команду в новом выделенном псевдотерминале. Также можно использовать псевдоним ::getpty.
Управляющий tty команды устанавливается на подчиненное устройство псевдотерминала, а стандартный ввод/вывод/ошибка перенаправляются на подчиненное устройство.
command и command_line — это полные команды для выполнения, заданные в виде строки. Любые дополнительные arguments будут переданы команде.
Возвращаемые значения
В режиме без блока возвращается массив размером три, [r, w,
pid].
В режиме с блоком эти же значения передаются в блок:
static VALUE
pty_open(VALUE klass)
{
int master_fd, slave_fd;
char slavename[DEVICELEN];
VALUE master_io, slave_file;
rb_io_t *master_fptr, *slave_fptr;
VALUE assoc;
getDevice(&master_fd, &slave_fd, slavename, 1);
master_io = rb_obj_alloc(rb_cIO);
MakeOpenFile(master_io, master_fptr);
master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
master_fptr->fd = master_fd;
master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
slave_file = rb_obj_alloc(rb_cFile);
MakeOpenFile(slave_file, slave_fptr);
slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
slave_fptr->fd = slave_fd;
slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
assoc = rb_assoc_new(master_io, slave_file);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
}
return assoc;
} Выделяет pty (псевдотерминал).
В режиме с блоком передаёт два аргумента master_io, slave_file и возвращает значение блока из open.
Объект IO и File закрываются после завершения блока, если они ещё не закрыты.
PTY.open {|master, slave|
p master #=> #<IO:masterpty:/dev/pts/1>
p slave #=> #<File:/dev/pts/1>
p slave.path #=> "/dev/pts/1"
}
В режиме без блока возвращает массив из двух элементов, [master_io,
slave_file].
master, slave = PTY.open # do something with master for IO, or the slave file
Аргументы в обоих режимах:
-
master_io -
мастер pty в виде IO.
-
slave_file -
подчиненное устройство pty в виде File. Путь к устройству терминала доступен через
slave_file.path
IO#raw! может использоваться для отключения преобразования строк перевода:
require 'io/console'
PTY.open {|m, s|
s.raw!
...
} static VALUE
pty_getpty(int argc, VALUE *argv, VALUE self)
{
VALUE res;
struct pty_info info;
rb_io_t *wfptr,*rfptr;
VALUE rport = rb_obj_alloc(rb_cFile);
VALUE wport = rb_obj_alloc(rb_cFile);
char SlaveName[DEVICELEN];
MakeOpenFile(rport, rfptr);
MakeOpenFile(wport, wfptr);
establishShell(argc, argv, &info, SlaveName);
rfptr->mode = rb_io_modestr_fmode("r");
rfptr->fd = info.fd;
rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
wfptr->mode = rb_io_modestr_fmode("w") | FMODE_SYNC;
wfptr->fd = rb_cloexec_dup(info.fd);
if (wfptr->fd == -1)
rb_sys_fail("dup()");
rb_update_max_fd(wfptr->fd);
wfptr->pathv = rfptr->pathv;
res = rb_ary_new2(3);
rb_ary_store(res,0,(VALUE)rport);
rb_ary_store(res,1,(VALUE)wport);
rb_ary_store(res,2,PIDT2NUM(info.child_pid));
if (rb_block_given_p()) {
rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
return Qnil;
}
return res;
} Запускает указанную команду в новом выделенном псевдотерминале. Также можно использовать псевдоним ::getpty.
Управляющий tty команды устанавливается на подчиненное устройство псевдотерминала, а стандартный ввод/вывод/ошибка перенаправляются на подчиненное устройство.
command и command_line — это полные команды для выполнения, заданные в виде строки. Любые дополнительные arguments будут переданы команде.
Возвращаемые значения
В режиме без блока возвращается массив размером три, [r, w,
pid].
В режиме с блоком эти же значения передаются в блок:
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.