4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 #include <nbdkit-plugin.h>
48 /* Backwards compatibility function for Lua 5.1.
50 * This is taken from https://github.com/keplerproject/lua-compat-5.3
51 * where it is distributed under a compatible license to nbdkit.
53 #ifndef HAVE_LUA_ISINTEGER
55 lua_isinteger (lua_State
*L
, int index
)
57 if (lua_type (L
, index
) == LUA_TNUMBER
) {
58 lua_Number n
= lua_tonumber (L
, index
);
59 lua_Integer i
= lua_tointeger (L
, index
);
66 #endif /* HAVE_LUA_ISINTEGER */
69 static const char *script
;
72 lua_plugin_load (void)
76 nbdkit_error ("could not create Lua interpreter: %m");
83 lua_plugin_unload (void)
89 /* Test if a function was defined by the Lua code. */
91 function_defined (const char *name
)
95 lua_getglobal (L
, name
);
96 r
= lua_isfunction (L
, -1) == 1;
102 lua_plugin_dump_plugin (void)
104 #ifdef LUA_VERSION_MAJOR
105 printf ("lua_version=%s", LUA_VERSION_MAJOR
);
106 #ifdef LUA_VERSION_MINOR
107 printf (".%s", LUA_VERSION_MINOR
);
108 #ifdef LUA_VERSION_RELEASE
109 printf (".%s", LUA_VERSION_RELEASE
);
115 if (script
&& function_defined ("dump_plugin")) {
116 lua_getglobal (L
, "dump_plugin");
117 if (lua_pcall (L
, 0, 0, 0) != 0) {
118 nbdkit_error ("dump_plugin: %s", lua_tostring (L
, -1));
125 lua_plugin_config (const char *key
, const char *value
)
128 /* The first parameter MUST be "script". */
129 if (strcmp (key
, "script") != 0) {
130 nbdkit_error ("the first parameter must be script=/path/to/script.lua");
137 /* Load the Lua file. */
138 if (luaL_loadfile (L
, script
) != 0) {
139 /* We don't need to print the script name because it's
140 * contained in the error message (as well as the line number).
142 nbdkit_error ("could not parse Lua script %s", lua_tostring (L
, -1));
146 if (lua_pcall (L
, 0, 0, 0) != 0) {
147 nbdkit_error ("could not run Lua script: %s", lua_tostring (L
, -1));
152 /* Minimal set of callbacks which are required (by nbdkit itself). */
153 if (!function_defined ("open") ||
154 !function_defined ("get_size") ||
155 !function_defined ("pread")) {
156 nbdkit_error ("%s: one of the required callbacks "
157 "'open', 'get_size' or 'pread' "
158 "is not defined by this Lua script. "
159 "nbdkit requires these callbacks.", script
);
163 else if (function_defined ("config")) {
164 lua_getglobal (L
, "config");
165 lua_pushstring (L
, key
);
166 lua_pushstring (L
, value
);
167 if (lua_pcall (L
, 2, 0, 0) != 0) {
168 nbdkit_error ("config: %s", lua_tostring (L
, -1));
175 /* Emulate what core nbdkit does if a config callback is NULL. */
176 nbdkit_error ("%s: this plugin does not need command line configuration",
185 lua_plugin_config_complete (void)
187 if (function_defined ("config_complete")) {
188 lua_getglobal (L
, "config_complete");
189 if (lua_pcall (L
, 0, 0, 0) != 0) {
190 nbdkit_error ("config_complete: %s", lua_tostring (L
, -1));
201 lua_plugin_open (int readonly
)
205 /* We store a Lua reference (an integer) in the handle. */
206 h
= malloc (sizeof *h
);
208 nbdkit_error ("malloc: %m");
212 lua_getglobal (L
, "open");
213 lua_pushboolean (L
, readonly
);
214 if (lua_pcall (L
, 1, 1, 0) != 0) {
215 nbdkit_error ("open: %s", lua_tostring (L
, -1));
221 /* Create a reference to the Lua handle returned by open(). */
222 *h
= luaL_ref (L
, LUA_REGISTRYINDEX
);
228 lua_plugin_close (void *handle
)
232 if (function_defined ("close")) {
233 lua_getglobal (L
, "close");
234 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
235 if (lua_pcall (L
, 1, 0, 0) != 0) {
236 nbdkit_error ("close: %s", lua_tostring (L
, -1));
241 /* Ensure that the Lua handle is freed. */
242 luaL_unref (L
, LUA_REGISTRYINDEX
, *h
);
248 lua_plugin_get_size (void *handle
)
253 lua_getglobal (L
, "get_size");
254 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
255 if (lua_pcall (L
, 1, 1, 0) != 0) {
256 nbdkit_error ("get_size: %s", lua_tostring (L
, -1));
260 if (lua_isinteger (L
, -1))
261 r
= lua_tointeger (L
, -1);
262 else if (lua_isnumber (L
, -1))
263 r
= (int64_t) lua_tonumber (L
, -1);
265 nbdkit_error ("get_size: cannot convert returned value to an integer");
273 lua_plugin_pread (void *handle
, void *buf
, uint32_t count
, uint64_t offset
)
279 lua_getglobal (L
, "pread");
280 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
281 lua_pushinteger (L
, count
);
282 lua_pushinteger (L
, offset
);
283 if (lua_pcall (L
, 3, 1, 0) != 0) {
284 nbdkit_error ("pread: %s", lua_tostring (L
, -1));
288 str
= lua_tolstring (L
, -1, &len
);
290 nbdkit_error ("pread: return value is not a string");
295 nbdkit_error ("pread: returned string length < count bytes");
299 memcpy (buf
, str
, count
);
305 lua_plugin_pwrite (void *handle
, const void *buf
,
306 uint32_t count
, uint64_t offset
)
310 if (function_defined ("pwrite")) {
311 lua_getglobal (L
, "pwrite");
312 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
313 lua_pushlstring (L
, buf
, count
);
314 lua_pushinteger (L
, offset
);
315 if (lua_pcall (L
, 3, 0, 0) != 0) {
316 nbdkit_error ("pwrite: %s", lua_tostring (L
, -1));
323 nbdkit_error ("pwrite not implemented");
328 lua_plugin_can_write (void *handle
)
333 if (function_defined ("can_write")) {
334 lua_getglobal (L
, "can_write");
335 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
336 if (lua_pcall (L
, 1, 1, 0) != 0) {
337 nbdkit_error ("can_write: %s", lua_tostring (L
, -1));
341 if (!lua_isboolean (L
, -1)) {
342 nbdkit_error ("can_write: return value is not a boolean");
346 r
= lua_toboolean (L
, -1);
350 /* No can_write callback, but there's a pwrite callback defined, so
351 * return 1. (In C modules, nbdkit would do this).
353 else if (function_defined ("pwrite"))
360 lua_plugin_can_flush (void *handle
)
365 if (function_defined ("can_flush")) {
366 lua_getglobal (L
, "can_flush");
367 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
368 if (lua_pcall (L
, 1, 1, 0) != 0) {
369 nbdkit_error ("can_flush: %s", lua_tostring (L
, -1));
373 if (!lua_isboolean (L
, -1)) {
374 nbdkit_error ("can_flush: return value is not a boolean");
378 r
= lua_toboolean (L
, -1);
382 /* No can_flush callback, but there's a plugin_flush callback
383 * defined, so return 1. (In C modules, nbdkit would do this).
385 else if (function_defined ("plugin_flush"))
392 lua_plugin_can_trim (void *handle
)
397 if (function_defined ("can_trim")) {
398 lua_getglobal (L
, "can_trim");
399 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
400 if (lua_pcall (L
, 1, 1, 0) != 0) {
401 nbdkit_error ("can_trim: %s", lua_tostring (L
, -1));
405 if (!lua_isboolean (L
, -1)) {
406 nbdkit_error ("can_trim: return value is not a boolean");
410 r
= lua_toboolean (L
, -1);
414 /* No can_trim callback, but there's a trim callback defined, so
415 * return 1. (In C modules, nbdkit would do this).
417 else if (function_defined ("trim"))
424 lua_plugin_is_rotational (void *handle
)
429 if (function_defined ("is_rotational")) {
430 lua_getglobal (L
, "is_rotational");
431 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
432 if (lua_pcall (L
, 1, 1, 0) != 0) {
433 nbdkit_error ("is_rotational: %s", lua_tostring (L
, -1));
437 if (!lua_isboolean (L
, -1)) {
438 nbdkit_error ("is_rotational: return value is not a boolean");
442 r
= lua_toboolean (L
, -1);
451 lua_plugin_flush (void *handle
)
455 if (function_defined ("flush")) {
456 lua_getglobal (L
, "flush");
457 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
458 if (lua_pcall (L
, 1, 0, 0) != 0) {
459 nbdkit_error ("flush: %s", lua_tostring (L
, -1));
466 /* Ignore lack of flush callback, although probably nbdkit will
467 * never call this since .can_flush returns false.
473 lua_plugin_trim (void *handle
, uint32_t count
, uint64_t offset
)
477 if (function_defined ("trim")) {
478 lua_getglobal (L
, "trim");
479 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
480 lua_pushinteger (L
, count
);
481 lua_pushinteger (L
, offset
);
482 if (lua_pcall (L
, 3, 0, 0) != 0) {
483 nbdkit_error ("trim: %s", lua_tostring (L
, -1));
490 /* Ignore lack of trim callback, although probably nbdkit will never
491 * call this since .can_trim returns false.
497 lua_plugin_zero (void *handle
, uint32_t count
, uint64_t offset
, int may_trim
)
501 if (function_defined ("zero")) {
502 lua_getglobal (L
, "zero");
503 lua_rawgeti (L
, LUA_REGISTRYINDEX
, *h
);
504 lua_pushinteger (L
, count
);
505 lua_pushinteger (L
, offset
);
506 lua_pushboolean (L
, may_trim
);
507 if (lua_pcall (L
, 4, 0, 0) != 0) {
508 nbdkit_error ("zero: %s", lua_tostring (L
, -1));
515 nbdkit_debug ("zero falling back to pwrite");
516 nbdkit_set_error (EOPNOTSUPP
);
520 #define lua_plugin_config_help \
521 "script=<FILENAME> (required) The Lua script to run.\n" \
522 "[other arguments may be used by the plugin that you load]"
524 #define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
526 static struct nbdkit_plugin plugin
= {
528 .version
= PACKAGE_VERSION
,
530 .load
= lua_plugin_load
,
531 .unload
= lua_plugin_unload
,
532 .dump_plugin
= lua_plugin_dump_plugin
,
534 .config
= lua_plugin_config
,
535 .config_complete
= lua_plugin_config_complete
,
536 .config_help
= lua_plugin_config_help
,
538 .open
= lua_plugin_open
,
539 .close
= lua_plugin_close
,
541 .get_size
= lua_plugin_get_size
,
542 .can_write
= lua_plugin_can_write
,
543 .can_flush
= lua_plugin_can_flush
,
544 .is_rotational
= lua_plugin_is_rotational
,
545 .can_trim
= lua_plugin_can_trim
,
547 .pread
= lua_plugin_pread
,
548 .pwrite
= lua_plugin_pwrite
,
549 .flush
= lua_plugin_flush
,
550 .trim
= lua_plugin_trim
,
551 .zero
= lua_plugin_zero
,
554 NBDKIT_REGISTER_PLUGIN (plugin
)