1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
@c -*-texinfo-*-
@c This file is part of Guile-SSH Reference Manual.
@c Copyright (C) 2015-2024 Artyom V. Poptsov
@c See the file guile-ssh.texi for copying conditions.
@node Remote Pipes
@section Remote Pipes
@cindex remote pipes
@code{(ssh popen)} provides API for working with remote pipes, akin to
@code{(ice-9 popen)} procedures (@pxref{Pipes,,, guile, The GNU Guile
Reference Manual})
@var{mode} argument allows to specify what kind of pipe should be created.
Allowed values are: @code{OPEN_READ}, @code{OPEN_WRITE}, @code{OPEN_BOTH}.
There is an additional value, @code{OPEN_PTY}, that allows to request a
@abbr{PTY, Pseudo Terminal}. The terminal is needed to run such commands as
@command{top}. Thus, to run @command{top} on the remote side you need to open
a remote pipe with ``t'' flag set.
@strong{Note} that when a PTY is used, a server merges @code{stderr} and
@code{stdout} streams.
Values of the aforementioned constants:
@table @samp
@item OPEN_READ
``r''
@item OPEN_WRITE
``w''
@item OPEN_BOTH
``r+''
@item OPEN_PTY
``t''
@end table
@deffn {Scheme Procedure} open-remote-pipe session command mode
Execute a @var{command} on the remote host using a @var{session} with a pipe
to it. Returns newly created channel port (@xref{Channels} for more info)
with the specified @var{mode}.
@end deffn
@deffn {Scheme Procedure} open-remote-pipe* session mode prog [args...]
Execute @var{prog} on the remote host with the given @var{args} using a
@var{session} with a pipe to it. Returns newly created channel port with the
specified @var{mode}.
The behavior is the same as for @code{open-pipe*} (@pxref{Pipes,,, guile, The
GNU Guile Reference Manual}) -- the program name and each argument is quoted
with single quotes and joined together separated by spaces, then the resulting
string is executed on the remote side as a single command.
@end deffn
@deffn {Scheme Procedure} open-remote-input-pipe session command
@deffnx {Scheme Procedure} open-remote-input-pipe* session prog [args...]
Equivalent to @code{open-remote-pipe} and @code{open-remote-pipe*} respectively
with mode @code{OPEN_READ}.
@end deffn
@deffn {Scheme Procedure} open-remote-output-pipe session command
@deffnx {Scheme Procedure} open-remote-output-pipe* session prog [args...]
Equivalent to @code{open-remote-pipe} and @code{open-remote-pipe*} respectively
with mode @code{OPEN_WRITE}.
@end deffn
@c -----------------------------------------------------------------------------
@subsection Examples
@subsubsection Simple cases
Here's a self-explanatory little script that executes @code{uname -o} command
on the local host and prints the result:
@lisp
#!/usr/bin/env -S guile -L modules -e main -s
!#
(use-modules (ice-9 rdelim) ; @{read,write@}-line
;; Guile-SSH
(ssh session)
(ssh auth)
(ssh popen)) ; remote pipes
(define (main args)
;; Make an SSH session to the local machine and the current user.
(let ((session (make-session #:host "localhost")))
;; Connect the session and perform the authentication.
(connect! session)
(authenticate-server session)
(userauth-agent! session)
;; Execute the command on the remote side and get the input pipe
;; to it.
(let ((channel (open-remote-input-pipe* session "uname" "-o")))
;; Read and display the result.
(write-line (read-line channel)))))
@end lisp
@c -----------------------------------------------------------------------------
@subsubsection Executing a command with a pseudo terminal
Surely we aren't limited to one-line outputs; for example, we can watch
@code{top} command executing on a remote side locally, by reading data from
the channel in a loop:
@lisp
(define OPEN_PTY_READ (string-append OPEN_PTY OPEN_READ))
(let ((channel (open-remote-pipe* session
OPEN_PTY_READ
"top" "-u" "avp")))
(let r ((line (read-line channel)))
(unless (eof-object? line)
(write-line line)
(r (read-line channel)))))
@end lisp
Or we can do the same, but this time with streams:
@lisp
(use-modules (srfi srfi-41) ; streams
(ssh session)
(ssh auth)
(ssh popen))
(define (pipe->stream p)
(stream-let loop ((c (read-char p)))
(if (eof-object? c)
(begin
(close-input-port p)
stream-null)
(stream-cons c (loop (read-char p))))))
(define OPEN_PTY_READ (string-append OPEN_PTY OPEN_READ))
(define (main args)
(let ((s (make-session #:host "example.org")))
(connect! s)
(userauth-agent! s)
(let ((rs (pipe->stream (open-remote-pipe* s
OPEN_PTY_READ
"top" "-u" "avp"))))
(stream-for-each display rs))))
@end lisp
@c -----------------------------------------------------------------------------
@subsubsection Controlling the pseudo terminal size
To set the size of a pseudo terminal, one may use @code{channel-set-pty-size!}
from @code{(ssh channel)}. For example:
@lisp
(use-modules (ssh popen)
(ssh auth)
(ssh channel))
(define OPEN_PTY_READ (string-append OPEN_PTY OPEN_READ))
;; Opening of a Guile-SSH session goes here ...
(let ((p (open-remote-pipe* session OPEN_PTY_READ "top" "-u" "avp")))
(channel-set-pty-size! p 80 50)
;; Reading output from a port ...
)
@end lisp
@c Local Variables:
@c TeX-master: "guile-ssh.texi"
@c End:
|