Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
nbdkit-sh-plugin(3)		    NBDKIT		   nbdkit-sh-plugin(3)

NAME
       nbdkit-sh-plugin	- nbdkit shell,	script or executable plugin

SYNOPSIS
	nbdkit sh /path/to/script [arguments...]

	nbdkit sh - <<'EOF'
	... shell script ...
	EOF

DESCRIPTION
       "nbdkit-sh-plugin" allows you to	write plugins for nbdkit(1) using
       arbitrary scripting languages, including	shells like bash(1), dash(1),
       csh(1), zsh(1) etc., other scripting environments, or any executable.

       Note if you want	to use an established scripting	language like Perl or
       Python, then nbdkit has specific	plugins	to handle those	languages and
       those will be more efficient (see nbdkit(1) for a complete list).

       To use shell script fragments from the nbdkit command line (rather than
       a separate script) see nbdkit-eval-plugin(1).

   If you have been given an nbdkit sh plugin
       Assuming	you have a shell script	which is an nbdkit plugin, you run it
       like this:

	nbdkit sh /path/to/script

       You may have to add further "key=value" arguments to the	command	line.
       The script must be executable ("chmod +x").

   Inline shell	scripts
       It is also possible to write a shell script plugin "inline" using "-"
       as the name of the script, like this:

	nbdkit sh - <<'EOF'
	  case "$1" in
	    get_size) echo 1M ;;
	    pread) dd if=/dev/zero count=$3 iflag=count_bytes ;;
	    *) exit 2 ;;
	  esac
	EOF

       By default the inline script runs under /bin/sh.	 You can add a shebang
       ("#!") to use other scripting languages.	 Of course, reading an inline
       script from stdin is incompatible with the "-s" ("--single") mode of
       nbdkit that connects a client on	stdin.

