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

				    value ($3)
				 key ($2)
		      method ($1)

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

						offset in bytes	($4)
					 request size in bytes ($3)
		      method ($1)  handle ($2)	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:

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

          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.

          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			  2025-04-13		   nbdkit-sh-plugin(3)

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

home | help