This can be used to filter a single partition from a disk image. --- TODO | 2 - configure.ac | 1 + filters/Makefile.am | 3 +- filters/delay/delay.c | 12 +-- filters/offset/nbdkit-offset-filter.pod | 17 ++- filters/offset/offset.c | 20 ++-- filters/partition/Makefile.am | 62 +++++++++++ filters/partition/nbdkit-partition-filter.pod | 94 +++++++++++++++++ filters/partition/partition.c | 145 ++++++++++++++++++++++++++ 9 files changed, 336 insertions(+), 20 deletions(-) diff --git a/TODO b/TODO index 3ec45fd..b1f922e 100644 --- a/TODO +++ b/TODO @@ -41,8 +41,6 @@ Suggestions for filters * copy-on-write, a popular feature in other servers -* export a single partition (like qemu-nbd -P) - Composing nbdkit ---------------- diff --git a/configure.ac b/configure.ac index 9376a2e..fd71ca6 100644 --- a/configure.ac +++ b/configure.ac @@ -515,6 +515,7 @@ AC_CONFIG_FILES([Makefile filters/Makefile filters/delay/Makefile filters/offset/Makefile + filters/partition/Makefile src/Makefile src/nbdkit.pc tests/Makefile]) diff --git a/filters/Makefile.am b/filters/Makefile.am index d4aa6c0..d918b81 100644 --- a/filters/Makefile.am +++ b/filters/Makefile.am @@ -32,4 +32,5 @@ SUBDIRS = \ delay \ - offset + offset \ + partition diff --git a/filters/delay/delay.c b/filters/delay/delay.c index c8d9ef2..66b7e56 100644 --- a/filters/delay/delay.c +++ b/filters/delay/delay.c @@ -121,30 +121,30 @@ delay_config (nbdkit_next_config *next, void *nxdata, /* Read data. */ static int -delay_pread (struct nbdkit_next *next, void *nxdata, +delay_pread (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, void *buf, uint32_t count, uint64_t offset) { read_delay (); - return next->pread (nxdata, buf, count, offset); + return next_ops->pread (nxdata, buf, count, offset); } /* Write data. */ static int -delay_pwrite (struct nbdkit_next *next, void *nxdata, +delay_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, const void *buf, uint32_t count, uint64_t offset) { write_delay (); - return next->pwrite (nxdata, buf, count, offset); + return next_ops->pwrite (nxdata, buf, count, offset); } /* Zero data. */ static int -delay_zero (struct nbdkit_next *next, void *nxdata, +delay_zero (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, uint32_t count, uint64_t offset, int may_trim) { write_delay (); - return next->zero (nxdata, count, offset, may_trim); + return next_ops->zero (nxdata, count, offset, may_trim); } static struct nbdkit_filter filter = { diff --git a/filters/offset/nbdkit-offset-filter.pod b/filters/offset/nbdkit-offset-filter.pod index 131a321..a95c2a6 100644 --- a/filters/offset/nbdkit-offset-filter.pod +++ b/filters/offset/nbdkit-offset-filter.pod @@ -36,7 +36,7 @@ Note it is an error if the range parameter is supplied and C<offset+range> is larger than the size of data served by the underlying plugin. -=head1 EXAMPLE +=head1 EXAMPLES Using L<nbdkit-file-plugin(1)>, serve the file C<disk.img> starting at offset C<1M>. The total length served is C<100M> (the underlying file @@ -44,11 +44,26 @@ must therefore be at least C<101M> in length): nbdkit --filter=offset file file=disk.img offset=1M range=100M +One way to serve a single partition from a disk is to find the start +and length of the partition, eg using: + + $ parted disk.img -- unit b print + ... + Number Start End Size Type File system Flags + 1 65536B 104792575B 104727040B primary ext2 + +You can then serve the partition only using: + + nbdkit --filter=offset file file=disk.img offset=65536 range=104727040 + +An easier way to do this is with L<nbdkit-partition-filter(1)>. + =head1 SEE ALSO L<nbdkit(1)>, L<nbdkit-file-plugin(1)>, L<nbdkit-filter(3)>. +L<nbdkit-partition-filter(1)>. =head1 AUTHORS diff --git a/filters/offset/offset.c b/filters/offset/offset.c index cd0c89b..892d5ec 100644 --- a/filters/offset/offset.c +++ b/filters/offset/offset.c @@ -81,10 +81,10 @@ offset_config_complete (nbdkit_next_config_complete *next, void *nxdata) /* Get the file size. */ static int64_t -offset_get_size (struct nbdkit_next *next, void *nxdata, +offset_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) { - int64_t real_size = next->get_size (nxdata); + int64_t real_size = next_ops->get_size (nxdata); if (range >= 0) { if (offset + range > real_size) { @@ -99,35 +99,35 @@ offset_get_size (struct nbdkit_next *next, void *nxdata, /* Read data. */ static int -offset_pread (struct nbdkit_next *next, void *nxdata, +offset_pread (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, void *buf, uint32_t count, uint64_t offs) { - return next->pread (nxdata, buf, count, offs + offset); + return next_ops->pread (nxdata, buf, count, offs + offset); } /* Write data. */ static int -offset_pwrite (struct nbdkit_next *next, void *nxdata, +offset_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, const void *buf, uint32_t count, uint64_t offs) { - return next->pwrite (nxdata, buf, count, offs + offset); + return next_ops->pwrite (nxdata, buf, count, offs + offset); } /* Trim data. */ static int -offset_trim (struct nbdkit_next *next, void *nxdata, +offset_trim (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, uint32_t count, uint64_t offs) { - return next->trim (nxdata, count, offs + offset); + return next_ops->trim (nxdata, count, offs + offset); } /* Zero data. */ static int -offset_zero (struct nbdkit_next *next, void *nxdata, +offset_zero (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, uint32_t count, uint64_t offs, int may_trim) { - return next->zero (nxdata, count, offs + offset, may_trim); + return next_ops->zero (nxdata, count, offs + offset, may_trim); } static struct nbdkit_filter filter = { diff --git a/filters/partition/Makefile.am b/filters/partition/Makefile.am new file mode 100644 index 0000000..0464e7c --- /dev/null +++ b/filters/partition/Makefile.am @@ -0,0 +1,62 @@ +# nbdkit +# Copyright (C) 2018 Red Hat Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +EXTRA_DIST = nbdkit-partition-filter.pod + +CLEANFILES = *~ + +filterdir = $(libdir)/nbdkit/filters + +filter_LTLIBRARIES = nbdkit-partition-filter.la + +nbdkit_partition_filter_la_SOURCES = \ + partition.c \ + $(top_srcdir)/include/nbdkit-filter.h + +nbdkit_partition_filter_la_CPPFLAGS = \ + -I$(top_srcdir)/include +nbdkit_partition_filter_la_CFLAGS = \ + $(WARNINGS_CFLAGS) +nbdkit_partition_filter_la_LDFLAGS = \ + -module -avoid-version -shared + +if HAVE_POD2MAN + +man_MANS = nbdkit-partition-filter.1 +CLEANFILES += $(man_MANS) + +nbdkit-partition-filter.1: nbdkit-partition-filter.pod + $(POD2MAN) $(POD2MAN_ARGS) --section=1 --name=`basename $@ .1` $< $@.t && \ + if grep 'POD ERROR' $@.t; then rm $@.t; exit 1; fi && \ + mv $@.t $@ + +endif diff --git a/filters/partition/nbdkit-partition-filter.pod b/filters/partition/nbdkit-partition-filter.pod new file mode 100644 index 0000000..133e73d --- /dev/null +++ b/filters/partition/nbdkit-partition-filter.pod @@ -0,0 +1,94 @@ +=encoding utf8 + +=head1 NAME + +nbdkit-partition-filter - nbdkit partition filter + +=head1 SYNOPSIS + + nbdkit --filter=partition plugin partition=PART [plugin-args...] + +=head1 DESCRIPTION + +C<nbdkit-partition-filter> is a filter that limits requests to a +single partition within a disk image that is served by another plugin. + +Partition numbers are specified by the required C<partition> +parameter, and count from 1. + +This works like the C<qemu-nbd -P> option. + +=head1 PARAMETERS + +=over 4 + +=item B<partition=PART> + +The partition number to serve, counting from 1. + +This parameter is required. + +=back + +=head1 EXAMPLE + +F<disk.img> is a partitioned disk image (eg. a virtual machine disk +image). To serve the first partition only use: + + nbdkit --filter=partition file file=disk.img partition=1 + +=head1 SEE ALSO + +L<nbdkit(1)>, +L<nbdkit-file-plugin(1)>, +L<nbdkit-filter(3)>. +L<nbdkit-offset-filter(1)>, +L<parted(8)>. + +=head1 AUTHORS + +Richard W.M. Jones + +=head1 COPYRIGHT + +Copyright (C) 2018 Red Hat Inc. + +=head1 LICENSE + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +=over 4 + +=item * + +Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +=item * + +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +=item * + +Neither the name of Red Hat nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +=back + +THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/filters/partition/partition.c b/filters/partition/partition.c new file mode 100644 index 0000000..2e18173 --- /dev/null +++ b/filters/partition/partition.c @@ -0,0 +1,145 @@ +/* nbdkit + * Copyright (C) 2018 Red Hat Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include <nbdkit-filter.h> + +static int partnum = -1; + +/* Called for each key=value passed on the command line. */ +static int +partition_config (nbdkit_next_config *next, void *nxdata, + const char *key, const char *value) +{ + if (strcmp (key, "partition") == 0) { + if (sscanf (value, "%d", &partnum) != 1 || partnum <= 0) { + nbdkit_error ("invalid partition number"); + return -1; + } + return 0; + } + else + return next (nxdata, key, value); +} + +/* Check the user did pass partition number. */ +static int +partition_config_complete (nbdkit_next_config_complete *next, void *nxdata) +{ + if (partnum == -1) { + nbdkit_error ("you must supply the partition parameter on the command line"); + return -1; + } + + return next (nxdata); +} + +#define partition_config_help \ + "partition=<PART> (required) The partition number (counting from 1)." + +#if 0 +/* Get the file size. */ +static int64_t +offset_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle) +{ + int64_t real_size = next_ops->get_size (nxdata); + + if (range >= 0) { + if (offset + range > real_size) { + nbdkit_error ("offset + range is larger than the real size of the underlying file or device"); + return -1; + } + return range; + } + else + return real_size - offset; +} + +/* Read data. */ +static int +offset_pread (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, void *buf, uint32_t count, uint64_t offs) +{ + return next_ops->pread (nxdata, buf, count, offs + offset); +} + +/* Write data. */ +static int +offset_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, + const void *buf, uint32_t count, uint64_t offs) +{ + return next_ops->pwrite (nxdata, buf, count, offs + offset); +} + +/* Trim data. */ +static int +offset_trim (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, uint32_t count, uint64_t offs) +{ + return next_ops->trim (nxdata, count, offs + offset); +} + +/* Zero data. */ +static int +offset_zero (struct nbdkit_next_ops *next_ops, void *nxdata, + void *handle, uint32_t count, uint64_t offs, int may_trim) +{ + return next_ops->zero (nxdata, count, offs + offset, may_trim); +} +#endif + +static struct nbdkit_filter filter = { + .name = "partition", + .longname = "nbdkit partition filter", + .version = PACKAGE_VERSION, + .config = partition_config, + .config_complete = partition_config_complete, + .config_help = partition_config_help, +#if 0 + .get_size = offset_get_size, + .pread = offset_pread, + .pwrite = offset_pwrite, + .trim = offset_trim, + .zero = offset_zero, +#endif +}; + +NBDKIT_REGISTER_FILTER(filter) -- 2.15.1