WRITING	AN NBDKIT SH PLUGIN
       For an example plugin written in	Bash, see:
       https://github.com/libguestfs/nbdkit/blob/master/plugins/sh/example.sh

       Broadly speaking, nbdkit	shell plugins work like	C ones,	so you should
       read nbdkit-plugin(3) first.

   Programming model
       This plugin has a simple	programming model: For every plugin method
       that needs to be	called,	the external script is invoked with parameters
       describing the method and its arguments.	 The first parameter is	always
       the method name.	 For example:

	/path/to/script	config file disk.img
			  a	 a   a
			  a	 a   aa	value ($3)
			  a	 aaa key ($2)
		      method ($1)

	/path/to/script	pread <handle> <count> <offset>
			  a	  a	  a	  a
			  a	  a	  a	  aa offset in bytes ($4)
			  a	  a	  aaa request size in bytes ($3)
		      method ($1) aaa handle ($2) a see	"Handles" below

       Scripts should ignore extra parameters that they	don't understand since
       we may add new parameters in future.

   Exit	codes
       The script should exit with specific exit codes:

       0   The method was executed successfully.

       1 and 8-127
	   There was an	error.	The script may print on	stderr an errno	name,
	   optionally followed by whitespace and a message, for	example:

	    echo 'ENOSPC Out of	space' >&2
	    exit 1

	   or if you don't need	the log	message:

	    echo ENOSPC	>&2
	    exit 1

	   If the script doesn't print anything	or the output cannot be	parsed
	   then	nbdkit assumes error "EIO".  Note that output to stderr	is
	   ignored if the command succeeds, so it is acceptable	to output a
	   potential error message prefix prior	to attempting a	command	which
	   will	add further details if a failure occurs.

       2   The requested method	is not supported by the	script.

       3   For methods which return booleans, this code	indicates false.

       4, 5, 6,	7
	   These exit codes are	reserved for future use.

   Temporary directory
       A fresh script is invoked for each method call (ie. scripts are
       stateless), so if the script needs to store state it has	to store it
       somewhere in the	filesystem in a	format and location which is left up
       to the author of	the script.

       However nbdkit helps by creating	a randomly named, empty	directory for
       the script.  This directory persists for	the lifetime of	nbdkit and is
       deleted when nbdkit exits.  The name of the directory is	passed to each
       script invocation in the	$tmpdir	environment variable.

   Handles
       Handles are arbitrary strings, but it is	best to	limit them to short
       alphanumeric strings.

       Per-connection state

       The temporary directory described above can be used for state for the
       lifetime	of the nbdkit instance (across multiple	connections).  If you
       want to store state per connection then one way to do it	is to create a
       randomly	named subdirectory under the temporary directory:

	case "$1" in
	  ...
	  open)
	    mktemp -d $tmpdir/handle-XXXXXX ;;

       The handle will be the subdirectory name, returned to the script	as $2
       in all connected	calls (eg. "pread", "get_size").  You can delete the
       subdirectory explicitly in "close":

	case "$1" in
	  ...
	  close)
	    rm -rf "$2"	;;

       or rely on nbdkit deleting the whole temporary directory	including all
       per-handle subdirectories when it exits.

   Performance
       This plugin has to fork on every	request, so performance	will never be
       great.  For best	performance, consider using the	nbdkit-plugin(3) API
       directly.  Having said that, if you have	a sh plugin and	want to
       improve performance then	the following tips may help:

       Relax the thread	model.
	   The default "thread_model" is "serialize_all_requests" meaning that
	   two instances of the	script can never be running at the same	time.
	   This	is safe	but slow.  If your script is safe to be	called in
	   parallel, set this to "parallel".

       Implement the "zero" method.
	   If the "zero" method	is not implemented then	nbdkit will fall back
	   to using "pwrite" which is considerably slower because nbdkit has
	   to send blocks of zeroes to the script.

       You don't have to write shell scripts.
	   This	plugin can run any external binary, not	only shell scripts.
	   You should get more performance by rewriting	the shell script as a
	   program in a	compiled language.

   Methods
       This just documents the arguments to the	script corresponding to	each
       plugin method, and any way that they differ from	the C callbacks.  In
       all other respects they work the	same way as the	C callbacks, so	you
       should go and read nbdkit-plugin(3).

       "load"
	    /path/to/script load

       "unload"
	    /path/to/script unload

	   This	is called just before nbdkit exits.  Errors from this method
	   are ignored.

       "dump_plugin"
	    /path/to/script dump_plugin

       "config"
	    /path/to/script config <key> <value>

       "config_complete"
	    /path/to/script config_complete

       "magic_config_key"
	    /path/to/script magic_config_key

	   If a	magic config key is needed, this should	echo it	to stdout.
	   See "Magic parameters" in nbdkit(1).

       "thread_model"
	    /path/to/script thread_model

	   On success this should print	the desired thread model of the
	   script, one of "serialize_connections", "serialize_all_requests",
	   "serialize_requests", or "parallel".

	   This	method is not required;	if omitted, then the plugin will be
	   executed under the safe "serialize_all_requests" model.  However,
	   this	means that this	method must be provided	if you want to use the
	   "parallel" or "serialize_requests" model.  Even then	your request
	   may be restricted for other reasons;	look for "thread_model"	in the
	   output of "nbdkit --dump-plugin sh script" to see what actually
	   gets	selected.

	   If an error occurs, the script should output	an error message and
	   exit	with status 1; unrecognized output is ignored.

       "get_ready"
	    /path/to/script get_ready

       "preconnect"
	    /path/to/script preconnect <readonly> <exportname>

       "open"
	    /path/to/script open <readonly> <exportname>

	   The "readonly" parameter will be "true" or "false".	The
	   "exportname"	parameter, if present, is the export name passed to
	   the server from the client.

	   On success this should print	the handle (any	string)	on stdout and
	   exit	with code 0.  If the handle ends with a	newline	character then
	   the newline is removed.

	   Unlike C plugins, this method is not	required.  If omitted then the
	   handle will be "" (empty string).

       "close"
	    /path/to/script close <handle>

       "get_size"
	    /path/to/script get_size <handle>

	   The script should print the size of the disk	image on stdout.  You
	   can print the size in bytes,	or use any format understood by
	   "nbdkit_parse_size" such as "1M" (see "PARSING SIZE PARAMETERS" in
	   nbdkit-plugin(3)).

	   This	method is required.

       "can_write"
       "can_flush"
       "can_trim"
       "can_zero"
       "can_extents"
	   Unlike in other languages, you must provide the "can_*" methods
	   otherwise they are assumed to all return false and your "pwrite",
	   "flush", "trim", "zero" and "extents" methods will never be called.
	   The reason for this is obscure: In other languages we can detect if
	   (eg)	a "pwrite" method is defined and synthesize an appropriate
	   response if no actual "can_write" method is defined.	 However
	   detecting if	methods	are present without running them is not
	   possible with this plugin.

	    /path/to/script can_write <handle>
	    /path/to/script can_flush <handle>
	    /path/to/script can_trim <handle>
	    /path/to/script can_zero <handle>
	    /path/to/script can_extents	<handle>

	   The script should exit with code 0 for true or code 3 for false.

       "is_rotational"
       "can_fast_zero"
	    /path/to/script is_rotational <handle>
	    /path/to/script can_fast_zero <handle>

	   The script should exit with code 0 for true or code 3 for false.

       "can_fua"
       "can_cache"
	    /path/to/script can_fua <handle>
	    /path/to/script can_cache <handle>

	   These control Forced	Unit Access (FUA) and caching behaviour	of the
	   core	server.

	   Unlike the other "can_*" callbacks, these two are not a boolean.
	   They	must print either "none", "emulate" or "native"	to stdout.
	   The meaning of these	is described in	nbdkit-plugin(3).
	   Furthermore,	you must provide a "can_cache" method if you desire
	   the "cache" callback	to be utilized,	similar	to the reasoning
	   behind requiring "can_write"	to utilize "pwrite".

       "can_multi_conn"
	    /path/to/script can_multi_conn <handle>

	   The script should exit with code 0 for true or code 3 for false.

       "pread"
	    /path/to/script pread <handle> <count> <offset>

	   The script should print the requested binary	data on	stdout.
	   Exactly "count" bytes must be printed.

	   This	method is required.

       "pwrite"
	    /path/to/script pwrite <handle> <count> <offset> <flags>

	   The script should read the binary data to be	written	from stdin.

	   The "flags" parameter can be	an empty string	or "fua".  In the
	   future, a comma-separated list of flags may be present.

	   Unlike in other languages, if you provide a "pwrite"	method you
	   must	also provide a "can_write" method which	exits with code	0
	   (true).

       "flush"
	    /path/to/script flush <handle>

	   Unlike in other languages, if you provide a "flush" method you must
	   also	provide	a "can_flush" method which exits with code 0 (true).

       "trim"
	    /path/to/script trim <handle> <count> <offset> <flags>

	   The "flags" parameter can be	an empty string	or "fua".  In the
	   future, a comma-separated list of flags may be present.

	   Unlike in other languages, if you provide a "trim" method you must
	   also	provide	a "can_trim" method which exits	with code 0 (true).

       "zero"
	    /path/to/script zero <handle> <count> <offset> <flags>

	   The "flags" parameter can be	an empty string	or a comma-separated
	   list	of the flags: "fua", "may_trim", and "fast" (eg. "", "fua",
	   "fua,may_trim,fast" are some	of the 8 possible values).

	   Unlike in other languages, if you provide a "zero" method you must
	   also	provide	a "can_zero" method which exits	with code 0 (true).

	   To trigger a	fallback to <pwrite> on	a normal zero request, or to
	   respond quickly to the "fast" flag that a specific zero request is
	   no faster than a corresponding write, the script must output
	   "ENOTSUP" or	"EOPNOTSUPP" to	stderr (possibly followed by a
	   description of the problem) before exiting with code	1 (failure).

       "extents"
	    /path/to/script extents <handle> <count> <offset> <flags>

	   The "flags" parameter can be	an empty string	or "req_one".

	   This	must print, one	per line on stdout, a list of one or more
	   extents in the format:

	    offset length type

	   which correspond to the inputs of the C "nbdkit_add_extent"
	   function (see nbdkit-plugin(3)).  The "offset" and "length" fields
	   may use any format understood by "nbdkit_parse_size".  The optional
	   "type" field	may be an integer, missing (same as 0),	or a comma-
	   separated list of the words "hole" and "zero".  An example of a
	   valid set of	extents	covering a "10M" disk where the	first megabyte
	   only	is allocated data:

	    0  1M
	    1M 9M  hole,zero

	   Unlike in other languages, if you provide an	"extents" method you
	   must	also provide a "can_extents" method which exits	with code 0
	   (true).

       "cache"
	    /path/to/script cache <handle> <count> <offset>

	   Unlike in other languages, if you provide a "cache" method you must
	   also	provide	a "can_cache" method which prints "native" and exits
	   with	code 0 (true).

   Missing callbacks
       Missing:	"name",	"version", "longname", "description", "config_help"
	   These are not yet supported.

