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
|
;;; popen.scm -- Remote popen emulation.
;; Copyright (C) 2015-2024 Artyom V. Poptsov <poptsov.artyom@gmail.com>
;;
;; This file is a part of Guile-SSH.
;;
;; Guile-SSH is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; Guile-SSH is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with Guile-SSH. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This module provides implementation of "remote popen". That is, you may
;; create either input, output or bidirectional pipes to remote process with
;; the procedures exported by the module.
;;
;; These procedures are exported:
;;
;; open-remote-pipe
;; open-remote-pipe*
;; open-remote-input-pipe
;; open-remote-input-pipe*
;; open-remote-output-pipe
;; open-remote-output-pipe*
;;
;; Variables exported:
;;
;; OPEN_PTY
;;
;; See the Info documentation for the detailed description of these
;; procedures.
;;; Code:
(define-module (ssh popen)
#:use-module (ssh channel)
#:export (open-remote-pipe
open-remote-pipe*
open-remote-input-pipe
open-remote-input-pipe*
open-remote-output-pipe
open-remote-output-pipe*
OPEN_PTY))
(define OPEN_PTY "t")
;; This procedure is taken from GNU Guile 3.0.0.
;;
;; Original comment:
;;
;; string-replace-substring By A. Wingo in
;; https://lists.gnu.org/archive/html/guile-devel/2014-03/msg00058.html
;; also in string-replace-substring guix:guix/utils.scm.
(define (string-replace-substring str substring replacement)
"Return a new string where every instance of @var{substring} in string
@var{str} has been replaced by @var{replacement}. For example:
@lisp
(string-replace-substring \"a ring of strings\" \"ring\" \"rut\")
@result{} \"a rut of struts\"
@end lisp
"
(let ((sublen (string-length substring)))
(with-output-to-string
(lambda ()
(let lp ((start 0))
(cond
((string-contains str substring start)
=> (lambda (end)
(display (substring/shared str start end))
(display replacement)
(lp (+ end sublen))))
(else
(display (substring/shared str start)))))))))
(define (shell-quote s)
"Quote string S for sh-compatible shells."
(string-append "'" (string-replace-substring s "'" "'\\''") "'"))
(define (open-remote-pipe session command mode)
"Execute a COMMAND on the remote host using a SESSION with a pipe to it.
Returns newly created channel port with the specified MODE."
(let ((channel (make-channel session mode)))
(unless channel
(throw 'guile-ssh-error "Could not create a channel" session command mode))
(channel-open-session channel)
(when (string-contains mode OPEN_PTY)
(channel-request-pty channel))
(channel-request-exec channel command)
channel))
(define (open-remote-pipe* session mode prog . args)
"Execute a PROG with optional ARGS on the remote host using a SESSION with a
pipe to it. Returns newly created channel port with the specified MODE."
(open-remote-pipe session
(string-join (cons (shell-quote prog)
(map shell-quote args)))
mode))
(define (open-remote-input-pipe session command)
"Execute a COMMAND on the remote host using a SESSION with an input pipe to it.
Returns newly created input channel port."
(open-remote-pipe session command OPEN_READ))
(define (open-remote-input-pipe* session prog . args)
"Execute a PROG with optional ARGS on the remote host using a SESSION with
an input pipe to it. Returns newly created input channel port."
(open-remote-pipe session
(string-join (cons (shell-quote prog)
(map shell-quote args)))
OPEN_READ))
(define (open-remote-output-pipe session command)
"Execute a COMMAND on the remote host using a SESSION with an input pipe to it.
Returns newly created input channel port."
(open-remote-pipe session command OPEN_WRITE))
(define (open-remote-output-pipe* session prog . args)
"Execute a PROG with optional ARGS on the remote host using a SESSION with
an output pipe to it. Returns newly created output channel port."
(open-remote-pipe session
(string-join (cons (shell-quote prog)
(map shell-quote args)))
OPEN_WRITE))
;;; popen.scm ends here.
|