Fwd: needinfo requested: [Bug 1828289] virt-v2v: error: libguestfs error: mountpoints: stat: /dev/centos/home: No such file or directory
by Savitha Sunil
Hi ,
with reference to bug https://bugzilla.redhat.com/show_bug.cgi?id=1828289
- the version of virt-v2v and p2v :
virt-p2v-maker-1.40.2-5.el7.7.7.0.0_0_250.x86_64
virt-v2v-1.40.2-5.el7.7.7.0.0_0_250.x86_64
- the hardware of the machine being converted - attached in the snapshot.
- the OS on the machine being converted - centos 7.6
- the complete logs of the conversion - is attached.
On Mon, Apr 27, 2020 at 7:44 PM <bugzilla(a)redhat.com> wrote:
>
>
> Product: Virtualization Tools
> Version: unspecified
> Component: libguestfs
>
> Pino Toscano <ptoscano(a)redhat.com> has asked savvy <
> savitha.sunil.n(a)gmail.com>
> for needinfo:
> Bug 1828289: virt-v2v: error: libguestfs error: mountpoints: stat:
> /dev/centos/home: No such file or directory
> https://bugzilla.redhat.com/show_bug.cgi?id=1828289
>
>
>
> --- Comment #1 from Pino Toscano <ptoscano(a)redhat.com> ---
> As mentioned in the other bug, please provide all the details about the
> conversion:
> - the version of virt-v2v
> - the version of virt-p2v
> - the hardware of the machine being converted
> - the OS on the machine being converted
> - the complete logs of the conversion
>
> You can find more details in the documentation of virt-p2v:
> http://libguestfs.org/virt-p2v.1.html
> see the "HOW VIRT-P2V WORKS" section about which files to fetch from the
> conversion server after a failed conversion.
>
4 years, 6 months
[PATCH v2] python: Fix UnicodeError in inspect_list_applications2() (RHBZ#1684004)
by Sam Eiderman
The python3 bindings create unicode objects from application strings
on the guest (i.e. installed rpm, deb packages).
It is documented that rpm package fields such as description should be
utf8 encoded - however in some cases they are not a valid unicode
string, on SLES11 SP4 the following packages fail to be converted to
unicode using guestfs_int_py_fromstring() (which invokes
PyUnicode_FromString()):
PackageKit
aaa_base
coreutils
dejavu
desktop-data-SLED
gnome-utils
hunspell
hunspell-32bit
hunspell-tools
libblocxx6
libexif
libgphoto2
libgtksourceview-2_0-0
libmpfr1
libopensc2
libopensc2-32bit
liborc-0_4-0
libpackagekit-glib10
libpixman-1-0
libpixman-1-0-32bit
libpoppler-glib4
libpoppler5
libsensors3
libtelepathy-glib0
m4
opensc
opensc-32bit
permissions
pinentry
poppler-tools
python-gtksourceview
splashy
syslog-ng
tar
tightvnc
xorg-x11
xorg-x11-xauth
yast2-mouse
Fix this by globally changing guestfs_int_py_fromstring()
and guestfs_int_py_fromstringsize() to decode utf-8 with the "replace"
error handler:
https://docs.python.org/3/library/codecs.html#error-handlers
For example, this will decode PackageKit's description on SLES4 the
following way:
Backend: pisi
S.�ağlar Onur <caglar(a)pardus.org.tr>
Signed-off-by: Sam Eiderman <sameid(a)google.com>
---
python/handle.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/handle.c b/python/handle.c
index 2fb8c18f0..427424707 100644
--- a/python/handle.c
+++ b/python/handle.c
@@ -387,7 +387,7 @@ guestfs_int_py_fromstring (const char *str)
#if PY_MAJOR_VERSION < 3
return PyString_FromString (str);
#else
- return PyUnicode_FromString (str);
+ return PyUnicode_Decode(str, strlen(str), "utf-8", "replace");
#endif
}
@@ -397,7 +397,7 @@ guestfs_int_py_fromstringsize (const char *str, size_t size)
#if PY_MAJOR_VERSION < 3
return PyString_FromStringAndSize (str, size);
#else
- return PyUnicode_FromStringAndSize (str, size);
+ return PyUnicode_Decode(str, size, "utf-8", "replace");
#endif
}
--
2.26.1.301.g55bc3eb7cb9-goog
4 years, 7 months
virt-v2v: error: no href in ovf:File (id=)
by Andrew Thurber (anthurbe)
Hello,
This multi-disk ovf generates “no href in ovf:File (id=)”
Other single-disk ovfs on the same system work. I don’t have another multi-disk ova to try.
I’ve compared the syntax with the test file on github and it appears to be essentially the same:
virt-v2v/tests/test-v2v-i-ova-two-disks.ovf
Any suggestions?
Side note: I tried building libguestfs from source but failed so haven’t tried with latest (separate issue, but I think I resolved dependencies, then hit a podwrapper.pl issue).
Thank you,
Andrew
[ with text changed for privacy ]
Head of the .ovf file:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope vmw:buildId="build-3620759" xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationS..." xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettin..." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<References>
<File ovf:href="aa-bb-cccc-1.2.3-45-release-200401.ova_v1.2_signed-disk1.vmdk" ovf:id="file1" ovf:size="1530541056"/>
<File ovf:href="aa-bb-cccc-1.2.3-45-release-200401.ova_v1.2_signed-disk2.vmdk" ovf:id="file2" ovf:size="6476920320"/>
<File ovf:href="aa-bb-cccc-1.2.3-45-release-200401.ova_v1.2_signed-disk3.vmdk" ovf:id="file3" ovf:size="1696059392"/>
</References>
<DeploymentOptionSection>
<Info>IP Network Stack in use by the product</Info>
<Configuration ovf:default="true" ovf:id="aa_ipv4">
<Label>IPv4 Network</Label>
<Description>Use IPv4 network stack for management and data traffic.</Description>
</Configuration>
<Configuration ovf:id="aa_ipv6">
<Label>IPv6 Network</Label>
<Description>Use IPv6 network stack for management and data traffic.</Description>
</Configuration>
<Configuration ovf:id="1int">
<Label>IPv4 Network on a Single Interface (demo mode)</Label>
<Description>Use a single interface for IPv4 management and data traffic.</Description>
</Configuration>
</DeploymentOptionSection>
<DiskSection>
<Info>Virtual disk information</Info>
<Disk ovf:capacity="50" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="3584360448"/>
<Disk ovf:capacity="156" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk2" ovf:fileRef="file2" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="16995385344"/>
<Disk ovf:capacity="76" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk6" ovf:fileRef="file3" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="1704001536"/>
<Disk ovf:capacity="${logfs}" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk3" ovf:fileRef="" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="0"/>
<Disk ovf:capacity="${corefs}" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk4" ovf:fileRef="" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="0"/>
<Disk ovf:capacity="${ddatafs}" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk5" ovf:fileRef="" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="0"/>
</DiskSection>
…
And the virt-v2v error:
[root@localhost ~]# virt-v2v -v -x -i ova aa-bb-cccc-1.2.3-45-release-200401.ova -of qcow2
virt-v2v: libguestfs 1.38.4rhel=8,release=14.module_el8.1.0+248+298dec18,libvirt (x86_64)
libvirt version: 4.5.0
[ 0.0] Opening the source -i ova aa-bb-cccc-1.2.3-45-release-200401.ova
libguestfs: trace: set_verbose true
libguestfs: trace: set_verbose = 0
libguestfs: trace: get_cachedir
libguestfs: trace: get_cachedir = "/var/tmp"
qemu-img info json:'{ "file": { "driver": "raw", "offset": 512, "size": 512, "file": { "filename": "/tmp/v2vqemuimgtst8f2fb6.img" } } }' >/dev/null
qemu-img supports "offset" and "size" in json URLs: true
libguestfs: trace: set_verbose true
libguestfs: trace: set_verbose = 0
libguestfs: trace: get_backend
libguestfs: trace: get_backend = "libvirt"
libvirt supports "raw" driver in json URL: true
tar -tf 'aa-bb-cccc-1.2.3-45-release-200401.ova'
tar -xf 'aa-bb-cccc-1.2.3-45-release-200401.ova' -C '/var/tmp/ova.1MI0Ml' 'aa-bb-cccc-1.2.3-45-release-200401.ova_v6.5_signed.ovf' 'aa-bb-cccc-1.2.3-45-release-200401.ova_v1.2_signed.mf'
virt-v2v: error: no href in ovf:File (id=)
rm -rf '/var/tmp/ova.1MI0Ml'
libguestfs: trace: close
libguestfs: closing guestfs handle 0x558469792ff0 (state 0)
libguestfs: trace: close
libguestfs: closing guestfs handle 0x558469781930 (state 0)
4 years, 7 months
[PATCH nbdkit] golang: Pass Plugin and Connection by reference not value.
by Richard W.M. Jones
For the current set of examples this doesn't matter. This also adds
another example where we use the Connection to store data, just to
check that actually works.
Thanks: James @ purpleidea, Dan Berrangé
---
plugins/golang/nbdkit-golang-plugin.pod | 10 +-
plugins/golang/Makefile.am | 9 +
plugins/golang/examples/disk/disk.go | 168 ++++++++++++++++++
.../golang/examples/dump-plugin/dumpplugin.go | 8 +-
plugins/golang/examples/minimal/minimal.go | 6 +-
plugins/golang/examples/ramdisk/ramdisk.go | 18 +-
.../src/libguestfs.org/nbdkit/nbdkit.go | 42 ++---
plugins/golang/test/test.go | 14 +-
8 files changed, 226 insertions(+), 49 deletions(-)
diff --git a/plugins/golang/nbdkit-golang-plugin.pod b/plugins/golang/nbdkit-golang-plugin.pod
index b15bb481..90732289 100644
--- a/plugins/golang/nbdkit-golang-plugin.pod
+++ b/plugins/golang/nbdkit-golang-plugin.pod
@@ -62,16 +62,16 @@ C<GetSize> and C<PRead>. What connects the two is the C<Open>
callback which is called when the client has connected and where you
should return a new instance of your connection struct. For example:
- func (p MyPlugin) Load() {
+ func (p *MyPlugin) Load() {
// global callback used for initializing the plugin
}
- func (p MyPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+ func (p *MyPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
// new client has connected
return &MyConnection{}, nil
}
- func (c MyConnection) GetSize() (uint64, error) {
+ func (c *MyConnection) GetSize() (uint64, error) {
// called per-client
return virtual_size, nil
}
@@ -106,11 +106,11 @@ unless you also implement a C<CanWrite> callback that returns true.
The same applies to C<Flush> (C<CanFlush>), C<Trim> (C<CanTrim>) and
C<Zero> (C<CanZero>).
- func (c MyConnection) CanWrite() (bool, error) {
+ func (c *MyConnection) CanWrite() (bool, error) {
return true, nil
}
- func (c MyConnection) PWrite(buf []byte, offset uint64,
+ func (c *MyConnection) PWrite(buf []byte, offset uint64,
flags uint32) error {
// ...
}
diff --git a/plugins/golang/Makefile.am b/plugins/golang/Makefile.am
index 74ad4a72..91711724 100644
--- a/plugins/golang/Makefile.am
+++ b/plugins/golang/Makefile.am
@@ -42,6 +42,7 @@ EXTRA_DIST = \
$(plugin_sources) \
config-test.go \
dump-plugin-examples.sh \
+ examples/disk/disk.go \
examples/dump-plugin/dumpplugin.go \
examples/minimal/minimal.go \
examples/ramdisk/ramdisk.go \
@@ -58,11 +59,19 @@ if HAVE_GOLANG
# Examples.
noinst_DATA = \
+ examples/disk/nbdkit-godisk-plugin.so \
examples/dump-plugin/nbdkit-godump-plugin.so \
examples/minimal/nbdkit-gominimal-plugin.so \
examples/ramdisk/nbdkit-goramdisk-plugin.so \
$(NULL)
+examples/disk/nbdkit-godisk-plugin.so: \
+ $(plugin_sources) examples/disk/disk.go
+ cd examples/disk && \
+ PKG_CONFIG_PATH="$(abs_top_builddir)/server/local$${PKG_CONFIG_PATH:+:$$PKG_CONFIG_PATH}" \
+ GOPATH="$(abs_builddir)" \
+ $(GOLANG) build -o nbdkit-godisk-plugin.so -buildmode=c-shared
+
examples/dump-plugin/nbdkit-godump-plugin.so: \
$(plugin_sources) examples/dump-plugin/dumpplugin.go
cd examples/dump-plugin && \
diff --git a/plugins/golang/examples/disk/disk.go b/plugins/golang/examples/disk/disk.go
new file mode 100644
index 00000000..37f449e0
--- /dev/null
+++ b/plugins/golang/examples/disk/disk.go
@@ -0,0 +1,168 @@
+/* Example plugin.
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * 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.
+ */
+
+package main
+
+import (
+ "C"
+ "io/ioutil"
+ "libguestfs.org/nbdkit"
+ "os"
+ "strconv"
+ "unsafe"
+)
+
+var pluginName = "disk"
+
+type DiskPlugin struct {
+ nbdkit.Plugin
+}
+
+type DiskConnection struct {
+ nbdkit.Connection
+ fd *os.File
+}
+
+var size uint64
+var size_set = false
+
+func (p *DiskPlugin) Config(key string, value string) error {
+ if key == "size" {
+ var err error
+ size, err = strconv.ParseUint(value, 0, 64)
+ if err != nil {
+ return err
+ }
+ size_set = true
+ return nil
+ } else {
+ return nbdkit.PluginError{Errmsg: "unknown parameter"}
+ }
+}
+
+func (p *DiskPlugin) ConfigComplete() error {
+ if !size_set {
+ return nbdkit.PluginError{Errmsg: "size parameter is required"}
+ }
+ return nil
+}
+
+func (p *DiskPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+ // Open a temporary file.
+ fd, err := ioutil.TempFile("/var/tmp", "nbdkitdisk")
+ if err != nil {
+ return nil, err
+ }
+ os.Remove(fd.Name())
+
+ // Truncate it to the right size.
+ err = fd.Truncate(int64(size))
+ if err != nil {
+ return nil, err
+ }
+
+ // Store the file descriptor of the temporary file in the
+ // Connection struct.
+ return &DiskConnection{fd: fd}, nil
+}
+
+func (c *DiskConnection) Close() {
+ c.fd.Close()
+}
+
+func (c *DiskConnection) GetSize() (uint64, error) {
+ // Return the size of the disk. We could just return the
+ // global "size" here, but make the example more interesting.
+ info, err := c.fd.Stat()
+ if err != nil {
+ return 0, err
+ }
+ return uint64(info.Size()), nil
+}
+
+// Multi-conn is NOT safe because each client sees a different disk.
+func (c *DiskConnection) CanMultiConn() (bool, error) {
+ return false, nil
+}
+
+func (c *DiskConnection) PRead(buf []byte, offset uint64,
+ flags uint32) error {
+ n, err := c.fd.ReadAt(buf, int64(offset))
+ if err != nil {
+ return err
+ }
+ // NBD requests must always read/write the whole requested
+ // amount, or else fail. Actually we should loop here (XXX).
+ if n != len(buf) {
+ return nbdkit.PluginError{Errmsg: "short read"}
+ }
+ return nil
+}
+
+// Note that CanWrite is required in golang plugins, otherwise PWrite
+// will never be called.
+func (c *DiskConnection) CanWrite() (bool, error) {
+ return true, nil
+}
+
+func (c *DiskConnection) PWrite(buf []byte, offset uint64,
+ flags uint32) error {
+ n, err := c.fd.WriteAt(buf, int64(offset))
+ if err != nil {
+ return err
+ }
+ // NBD requests must always read/write the whole requested
+ // amount, or else fail. Actually we should loop here (XXX).
+ if n != len(buf) {
+ return nbdkit.PluginError{Errmsg: "short write"}
+ }
+ return nil
+}
+
+//----------------------------------------------------------------------
+//
+// The boilerplate below this line is required by all golang plugins,
+// as well as importing "C" and "unsafe" modules at the top of the
+// file.
+
+//export plugin_init
+func plugin_init() unsafe.Pointer {
+ // If your plugin needs to do any initialization, you can
+ // either put it here or implement a Load() method.
+ // ...
+
+ // Then you must call the following function.
+ return nbdkit.PluginInitialize(pluginName, &DiskPlugin{})
+}
+
+// This is never(?) called, but must exist.
+func main() {}
diff --git a/plugins/golang/examples/dump-plugin/dumpplugin.go b/plugins/golang/examples/dump-plugin/dumpplugin.go
index 518be078..d30ec3f1 100644
--- a/plugins/golang/examples/dump-plugin/dumpplugin.go
+++ b/plugins/golang/examples/dump-plugin/dumpplugin.go
@@ -51,19 +51,19 @@ type DumpConnection struct {
var size uint64 = 1024 * 1024
-func (p DumpPlugin) DumpPlugin() {
+func (p *DumpPlugin) DumpPlugin() {
fmt.Println("golang_dump_plugin=1")
}
-func (p DumpPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+func (p *DumpPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
return &DumpConnection{}, nil
}
-func (c DumpConnection) GetSize() (uint64, error) {
+func (c *DumpConnection) GetSize() (uint64, error) {
return size, nil
}
-func (c DumpConnection) PRead(buf []byte, offset uint64,
+func (c *DumpConnection) PRead(buf []byte, offset uint64,
flags uint32) error {
for i := 0; i < len(buf); i++ {
buf[i] = 0
diff --git a/plugins/golang/examples/minimal/minimal.go b/plugins/golang/examples/minimal/minimal.go
index e010bfcb..0f862889 100644
--- a/plugins/golang/examples/minimal/minimal.go
+++ b/plugins/golang/examples/minimal/minimal.go
@@ -50,15 +50,15 @@ type MinimalConnection struct {
var size uint64 = 1024 * 1024
-func (p MinimalPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+func (p *MinimalPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
return &MinimalConnection{}, nil
}
-func (c MinimalConnection) GetSize() (uint64, error) {
+func (c *MinimalConnection) GetSize() (uint64, error) {
return size, nil
}
-func (c MinimalConnection) PRead(buf []byte, offset uint64,
+func (c *MinimalConnection) PRead(buf []byte, offset uint64,
flags uint32) error {
for i := 0; i < len(buf); i++ {
buf[i] = 0
diff --git a/plugins/golang/examples/ramdisk/ramdisk.go b/plugins/golang/examples/ramdisk/ramdisk.go
index c848f575..78cb1f4c 100644
--- a/plugins/golang/examples/ramdisk/ramdisk.go
+++ b/plugins/golang/examples/ramdisk/ramdisk.go
@@ -53,7 +53,7 @@ var size uint64
var size_set = false
var disk []byte
-func (p RAMDiskPlugin) Config(key string, value string) error {
+func (p *RAMDiskPlugin) Config(key string, value string) error {
if key == "size" {
var err error
size, err = strconv.ParseUint(value, 0, 64)
@@ -67,33 +67,33 @@ func (p RAMDiskPlugin) Config(key string, value string) error {
}
}
-func (p RAMDiskPlugin) ConfigComplete() error {
+func (p *RAMDiskPlugin) ConfigComplete() error {
if !size_set {
return nbdkit.PluginError{Errmsg: "size parameter is required"}
}
return nil
}
-func (p RAMDiskPlugin) GetReady() error {
+func (p *RAMDiskPlugin) GetReady() error {
// Allocate the RAM disk.
disk = make([]byte, size)
return nil
}
-func (p RAMDiskPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+func (p *RAMDiskPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
return &RAMDiskConnection{}, nil
}
-func (c RAMDiskConnection) GetSize() (uint64, error) {
+func (c *RAMDiskConnection) GetSize() (uint64, error) {
return size, nil
}
// Clients are allowed to make multiple connections safely.
-func (c RAMDiskConnection) CanMultiConn() (bool, error) {
+func (c *RAMDiskConnection) CanMultiConn() (bool, error) {
return true, nil
}
-func (c RAMDiskConnection) PRead(buf []byte, offset uint64,
+func (c *RAMDiskConnection) PRead(buf []byte, offset uint64,
flags uint32) error {
copy(buf, disk[offset:int(offset)+len(buf)])
return nil
@@ -101,11 +101,11 @@ func (c RAMDiskConnection) PRead(buf []byte, offset uint64,
// Note that CanWrite is required in golang plugins, otherwise PWrite
// will never be called.
-func (c RAMDiskConnection) CanWrite() (bool, error) {
+func (c *RAMDiskConnection) CanWrite() (bool, error) {
return true, nil
}
-func (c RAMDiskConnection) PWrite(buf []byte, offset uint64,
+func (c *RAMDiskConnection) PWrite(buf []byte, offset uint64,
flags uint32) error {
copy(disk[offset:int(offset)+len(buf)], buf)
return nil
diff --git a/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go b/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
index 155034d9..8e9e9bbd 100644
--- a/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
+++ b/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
@@ -145,83 +145,83 @@ type ConnectionInterface interface {
type Plugin struct{}
type Connection struct{}
-func (p Plugin) Load() {
+func (p *Plugin) Load() {
}
-func (p Plugin) Unload() {
+func (p *Plugin) Unload() {
}
-func (p Plugin) DumpPlugin() {
+func (p *Plugin) DumpPlugin() {
}
-func (p Plugin) Config(key string, value string) error {
+func (p *Plugin) Config(key string, value string) error {
return nil
}
-func (p Plugin) ConfigComplete() error {
+func (p *Plugin) ConfigComplete() error {
return nil
}
-func (p Plugin) GetReady() error {
+func (p *Plugin) GetReady() error {
return nil
}
-func (p Plugin) PreConnect(readonly bool) error {
+func (p *Plugin) PreConnect(readonly bool) error {
return nil
}
-func (p Plugin) Open(readonly bool) (ConnectionInterface, error) {
+func (p *Plugin) Open(readonly bool) (ConnectionInterface, error) {
panic("plugin must implement Open()")
}
-func (c Connection) Close() {
+func (c *Connection) Close() {
}
-func (c Connection) GetSize() (uint64, error) {
+func (c *Connection) GetSize() (uint64, error) {
panic("plugin must implement GetSize()")
}
-func (c Connection) CanWrite() (bool, error) {
+func (c *Connection) CanWrite() (bool, error) {
return false, nil
}
-func (c Connection) CanFlush() (bool, error) {
+func (c *Connection) CanFlush() (bool, error) {
return false, nil
}
-func (c Connection) IsRotational() (bool, error) {
+func (c *Connection) IsRotational() (bool, error) {
return false, nil
}
-func (c Connection) CanTrim() (bool, error) {
+func (c *Connection) CanTrim() (bool, error) {
return false, nil
}
-func (c Connection) CanZero() (bool, error) {
+func (c *Connection) CanZero() (bool, error) {
return false, nil
}
-func (c Connection) CanMultiConn() (bool, error) {
+func (c *Connection) CanMultiConn() (bool, error) {
return false, nil
}
-func (c Connection) PRead(buf []byte, offset uint64, flags uint32) error {
+func (c *Connection) PRead(buf []byte, offset uint64, flags uint32) error {
panic("plugin must implement PRead()")
}
-func (c Connection) PWrite(buf []byte, offset uint64, flags uint32) error {
+func (c *Connection) PWrite(buf []byte, offset uint64, flags uint32) error {
panic("plugin CanWrite returns true, but no PWrite() function")
}
-func (c Connection) Flush(flags uint32) error {
+func (c *Connection) Flush(flags uint32) error {
panic("plugin CanFlush returns true, but no Flush() function")
}
-func (c Connection) Trim(count uint32, offset uint64, flags uint32) error {
+func (c *Connection) Trim(count uint32, offset uint64, flags uint32) error {
panic("plugin CanTrim returns true, but no Trim() function")
}
-func (c Connection) Zero(count uint32, offset uint64, flags uint32) error {
+func (c *Connection) Zero(count uint32, offset uint64, flags uint32) error {
panic("plugin CanZero returns true, but no Zero() function")
}
diff --git a/plugins/golang/test/test.go b/plugins/golang/test/test.go
index 7186ffa8..e585a971 100644
--- a/plugins/golang/test/test.go
+++ b/plugins/golang/test/test.go
@@ -52,15 +52,15 @@ type TestConnection struct {
var size uint64
var size_set = false
-func (p TestPlugin) Load() {
+func (p *TestPlugin) Load() {
nbdkit.Debug("golang code running in the .load callback")
}
-func (p TestPlugin) Unload() {
+func (p *TestPlugin) Unload() {
nbdkit.Debug("golang code running in the .unload callback")
}
-func (p TestPlugin) Config(key string, value string) error {
+func (p *TestPlugin) Config(key string, value string) error {
if key == "size" {
var err error
size, err = strconv.ParseUint(value, 0, 64)
@@ -74,24 +74,24 @@ func (p TestPlugin) Config(key string, value string) error {
}
}
-func (p TestPlugin) ConfigComplete() error {
+func (p *TestPlugin) ConfigComplete() error {
if !size_set {
return nbdkit.PluginError{Errmsg: "size parameter is required"}
}
return nil
}
-func (p TestPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+func (p *TestPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
nbdkit.Debug("golang code running in the .open callback")
return &TestConnection{}, nil
}
-func (c TestConnection) GetSize() (uint64, error) {
+func (c *TestConnection) GetSize() (uint64, error) {
nbdkit.Debug("golang code running in the .get_size callback")
return size, nil
}
-func (c TestConnection) PRead(buf []byte, offset uint64, flags uint32) error {
+func (c *TestConnection) PRead(buf []byte, offset uint64, flags uint32) error {
nbdkit.Debug("golang code running in the .pread callback")
for i := 0; i < len(buf); i++ {
buf[i] = 0
--
2.25.0
4 years, 7 months
[PATCH nbdkit] golang: Compile against the local nbdkit build, not installed.
by Richard W.M. Jones
When compiling when an older nbdkit is installed, the build would fail
because certain symbols such as .get_ready were not defined:
../../src/libguestfs.org/nbdkit/nbdkit.go:541:8: plugin.get_ready undefined (type _Ctype_struct_nbdkit_plugin has no field or method get_ready)
This happens because we were using the installed <nbdkit-plugin.h>
rather than the local copy.
We don't want to modify the *.go files themselves as they might be
copied into other projects. Instead we can set PKG_CONFIG to point to
a fake pkg-config binary which will return the correct CFLAGS.
Fixes: commit 1ff44288ae1cf95428283e252edd9474c3fe3b55
Thanks: Dan Berrangé, Eric Blake
---
.gitignore | 1 +
configure.ac | 2 ++
plugins/golang/Makefile.am | 4 +++
plugins/golang/golang-pkgconf.sh.in | 40 +++++++++++++++++++++++++++++
4 files changed, 47 insertions(+)
diff --git a/.gitignore b/.gitignore
index 4f6fcf1b..bda3b05a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,6 +74,7 @@ plugins/*/*.3
/plugins/eval/methods.c
/plugins/golang/examples/*/nbdkit-*-plugin.h
/plugins/golang/examples/*/nbdkit-*-plugin.so
+/plugins/golang/golang-pkgconf.sh
/plugins/golang/test/nbdkit-gotest-plugin.h
/plugins/golang/test/nbdkit-gotest-plugin.so
/plugins/ocaml/nbdkit-ocamlexample-plugin.so
diff --git a/configure.ac b/configure.ac
index b71d9d8c..405890f5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1007,6 +1007,8 @@ AC_CONFIG_FILES([podwrapper.pl],
[chmod +x,-w podwrapper.pl])
AC_CONFIG_FILES([common/protocol/generate-protostrings.sh],
[chmod +x,-w common/protocol/generate-protostrings.sh])
+AC_CONFIG_FILES([plugins/golang/golang-pkgconf.sh],
+ [chmod +x,-w plugins/golang/golang-pkgconf.sh])
AC_CONFIG_FILES([Makefile
bash/Makefile
common/bitmap/Makefile
diff --git a/plugins/golang/Makefile.am b/plugins/golang/Makefile.am
index f189184c..60539229 100644
--- a/plugins/golang/Makefile.am
+++ b/plugins/golang/Makefile.am
@@ -66,18 +66,21 @@ noinst_DATA = \
examples/dump-plugin/nbdkit-godump-plugin.so: \
$(plugin_sources) examples/dump-plugin/dumpplugin.go
cd examples/dump-plugin && \
+ PKG_CONFIG=$(abs_builddir)/golang-pkgconf.sh \
GOPATH="$(abs_builddir)" \
$(GOLANG) build -o nbdkit-godump-plugin.so -buildmode=c-shared
examples/minimal/nbdkit-gominimal-plugin.so: \
$(plugin_sources) examples/minimal/minimal.go
cd examples/minimal && \
+ PKG_CONFIG=$(abs_builddir)/golang-pkgconf.sh \
GOPATH="$(abs_builddir)" \
$(GOLANG) build -o nbdkit-gominimal-plugin.so -buildmode=c-shared
examples/ramdisk/nbdkit-goramdisk-plugin.so: \
$(plugin_sources) examples/ramdisk/ramdisk.go
cd examples/ramdisk && \
+ PKG_CONFIG=$(abs_builddir)/golang-pkgconf.sh \
GOPATH="$(abs_builddir)" \
$(GOLANG) build -o nbdkit-goramdisk-plugin.so -buildmode=c-shared
@@ -87,6 +90,7 @@ check_DATA = test/nbdkit-gotest-plugin.so
test/nbdkit-gotest-plugin.so: $(plugin_sources) test/test.go
cd test && \
+ PKG_CONFIG=$(abs_builddir)/golang-pkgconf.sh \
GOPATH="$(abs_builddir)" \
$(GOLANG) build -o nbdkit-gotest-plugin.so -buildmode=c-shared
diff --git a/plugins/golang/golang-pkgconf.sh.in b/plugins/golang/golang-pkgconf.sh.in
new file mode 100644
index 00000000..11af3718
--- /dev/null
+++ b/plugins/golang/golang-pkgconf.sh.in
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2020 Red Hat Inc.
+#
+# 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.
+
+# This fake pkg-config program is used to trick cgo so that
+# "#cgo pkg-config nbdkit" lines are processed relative to the local
+# directory and not the installed nbdkit.
+
+case "$1" in
+ --cflags*) echo "-I@abs_top_builddir@/include" ;;
+ *) ;;
+esac
--
2.18.2
4 years, 7 months
[PATCH nbdkit v2] Add the ability to write plugins in golang.
by Richard W.M. Jones
Thanks: Dan Berrangé
XXX UNFINISHED:
- Is using uintptr for the handle a good idea? Plugins must return
something != 0. In other languages we would allow plugins to
return an arbitrary object here, but this is not possible in golang
because of lack of GC roots.
- Default can_* methods are hard to implement. Ideally we would be
able to test if a user plugin implements a particular callback
(eg. TestPlugin.PWrite) or else defaults to the default callback,
but even with reflection I don't think this is possible in golang.
- Write wrappers etc for all the other methods.
- Write documentation.
---
plugins/golang/nbdkit-golang-plugin.pod | 34 +++
configure.ac | 32 +++
plugins/golang/Makefile.am | 80 +++++++
.../src/libguestfs.org/nbdkit/wrappers.h | 39 +++
plugins/golang/config-test.go | 38 +++
.../src/libguestfs.org/nbdkit/nbdkit.go | 224 ++++++++++++++++++
.../golang/src/libguestfs.org/nbdkit/utils.go | 75 ++++++
.../src/libguestfs.org/nbdkit/wrappers.go | 88 +++++++
plugins/golang/test/run-test.sh | 42 ++++
plugins/golang/test/test.go | 102 ++++++++
.gitignore | 2 +
README | 4 +
12 files changed, 760 insertions(+)
diff --git a/plugins/golang/nbdkit-golang-plugin.pod b/plugins/golang/nbdkit-golang-plugin.pod
new file mode 100644
index 00000000..b449a830
--- /dev/null
+++ b/plugins/golang/nbdkit-golang-plugin.pod
@@ -0,0 +1,34 @@
+=head1 NAME
+
+nbdkit-golang-plugin - writing nbdkit plugins in Go
+
+=head1 SYNOPSIS
+
+ nbdkit /path/to/plugin.so [arguments...]
+
+=head1 DESCRIPTION
+
+This manual page describes how to write nbdkit plugins in compiled
+Golang code. Go plugins are compiled to F<*.so> files (the same as
+plugins written in C) and are used in the same way.
+
+XXX MORE DOCS
+
+
+
+=head1 VERSION
+
+Golang plugins first appeared in nbdkit 1.20.
+
+=head1 SEE ALSO
+
+L<nbdkit(1)>,
+L<nbdkit-plugin(3)>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones
+
+=head1 COPYRIGHT
+
+Copyright (C) 2020 Red Hat Inc.
diff --git a/configure.ac b/configure.ac
index c1aec8fa..7fbf7abe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,7 @@ LT_INIT
dnl List of plugins and filters.
lang_plugins="\
+ golang \
lua \
ocaml \
perl \
@@ -754,6 +755,34 @@ AS_IF([test "x$enable_lua" != "xno"],[
])
AM_CONDITIONAL([HAVE_LUA],[test "x$enable_lua" = "xyes"])
+dnl Check for golang.
+AC_ARG_ENABLE([golang],
+ AS_HELP_STRING([--disable-golang], [disable Go language plugin]),
+ [],
+ [enable_golang=yes])
+AS_IF([test "x$enable_golang" != "xno"],[
+ AC_CHECK_PROG([GOLANG],[go],[go],[no])
+ AS_IF([test "x$GOLANG" != "xno"],[
+ AC_MSG_CHECKING([if $GOLANG is usable])
+ AS_IF([$GOLANG run $srcdir/plugins/golang/config-test.go 2>&AS_MESSAGE_LOG_FD],[
+ AC_MSG_RESULT([yes])
+
+ # Substitute some golang environment.
+ GOOS=`$GOLANG env GOOS`
+ GOARCH=`$GOLANG env GOARCH`
+ GOROOT=`$GOLANG env GOROOT`
+ AC_SUBST([GOOS])
+ AC_SUBST([GOARCH])
+ AC_SUBST([GOROOT])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_MSG_WARN([golang ($GOLANG) is installed but not usable])
+ GOLANG=no
+ ])
+ ])
+],[GOLANG=no])
+AM_CONDITIONAL([HAVE_GOLANG],[test "x$GOLANG" != "xno"])
+
dnl Check for curl (only if you want to compile the curl plugin).
AC_ARG_WITH([curl],
[AS_HELP_STRING([--without-curl],
@@ -1002,6 +1031,7 @@ AC_CONFIG_FILES([Makefile
plugins/file/Makefile
plugins/floppy/Makefile
plugins/full/Makefile
+ plugins/golang/Makefile
plugins/guestfs/Makefile
plugins/gzip/Makefile
plugins/info/Makefile
@@ -1125,6 +1155,8 @@ feature "vddk ................................... " \
echo
echo "Languages:"
echo
+feature "go ..................................... " \
+ test "x$HAVE_GOLANG_TRUE" = "x"
feature "lua .................................... " \
test "x$HAVE_LUA_TRUE" = "x"
feature "ocaml .................................. " \
diff --git a/plugins/golang/Makefile.am b/plugins/golang/Makefile.am
new file mode 100644
index 00000000..4f69f03f
--- /dev/null
+++ b/plugins/golang/Makefile.am
@@ -0,0 +1,80 @@
+# nbdkit
+# Copyright (C) 2020 Red Hat Inc.
+#
+# 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 $(top_srcdir)/common-rules.mk
+
+EXTRA_DIST = \
+ nbdkit-golang-plugin.pod \
+ src/libguestfs.org/nbdkit/nbdkit.go \
+ src/libguestfs.org/nbdkit/utils.go \
+ src/libguestfs.org/nbdkit/wrappers.go \
+ src/libguestfs.org/nbdkit/wrappers.h \
+ test/run-test.sh \
+ test/test.go \
+ $(NULL)
+
+if HAVE_GOLANG
+
+# There is nothing to build. Everything is statically compiled and
+# linked together when we compile the test.
+
+TESTS = test/run-test.sh
+check_DATA = test/nbdkit-gotest-plugin.so
+
+test/nbdkit-gotest-plugin.so: \
+ src/libguestfs.org/nbdkit/nbdkit.go \
+ src/libguestfs.org/nbdkit/utils.go \
+ src/libguestfs.org/nbdkit/wrappers.go \
+ src/libguestfs.org/nbdkit/wrappers.h \
+ test/test.go
+ cd test && \
+ GOPATH="$(abs_builddir)" \
+ $(GOLANG) build \
+ -o nbdkit-gotest-plugin.so -buildmode=c-shared
+
+CLEANFILES += \
+ test/nbdkit-gotest-plugin.h \
+ test/nbdkit-gotest-plugin.so \
+ $(NULL)
+
+if HAVE_POD
+
+man_MANS = nbdkit-golang-plugin.3
+CLEANFILES += $(man_MANS)
+
+nbdkit-golang-plugin.3: nbdkit-golang-plugin.pod
+ $(PODWRAPPER) --section=3 --man $@ \
+ --html $(top_builddir)/html/$@.html \
+ $<
+
+endif HAVE_POD
+
+endif HAVE_GOLANG
diff --git a/plugins/golang/src/libguestfs.org/nbdkit/wrappers.h b/plugins/golang/src/libguestfs.org/nbdkit/wrappers.h
new file mode 100644
index 00000000..e385663f
--- /dev/null
+++ b/plugins/golang/src/libguestfs.org/nbdkit/wrappers.h
@@ -0,0 +1,39 @@
+/* cgo wrappers.
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * 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.
+ */
+
+extern int config_wrapper (const char *key, const char *value);
+extern int config_complete_wrapper (void);
+extern void *open_wrapper (int readonly);
+extern void close_wrapper (void *handle);
+extern int64_t get_size_wrapper (void *handle);
+extern int pread_wrapper (void *handle, void *buf,
+ uint32_t count, uint64_t offset, uint32_t flags);
diff --git a/plugins/golang/config-test.go b/plugins/golang/config-test.go
new file mode 100644
index 00000000..0f5cfe6b
--- /dev/null
+++ b/plugins/golang/config-test.go
@@ -0,0 +1,38 @@
+/* Go configuration test
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * 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.
+ */
+
+/* Used by ./configure to check golang is functional. */
+
+package main
+
+func main() {
+}
diff --git a/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go b/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
new file mode 100644
index 00000000..3abf39bc
--- /dev/null
+++ b/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
@@ -0,0 +1,224 @@
+/* Go helper functions.
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * 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.
+ */
+
+package nbdkit
+
+/*
+#cgo pkg-config: nbdkit
+#cgo LDFLAGS: -Wl,--unresolved-symbols=ignore-in-object-files
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NBDKIT_API_VERSION 2
+#include <nbdkit-plugin.h>
+#include "wrappers.h"
+*/
+import "C"
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+// The plugin may raise errors by returning this struct (instead of nil).
+type PluginError struct {
+ Errmsg string // string (passed to nbdkit_error)
+ Errno syscall.Errno // errno (optional, use 0 if not available)
+}
+
+func (e PluginError) String() string {
+ if e.Errno != 0 {
+ return e.Errmsg
+ } else {
+ return fmt.Sprintf("%s (errno %d)", e.Errmsg, e.Errno)
+ }
+}
+
+func (e PluginError) Error() string {
+ return e.String()
+}
+
+// The plugin interface.
+type PluginInterface interface {
+ // Open, GetSize and PRead are required for all plugins.
+ // Other methods are optional.
+ Config(key string, value string) error
+ ConfigComplete() error
+ Open(readonly bool) (uintptr, error)
+ Close(handle uintptr)
+ GetSize(handle uintptr) (uint64, error)
+ PRead(handle uintptr, buf []byte, offset uint64,
+ flags uint32) error
+}
+
+// Default implementations for plugin interface methods.
+type Plugin struct{}
+
+func (p Plugin) Config(key string, value string) error {
+ return nil
+}
+
+func (p Plugin) ConfigComplete() error {
+ return nil
+}
+
+func (p Plugin) Open(readonly bool) (uintptr, error) {
+ panic("plugin must implement Open()")
+}
+
+func (p Plugin) Close(hande uintptr) {
+}
+
+func (p Plugin) GetSize(handle uintptr) (uint64, error) {
+ panic("plugin must implement GetSize()")
+}
+
+func (p Plugin) PRead(handle uintptr, buf []byte,
+ offset uint64, flags uint32) error {
+ panic("plugin must implement PRead()")
+}
+
+// The implementation of the user plugin.
+var pluginImpl PluginInterface
+
+// Callbacks from the server. These translate C to Go and back.
+
+func set_error(err error) {
+ perr, ok := err.(PluginError)
+ if ok {
+ if perr.Errno != 0 {
+ SetError(perr.Errno)
+ }
+ Error(perr.Errmsg)
+ } else {
+ Error(err.Error())
+ }
+}
+
+//export implConfig
+func implConfig(key *C.char, value *C.char) C.int {
+ err := pluginImpl.Config(C.GoString(key), C.GoString(value))
+ if err != nil {
+ set_error(err)
+ return -1
+ }
+ return 0
+}
+
+//export implConfigComplete
+func implConfigComplete() C.int {
+ err := pluginImpl.ConfigComplete()
+ if err != nil {
+ set_error(err)
+ return -1
+ }
+ return 0
+}
+
+//export implOpen
+func implOpen(c_readonly C.int) unsafe.Pointer {
+ readonly := false
+ if c_readonly != 0 {
+ readonly = true
+ }
+ h, err := pluginImpl.Open(readonly)
+ if err != nil {
+ set_error(err)
+ return nil
+ }
+ if h == 0 {
+ panic("Open method: handle must be != 0")
+ }
+ return unsafe.Pointer(h)
+}
+
+//export implClose
+func implClose(handle unsafe.Pointer) {
+ pluginImpl.Close(uintptr(handle))
+}
+
+//export implGetSize
+func implGetSize(handle unsafe.Pointer) C.int64_t {
+ size, err := pluginImpl.GetSize(uintptr(handle))
+ if err != nil {
+ set_error(err)
+ return -1
+ }
+ return C.int64_t(size)
+}
+
+//export implPRead
+func implPRead(handle unsafe.Pointer, buf unsafe.Pointer,
+ count C.uint32_t, offset C.uint64_t, flags C.uint32_t) C.int {
+ err := pluginImpl.PRead(uintptr(handle),
+ C.GoBytes(buf, C.int(count)),
+ uint64(offset), uint32(flags))
+ if err != nil {
+ set_error(err)
+ return -1
+ }
+ return 0
+}
+
+// Called from C plugin_init function.
+func PluginInitialize(name string, impl PluginInterface) unsafe.Pointer {
+ pluginImpl = impl
+
+ plugin := C.struct_nbdkit_plugin{}
+
+ // Set up the hidden plugin fields as for C.
+ struct_size := C.ulong(unsafe.Sizeof(plugin))
+ plugin._struct_size = struct_size
+ plugin._api_version = C.NBDKIT_API_VERSION
+ plugin._thread_model = C.NBDKIT_THREAD_MODEL_PARALLEL
+
+ // Set up the other fields.
+ plugin.name = C.CString(name)
+ plugin.config = (*[0]byte)(C.config_wrapper)
+ plugin.config_complete = (*[0]byte)(C.config_complete_wrapper)
+ plugin.open = (*[0]byte)(C.open_wrapper)
+ plugin.close = (*[0]byte)(C.close_wrapper)
+ plugin.get_size = (*[0]byte)(C.get_size_wrapper)
+ plugin.pread = (*[0]byte)(C.pread_wrapper)
+
+ // Golang plugins don't preserve errno correctly.
+ plugin.errno_is_preserved = 0
+
+ // Return a newly malloced copy of the struct. This must be
+ // globally available to the C code in the server, so it is
+ // never freed.
+ p := (*C.struct_nbdkit_plugin)(C.malloc(struct_size))
+ *p = plugin
+ return unsafe.Pointer(p)
+}
diff --git a/plugins/golang/src/libguestfs.org/nbdkit/utils.go b/plugins/golang/src/libguestfs.org/nbdkit/utils.go
new file mode 100644
index 00000000..d9c0c188
--- /dev/null
+++ b/plugins/golang/src/libguestfs.org/nbdkit/utils.go
@@ -0,0 +1,75 @@
+/* cgo wrappers.
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * 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.
+ */
+
+package nbdkit
+
+/*
+#cgo pkg-config: nbdkit
+
+#define NBDKIT_API_VERSION 2
+#include <nbdkit-plugin.h>
+
+// cgo cannot call varargs functions.
+void
+_nbdkit_debug (const char *s)
+{
+ nbdkit_debug ("%s", s);
+}
+
+// cgo cannot call varargs functions.
+void
+_nbdkit_error (const char *s)
+{
+ nbdkit_error ("%s", s);
+}
+*/
+import "C"
+import "syscall"
+
+// Utility functions.
+
+func Debug(s string) {
+ C._nbdkit_debug(C.CString(s))
+}
+
+// This function is provided but plugins would rarely need to call
+// this explicitly since returning an error from a plugin callback
+// will call it implicitly.
+func Error(s string) {
+ C._nbdkit_error(C.CString(s))
+}
+
+// Same applies as for Error(). Callers should not usually need to
+// call this.
+func SetError(err syscall.Errno) {
+ C.nbdkit_set_error(C.int(err))
+}
diff --git a/plugins/golang/src/libguestfs.org/nbdkit/wrappers.go b/plugins/golang/src/libguestfs.org/nbdkit/wrappers.go
new file mode 100644
index 00000000..b18521f1
--- /dev/null
+++ b/plugins/golang/src/libguestfs.org/nbdkit/wrappers.go
@@ -0,0 +1,88 @@
+/* cgo wrappers.
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * 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.
+ */
+
+package nbdkit
+
+/*
+#cgo pkg-config: nbdkit
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NBDKIT_API_VERSION 2
+#include <nbdkit-plugin.h>
+#include "wrappers.h"
+
+extern int implConfig ();
+int
+config_wrapper (const char *key, const char *value)
+{
+ return implConfig (key, value);
+}
+
+extern int implConfigComplete ();
+int
+config_complete_wrapper (void)
+{
+ return implConfigComplete ();
+}
+
+extern void *implOpen ();
+void *
+open_wrapper (int readonly)
+{
+ return implOpen (readonly);
+}
+
+extern void implClose ();
+void
+close_wrapper (void *handle)
+{
+ return implClose (handle);
+}
+
+extern int64_t implGetSize ();
+int64_t
+get_size_wrapper (void *handle)
+{
+ return implGetSize (handle);
+}
+
+extern int implPRead ();
+int
+pread_wrapper (void *handle, void *buf,
+ uint32_t count, uint64_t offset, uint32_t flags)
+{
+ return implPRead (handle, buf, count, offset, flags);
+}
+*/
+import "C"
diff --git a/plugins/golang/test/run-test.sh b/plugins/golang/test/run-test.sh
new file mode 100755
index 00000000..f4da139e
--- /dev/null
+++ b/plugins/golang/test/run-test.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2020 Red Hat Inc.
+#
+# 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.
+
+set -e
+set -x
+
+if ! qemu-img --version; then
+ echo "qemu-img is required to run this test"
+ exit 1
+fi
+
+../../nbdkit -f -v test/nbdkit-gotest-plugin.so size=$((1024 * 1024)) \
+ --run 'qemu-img info $nbd'
diff --git a/plugins/golang/test/test.go b/plugins/golang/test/test.go
new file mode 100644
index 00000000..f5b1a33b
--- /dev/null
+++ b/plugins/golang/test/test.go
@@ -0,0 +1,102 @@
+/* Test plugin.
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * 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.
+ */
+
+package main
+
+import (
+ "C"
+ "libguestfs.org/nbdkit"
+ "strconv"
+ "unsafe"
+)
+
+type TestPlugin struct {
+ nbdkit.Plugin
+}
+
+var pluginName = "test"
+var size uint64
+var size_set = false
+
+func (p TestPlugin) Config(key string, value string) error {
+ if key == "size" {
+ var err error
+ size, err = strconv.ParseUint(value, 0, 64)
+ if err != nil {
+ return err
+ }
+ size_set = true
+ return nil
+ } else {
+ return nbdkit.PluginError{Errmsg: "unknown parameter"}
+ }
+}
+
+func (p TestPlugin) ConfigComplete() error {
+ if !size_set {
+ return nbdkit.PluginError{Errmsg: "size parameter is required"}
+ }
+ return nil
+}
+
+func (p TestPlugin) Open(readonly bool) (uintptr, error) {
+ nbdkit.Debug("golang code running in the .open callback")
+ return 1, nil
+}
+
+func (p TestPlugin) GetSize(handle uintptr) (uint64, error) {
+ nbdkit.Debug("golang code running in the .get_size callback")
+ return size, nil
+}
+
+func (p TestPlugin) PRead(handle uintptr, buf []byte,
+ offset uint64, flags uint32) error {
+ nbdkit.Debug("golang code running in the .pread callback")
+ for i := 0; i < len(buf); i++ {
+ buf[i] = 0
+ }
+ return nil
+}
+
+// This is never(?) called, but must exist.
+func main() {}
+
+//----------------------------------------------------------------------
+// The boilerplate below this line is required by all golang plugins.
+
+//export plugin_init
+func plugin_init() unsafe.Pointer {
+ // If your plugin needs to do any initialization, put it here.
+ //...
+ // Then you must call the following function.
+ return nbdkit.PluginInitialize(pluginName, &TestPlugin{})
+}
diff --git a/.gitignore b/.gitignore
index 11cd976b..f681f526 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,6 +72,8 @@ plugins/*/*.3
/plugins/example4/nbdkit-example4-plugin
/plugins/eval/call.c
/plugins/eval/methods.c
+/plugins/golang/test/nbdkit-gotest-plugin.h
+/plugins/golang/test/nbdkit-gotest-plugin.so
/plugins/ocaml/nbdkit-ocamlexample-plugin.so
/plugins/rust/Cargo.lock
/plugins/rust/Cargo.toml
diff --git a/README b/README
index a33c5693..62fc93e9 100644
--- a/README
+++ b/README
@@ -148,6 +148,10 @@ For the Rust plugin:
- cargo (other dependencies will be downloaded at build time)
+To be able to write plugins in golang:
+
+ - go >= 1.5
+
For bash tab completion:
- bash-completion >= 1.99
--
2.25.0
4 years, 7 months
[PATCH nbdkit 1/2] vddk: Use new vector library to allocate the argv list.
by Richard W.M. Jones
---
plugins/vddk/vddk.c | 41 +++++++++++++++++++++++++----------------
TODO | 1 -
2 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
index 87c0d146..d1a3015f 100644
--- a/plugins/vddk/vddk.c
+++ b/plugins/vddk/vddk.c
@@ -51,6 +51,7 @@
#include "isaligned.h"
#include "minmax.h"
#include "rounding.h"
+#include "vector.h"
#include "vddk-structs.h"
@@ -256,12 +257,23 @@ vddk_config (const char *key, const char *value)
* the caller prefers to proceed as if this had not been attempted.
* Thus, no return value is needed.
*/
+DEFINE_VECTOR_TYPE(string_vector, char *);
+
+#define CLEANUP_FREE_STRING_VECTOR \
+ __attribute__((cleanup (cleanup_free_string_vector)))
+
+static void
+cleanup_free_string_vector (string_vector *v)
+{
+ string_vector_iter (v, (void *) free);
+ free (v->ptr);
+}
+
static void
perform_reexec (const char *env, const char *prepend)
{
CLEANUP_FREE char *library = NULL;
- int argc = 0;
- CLEANUP_FREE char **argv = NULL;
+ CLEANUP_FREE_STRING_VECTOR string_vector argv = empty_vector;
int fd;
size_t len = 0, buflen = 512;
CLEANUP_FREE char *buf = NULL;
@@ -301,25 +313,22 @@ perform_reexec (const char *env, const char *prepend)
buflen = len;
len = 0;
while (len < buflen) {
- char **tmp = realloc (argv, sizeof *argv * (argc + 3));
-
- if (!tmp) {
- nbdkit_debug ("failure to parse original argv: %m");
+ if (string_vector_append (&argv, buf + len) == -1) {
+ argv_realloc_fail:
+ nbdkit_debug ("argv: realloc: %m");
return;
}
- argv = tmp;
- argv[argc++] = buf + len;
len += strlen (buf + len) + 1;
}
if (!env)
env = "";
- nbdkit_debug ("original argc == %d, adding reexeced_=%s", argc, env);
- if (asprintf (&reexeced, "reexeced_=%s", env) == -1) {
- nbdkit_debug ("failure to re-exec: %m");
- return;
- }
- argv[argc++] = reexeced;
- argv[argc] = NULL;
+ nbdkit_debug ("adding reexeced_=%s", env);
+ if (asprintf (&reexeced, "reexeced_=%s", env) == -1)
+ goto argv_realloc_fail;
+ if (string_vector_append (&argv, reexeced) == -1)
+ goto argv_realloc_fail;
+ if (string_vector_append (&argv, NULL) == -1)
+ goto argv_realloc_fail;
if (env[0]) {
if (asprintf (&library, "%s:%s", prepend, env) == -1)
@@ -334,7 +343,7 @@ perform_reexec (const char *env, const char *prepend)
nbdkit_debug ("re-executing with updated LD_LIBRARY_PATH=%s", library);
fflush (NULL);
- execvp ("/proc/self/exe", argv);
+ execvp ("/proc/self/exe", argv.ptr);
nbdkit_debug ("failure to execvp: %m");
}
diff --git a/TODO b/TODO
index 0c06b968..967c58f3 100644
--- a/TODO
+++ b/TODO
@@ -101,7 +101,6 @@ General ideas for improvements
* common/utils/vector.h could be extended and used in other places:
- there are some more possible places in the server (anywhere using
realloc is suspect)
- - nbdkit-vddk-plugin, where it builds the new argv
- allow insertion, and use it in nbdkit-extentlist-filter
- allow insertion and keep sorted, use it in nbdkit-eval-plugin
- same, and use it in common/sparse/sparse.c
--
2.25.0
4 years, 7 months
[PATCH] python: Fix UnicodeError in inspect_list_applications2() (RHBZ#1684004)
by Sam Eiderman
The python3 bindings create unicode objects from application strings
on the guest (i.e. installed rpm, deb packages).
It is documented that rpm package fields such as description should be
utf8 encoded - however in some cases they are not a valid unicode
string, on SLES11 SP4 the following packages fail to be converted to
unicode using guestfs_int_py_fromstring() (which invokes
PyUnicode_FromString()):
PackageKit
aaa_base
coreutils
dejavu
desktop-data-SLED
gnome-utils
hunspell
hunspell-32bit
hunspell-tools
libblocxx6
libexif
libgphoto2
libgtksourceview-2_0-0
libmpfr1
libopensc2
libopensc2-32bit
liborc-0_4-0
libpackagekit-glib10
libpixman-1-0
libpixman-1-0-32bit
libpoppler-glib4
libpoppler5
libsensors3
libtelepathy-glib0
m4
opensc
opensc-32bit
permissions
pinentry
poppler-tools
python-gtksourceview
splashy
syslog-ng
tar
tightvnc
xorg-x11
xorg-x11-xauth
yast2-mouse
This is a surgical fix for inspect_list_applications2()'s description
field.
Signed-off-by: Sam Eiderman <sameid(a)google.com>
---
generator/python.ml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/generator/python.ml b/generator/python.ml
index f0d6b5d96..7394a943a 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -170,6 +170,14 @@ and generate_python_structs () =
function
| name, FString ->
pr " value = guestfs_int_py_fromstring (%s->%s);\n" typ name;
+ (match typ, name with
+ | "application", "app_description"
+ | "application2", "app2_description" ->
+ pr " if (value == NULL) {\n";
+ pr " value = guestfs_int_py_fromstring (\"\");\n";
+ pr " PyErr_Clear ();\n";
+ pr " }\n";
+ | _ -> pr ""; );
pr " if (value == NULL)\n";
pr " goto err;\n";
pr " PyDict_SetItemString (dict, \"%s\", value);\n" name;
--
2.26.1.301.g55bc3eb7cb9-goog
4 years, 7 months