FILES
       $plugindir/nbdkit-sh-plugin.so
	   The plugin.

	   Use "nbdkit --dump-config" to find the location of $plugindir.

VERSION
       "nbdkit-sh-plugin" first	appeared in nbdkit 1.8.

SEE ALSO
       nbdkit(1), nbdkit-plugin(3), nbdkit-eval-plugin(1).

AUTHORS
       Richard W.M. Jones

COPYRIGHT
       Copyright (C) 2018-2020 Red Hat Inc.

LICENSE
       Redistribution and use in source	and binary forms, with or without
       modification, are permitted provided that the following conditions are
       met:

       o   Redistributions of source code must retain the above	copyright
	   notice, this	list of	conditions and the following disclaimer.

       o   Redistributions in binary form must reproduce the above copyright
	   notice, this	list of	conditions and the following disclaimer	in the
	   documentation and/or	other materials	provided with the
	   distribution.

       o   Neither the name of Red Hat nor the names of	its contributors may
	   be used to endorse or promote products derived from this software
	   without specific prior written permission.

       THIS SOFTWARE IS	PROVIDED BY RED	HAT AND	CONTRIBUTORS ''AS IS'' AND ANY
       EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR CONTRIBUTORS BE
       LIABLE FOR ANY DIRECT, INDIRECT,	INCIDENTAL, SPECIAL, EXEMPLARY,	OR
       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       SUBSTITUTE GOODS	OR SERVICES; LOSS OF USE, DATA,	OR PROFITS; OR
       BUSINESS	INTERRUPTION) HOWEVER CAUSED AND ON ANY	THEORY OF LIABILITY,
       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
       OTHERWISE) ARISING IN ANY WAY OUT OF THE	USE OF THIS SOFTWARE, EVEN IF
       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

nbdkit-1.20.4			  2021-09-21		   nbdkit-sh-plugin(3)

NAME | SYNOPSIS | DESCRIPTION | WRITING AN NBDKIT SH PLUGIN | FILES | VERSION | SEE ALSO | AUTHORS | COPYRIGHT | LICENSE

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=nbdkit-sh-plugin&sektion=3&manpath=FreeBSD+13.0-RELEASE+and+Ports>

home | help