This manual documents Guile-SSH version 0.16.4.
Copyright (C) 2014-2022 Artyom V. Poptsov
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License.”
[ < ] | [ > ] | [Contents] | [Index] | [ ? ] |
This manual documents Guile-SSH version 0.16.4.
Copyright (C) 2014-2022 Artyom V. Poptsov
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License.”
1 Introduction | ||
2 Installation | ||
3 API Reference | ||
4 Examples | ||
5 Acknowledgments | ||
Appendices | ||
---|---|---|
Appendix A GNU Free Documentation License | The license of this manual. | |
Indices | ||
Type Index | ||
Procedure Index | ||
Concept Index | ||
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Guile-SSH is a library that provides access to the SSH protocol for programs written in GNU Guile. It is a wrapper to the underlying libssh library. This manual is partly based on libssh documentation.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Most projects are humble, it’s the combination that’s interesting :-)
— Ludovic Courtès
Now let me explain what are the goals of the whole project. Aside from the fact that I am having lots of fun with the project itself (and the project is helping me to grow as a free software developer, many thanks to all advices and comments from the community!), there are practical goals that the project struggling to achieve.
For me, the main goal is to provide convenient means to write truly distributed applications in my favourite programming language.
Computers are getting cheaper and more and more ubiquitous, and so different kind of networks. In my opinion the question is – how we are going to utilize those new computational resources? Using multi-core systems effectively may be tricky; fortunately some languages (such as Scheme/GNU Guile) already provide convenient API to utilize those systems. But what about systems that distributed over a network?
I am dreaming of the times when using computer resources distributed over a network in GNU Guile will be as easy as using local ones. You should not be asking question “how to do it?” – what you should be asking yourself is “how can I use it?”
But Guile-SSH itself is just a library; a tool that can be used to solve some problems (and, perhaps, to cause new ones ;-)). So, as was noted in the quotation above, it’s the combination of projects that may lead to the most interesting results. With that said, I would love to see Guile-SSH used in another projects, and to hear positive (and negative) feedback from you.
Happy hacking!
- avp
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The latest stable Guile-SSH is available from GNU Guix repository:
$ guix install guile-ssh
If you want to get the environment for Guile-SSH development there’s
‘guix.scm’ file in the root of the repository that can be used with
guix shell
:
$ guix shell -D -f ./guix.scm
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
$ sudo apt install guile-ssh
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Guile-SSH is also available from the default repositories at least on the following platforms:
Please refer to the official document for each platform for the instructions on how to install the package.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Guile-SSH sources are available from GitHub at https://github.com/artyom-poptsov/guile-ssh/. This section describes requirements of Guile-SSH and the manual installation process.
Guile-SSH depends on the following packages:
Get the sources of Guile-SSH from GitHub:
$ git clone git@github.com:artyom-poptsov/guile-ssh.git
Configure the sources:
$ cd guile-ssh/ $ autoreconf -if $ ./configure
Build and install the library:
$ make $ make install
For a basic explanation of the installation of the package, see the ‘INSTALL’ file.
Please note that you will need
Automake version 1.12 or
later to run self-tests with make check
(but the library
itself can be built with older Automake version such as 1.11).
important You probably want to call configure
with
the ‘--with-guilesitedir’ option so that this package is
installed in Guile’s default path. But, if you don’t know where your
Guile site directory is, run configure
without the option,
and it will give you a suggestion.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
3.1 Sessions | Session management | |
3.2 Auth | Authentication procedures | |
3.3 Agent | Interaction with SSH agent instances. | |
3.4 Keys | Public and private keys | |
3.5 Channels | Channel manipulation procedures | |
3.6 Tunnels | SSH tunnels | |
3.7 Remote Pipes | Creating of input, output or bidirectional pipes to remote processes | |
3.8 Shell | A high-level interface to remote shell built upon remote pipes | |
3.9 Logging | Interface to the libssh logging | |
3.10 Version | Get information about versions | |
Guile-SSH Server API | ||
---|---|---|
3.11 Servers | Creating and managing Guile-SSH servers | |
3.12 Messages | Handling of messages | |
SFTP | ||
3.13 SFTP | Guile-SSH SFTP client API. | |
Distributed Computing | ||
3.14 Distributed Forms | ||
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
3.1.1 Session Management | ||
3.1.2 Callbacks |
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A session is an object that holds all the information about connection to a specified server or a client. This information includes server’s port and address, name of the user, compression level, private keys and so on.
A session may contain zero or more channels (see section Channels). Channels are “pipes” that link the client and the server together and that can be used for transferring of data in both directions.
So the overall picture can be thought like this:
[client] [server] \____________________________/ SSH session ============================ ============================ SSH channels ============================ ____________________________ / \
libssh docs say that there is no limit to number of channels for a single session in theory.
This chapter describes session management. The code is in the
(ssh session)
module.
Returns #t
if x is a Guile-SSH session, #f
otherwise.
Create a new Guile-SSH session.
Create a new Guile-SSH session and set its options. Options can be passed as keywords.
Return a new Guile-SSH session.
This procedure is more convenient than primitive %make-session
,
but on other hand it should be a bit slower because of additional
checks.
Example:
(let ((s (make-session #:user "alice" #:host "example.com" #:port 12345 #:identity "/home/alice/.ssh/id_rsa" #:log-verbosity 'nolog))) ...)
List of allowed keywords:
Preferred public key algorithms to be used for authentication (comma-separated list as a string). Example: “ssh-rsa,rsa-sha2-256,ssh-dss,ecdh-sha2-nistp256”
This option available only in libssh 0.8.3 or later versions.
Blocking flush of the outgoing buffer of session. Return on of the following symbols:
Success.
timeout occurred.
An error occurred.
Set a option to value
for the given Guile-SSH
session. Throw a guile-ssh-error
on error. Return value
is undefined.
Here is the description of available options. The description is based on libssh documentation:
The hostname or IP address to connect to.
Expected type of value: string.
The port to connect to.
Expected type of value: number.
The file descriptor to use.
If you wish to open the socket yourself for a reason or another, set the file descriptor. Don’t forget to set the hostname as the hostname is used as a key in the known_host mechanism.
Expected type of value: number.
The address to bind the client to.
Expected type of value: string.
The username for authentication.
Expected type of value: string.
Set the SSH directory.
The ssh directory is used for files like known_hosts and identity
(private and public key). It may include %s
which will be
replaced by the user home directory.
Expected type of value: string.
Set the identity file name. By default identity, ‘id_dsa’ and ‘id_rsa’ are checked.
The identity file used authenticate with public key. It may include
%s
which will be replaced by the user home directory.
Set the known hosts file name. Default value is ‘~/.ssh/known_hosts’.
The known hosts file is used to certify remote hosts are genuine. The
string may include %s
which will be replaced by the user home
directory.
Expected type of value: string.
Set a timeout for the connection in seconds.
Expected type of value: number.
Set a timeout for the connection in micro seconds.
Expected type of value: number.
Allow or deny the connection to SSH1 servers.
Expected type of value: boolean.
Allow or deny the connection to SSH2 servers
Expected type of value: boolean.
Set the session logging verbosity. Possible values:
No logging at all
Only rare and noteworthy events
High level protocol information
Lower level protocol infomations, packet level
Every function path
Expected type of value: symbol.
Set the symmetric cipher client to server. The value must be a string of comma-separated values.
Set the symmetric cipher server to client. The value must be a string of comma-separated values.
Set the compression to use for client to server. The value must be “yes”, “no” or a specific algorithm name if needed ("zlib", "zlib@openssh.com", "none").
Expected type of value: string.
Set the compression to use for server to client. The value must be “yes”, “no” or a specific algorithm name if needed ("zlib", "zlib@openssh.com", "none").
Expected type of value: string.
Set the command to be executed in order to connect to server.
Expected type of value: string.
Set the parameter StrictHostKeyChecking
to avoid asking about a
fingerprint.
Set the compression to use for both directions communication. The value must be “yes”, “no” or a specific algorithm name if needed ("zlib", "zlib@openssh.com", "none").
Expected type of value: string.
Set the compression level to use for zlib functions. The value is expected to be a number from 1 to 9, 9 being the most efficient but slower.
Set callbacks that will be called on related events (see section Callbacks.)
Expected type of value: an association list (alist).
The option specifies whether an SSH config should be parsed or not, and optionally the path to a config file.
Setting the value to #t
means that the default
‘~/.ssh/config’ should be parsed; in turn, setting the option to
#f
(the default value) means that the config should not be parsed at
all. If the value is a string, then the string is expected to be a path to
config file.
The procedure reads the config file after all other specified options are set. When the config file is read, the options for session are set, overwriting those that were passed to the procedure.
You must specify at least a host name when using this option, otherwise the procedure will fail.
Optionally you could use session-parse-config!
procedure explicitly to
read the config (see below.)
Expected types of value: Either a string or a boolean value.
Parse an SSH config file-name and set session options. If
file-name is not set, the default SSH ‘~/.ssh/config’ is used.
Throw guile-ssh-error
on an error. Return value is undefined.
Get value of the option for session. The option is expected to be a symbol.
Please not that currently not all the possible session options can be gotten with this procedure. Here is the list of allowed options:
Connect session to a SSH server. Return one of the following symbols:
ok
, again
, error
.
Disconnect the session. This procedure can be used by a client as well as by a server.
Authenticate the server.
Throw wrong-type-arg
exception if a disconnected session is
passed as an argument.
Return one of the following symbols:
The server is known and has not changed.
The server key has changed. Either you are under attack or the administrator changed the key. You have to warn the user about a possible attack.
The server gave use a key of a type while we had an other type recorded. It is a possible attack.
The server is unknown. User should confirm the MD5 is correct.
The known host file does not exist. The host is thus unknown. File will be created if host key is accepted.
An error occurred.
Get server public key from a session. Return the server’s
public key. Throw guile-ssh-error
on error.
Also throw wrong-type-arg
exception if a disconnected session is
passed as an argument.
See also get-public-key-hash
in see section Keys.
Write the current server as known in the known hosts file. Throw
guile-ssh-error
on error. Throw wrong-type-arg
exception if a
disconnected session is passed as an argument. Return value is undefined.
Check if we are connected. Return #f
if we are connected to a
server, #f
if we aren’t.
Retrieve the error text message from the last error related to session.
Get version of SSH protocol. Return 1 for SSH1, 2 for SSH2 or
#f
on error.
Throw wrong-type-arg
exception if a disconnected session is
passed as an argument.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Guile-SSH uses an association list (alist) to represent session callbacks; the key is a callback name, and the value is expecting to be a procedure.
Session callbacks is the way to handle some events, notably the incoming
reverse port forwarding requests on the server side. Each callback is called
with the optional user-data
argument which can be specified in the
callbacks alist as well.
A server-side callback that is called on a global request (e.g. when an SSH client asks for reverse port forwarding.)
The callback should be set on an accepted Guile-SSH session (see section Servers) in case when global requests must be handled; note that if the callback is not set then the server will always deny global requests, which may be confusing.
Example:
(define (handle-global-request session message user-data) (let ((port-number 12345)) (message-reply-success message port-number))) ;; Let's suppose that the session was created earlier. ;; Now we can set our callback: (session-set! session 'callbacks `((user-data . #f) (global-request-callback . ,handle-global-request))) ;; Note that 'user-data' is optional, so the following example ;; is valid: (session-set! session 'callbacks `((global-request-callback . ,handle-global-request)))
This callback is called during connection establishment process (that is,
after connect!
is called) with a server. A connection status is
a number that shows what percentage of connection esablishment is done.
Example:
(define (print-status session status user-data) (let ((percentage (truncate (* status 100)))) (format #t "~a: connecting ... ~a%~%" session percentage))) ;; Let's suppose that the session was created earlier. (session-set! session 'callbacks `((user-data . #f) (connect-status-callback . ,print-status))) ;; Or we can set two callbacks simultaneously: (define (handle-global-request session message user-data) (let ((port-number 12345)) (message-reply-success message port-number))) (session-set! session 'callbacks `((user-data . #f) (connect-status-callback . ,print-status) (global-request-callback . ,handle-global-request)))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh auth)
module provides authentication procedures for a
Guile-SSH client.
Please note that you must specify a username either on creation of a
session or by session-set!
call (see section Sessions) before
calling of procedures from this section.
Also note that the session must be connected before calling to these
procedures, otherwise the wrong-type-arg
exception will be thrown.
Try to authenticate with a public/private key.
Return one of the following symbols:
Authentication success.
You’ve been partially authenticated, you still have to use another method.
Authentication failed: use another method.
A serious error happened.
Try to automatically authenticate with none
method first and
then with public keys. The procedure will try to get a cached private
key from a SSH agent and if it fails it will try to read a
key from a file. If the key is encrypted the user will be asked for a
passphrase.
Return one of the following symbols:
Authentication success.
You’ve been partially authenticated, you still have to use another method.
Authentication failed: use another method.
A serious error happened.
Try to authenticate with the given public-key.
To avoid unnecessary processing and user interaction, the following method is provided for querying whether authentication using the public-key would be possible.
Return one of the following symbols:
The public key is accepted, you want now to use
userauth-public-key!
.
You’ve been partially authenticated, you still have to use another method.
Authentication failed: use another method.
A serious error happened.
Try to do public key authentication with ssh agent.
Return one of the following symbols:
Authentication success.
You’ve been partially authenticated, you still have to use another method.
Authentication failed: use another method.
A serious error happened.
Try to authenticate by password.
Return one of the following symbols:
Authentication success.
You’ve been partially authenticated, you still have to use another method.
Authentication failed: use another method.
A serious error happened.
In nonblocking mode, you’ve got to call this again later.
Try to authenticate through the gssapi-with-mic
method.
Return one of the following symbols:
Authentication success.
You’ve been partially authenticated, you still have to use another method.
In nonblocking mode, you’ve got to call this again later.
Authentication failed: use another method.
A serious error happened.
Try to authenticate through the none
method.
Return one of the following symbols:
Authentication success.
You’ve been partially authenticated, you still have to use another method.
In nonblocking mode, you’ve got to call this again later.
Authentication failed: use another method.
A serious error happened.
Get available authentication methods for a session. Return list of available methods.
This call will block, even in nonblocking mode, if run for the first
time before a (complete) call to userauth-none!
.
Possible methods are: password
, public-key
,
host-based
, interactive
.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh agent)
module provides procedures for interacting with SSH
authentication agent instances.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Start an OpenSSH agent. Return a list with SSH agent information of the following form:
'((SSH_AUTH_SOCK . <agent-socket-file-path>) (SSH_AGENT_PID . <agent-pid>))
Kill the current agent (given by the SSH_AGENT_PID
environment
variable).
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The procedure tries to find information about all running SSH authentication agent instances by searching the specified path for a given user.
The agent subdirectory pattern is used as specified in the ssh-agent
man page: ssh-XXXXXXXXXX/agent.<ppid>
Returns an associative list of the following form:
'(((SSH_AUTH_SOCK . <agent-socket-file-path-1>) (SSH_AGENT_PID . <agent-pid-1>)) ((SSH_AUTH_SOCK . <agent-socket-file-path-2>) (SSH_AGENT_PID . <agent-pid-2>)) ...)
One might use the procedure to configure the environment in a REPL to use SSH
userauth-agent!
procedure later:
(define s (make-session #:host "localhost")) (connect! s) (ssh-agent-sock-set! (assoc-ref (car (ssh-agent-info)) 'SSH_AUTH_SOCK)) (userauth-agent! s) (with-ssh (make-node s) (version))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Get the SSH__AGENT__SOCK
environment variable value.
Set the value of SSH__AGENT__SOCK
environment variable to the
sock-file.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh key)
module provides procedures for handling of
Guile-SSH keys.
Note that Guile-SSH does not support ECDSA keys if libssh 0.6.3 is compiled with GCrypt instead of OpenSSL.
Generate a keypair of specified type and length (in bits). This may take some time.
Possible key types are: dss
, rsa
, rsa1
, ecdsa
.
Return newly generated private key. Throw guile-ssh-error
on error.
Return #t
if x is a Guile-SSH key, #f
otherwise.
Return #t
if x is a Guile-SSH key and it contains a
public key, #f
otherwise. What it means is that the procedure will
return #t
for a private key too (because the private key contains a
public key in some sense).
Return #t
if x is a Guile-SSH private key, #f
otherwise.
Convert public-key to a string.
Convert a public key of type represented as Base64 string
to a Guile-SSH key. Throw guile-ssh-error
on error.
The type must be one of the following symbols: dss
,
rsa
, rsa1
, ecdsa
Read private key from a file. If the the key is encrypted the user will be asked using auth-callback for passphrase to decrypt the key. When auth-callback is called, user-data is passed to it as an argument. If no auth-callback is provided then the procedure denies access to an encrypted key.
Return a new Guile-SSH key or #f
on error.
The procedure performs auth-callback call as follows:
(auth-callback prompt maximum-password-length echo? verify? user-data)
Where prompt
is a string that specifies the password prompt to use.
The callback must return either a password as a string or #f
if access
must be denied.
Usage example:
(use-modules (ssh key)) (define (callback prompt max-len echo? verify? user-data) (getpass (format #f "~a: " prompt))) (define key (private-key-from-file (string-append (getenv "HOME") "/.ssh/id_rsa") #:auth-callback callback))
Export private-key to a PAM file file-name on a disk. Throw
guile-ssh-error
on error. Return value is undefined.
Note that this procedure won’t work if libssh 0.6.3 is compiled with GCrypt cryptographic library.
Get a public key from the private-key.
Read public key from a file. Return a public key or #f
on error.
Get a symbol that represents the type of the Guile-SSH key.
Possible types are: dss
, rsa
, rsa1
, unknown
.
Get a public-key hash of type as a bytevector. Return the
bytevector on success, #f
on error.
See also get-server-public-key
in see section Sessions.
The type can be one of the following symbols: md5
,
sha1
.
Example:
(let ((pubkey (get-server-public-key session))) (get-public-key-hash pubkey 'md5)) ⇒ #vu8(15 142 110 203 162 228 250 211 20 212 26 217 118 57 217 66)
Convert the given bytevector bv to a colon separated string.
Example:
(let ((hash (get-public-key-hash pubkey 'md5))) (bytevector->hex-string hash)) ⇒ "0f:8e:6e:cb:a2:e4:fa:d3:14:d4:1a:d9:76:39:d9:42"
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
3.5.1 Channel Management | ||
3.5.2 Port Forwarding |
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh channel)
module provides facilities to create
Guile-SSH channels and manipulating of them.
Channels are implemented as GNU Guile ports. Therefore they can be
used with regular I/O procedures such as display
, write
,
read-line
and friends (see Input and Output in The GNU Guile Reference Manual). This section describes operations that
are specific for the channels.
When a channel is closed by the remote side, the local side detects it; reading from such channel gives an EOF object when all data is read.
Note that when the parent session from which a channel is made is freed the channel is freed as well.
Return #t
if x is a Guile-SSH channel, #f
otherwise.
Allocate a new Guile-SSH channel for the session (see section Sessions).
flags are determine what kind of a channel should be created. Possible
modes are: OPEN_READ
, OPEN_WRITE
, OPEN_BOTH
. They allow
to create either an input channel, output channel or input/output channel
respectively.
Open a session channel. This procedure actually turn the
channel into an open port available for I/O operations. Throw
guile-ssh-error
on error. Return value is undefined.
Return #t
if a channel is open, #f otherwise. Note that this procedure
also returns #f
when the remote side is closed.
Run a shell command without an interactive shell. The channel
must be open. Throw guile-ssh-error
on error. Return value is
undefined.
This procedure is a low-level one and you should use remote pipes instead (see section Remote Pipes).
Note that the procedure only can be used to execute a single command
on the remote host, so you should close the channel after
channel-request-exec
. If you want to execute another command then you
must open a new channel and use it.
Example:
(let ((channel (make-channel session))) (channel-open-session channel) (channel-request-exec channel "uname") (read-line channel)) ⇒ "Linux"
Request a PTY (pseudo terminal). Throw guile-ssh-error
on
error. The channel must be open. Return value is undefined.
Request a shell. The channel must be open. Throw
guile-ssh-error
on error. Return value is undefined.
Set an environment variable to value. Throw
guile-ssh-error
on error. The channel must be open. Return
value is undefined.
Send an exit-status to the remote process (as described in RFC 4254, section 6.10). Only SSH-v2 is supported. Return value is undefined.
The channel needs to be closed with after this message.
Change size of the PTY to columns and rows. The channel must be open. Return value is undefined.
Set default stream for channel. stream must be one of the
following symbols: stdout
(default), stderr
. The channel
must be open. Throw guile-ssh-error
on error. Return value is
undefined.
Example:
(channel-set-stream! channel 'stderr)
Get current stream name from channel. The channel must be open.
Throw guile-ssh-error
on error. Return one of the following symbols:
stdout
, stderr
.
Example:
(channel-get-stream channel) ⇒ 'stderr
Get the session to which belongs the channel. Throw
guile-ssh-error
on an error. Return the session.
Send an end of file (EOF) on the channel. This action doesn’t close the
channel; you may still read from it but not write. Throw
guile-ssh-error
on an error. Return value is undefined.
Example:
(use-modules (ice-9 rdelim) ;; Guile-SSH modules. (ssh auth) (ssh popen) (ssh session) (ssh channel)) ;; Make a session (define s (make-session #:host "example.org")) ;; Connect to the server (connect! s) ;; Authenticate (userauth-agent! s) ;; Open a remote pipe to 'wc' command running on ;; the server. (let ((p (open-remote-pipe s "wc" OPEN_BOTH))) ;; Send data to 'wc' command using the remote pipe. (display "Hello Scheme World!" p) ;; 'wc' reads data until EOF and writes its result ;; afterwards. (channel-send-eof p) ;; Read the 'wc' output. (read-line p)) ⇒ " 0 3 19"
Return #t
if remote has sent EOF, #f
otherwise. Throw
guile-ssh-error
if the channel has been closed and freed.
Get the exit status of the channel (error code from the executed
instruction). The channel must be open. Return the exist status, or
#f
if no exit status has been returned (yet). Throw
guile-ssh-error
on error.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Low-level API from (ssh channel)
module to manage SSH port
forwarding. These procedures do not bind the ports and do not
automatically forward the content of a socket to the channel. You should
either implement binding and data forwarding in your application or use the
tunnel API (see section Guile-SSH tunnel API)
Open a (local) TCP/IP forwarding channel. Connect to a remote-host and remote-port, and use source-host and local-port as origination of connections.
The procedure returns one of the following symbols:
Success.
We are in the nonblocking mode and the call to be done again.
An error occurred.
The local port forwarding works as follows:
local-host remote-host ,..............., ,................. : : : : : [a browser] : : [a web server] : : | : : A : : | : : | : : port 8080 : : port 80 : : | : : | : : V : : | : : [SSH client]===========>[SSH server] : : : : : '...............' '................'
Where port 8080 is an arbitrary local-port and port 80 is a remote-port.
Also in our case, “SSH client” is an application that uses Guile-SSH and
calls channel-open-forward
.
Example:
(channel-open-forward channel #:local-port 8080 #:remote-host "www.example.org" #:remote-port 80)
Start a TCP/IP reverse (remote) port forwarding. Send the “tcpip-forward” global request using session to ask the server to begin listening for inbound connections on the specified address and port.
If address is not specified (or set to #f
) then the server binds
all addresses on all protocol families supported by the server. When 0 is
passed as a port then server allocates the next unprivileged port.
The procedure returns two values: the first value is the result of the operation, and the second value is the bound port number; if port was set to 0 then the procedure returns the chosen port number.
The result of the operation can be one of the following symbols:
Success.
We are in the nonblocking mode and the call to be done again.
An error occurred.
Reverse port forwarding looks as follows:
local-host remote-host ,................, ,................. : : : : : [a web server] : : [a browser] : : A : : | : : | : : | : : port 80 : : port 8080 : : | : : | : : | : : V : : [SSH client]<===========[SSH server] : : : : : '................' '................'
Accept an incoming TCP/IP forwarding channel and get information about incoming connection. Return two values: the first value is the incoming channel, and the second value is a port number on which the connection was issued.
Send “cancel-tcpip-forward” global request to session to ask the server to cancel a “tcpip-forward” request on the bound address and port.
The result of the operation can be one of the following symbols:
Success.
We are in the nonblocking mode and the call to be done again.
An error occurred.
Here’s an example Guile program that uses channel-cancel-forward
to
cancel reverse port forwarding on a server:
#!/usr/bin/guile \ -e main !# (use-modules (ssh session) (ssh auth) (ssh channel)) (define (main args) (let ((session (make-session #:user "alice" #:host "127.0.0.1" #:port 22 #:log-verbosity 'rare))) (connect! session) (userauth-agent! session) ;; Send "tcpip-forward" request to an SSH server (channel-listen-forward session #:address "localhost" #:port 12345) ;; Accept incoming reverse port forwarding requests with ;; 'channel-accept-forward' in some kind of loop... ;; Cancel the issued "tcpip-forward" request with ;; "cancel-tcpip-forward" request (channel-cancel-forward session "localhost" 12345)))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following procedures from (ssh tunnel)
module are a high-level API
built upon the basic port forwarding facilities for managing port forwards.
Make a new SSH tunnel using session from bind-address and port to a host and host-port.
The procedure is capable of creating both direct and reverse port forwarding
tunnels; the type of a tunnel is determined by reverse? argument. If
reverse? is set to #f
then a reverse port forwarding tunnel will
be created.
Setting reverse? to #t
changes the direction of the tunnel and a
reverse port forwarding tunnel will be created. In this case a server
allocates a socket to listen to port on the remote side, and whenever a
connection is made to this port, the connection is forwarded over the secure
channel, and a connection is made to host and host-port from the
local machine. host can be set to #f
to tell the server to
listen on all addresses and known protocol families. Setting a port to
0 tells the server to bind the first unprivileged port.
The procedure does not binds ports nor transfers data to the port (in case of
reverse port forwarding), you should start port forwarding by means of the
procedures that operate on a <tunnel> object – e.g. start-forward
or
call-with-ssh-forward
.
Return a new tunnel object.
Return #t
if x is an Guile-SSH tunnel, #f
otherwise.
Check if x is a reverse port forwarding tunnel.
Get a session associated with a tunnel.
Get a source host of a tunnel.
Get a local port of a tunnel.
Get a remote host of a tunnel.
Get a remote port of a tunnel.
Start port forwarding on tunnel. The procedure actually binds tunnel ports and forwards data.
Open a new tunnel and start port forwarding. proc is called with an open channel as an argument. All I/O on the channel will be forwarded to the remote host and port of a tunnel. Return the result the proc call.
As a practical example, let’s say you want to use
Guile-RPC over SSH. Here’s how
you can implement a using call-with-ssh-forward
:
(let ((pid (primitive-fork))) (if (zero? pid) ;; Make a new SSH session, connect it and authenticate the user. (let* ((host "example.org") (user "alice") (session (make-session #:user user #:host host #:port 22 #:log-verbosity 'nolog))) (connect! session) (userauth-agent! session) ;; Make a new SSH tunnel. (let ((tunnel (make-tunnel session #:port 12345 ;; Guile-RPC server listens on 127.0.0.1 ;; on the remote host. #:host "127.0.0.1" ;; Guile-RPC server port. #:host-port 6666))) ;; Start the forwarder loop. (start-forward tunnel))) ;; Parent process. (let ((sock (socket PF_INET SOCK_STREAM 0))) (dynamic-wind (const #t) (lambda () (sleep 1) ;; Connect to the port that is listened to by the spawned process. (connect sock AF_INET (inet-pton AF_INET "127.0.0.1") 12345) ;; Make an RPC call using the SSH tunnel. (display (invoke-split-number 3.14 #x7777 sock)) (newline)) (lambda () (close sock) (kill pid SIGTERM) (waitpid pid))))))
The full example of an RPC client that uses a SSH tunnel is in ‘$prefix/share/guile-ssh/examples/rpc’ directory.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Here is a simple Guile program that connects to “www.example.org” and starts port forwading from the local port 8080 to the port 80 on the remote host:
#!/usr/bin/guile \ -e main !# (use-modules (ssh session) (ssh auth) (ssh key) (ssh tunnel)) (define (main args) (let ((s (make-session #:user "alice" #:host "localhost" #:port 22 #:log-verbosity 'nolog)) (k (private-key-from-file "/home/alice/.ssh/id_rsa"))) (connect! s) (userauth-public-key! s k) (let ((t (make-tunnel s #:port 8080 #:host "www.example.org" #:host-port 80))) (start-forward t))))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
(ssh popen)
provides API for working with remote pipes, akin to
(ice-9 popen)
procedures (see Pipes in The GNU Guile Reference Manual)
mode argument allows to specify what kind of pipe should be created.
Allowed values are: OPEN_READ
, OPEN_WRITE
, OPEN_BOTH
.
There is an additional value, OPEN_PTY
, that allows to request a pseudo
terminal. The terminal is needed to run such commands as top
. Thus,
to run top
on the remote side you need to open a remote pipe with "t"
flag set.
Note that when a PTY is used, a server merges stderr stream with stdout.
Values of the aforementioned constants:
“r”
“w”
“r+”
“t”
Execute a command on the remote host using a session with a pipe to it. Returns newly created channel port with the specified mode.
Execute prog on the remote host with the given args using a session with a pipe to it. Returns newly created channel port with the specified mode.
Equivalent to open-remote-pipe
and open-remote-pipe*
respectively
with mode OPEN_READ
.
Equivalent to open-remote-pipe
and open-remote-pipe*
respectively
with mode OPEN_WRITE
.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Here’s a self-explanatory little script that executes uname -o
command
on the local host and prints the result:
#!/usr/bin/guile \ -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 a session with 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)))))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Surely we aren’t limited to one-line outputs; for example, we can watch
top
command executing on a remote side locally, by reading data from
the channel in a loop:
(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)))))
Or we can do the same, but this time with streams:
(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))))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To set the size of a pseudo terminal, one may use channel-set-pty-size!
from (ssh channel)
. For example:
(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 ... )
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A high-level interface to a remote shell built upon (ssh popen)
API.
The procedures described in this section uses GNU Coreutils on the remote side
and may depend on some other packages; see the notes for each procedure.
Execute a command on the remote side. Return two values: list of output lines returned by a command and its exit code.
Check if a program-name is available on a remote side. Return two values: a path to a command if it is found and a return code.
The procedure uses shell build-in command which
on the remote side.
Example:
(use-modules (ssh session) (ssh auth) (ssh shell)) (let ((s (make-session #:host "example.org"))) (connect! s) (userauth-agent! s) (which s "guile")) ⇒ ("/usr/bin/guile") ⇒ 0
Check if a command is available on a remote machine represented by a session.
Search for a process with a pattern cmdline on a machine represented by a session. Return two values: a list of PIDs and a return code.
The procedure uses a pgrep
from procps package on the remote side
when use-guile? is set to #f
(this is by default.)
When use-guile? is set to #t
, the procedure will execute a Scheme
code using GNU Guile on the remote side to kill processes.
Send a signal to a process which name matches to pattern on a remote machine represented by a session. Return two values: a list of PIDs of killed processes and a return code.
The signal must be a numeric value as for Guile kill
procedure.
The procedure uses a pkill
from procps package on the remote side
when use-guile? is set to #f
(this is by default.)
When use-guile? is set to #t
, the procedure will execute a Scheme
code using GNU Guile on the remote side to kill processes.
Get average load of a host using a session. Return a list of five elements as described in proc(5) man page.
Example:
(use-modules (ssh session) (ssh auth) (ssh shell)) (let ((s (make-session #:host "example.org"))) (connect! s) (userauth-agent! s) (loadavg s)) ⇒ ("0.01" "0.05" "0.10" "4/1927" "242011")
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh log)
module provides procedures to control the libssh logging
facilities.
Default callback for printing log messages to the current error port. The procedure comments out log messages with “;;; “ to make it easier to distinguish libssh traces from Guile-SSH messages in REPL mode.
This callback is set by default.
The procedure makes log messages in the same format as the libssh default log formatter.
Return the current logging callback. Returns a procedure or #f
if the
callback is not set.
Change the current logging callback to callback. The callback must be a procedure that takes four arguments: priority of a log message, a function name, the message and a custom user data.
Throw guile-ssh-error
on an error. Return value is undefined.
Here is an example of a custom callback which indents each log message according to its priority:
(define (pretty-log-printer priority function message userdata) (do ((i 1 (1+ i))) ((> i priority)) (display " " (current-error-port))) (format (current-error-port) "[~a] ~a~%" (strftime "%Y-%m-%dT%H:%M:%S%z" (localtime (current-time))) message)) (set-logging-callback! pretty-log-printer)
You can restore the default callback as the follows:
(set-logging-callback! %default-log-printer)
Set an arbitrary user-data to be passed to a logging callback.
Throw guile-ssh-error
on an error. Return value is undefined.
By default the user data is set to #f
.
Get the current user data.
Write a formatted message to the libssh log with the given priority. Return value is undefined.
Syntax for the format-string is the same as for format
procedure.
priority is expected to be a symbol. Acceptable priority levels are:
The message will be printed even if the logging is disabled
Rare and noteworthy events
High level protocol information
Lower level protocol infomations, packet level
Function path
Note that the procedure uses the provided logging callback directly, bypassing the libssh logging facilities.
Set the global log verbosity to a verbosity. Throw
guile-ssh-error
on error. Return value is undefined.
verbosity is expected to be one of the following symbols:
The message will be printed even if the logging is disabled
Rare and noteworthy events
High level protocol information
Lower level protocol infomations, packet level
Function path
Get global log verbosity value.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh version)
module provides functions that is used for
getting information about current versions.
Get version of the libssh. Returns libssh version as a string in the follwing format:
<version> ::= <major> "." <minor> "." <micro>
For example, ‘0.5.2’.
Low-level procedure that returns a version string in libssh format, eg. "0.6.3/openssl/zlib".
Get cryptographic library name with which libssh was compiled. Possible
values are: 'openssl
, 'gnutls
.
Return #t
if libssh was compiled wit zlib support, #f
otherwise.
Return #t
if Guile-SSH was compiled with DSA public key algorithm
support, #f
otherwise.
Get version of the Guile-SSH.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh server)
module provides facilities for creation and
managing of Guile-SSH servers.
Return #t
if x is a Guile-SSH server, #f
otherwise.
Make a new Guile-SSH server.
Make a new Guile-SSH server with the specified configuration specified by keywords. Return a new Guile-SSH server.
Example:
(let ((s (make-server #:bindport 12345 #:rsakey "/home/bob/.ssh/id_rsa" #:log-verbosity 'nolog))) ...)
Set a option to value for Guile-SSH server. Throw
guile-ssh-error
on error. Return value is undefined.
Here is the description of available options. The description is based on libssh documentation:
Set the bind address for the server.
Expected type of value: string.
Set the bind port for the server, default is 22.
Expected type of value: number.
Set the server public key type: “ssh-rsa” or “ssh-dss”.
libssh 0.7 note: you should pass a path to an ssh key for this
option. Only one key from per key type (RSA, DSA, ECDSA) is allowed in an
server at a time, and later calls to server-set!
with this option for
the same key type will override prior calls.
Expected type of value: string.
Set the path to the SSH host DSA key.
Expected type of value: string.
Set the path to the SSH host RSA key.
Expected type of value: string.
Set the server banner sent to clients.
Expected type of value: string.
Set the logging verbosity. Possible values:
No logging at all
Only rare and noteworthy events
High level protocol information
Lower level protocol infomations, packet level
Every function path
Expected type of value: symbol.
Set the server to blocking/nonblocking mode according to
value. The value is expected to be #t
or
#f
.
Expected type of value: boolean.
Get value of option for Guile-SSH server. Return option
value, or #f
if the option does not set. Throw
guile-ssh-error
on error.
Start listening to the socket. Throw guile-ssh-error
on error.
Return value undefined.
Accept an incoming SSH connection to the server.
Return a new Guile-SSH session. Throw guile-ssh-error
on error.
Example:
(let ((session (catch 'guile-ssh-error (lambda () (server-accept server)) (lambda (key . args) ;; Handle error #f)))) ...)
One of the possible causes of errors might be that your server has no access to host keys.
If you get an exception and it shows no cause of the error then try to
set log-verbosity
to a value other than nolog
(e.g. to
rare
, see server-set!
above) and check printouts from
the libssh.
Handle key exchange for a session and setup encryption. Throw
guile-ssh-error
on error. Return value is undefined.
Get a message from a SSH client (see section Messages). Return a new
Guile-SSH message, or #f
on error.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh message)
module provides procedures for handling of
Guile-SSH messages.
3.12.1 Messages Handling | ||
3.12.2 Parsing of Requests |
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A message is an object that represents a single request to a Guile-SSH
server. Basically the server handles requests in some loop in which
it accepts messages with server-message-get
procedure
(see section Servers), handles the received request and replies to the
message.
Return #t
if x a Guile-SSH message, #f
otherwise.
Reply with SSH_MSG_UNIMPLEMENTED. Throw guile-ssh-error
on error. Return value is undefined.
Reply “success” to the message. This procedure is a
convenient wrapper for other *-reply-success
procedures (see
below). The right procedure to use will be selected depending on a
type of the message
. The procedure may take additional
argument 'partial
for that changes reply to authentication
request, and a bound-port
for a global request.
Throw an exception on error. Return value is undefined.
Reply with “success” status on the service-request message.
Throw guile-ssh-error
on error. Return value is undefined.
Reply with “success” on the auth-request message. Throw
guile-ssh-error
on error. Return value is undefined.
Reply “success” on a channel-request message.
Throw guile-ssh-error
on error. Return value is undefined.
Reply “success” on a global request message. Throw
guile-ssh-error
on error. Return value is undefined.
Reply “OK” on the public key auth-request message. Throw
guile-ssh-error
on error. Return value is undefined.
Accept open-channel request. Return a new Guile-SSH channel, or
#f
on error.
Get type of the message in the following format:
<msg-type> = "'(" <type> [<WSP> <subtype>] ")"
The procedure returns #f
on error.
Example:
(message-get-type msg) ⇒ '(request-auth auth-method-none)
Possible types:
Subtypes:
Subtypes:
Subtypes:
Subtypes:
Get a request object from the message. Returns a new request
object (see section Parsing of Requests). Throw guile-ssh-error
on
error.
Set authentication methods to methods-list. Possible methods
are: password
, public-key
, interactive
,
host-based
. Throw guile-ssh-error
on error. Return
value is undefined.
Get the session from which the message was received. Return the session.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Get service name from a service request.
Get originator, originator-port, destination and destination-port from the channel-open request.
Get user, password, public key and public key state from the auth request.
Get terminal, terminal width, terminal height, terminal pxwidth and terminal pxheight from the PTY request.
Get environment variable name and its value from the environment request.
Get a command from the exec request.
Get address and port from the global request.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh sftp)
module provides procedures for working with SFTP (Secure File Transfer Protocol).
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Make a new SFTP session using a ssh-session, initialize the session with
a server. Return initialized SFTP session or throw guile-ssh-error
exception on an error.
Return #t
if x is a SFTP session, #f
otherwise.
Get the parent SSH session for a sftp-session.
Get the last SFTP error from a sftp-session. Return the error name as a
symbol, or throw guile-ssh-error
on if an error occurred in the
procedure itself.
The procedure returns one of the following values:
No error.
End-of-file encountered.
File doesn’t exist.
Permission denied.
Generic failure.
Garbage received from the server.
No connection has been set up.
There was a connection, but we lost it.
Operation not supported by the server.
Invalid file handle.
No such file or directory path exists.
An attempt to create an already existing file or directory has been made.
We are trying to write on a write-protected filesystem.
No media in remote drive.
Create a directory dirname using a sftp-session with a mode. If the mode is omitted, the current umask value is used.
Remove a directory dirname. Throw guile-ssh-error
on an error.
Return value is undefined.
Move or rename a file source into a dest. Throw
guile-ssh-error
on an error. Return value is undefined.
Create a symbolic link to a target in a dest. Throw
guile-ssh-error
on an error. Return value is undefined.
Read the value of a symbolic link pointed by a path. Return the value
or #f
on an error.
Change permissions of a remote filename using sftp-session.
Permissions are set to mode & ~umask
. Throw guile-ssh-error
on
an error. Return value is undefined.
Unlink (delete) a remote filename using sftp-session. Throw
guile-ssh-error
on an error. Return value is undefined.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Make a new SFTP session using a ssh-session without initialization of
the session with a server. Throw guile-ssh-error
exception on an
error.
Note that you should call %sftp-init
on the returned SFTP session before
using it.
Initialize a sftp-session with the server. Throw guile-ssh-error
exception on an error, return value is undefined.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Remote files are represented as regular Guile ports that allow random access (see Input and Output in The GNU Guile Reference Manual.)
Open a remote filename using an sftp-session, return an open file
port. Throw guile-ssh-error
on an error.
Return #t
if x is an SFTP file port, #f
otherwise.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Those procedures allow to read directory contents on the remote side.
Check if an x is an SFTP directory instance. Return #t
if it is,
#f
otherwise.
Open a remote directory with the specified path using sftp-session. Return an SFTP directory as opaque object.
Open a remote directory with the specified path using sftp-session. Return an ice-9 stream of SFTP file attributes.
Usage example:
(use-modules (ice-9 streams) (ice-9 pretty-print) (ssh session) (ssh auth) (ssh sftp)) (define (main args) (let ((session (make-session #:host "example.org" #:user "avp"))) (connect! session) (userauth-agent! session) (let* ((sftp-session (make-sftp-session session)) (stream (sftp-dir-open-stream sftp-session "/tmp/"))) (stream-for-each (lambda (attrs) (pretty-print attrs)) stream))))
Get the path associated with an sftp-directory.
Get the parent SFTP session for an sftp-directory.
Close an sftp-directory. Return value is undefined.
CHeck if an sftp-directory pointed to an EOF object.
Read an sftp-directory. Return an alist with the next directory attributes.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Call a proc with a remote file port opened for input using an sftp-session. proc should be a procedure of one argument, filename should be a string naming a file. The behaviour is unspecified if a file already exists.
The procedure calls proc with one argument: the port obtained by opening the named remote file for input.
If the procedure returns, then the port is closed automatically and the values yielded by the procedure are returned. If the procedure does not return, then the port will not be closed automatically unless it is possible to prove that the port will never again be used for a read or write operation.
Call a proc with a remote file port opened for output using an sftp-session. proc should be a procedure of one argument, filename should be a string naming a file. The behaviour is unspecified if a file already exists.
The procedure calls proc with one argument: the port obtained by opening the named remote file for output.
If the procedure returns, then the port is closed automatically and the values yielded by the procedure are returned. If the procedure does not return, then the port will not be closed automatically unless it is possible to prove that the port will never again be used for a read or write operation.
thunk must be a procedure of no arguments, and filename must be a
string naming a file. The file must already exist. The file is opened for
input, an input port connected to it is made the default value returned by
current-input-port
, and the thunk is called with no arguments.
When the thunk returns, the port is closed and the previous default is
restored. Returns the values yielded by thunk. If an escape procedure
is used to escape from the continuation of these procedures, their behavior is
implementation dependent.
Example:
(define (rcat user host filename) "Print contents of a remote file on a HOST pointed by a FILENAME to stdout." (let ((session (make-session #:user user #:host host))) ;; Connect to an SSH server. (connect! session) (authenticate-server session) ;; Authenticate with an SSH server using a SSH agent. (userauth-agent! session) (let ((sftp-session (make-sftp-session session))) ;; Read read a file line-by-line and print it to stdout. (with-input-from-remote-file sftp-session filename (lambda () (do ((line (read-line) (read-line))) ((eof-object? line)) (write-line line)))))))
thunk must be a procedure of no arguments, and filename must be a
string naming a file. The effect is unspecified if the file already exists.
The file is opened for output, an output port connected to it is made the
default value returned by current-output-port
, and the thunk is
called with no arguments. When the thunk returns, the port is closed
and the previous default is restored. Returns the values yielded by
thunk. If an escape procedure is used to escape from the continuation
of these procedures, their behavior is implementation dependent.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The (ssh dist)
module provides the spirit of distributed computing for
Guile.
To make use of the procedures listed in this section you will need an SSH daemon and a GNU Guile REPL server both running on the remote host.
Also note that currently there may be cases in which distributed procedures
may fail to (de)serialise data; namely make-vector
is one of such
procedures which output may be troublesome for with-ssh
. To overcome
this specific case one could pass the fill
argument to
make-vector
to fill the newly created vector with the specified filling
instead of #<unspecified>
.
Node management procedures:
Make a new node that uses an SSH session to connect to a repl-port number on the remote side. Return a new node.
If start-repl-server? is set to #t
(which is by default) then
start a REPL server on a remote host automatically in case when it is not
started yet.
If stop-repl-server? is set to #t then a REPL server will be stopped as
soon as an evaluation is done. Alternatively you could use
node-stop-server
procedure from (ssh dist node)
to stop the
server when it is not needed anymore.
Note that when either start-repl-server? or stop-repl-server? are
specified, Guile-SSH tries to use pgrep
/pkill
from
procps package first to start/stop
a remote Guile process, but if the package is missing then the Guile-SSH falls
back to its own implementation of the commands (for more details see
see section Guile-SSH shell API)
Return #t
if x is a node object, #f
otherwise.
Get underlying SSH session from node.
Get REPL port number from a node.
Get average load of a node. Return multiple values. The 1st value is
an alist of five elements as described in proc(5) man page. The rest of
values are as described in documentation for node-eval
procedure.
For example:
(use-modules (ssh auth) (ssh session) (ssh dist node)) (let ((s (make-session #:host "example.org"))) (connect! s) (userauth-agent! s) (let ((n (make-node s))) (node-loadavg n))) ⇒ ((one . 0.15) (five . 0.14) (fifteen . 0.16) (scheduling-entities 1 189) (last-pid . 15629)) ⇒ 1 ⇒ "(guile-user)" ⇒ "scheme"
Interaction with remote REPLs:
Evaluate each expr in parallel, using distributed computation. Split the job to nearly equal parts and hand out each of resulting sub-jobs to nodes list. Return the results of N expressions as a set of N multiple values (see Multiple Values in The GNU Guile Reference Manual).
Do list mapping using distributed computation. Split the work into nearly equal parts and hand out the resulting jobs to nodes list. Return the result of computation.
If for some reason a job could not be executed on a node (for example, if
connection to a remote REPL fails), dist-map
transfers the job to
another node from the nodes list. When job execution failed on all
nodes, an error is reported.
In a case when an error that occurred during job execution is considered non-recoverable (eg. when evaluation of proc on a node failed due to an unbound variable) then execution of a job stops immediately.
Evaluate expressions on a remote REPL using a node, return four values:
an evaluation result, a number of the evaluation, a module name and a language
name. Throw node-error
or node-repl-error
on an error.
Example:
(use-modules (ssh session) (ssh auth) (ssh dist)) (let ((session (make-session #:user "alice" #:host "www.example.org"))) (connect! session) (userauth-agent! session) (display (with-ssh (make-node session) (gethostname))) (newline))
If an expression is evaluated to multiple values then the 1st value returned
by with-ssh
will be a vector of the evaluated values and the 2nd value
will be a vector of evaluation numbers. In this case the 2nd value can be
used to check whether with-ssh
body evaluated to multiple values or
not. For example:
(use-modules (ssh session) (ssh auth) (ssh dist)) (let ((session (make-session #:user "alice" #:host "www.example.org"))) (connect! session) (userauth-agent! session) (with-ssh (make-node session) (values 1 2))) => #(1 2) => #(39 40) => "(guile-user)" => "scheme"
Start an interactive remote REPL (RREPL) session using node.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The module (ssh dist node)
provides low-level API for node management.
Here’s the description of the format of node type printed representation:
#<node avp@127.0.0.1:22/37146 a0dbdc0> A A A A A | | | | | ,---' | ,-' '---. '-----------. | | | | | user host port REPL port object address
There are two types of node errors: recoverable and non-recoverable. The
first group is represented by node-error
exceptions. If an exception
of this kind is occurred then there is a chance that a job can be executed on
another node. That’s because such an exception occures in cases when a node
is unreachable, for example. The second group is represented by
node-repl-error
exceptions. Such exceptions mean that an error is
occurred during execution of a job on a node’s REPL – eg. due to the malformed
job. Those errors are non-recoverable because if the job is broken it will
likely fail on another nodes as well.
In addition to make-node
, node?
, node-session
and
node-repl-port
the module provides:
Evaluate a quoted-exp on a node and return four values: an
evaluation result, a number of the evaluation, a module name and a language
name. Throw node-repl-error
if a non-recoverable error occurred, or
node-error
if the evaluation potentially could be succesfully evaluated
on another node.
Note that procps version
3.3.12 or later is needed on the server side in case of either
start-repl-server?
or stop-repl-server?
was set to #t
for
a NODE (see the documentation for make-node
.)
Open a remote REPL (RREPL). Return a new RREPL channel.
Run a REPL server on a node. Throw node-error
with the current
node and the Guile return code from a server on an error.
Stop a RREPL server on a node.
Get Guile version installed on a node, return the version string.
Return #f
if Guile is not installed.
Check if a REPL server is running on a node, return #t
if it is
running and listens on an expected port, return #f
otherwise.
Evaluate expression expr using rrepl-channel, return four values:
an evaluation result, a number of the evaluation, a module name and a language
name. Throw node-repl-error
on an error.
Read from rrepl-channel until REPL is observed. Throw node-error
on an error.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The module (ssh dist job)
provides low-level API for job management.
Here’s the description of the format of node type printed representation:
#<job map #<node avp@127.0.0.1:22/37147 a0dbdc0> a1345a0> A A A | | | | '----------. | | | | job type node (see above) job object address
Split a list lst into count chunks. Return a list of chunks.
Example:
(split '(a b c d) 2) ⇒ '((a b) (c d))
Make a new job of type using node.
Return #t
if x is a job object, #f
otherwise.
Get type of a job.
Get a job node.
Transfer job to a new node. Return a new job object.
Get a job data.
Get a job procedure.
Split an expressions list to nearly equal parts according to the length of a nodes list and assign each evaluation job to a node. Return a list of assigned jobs.
Split the work to nearly equal parts according to length of nodes list and assign each part of work to a node. Return list of assigned jobs.
Hand out job to the assigned node and return the result of computation.
Convert a job to an equivalent symbolic expression.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There are working examples that come with Guile-SSH. These examples are normally installed in ‘$prefix/share/guile-ssh/examples’ directory:
Guile-SSH client and server example.
Echo client and server example.
In addition, the following sections will provide an overview of programming with Guile-SSH.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In this example we will connect to a server, open a channel and execute a command. Then we will read output from the command and close connection to the server.
(use-modules (ssh channel) (ssh session) (ssh auth) (ssh key)) (let ((session (make-session #:user "bob" #:host "example.com" #:port 22 #:log-verbosity 'nolog))) ; Be quiet ;; Connect to the server (connect! session) ;; Perform server authentication (case (authenticate-server session) ...) ; Check the result ;; Try to authenticate on the server with one of the `userauth-*' ;; procedures. Let's use `userauth-agent!'. (case (userauth-agent! session) ...) ; Check the result ;; Suppose the authentication went successfully. ;; Now we need to open a channel. (let ((channel (make-channel session))) (if (not channel) ...) ; Handle an error ;; Open a session so we will be able to execute a command ;; on the server (catch 'guile-ssh-error (lambda () (channel-open-session channel)) (lambda (key . args) ...)) ; Handle an error ;; Execute a command (channel-request-exec channel "uname") ;; Check the exit status of the command (or (zero? (channel-get-exit-status channel)) ...) ; Handle error ;; Poll the channel for data (let poll ((ready? #f)) (if ready? (begin ...) ; Read the output from the command (poll (char-ready? channel)))) ;; Close the channel (close channel) ;; Disconnect from the server (disconnect! session)))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In this example we will create a new server and start the server loop.
(use-modules (ssh server) (ssh message) (ssh session) (ssh channel) (ssh key) (ssh auth)) (let ((server (make-server #:bindport 22 #:rsakey "/home/alice/.ssh/host_rsa_key" #:dsakey "/home/alice/.ssh/host_dsa_key" #:log-verbosity 'nolog))) ; Be quiet ;; Start listen to incoming connections. (server-listen server) ;; Start the main loop of the server (while #t ;; Accept new connections from clients. Every connection is ;; handled in its own SSH session. (let ((session (catch 'guile-ssh-error (lambda () (server-accept server)) (lambda (key . args) ;; Handle an error #f)))) (if (not session) (begin (sleep 1) (continue))) ;; Handle server authentication request from a client (server-handle-key-exchange session) ;; Start the session loop. Handle incoming messages from ;; the client (let session-loop ((msg (server-message-get session))) (if (not msg) ...) ; Handle an error ;; Get type of the received message (let ((msg-type (message-get-type msg))) ;; Handle the message according to the type. Type is a list of ;; symbols where the car is the type and cadr is subtype. (case (car msg-type) ((request-service) ...) ; Handle service request ((request-auth) ...) ; Handle authentication request ((request-channel-open) ...) ; Handle request ((request-channel) ...))) ; Handle request (if (connected? session) (session-loop (server-message-get session)))) (disconnect! session))))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The libssh that is used by Guile-SSH is initially written by Aris Adamantiadis and being developed by the developer community. See ‘AUTHORS’ file that comes along with libssh distribution for full authors list.
Also I’d like to thank all the people who contributed their precious time and skills to send bug reports and patches for Guile-SSH. Please see ‘THANKS’ file in the Guile-SSH repository for the full list of contributors.
Thank you.
- Artyom “avp” Poptsov
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Version 1.3, 3 November 2008
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. http://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.
The “publisher” means any person or entity that distributes copies of the Document to the public.
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.
“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.
An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (C) year your name. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''.
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:
with the Invariant Sections being list their titles, with the Front-Cover Texts being list, and with the Back-Cover Texts being list.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | C F J K M N R S |
---|
Jump to: | C F J K M N R S |
---|
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | %
A B C D E F G H J K L M N O P R S T U W Z |
---|
Jump to: | %
A B C D E F G H J K L M N O P R S T U W Z |
---|
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | A C D F H L N P R S T V |
---|
Jump to: | A C D F H L N P R S T V |
---|
[Top] | [Contents] | [Index] | [ ? ] |
[Top] | [Contents] | [Index] | [ ? ] |
This document was generated on December 17, 2023 using texi2html 5.0.
The buttons in the navigation panels have the following meaning:
Button | Name | Go to | From 1.2.3 go to |
---|---|---|---|
[ << ] | FastBack | Beginning of this chapter or previous chapter | 1 |
[ < ] | Back | Previous section in reading order | 1.2.2 |
[ Up ] | Up | Up section | 1.2 |
[ > ] | Forward | Next section in reading order | 1.2.4 |
[ >> ] | FastForward | Next chapter | 2 |
[Top] | Top | Cover (top) of document | |
[Contents] | Contents | Table of contents | |
[Index] | Index | Index | |
[ ? ] | About | About (help) |
where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:
This document was generated on December 17, 2023 using texi2html 5.0.