2 * Copyright (C) 2013-2018 Red Hat Inc.
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
49 #include <nbdkit-plugin.h>
53 static PerlInterpreter
*my_perl
;
54 static const char *script
;
60 const char *argv
[2] = { "nbdkit", NULL
};
62 /* Full Perl interpreter initialization is deferred until we read
63 * the first config parameter (which MUST be "script").
65 PERL_SYS_INIT3 (&argc
, (char ***) &argv
, &environ
);
66 my_perl
= perl_alloc ();
68 nbdkit_error ("out of memory allocating Perl interpreter");
71 perl_construct (my_perl
);
77 if (my_perl
!= NULL
) {
78 perl_destruct (my_perl
);
84 /* We use this function to test if the named callback is defined
85 * in the loaded Perl code.
88 callback_defined (const char *perl_func_name
)
91 CLEANUP_FREE
char *cmd
= NULL
;
93 if (asprintf (&cmd
, "defined &%s", perl_func_name
) == -1) {
98 ret
= eval_pv (cmd
, FALSE
);
103 /* Check for a Perl exception, and convert it to an nbdkit error. */
105 check_perl_failure (void)
107 SV
*errsv
= get_sv ("@", TRUE
);
109 if (SvTRUE (errsv
)) {
112 CLEANUP_FREE
char *err_copy
= NULL
;
114 err
= SvPV (errsv
, n
);
116 /* Need to chop off the final \n if there is one. The only way to
117 * do this is to copy the string.
119 err_copy
= strndup (err
, n
);
120 if (err_copy
== NULL
) {
121 nbdkit_error ("malloc failure: original error: %s", err
);
124 if (n
> 0 && err_copy
[n
-1] == '\n')
125 err_copy
[n
-1] = '\0';
127 nbdkit_error ("%s", err_copy
);
135 static int last_error
;
140 /* Is it worth adding error checking for bad arguments? */
142 last_error
= SvIV (ST (0));
143 nbdkit_set_error (last_error
);
148 EXTERN_C
void boot_DynaLoader (pTHX_ CV
*cv
);
153 char *file
= __FILE__
;
154 newXS ("DynaLoader::boot_DynaLoader", boot_DynaLoader
, file
);
155 newXS ("Nbdkit::set_error", set_error
, file
);
159 perl_dump_plugin (void)
163 #ifdef PERL_VERSION_STRING
164 printf ("perl_version=%s\n", PERL_VERSION_STRING
);
167 if (script
&& callback_defined ("dump_plugin")) {
172 call_pv ("dump_plugin", G_EVAL
|G_VOID
|G_DISCARD
);
181 perl_config (const char *key
, const char *value
)
185 char *argv
[3] = { "nbdkit", NULL
, NULL
};
187 /* The first parameter MUST be "script". */
188 if (strcmp (key
, "script") != 0) {
189 nbdkit_error ("the first parameter must be "
190 "script=/path/to/perl/script.pl");
197 /* Load the Perl script. */
198 argv
[1] = (char *) script
;
199 if (perl_parse (my_perl
, xs_init
, argc
, argv
, NULL
) == -1) {
200 nbdkit_error ("%s: error parsing this script", script
);
204 /* Run the Perl script. Note that top-level definitions such as
205 * global variables don't work at all unless you do this.
207 if (perl_run (my_perl
) == -1) {
208 nbdkit_error ("%s: error running this script", script
);
212 /* Minimal set of callbacks which are required (by nbdkit itself). */
213 if (!callback_defined ("open") ||
214 !callback_defined ("get_size") ||
215 !callback_defined ("pread")) {
216 nbdkit_error ("%s: one of the required callbacks "
217 "'open', 'get_size' or 'pread' "
218 "is not defined by this Perl script. "
219 "nbdkit requires these callbacks.", script
);
223 else if (callback_defined ("config")) {
226 /* Other parameters are passed to the Perl .config callback. */
230 XPUSHs (sv_2mortal (newSVpv (key
, strlen (key
))));
231 XPUSHs (sv_2mortal (newSVpv (value
, strlen (value
))));
233 call_pv ("config", G_EVAL
|G_VOID
|G_DISCARD
);
239 if (check_perl_failure () == -1)
243 /* Emulate what core nbdkit does if a config callback is NULL. */
244 nbdkit_error ("%s: this plugin does not need command line configuration",
253 perl_config_complete (void)
257 if (callback_defined ("config_complete")) {
262 call_pv ("config_complete", G_EVAL
|G_VOID
|G_DISCARD
);
267 if (check_perl_failure () == -1)
275 perl_open (int readonly
)
280 /* We check in perl_config that this callback is defined. */
284 XPUSHs (readonly
? &PL_sv_yes
: &PL_sv_no
);
286 call_pv ("open", G_EVAL
|G_SCALAR
);
293 if (check_perl_failure () == -1)
296 nbdkit_debug ("open returns handle (SV *) = %p (type %d)",
303 perl_close (void *handle
)
307 nbdkit_debug ("close called with handle (SV *) = %p (type %d)",
308 handle
, SvTYPE ((SV
*) handle
));
310 if (callback_defined ("close")) {
316 call_pv ("close", G_EVAL
|G_VOID
|G_DISCARD
);
322 check_perl_failure (); /* ignore return value */
325 /* Since nbdkit has closed (and forgotten) the handle, we can now
328 SvREFCNT_dec ((SV
*) handle
);
332 perl_get_size (void *handle
)
338 /* We check in perl_config that this callback is defined. */
344 call_pv ("get_size", G_EVAL
|G_SCALAR
);
346 /* For some reason, this only works if split into two separate statements: */
353 if (check_perl_failure () == -1)
356 nbdkit_debug ("get_size returned %" PRIi64
, size
);
362 perl_boolean (void *handle
, const char *callback_name
, const char *fn_name
)
368 if (callback_defined (callback_name
)) {
369 /* If there's a Perl callback, call it. */
375 call_pv (callback_name
, G_EVAL
|G_SCALAR
);
383 if (check_perl_failure () == -1)
388 /* No Perl callback. If the function is defined, return 1. */
389 else if (fn_name
&& callback_defined (fn_name
))
396 perl_can_write (void *handle
)
398 return perl_boolean (handle
, "can_write", "write");
402 perl_can_flush (void *handle
)
404 return perl_boolean (handle
, "can_flush", "flush");
408 perl_can_trim (void *handle
)
410 return perl_boolean (handle
, "can_trim", "trim");
414 perl_is_rotational (void *handle
)
416 return perl_boolean (handle
, "is_rotational", NULL
);
420 perl_pread (void *handle
, void *buf
,
421 uint32_t count
, uint64_t offset
)
429 /* We check in perl_config that this callback is defined. */
434 XPUSHs (sv_2mortal (newSViv (count
)));
435 XPUSHs (sv_2mortal (newSViv (offset
)));
437 call_pv ("pread", G_EVAL
|G_SCALAR
);
440 pbuf
= SvPV (sv
, len
);
442 nbdkit_error ("buffer returned from pread is too small");
446 memcpy (buf
, pbuf
, count
);
451 if (check_perl_failure () == -1)
458 perl_pwrite (void *handle
, const void *buf
,
459 uint32_t count
, uint64_t offset
)
463 if (callback_defined ("pwrite")) {
468 XPUSHs (sv_2mortal (newSVpv (buf
, count
)));
469 XPUSHs (sv_2mortal (newSViv (offset
)));
471 call_pv ("pwrite", G_EVAL
|G_VOID
|G_DISCARD
);
477 if (check_perl_failure () == -1)
483 nbdkit_error ("write not implemented");
488 perl_zero (void *handle
, uint32_t count
, uint64_t offset
, int may_trim
)
492 if (callback_defined ("zero")) {
498 XPUSHs (sv_2mortal (newSViv (count
)));
499 XPUSHs (sv_2mortal (newSViv (offset
)));
500 XPUSHs (sv_2mortal (newSViv (may_trim
)));
502 call_pv ("zero", G_EVAL
|G_SCALAR
);
508 if (last_error
== EOPNOTSUPP
) {
509 /* When user requests this particular error, we want to
510 gracefully fall back, and to accomodate both a normal return
512 nbdkit_debug ("zero requested falling back to pwrite");
515 if (check_perl_failure () == -1)
521 nbdkit_debug ("zero falling back to pwrite");
522 nbdkit_set_error (EOPNOTSUPP
);
527 perl_flush (void *handle
)
531 if (callback_defined ("flush")) {
537 call_pv ("flush", G_EVAL
|G_VOID
|G_DISCARD
);
543 if (check_perl_failure () == -1)
549 /* Ignore lack of flush callback in Perl, although probably nbdkit
550 * will never call this since .can_flush returns false.
556 perl_trim (void *handle
, uint32_t count
, uint64_t offset
)
560 if (callback_defined ("trim")) {
565 XPUSHs (sv_2mortal (newSViv (count
)));
566 XPUSHs (sv_2mortal (newSViv (offset
)));
568 call_pv ("trim", G_EVAL
|G_VOID
|G_DISCARD
);
574 if (check_perl_failure () == -1)
580 /* Ignore lack of trim callback in Perl, although probably nbdkit
581 * will never call this since .can_trim returns false.
586 #define perl_config_help \
587 "script=<FILENAME> (required) The Perl plugin to run.\n" \
588 "[other arguments may be used by the plugin that you load]"
590 #define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
592 static struct nbdkit_plugin plugin
= {
594 .version
= PACKAGE_VERSION
,
597 .unload
= perl_unload
,
598 .dump_plugin
= perl_dump_plugin
,
600 .config
= perl_config
,
601 .config_complete
= perl_config_complete
,
602 .config_help
= perl_config_help
,
607 .get_size
= perl_get_size
,
608 .can_write
= perl_can_write
,
609 .can_flush
= perl_can_flush
,
610 .is_rotational
= perl_is_rotational
,
611 .can_trim
= perl_can_trim
,
614 .pwrite
= perl_pwrite
,
620 NBDKIT_REGISTER_PLUGIN(plugin
)