5 # This example can be freely used for any purpose.
7 # Run it from the build directory like this:
9 # ./nbdkit -f -v sh ./plugins/sh/example.sh file=disk.img
11 # Or run it after installing nbdkit like this:
13 # nbdkit -f -v sh ./plugins/sh/example.sh file=disk.img
15 # The file= prefix is optional: see nbdkit(1) section "Magic
16 # parameters" and the magic_config_key setting below.
18 # The -f -v arguments are optional. They cause the server to stay in
19 # the foreground and print debugging, which is useful when testing.
21 # You can connect to the server using guestfish or qemu, eg:
23 # guestfish --format=raw -a nbd://localhost
25 # ><fs> list-filesystems
26 # ><fs> mount /dev/sda1 /
28 # Note that the exit code of the script matters:
31 # 2 => Method is missing
33 # For other values, see the nbdkit-sh-plugin(3) manual page.
35 # Check we're being run from nbdkit.
37 # Because the script has to be executable (for nbdkit to run it) there
38 # is a danger that someone could run the script standalone which won't
39 # work. Use two tests to try to make sure we are run from nbdkit:
41 # - $tmpdir is set to a random, empty directory by nbdkit. Note the
42 # contents are deleted when nbdkit exits.
44 # - $1 is set (to a method name).
45 if [ ! -d $tmpdir ] ||
[ "x$1" = "x" ]; then
46 echo "$0: this script must be run from nbdkit" >&2
47 echo "Use ‘nbdkit sh $0’" >&2
51 # We make a symlink to the file in the tmpdir directory.
56 # This is called from: nbdkit sh example.sh --dump-plugin
61 # We expect a file=... parameter pointing to the file to serve.
62 if [ "$2" = "file" ]; then
63 if [ ! -r "$3" ]; then
64 echo "file $3 does not exist or is not readable" >&2
67 ln -sf "$(realpath "$3")" $f
69 echo "unknown parameter $2=$3" >&2
75 # Check the file parameter was passed.
77 echo "file parameter missing" >&2
83 # You must opt-in for parallel behavior; the default is
84 # serialize_all_requests.
88 list_exports | default_export
)
89 # The following lists the names of all files in the current
90 # directory that do not contain whitespace, backslash, or single
91 # quotes. No description accompanies the export names.
92 # The first file listed is used when a client requests export ''.
93 find .
-type f \
! -name "*['\\\\[:space:]]*"
97 # Open a new client connection.
99 # Create a directory to store per-connection state. The
100 # directory name is printed out by the mktemp command, that
101 # output is captured by nbdkit, and it is passed back as the
102 # handle parameter ($2) in subsequent calls below.
104 # You can use this directory to store per-connection state,
105 # and it along with everything in $tmpdir is cleaned up by
108 # (This plugin does not actually use per-connection state,
109 # it's just an example.)
110 mktemp
-d $tmpdir/handle-XXXXXX
114 # Print the disk size on stdout.
115 stat
-L -c '%s' $f ||
exit 1
119 # Read the requested part of the disk and write to stdout.
120 dd iflag
=skip_bytes
,count_bytes skip
=$4 count
=$3 if=$f ||
exit 1
124 # Copy data from stdin and write it to the disk.
125 dd oflag
=seek_bytes conv
=notrunc seek
=$4 of
=$f ||
exit 1
129 # If we provide a pwrite method, we must provide this method
130 # (and similarly for flush and trim). See nbdkit-sh-plugin(3)
131 # for details. This will exit 0 (below) which means true.
132 # Use ‘exit 3’ if false.
136 # Punch a hole in the backing file, if supported.
137 fallocate
-p -o $4 -l $3 -n $f ||
exit 1
140 # We can trim if the fallocate command exists.
141 fallocate
--help >/dev
/null
2>&1 ||
exit 3
145 # Efficiently zero the backing file, if supported.
146 # Try punching a hole if flags includes may_trim, otherwise
147 # request to leave the zeroed range allocated.
148 # Attempt a fallback to write on any failure, but this requires
149 # specific prefix on stderr prior to any message from fallocate;
150 # exploit the fact that stderr is ignored on success.
153 *,may_trim
,*) fallocate
-p -o $4 -l $3 -n $f ||
exit 1 ;;
154 *) fallocate
-z -o $4 -l $3 -n $f ||
exit 1 ;;
158 # We can efficiently zero if the fallocate command exists.
159 fallocate
--help >/dev
/null
2>&1 ||
exit 3
163 # Implement an efficient prefetch, if desired.
164 # It is intentionally omitted from this example.
165 # dd iflag=skip_bytes,count_bytes skip=$4 count=$3 \
166 # if=$f of=/dev/null || exit 1
170 # Caching is not advertised to the client unless can_cache prints
171 # a tri-state value. Here, we choose for caching to be a no-op,
172 # by omitting counterpart handling for 'cache'.
177 # Report extent (block status) information as 'offset length [type]'.
178 # This example could omit the handler, since it just matches
179 # the default behavior of treating everything as data; but if
180 # your code can detect holes, this demonstrates the usage.
181 echo "$4 $(($3/2)) 0"
182 echo "$(($4+$3/2)) $(($3/2))"
183 # echo "$4 $3 hole,zero"
187 # Similar to can_write
191 # See nbdkit(1) section "Magic parameters" for what this does.
196 # Unknown methods must exit with code 2.