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
40 #include <sys/types.h>
43 #include <nbdkit-plugin.h>
49 static const char *name
; /* Name or URI of container image. */
50 static int layer
= 0; /* Layer (may be negative to count from end). */
52 /* The script that we run to pull and unpack the image. */
53 static const char script
[] =
56 /* Avoid stdin/stdout leaking (because of nbdkit -s).
57 * XXX Capture errors to a temporary file.
59 "exec </dev/null >/dev/null\n"
60 /* Create a temporary directory to extract the image to. */
62 "podman pull \"$name\"\n"
63 "podman save --format oci-dir -o \"$d\" \"$name\"\n"
64 "f=\"$d/$( jq -r \".layers[$layer].digest\" < \"$d/manifest.json\" |\n"
66 "if ! test -f \"$f\"; then\n"
67 " echo \"cdi: could not extract layer\"\n"
71 "mv \"$f\" \"$tmpfile\"\n"
74 /* The temporary file. */
77 /* Construct the temporary file. */
82 CLEANUP_FREE
char *template = NULL
;
83 CLEANUP_FREE
char *command
= NULL
;
84 size_t command_len
= 0;
88 /* Path for temporary file. */
89 tmpdir
= getenv ("TMPDIR");
91 tmpdir
= LARGE_TMPDIR
;
92 if (asprintf (&template, "%s/imageXXXXXX", tmpdir
) == -1) {
93 nbdkit_error ("asprintf: %m");
97 fd
= mkstemp (template);
99 nbdkit_error ("mkstemp: %s: %m", template);
103 /* Construct the podman script. */
104 fp
= open_memstream (&command
, &command_len
);
106 nbdkit_error ("open_memstream: %m");
109 fprintf (fp
, "name="); shell_quote (name
, fp
); putc ('\n', fp
);
110 fprintf (fp
, "layer=%d\n", layer
);
111 fprintf (fp
, "tmpfile="); shell_quote (template, fp
); putc ('\n', fp
);
113 fprintf (fp
, "%s", script
);
114 if (fclose (fp
) == EOF
) {
115 nbdkit_error ("memstream failed: %m");
119 /* Run the command. */
120 nbdkit_debug ("%s", command
);
121 r
= system (command
);
122 if (exit_status_to_nbd_error (r
, "podman") == -1)
125 /* Expect that the script creates 'template'. */
126 if (access (template, F_OK
) != 0) {
127 nbdkit_error ("internal error: expected %s to be created", template);
131 /* Since the script likely overwrites the file, we need to reopen it. */
133 fd
= open (template, O_RDONLY
|O_CLOEXEC
);
135 nbdkit_error ("open: %s: %m", template);
140 /* Since we've opened the file, we can unlink it. */
154 cdi_config (const char *key
, const char *value
)
156 if (strcmp (key
, "name") == 0)
158 else if (strcmp (key
, "layer") == 0) {
159 if (nbdkit_parse_int ("layer", value
, &layer
) == -1)
163 nbdkit_error ("unknown parameter '%s'", key
);
171 cdi_config_complete (void)
174 nbdkit_error ("you must supply the 'name' parameter "
175 "after the plugin name on the command line");
182 #define cdi_config_help \
183 "name=NAME[:TAG|@DIGEST] (required) Name or URI of container image.\n" \
184 "layer=<N> Layer of image to export."
189 return make_layer ();
193 cdi_open (int readonly
)
195 return NBDKIT_HANDLE_NOT_NEEDED
;
198 #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
200 /* Get the file size. */
202 cdi_get_size (void *handle
)
206 if (fstat (fd
, &statbuf
) == -1) {
207 nbdkit_error ("fstat: %m");
211 return statbuf
.st_size
;
214 /* Serves the same data over multiple connections. */
216 cdi_can_multi_conn (void *handle
)
222 cdi_can_cache (void *handle
)
224 /* Let nbdkit call pread to populate the file system cache. */
225 return NBDKIT_CACHE_EMULATE
;
228 /* Read data from the file. */
230 cdi_pread (void *handle
, void *buf
, uint32_t count
, uint64_t offset
)
233 ssize_t r
= pread (fd
, buf
, count
, offset
);
235 nbdkit_error ("pread: %m");
239 nbdkit_error ("pread: unexpected end of file");
250 static struct nbdkit_plugin plugin
= {
252 .longname
= "nbdkit containerized data importer plugin",
253 .version
= PACKAGE_VERSION
,
254 .unload
= cdi_unload
,
255 .config
= cdi_config
,
256 .config_complete
= cdi_config_complete
,
257 .config_help
= cdi_config_help
,
258 .magic_config_key
= "name",
259 .get_ready
= cdi_get_ready
,
261 .get_size
= cdi_get_size
,
262 .can_multi_conn
= cdi_can_multi_conn
,
263 .can_cache
= cdi_can_cache
,
265 .errno_is_preserved
= 1,
268 NBDKIT_REGISTER_PLUGIN (plugin
)