Update Red Hat Copyright Notices
[nbdkit.git] / plugins / lua / lua.c
blobd9f00adb1ff1c4964a889c6432008bffdd4210da
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <assert.h>
42 #include <lua.h>
43 #include <lauxlib.h>
44 #include <lualib.h>
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
54 static int
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);
61 if (i == n)
62 return 1;
64 return 0;
66 #endif /* HAVE_LUA_ISINTEGER */
68 static lua_State *L;
69 static const char *script;
71 static void
72 lua_plugin_load (void)
74 L = luaL_newstate ();
75 if (L == NULL) {
76 nbdkit_error ("could not create Lua interpreter: %m");
77 exit (EXIT_FAILURE);
79 luaL_openlibs (L);
82 static void
83 lua_plugin_unload (void)
85 if (L)
86 lua_close (L);
89 /* Test if a function was defined by the Lua code. */
90 static int
91 function_defined (const char *name)
93 int r;
95 lua_getglobal (L, name);
96 r = lua_isfunction (L, -1) == 1;
97 lua_pop (L, 1);
98 return r;
101 static void
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);
110 #endif
111 #endif
112 printf ("\n");
113 #endif
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));
119 lua_pop (L, 1);
124 static int
125 lua_plugin_config (const char *key, const char *value)
127 if (!script) {
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");
131 return -1;
133 script = value;
135 assert (L);
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));
143 lua_pop (L, 1);
144 return -1;
146 if (lua_pcall (L, 0, 0, 0) != 0) {
147 nbdkit_error ("could not run Lua script: %s", lua_tostring (L, -1));
148 lua_pop (L, 1);
149 return -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);
160 return -1;
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));
169 lua_pop (L, 1);
170 return -1;
172 return 0;
174 else {
175 /* Emulate what core nbdkit does if a config callback is NULL. */
176 nbdkit_error ("%s: this plugin does not need command line configuration",
177 script);
178 return -1;
181 return 0;
184 static int
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));
191 lua_pop (L, 1);
192 return -1;
194 return 0;
197 return 0;
200 static void *
201 lua_plugin_open (int readonly)
203 int *h;
205 /* We store a Lua reference (an integer) in the handle. */
206 h = malloc (sizeof *h);
207 if (h == NULL) {
208 nbdkit_error ("malloc: %m");
209 return NULL;
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));
216 lua_pop (L, 1);
217 free (h);
218 return NULL;
221 /* Create a reference to the Lua handle returned by open(). */
222 *h = luaL_ref (L, LUA_REGISTRYINDEX);
224 return h;
227 static void
228 lua_plugin_close (void *handle)
230 int *h = 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));
237 lua_pop (L, 1);
241 /* Ensure that the Lua handle is freed. */
242 luaL_unref (L, LUA_REGISTRYINDEX, *h);
243 /* Free C handle. */
244 free (handle);
247 static int64_t
248 lua_plugin_get_size (void *handle)
250 int *h = handle;
251 int64_t r;
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));
257 lua_pop (L, 1);
258 return -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);
264 else {
265 nbdkit_error ("get_size: cannot convert returned value to an integer");
266 r = -1;
268 lua_pop (L, 1);
269 return r;
272 static int
273 lua_plugin_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
275 int *h = handle;
276 size_t len;
277 const char *str;
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));
285 lua_pop (L, 1);
286 return -1;
288 str = lua_tolstring (L, -1, &len);
289 if (str == NULL) {
290 nbdkit_error ("pread: return value is not a string");
291 lua_pop (L, 1);
292 return -1;
294 if (len < count) {
295 nbdkit_error ("pread: returned string length < count bytes");
296 lua_pop (L, 1);
297 return -1;
299 memcpy (buf, str, count);
300 lua_pop (L, 1);
301 return 0;
304 static int
305 lua_plugin_pwrite (void *handle, const void *buf,
306 uint32_t count, uint64_t offset)
308 int *h = handle;
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));
317 lua_pop (L, 1);
318 return -1;
320 return 0;
323 nbdkit_error ("pwrite not implemented");
324 return -1;
327 static int
328 lua_plugin_can_write (void *handle)
330 int *h = handle;
331 int r;
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));
338 lua_pop (L, 1);
339 return -1;
341 if (!lua_isboolean (L, -1)) {
342 nbdkit_error ("can_write: return value is not a boolean");
343 lua_pop (L, 1);
344 return -1;
346 r = lua_toboolean (L, -1);
347 lua_pop (L, 1);
348 return r;
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"))
354 return 1;
355 else
356 return 0;
359 static int
360 lua_plugin_can_flush (void *handle)
362 int *h = handle;
363 int r;
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));
370 lua_pop (L, 1);
371 return -1;
373 if (!lua_isboolean (L, -1)) {
374 nbdkit_error ("can_flush: return value is not a boolean");
375 lua_pop (L, 1);
376 return -1;
378 r = lua_toboolean (L, -1);
379 lua_pop (L, 1);
380 return r;
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"))
386 return 1;
387 else
388 return 0;
391 static int
392 lua_plugin_can_trim (void *handle)
394 int *h = handle;
395 int r;
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));
402 lua_pop (L, 1);
403 return -1;
405 if (!lua_isboolean (L, -1)) {
406 nbdkit_error ("can_trim: return value is not a boolean");
407 lua_pop (L, 1);
408 return -1;
410 r = lua_toboolean (L, -1);
411 lua_pop (L, 1);
412 return r;
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"))
418 return 1;
419 else
420 return 0;
423 static int
424 lua_plugin_is_rotational (void *handle)
426 int *h = handle;
427 int r;
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));
434 lua_pop (L, 1);
435 return -1;
437 if (!lua_isboolean (L, -1)) {
438 nbdkit_error ("is_rotational: return value is not a boolean");
439 lua_pop (L, 1);
440 return -1;
442 r = lua_toboolean (L, -1);
443 lua_pop (L, 1);
444 return r;
446 else
447 return 0;
450 static int
451 lua_plugin_flush (void *handle)
453 int *h = 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));
460 lua_pop (L, 1);
461 return -1;
463 return 0;
466 /* Ignore lack of flush callback, although probably nbdkit will
467 * never call this since .can_flush returns false.
469 return 0;
472 static int
473 lua_plugin_trim (void *handle, uint32_t count, uint64_t offset)
475 int *h = handle;
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));
484 lua_pop (L, 1);
485 return -1;
487 return 0;
490 /* Ignore lack of trim callback, although probably nbdkit will never
491 * call this since .can_trim returns false.
493 return 0;
496 static int
497 lua_plugin_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
499 int *h = handle;
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));
509 lua_pop (L, 1);
510 return -1;
512 return 0;
515 nbdkit_debug ("zero falling back to pwrite");
516 nbdkit_set_error (EOPNOTSUPP);
517 return -1;
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 = {
527 .name = "lua",
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)