Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libnbd for openSUSE:Factory checked 
in at 2025-09-14 18:50:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libnbd (Old)
 and      /work/SRC/openSUSE:Factory/.libnbd.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libnbd"

Sun Sep 14 18:50:04 2025 rev:21 rq:1304457 version:1.22.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/libnbd/libnbd.changes    2025-08-05 
14:21:47.434501474 +0200
+++ /work/SRC/openSUSE:Factory/.libnbd.new.1977/libnbd.changes  2025-09-14 
18:50:42.595440303 +0200
@@ -1,0 +2,26 @@
+Fri Sep 05 21:02:25 UTC 2025 - Charles Arnold <carn...@suse.com>
+
+- Update to version 1.22.4:
+  * Version 1.22.4.
+  * docs: nbd_connect_uri: Combine export name sections together
+  * docs: nbd_connect_uri: Minor copyedits
+  * docs: nbd_connect_uri: Split up URI parsing section
+  * lib/uri.c: Use uri_query_list functions to free
+  * lib/uri.c: Add static annotation to parse_bool
+  * docs: Clarify documentation for export names in nbd_connect_uri
+  * docs: Add S<...> around qemu versions to avoid distracting linebreak
+  * generator: rust: Parse S<...> (non-breaking spaces) in POD
+  * generator: rust: Allow nested X<..X<..>..> expressions in POD
+  * generator: Don't list nbd_is_uri as a "flag call"
+  * generator: Clarify documentation for nbd_set_private_data
+  * ocaml: Small tweaks to the generated documentation
+  * ci: Remove fedora-40, alpine-320, add fedora-42, alpine-322
+  * common: utils: Add const to <vector>_duplicate variable decls
+  * copy, info: Use new vector_array_append functions in a couple of places
+  * common: utils: vector: Fix vector_uniq prototype and add a test
+  * common: utils: vector: Add range functions for insert, append and remove
+  * common: utils: vector: Prefer vector_reset over free()
+  * common: utils: vector: Add new vector_uniq function
+  * common/utils: Add convenient string_append_format function
+
+-------------------------------------------------------------------

Old:
----
  libnbd-1.22.3.tar.bz2

New:
----
  libnbd-1.22.4.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libnbd.spec ++++++
--- /var/tmp/diff_new_pack.l1IRlQ/_old  2025-09-14 18:50:43.107461758 +0200
+++ /var/tmp/diff_new_pack.l1IRlQ/_new  2025-09-14 18:50:43.111461926 +0200
@@ -19,7 +19,7 @@
 %define sover 0
 
 Name:           libnbd
-Version:        1.22.3
+Version:        1.22.4
 Release:        0
 Summary:        NBD client library in userspace
 License:        LGPL-2.1-or-later

++++++ _service ++++++
--- /var/tmp/diff_new_pack.l1IRlQ/_old  2025-09-14 18:50:43.143463267 +0200
+++ /var/tmp/diff_new_pack.l1IRlQ/_new  2025-09-14 18:50:43.143463267 +0200
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="manual">
     <param name="filename">libnbd</param>
-    <param name="revision">v1.22.3</param>
+    <param name="revision">v1.22.4</param>
     <param name="scm">git</param>
     <param name="submodules">disable</param>
     <param name="url">https://gitlab.com/nbdkit/libnbd.git</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.l1IRlQ/_old  2025-09-14 18:50:43.167464272 +0200
+++ /var/tmp/diff_new_pack.l1IRlQ/_new  2025-09-14 18:50:43.167464272 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param name="url">https://gitlab.com/nbdkit/libnbd.git</param>
-              <param 
name="changesrevision">e6383d73b38fc5b7c06b3d8cd9f22e42ad16edfc</param></service></servicedata>
+              <param 
name="changesrevision">caf41ba1847f79ab25e3a73401f8170cbe351908</param></service></servicedata>
 (No newline at EOF)
 

++++++ libnbd-1.22.3.tar.bz2 -> libnbd-1.22.4.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/buildenv/alpine-320.sh 
new/libnbd-1.22.4/ci/buildenv/alpine-320.sh
--- old/libnbd-1.22.3/ci/buildenv/alpine-320.sh 2025-07-17 15:05:46.000000000 
+0200
+++ new/libnbd-1.22.4/ci/buildenv/alpine-320.sh 1970-01-01 01:00:00.000000000 
+0100
@@ -1,62 +0,0 @@
-# THIS FILE WAS AUTO-GENERATED
-#
-#  $ lcitool manifest ci/manifest.yml
-#
-# https://gitlab.com/libvirt/libvirt-ci
-
-function install_buildenv() {
-    apk update
-    apk upgrade
-    apk add \
-        autoconf \
-        automake \
-        bash \
-        bash-completion \
-        busybox \
-        ca-certificates \
-        cargo \
-        ccache \
-        clang \
-        diffutils \
-        fuse3 \
-        fuse3-dev \
-        g++ \
-        gcc \
-        git \
-        glib-dev \
-        gnutls-dev \
-        gnutls-utils \
-        go \
-        hexdump \
-        iproute2 \
-        jq \
-        libev-dev \
-        libtool \
-        libxml2-dev \
-        make \
-        musl-dev \
-        nbd \
-        nbd-client \
-        ocaml \
-        ocaml-findlib-dev \
-        ocaml-ocamldoc \
-        perl \
-        pkgconf \
-        py3-flake8 \
-        python3-dev \
-        qemu \
-        qemu-img \
-        sed \
-        valgrind
-    apk list --installed | sort > /packages.txt
-    mkdir -p /usr/libexec/ccache-wrappers
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
-}
-
-export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers"
-export LANG="en_US.UTF-8"
-export MAKE="/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/buildenv/alpine-322.sh 
new/libnbd-1.22.4/ci/buildenv/alpine-322.sh
--- old/libnbd-1.22.3/ci/buildenv/alpine-322.sh 1970-01-01 01:00:00.000000000 
+0100
+++ new/libnbd-1.22.4/ci/buildenv/alpine-322.sh 2025-08-23 18:09:41.000000000 
+0200
@@ -0,0 +1,62 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+#  $ lcitool manifest ci/manifest.yml
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+function install_buildenv() {
+    apk update
+    apk upgrade
+    apk add \
+        autoconf \
+        automake \
+        bash \
+        bash-completion \
+        busybox \
+        ca-certificates \
+        cargo \
+        ccache \
+        clang \
+        diffutils \
+        fuse3 \
+        fuse3-dev \
+        g++ \
+        gcc \
+        git \
+        glib-dev \
+        gnutls-dev \
+        gnutls-utils \
+        go \
+        hexdump \
+        iproute2 \
+        jq \
+        libev-dev \
+        libtool \
+        libxml2-dev \
+        make \
+        musl-dev \
+        nbd \
+        nbd-client \
+        ocaml \
+        ocaml-findlib-dev \
+        ocaml-ocamldoc \
+        perl \
+        pkgconf \
+        py3-flake8 \
+        python3-dev \
+        qemu \
+        qemu-img \
+        sed \
+        valgrind
+    apk list --installed | sort > /packages.txt
+    mkdir -p /usr/libexec/ccache-wrappers
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
+}
+
+export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers"
+export LANG="en_US.UTF-8"
+export MAKE="/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/buildenv/fedora-40.sh 
new/libnbd-1.22.4/ci/buildenv/fedora-40.sh
--- old/libnbd-1.22.3/ci/buildenv/fedora-40.sh  2025-07-17 15:05:46.000000000 
+0200
+++ new/libnbd-1.22.4/ci/buildenv/fedora-40.sh  1970-01-01 01:00:00.000000000 
+0100
@@ -1,65 +0,0 @@
-# THIS FILE WAS AUTO-GENERATED
-#
-#  $ lcitool manifest ci/manifest.yml
-#
-# https://gitlab.com/libvirt/libvirt-ci
-
-function install_buildenv() {
-    dnf update -y
-    dnf install -y \
-        autoconf \
-        automake \
-        bash \
-        bash-completion \
-        ca-certificates \
-        cargo \
-        ccache \
-        clang \
-        diffutils \
-        fuse3 \
-        fuse3-devel \
-        gawk \
-        gcc \
-        gcc-c++ \
-        git \
-        glib2-devel \
-        glibc-devel \
-        glibc-langpack-en \
-        glibc-utils \
-        gnutls-devel \
-        gnutls-utils \
-        golang \
-        iproute \
-        jq \
-        libev-devel \
-        libtool \
-        libxml2-devel \
-        make \
-        nbd \
-        nbdkit \
-        ocaml \
-        ocaml-findlib \
-        ocamldoc \
-        perl-Pod-Simple \
-        perl-base \
-        perl-podlators \
-        pkgconfig \
-        python3-devel \
-        python3-flake8 \
-        qemu-img \
-        qemu-kvm \
-        sed \
-        util-linux \
-        valgrind
-    rpm -qa | sort > /packages.txt
-    mkdir -p /usr/libexec/ccache-wrappers
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
-}
-
-export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers"
-export LANG="en_US.UTF-8"
-export MAKE="/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/buildenv/fedora-42.sh 
new/libnbd-1.22.4/ci/buildenv/fedora-42.sh
--- old/libnbd-1.22.3/ci/buildenv/fedora-42.sh  1970-01-01 01:00:00.000000000 
+0100
+++ new/libnbd-1.22.4/ci/buildenv/fedora-42.sh  2025-08-23 18:09:41.000000000 
+0200
@@ -0,0 +1,65 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+#  $ lcitool manifest ci/manifest.yml
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+function install_buildenv() {
+    dnf update -y
+    dnf install -y \
+        autoconf \
+        automake \
+        bash \
+        bash-completion-devel \
+        ca-certificates \
+        cargo \
+        ccache \
+        clang \
+        diffutils \
+        fuse3 \
+        fuse3-devel \
+        gawk \
+        gcc \
+        gcc-c++ \
+        git \
+        glib2-devel \
+        glibc-devel \
+        glibc-langpack-en \
+        glibc-utils \
+        gnutls-devel \
+        gnutls-utils \
+        golang \
+        iproute \
+        jq \
+        libev-devel \
+        libtool \
+        libxml2-devel \
+        make \
+        nbd \
+        nbdkit \
+        ocaml \
+        ocaml-findlib \
+        ocamldoc \
+        perl-Pod-Simple \
+        perl-base \
+        perl-podlators \
+        pkgconfig \
+        python3-devel \
+        python3-flake8 \
+        qemu-img \
+        qemu-kvm \
+        sed \
+        util-linux \
+        valgrind
+    rpm -qa | sort > /packages.txt
+    mkdir -p /usr/libexec/ccache-wrappers
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
+}
+
+export CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers"
+export LANG="en_US.UTF-8"
+export MAKE="/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/containers/alpine-320.Dockerfile 
new/libnbd-1.22.4/ci/containers/alpine-320.Dockerfile
--- old/libnbd-1.22.3/ci/containers/alpine-320.Dockerfile       2025-07-17 
15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/ci/containers/alpine-320.Dockerfile       1970-01-01 
01:00:00.000000000 +0100
@@ -1,62 +0,0 @@
-# THIS FILE WAS AUTO-GENERATED
-#
-#  $ lcitool manifest ci/manifest.yml
-#
-# https://gitlab.com/libvirt/libvirt-ci
-
-FROM docker.io/library/alpine:3.20
-
-RUN apk update && \
-    apk upgrade && \
-    apk add \
-        autoconf \
-        automake \
-        bash \
-        bash-completion \
-        busybox \
-        ca-certificates \
-        cargo \
-        ccache \
-        clang \
-        diffutils \
-        fuse3 \
-        fuse3-dev \
-        g++ \
-        gcc \
-        git \
-        glib-dev \
-        gnutls-dev \
-        gnutls-utils \
-        go \
-        hexdump \
-        iproute2 \
-        jq \
-        libev-dev \
-        libtool \
-        libxml2-dev \
-        make \
-        musl-dev \
-        nbd \
-        nbd-client \
-        ocaml \
-        ocaml-findlib-dev \
-        ocaml-ocamldoc \
-        perl \
-        pkgconf \
-        py3-flake8 \
-        python3-dev \
-        qemu \
-        qemu-img \
-        sed \
-        valgrind && \
-    apk list --installed | sort > /packages.txt && \
-    mkdir -p /usr/libexec/ccache-wrappers && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
-
-ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
-ENV LANG "en_US.UTF-8"
-ENV MAKE "/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/containers/alpine-322.Dockerfile 
new/libnbd-1.22.4/ci/containers/alpine-322.Dockerfile
--- old/libnbd-1.22.3/ci/containers/alpine-322.Dockerfile       1970-01-01 
01:00:00.000000000 +0100
+++ new/libnbd-1.22.4/ci/containers/alpine-322.Dockerfile       2025-08-23 
18:09:41.000000000 +0200
@@ -0,0 +1,62 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+#  $ lcitool manifest ci/manifest.yml
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+FROM docker.io/library/alpine:3.22
+
+RUN apk update && \
+    apk upgrade && \
+    apk add \
+        autoconf \
+        automake \
+        bash \
+        bash-completion \
+        busybox \
+        ca-certificates \
+        cargo \
+        ccache \
+        clang \
+        diffutils \
+        fuse3 \
+        fuse3-dev \
+        g++ \
+        gcc \
+        git \
+        glib-dev \
+        gnutls-dev \
+        gnutls-utils \
+        go \
+        hexdump \
+        iproute2 \
+        jq \
+        libev-dev \
+        libtool \
+        libxml2-dev \
+        make \
+        musl-dev \
+        nbd \
+        nbd-client \
+        ocaml \
+        ocaml-findlib-dev \
+        ocaml-ocamldoc \
+        perl \
+        pkgconf \
+        py3-flake8 \
+        python3-dev \
+        qemu \
+        qemu-img \
+        sed \
+        valgrind && \
+    apk list --installed | sort > /packages.txt && \
+    mkdir -p /usr/libexec/ccache-wrappers && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
+
+ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
+ENV LANG "en_US.UTF-8"
+ENV MAKE "/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/containers/fedora-40.Dockerfile 
new/libnbd-1.22.4/ci/containers/fedora-40.Dockerfile
--- old/libnbd-1.22.3/ci/containers/fedora-40.Dockerfile        2025-07-17 
15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/ci/containers/fedora-40.Dockerfile        1970-01-01 
01:00:00.000000000 +0100
@@ -1,77 +0,0 @@
-# THIS FILE WAS AUTO-GENERATED
-#
-#  $ lcitool manifest ci/manifest.yml
-#
-# https://gitlab.com/libvirt/libvirt-ci
-
-FROM registry.fedoraproject.org/fedora:40
-
-RUN dnf install -y nosync && \
-    printf '#!/bin/sh\n\
-if test -d /usr/lib64\n\
-then\n\
-    export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\
-else\n\
-    export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\
-fi\n\
-exec "$@"\n' > /usr/bin/nosync && \
-    chmod +x /usr/bin/nosync && \
-    nosync dnf update -y && \
-    nosync dnf install -y \
-               autoconf \
-               automake \
-               bash \
-               bash-completion \
-               ca-certificates \
-               cargo \
-               ccache \
-               clang \
-               diffutils \
-               fuse3 \
-               fuse3-devel \
-               gawk \
-               gcc \
-               gcc-c++ \
-               git \
-               glib2-devel \
-               glibc-devel \
-               glibc-langpack-en \
-               glibc-utils \
-               gnutls-devel \
-               gnutls-utils \
-               golang \
-               iproute \
-               jq \
-               libev-devel \
-               libtool \
-               libxml2-devel \
-               make \
-               nbd \
-               nbdkit \
-               ocaml \
-               ocaml-findlib \
-               ocamldoc \
-               perl-Pod-Simple \
-               perl-base \
-               perl-podlators \
-               pkgconfig \
-               python3-devel \
-               python3-flake8 \
-               qemu-img \
-               qemu-kvm \
-               sed \
-               util-linux \
-               valgrind && \
-    nosync dnf autoremove -y && \
-    nosync dnf clean all -y && \
-    rpm -qa | sort > /packages.txt && \
-    mkdir -p /usr/libexec/ccache-wrappers && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
-    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
-
-ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
-ENV LANG "en_US.UTF-8"
-ENV MAKE "/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/containers/fedora-42.Dockerfile 
new/libnbd-1.22.4/ci/containers/fedora-42.Dockerfile
--- old/libnbd-1.22.3/ci/containers/fedora-42.Dockerfile        1970-01-01 
01:00:00.000000000 +0100
+++ new/libnbd-1.22.4/ci/containers/fedora-42.Dockerfile        2025-08-23 
18:09:41.000000000 +0200
@@ -0,0 +1,77 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+#  $ lcitool manifest ci/manifest.yml
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+FROM registry.fedoraproject.org/fedora:42
+
+RUN dnf install -y nosync && \
+    printf '#!/bin/sh\n\
+if test -d /usr/lib64\n\
+then\n\
+    export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\
+else\n\
+    export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\
+fi\n\
+exec "$@"\n' > /usr/bin/nosync && \
+    chmod +x /usr/bin/nosync && \
+    nosync dnf update -y && \
+    nosync dnf install -y \
+               autoconf \
+               automake \
+               bash \
+               bash-completion-devel \
+               ca-certificates \
+               cargo \
+               ccache \
+               clang \
+               diffutils \
+               fuse3 \
+               fuse3-devel \
+               gawk \
+               gcc \
+               gcc-c++ \
+               git \
+               glib2-devel \
+               glibc-devel \
+               glibc-langpack-en \
+               glibc-utils \
+               gnutls-devel \
+               gnutls-utils \
+               golang \
+               iproute \
+               jq \
+               libev-devel \
+               libtool \
+               libxml2-devel \
+               make \
+               nbd \
+               nbdkit \
+               ocaml \
+               ocaml-findlib \
+               ocamldoc \
+               perl-Pod-Simple \
+               perl-base \
+               perl-podlators \
+               pkgconfig \
+               python3-devel \
+               python3-flake8 \
+               qemu-img \
+               qemu-kvm \
+               sed \
+               util-linux \
+               valgrind && \
+    nosync dnf autoremove -y && \
+    nosync dnf clean all -y && \
+    rpm -qa | sort > /packages.txt && \
+    mkdir -p /usr/libexec/ccache-wrappers && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
+    ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
+
+ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
+ENV LANG "en_US.UTF-8"
+ENV MAKE "/usr/bin/make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/gitlab/builds.yml 
new/libnbd-1.22.4/ci/gitlab/builds.yml
--- old/libnbd-1.22.3/ci/gitlab/builds.yml      2025-07-17 15:05:46.000000000 
+0200
+++ new/libnbd-1.22.4/ci/gitlab/builds.yml      2025-08-23 18:09:41.000000000 
+0200
@@ -7,26 +7,26 @@
 
 # Native build jobs
 
-x86_64-alpine-320:
+x86_64-alpine-321:
   extends: .native_build_job
   needs:
-    - job: x86_64-alpine-320-container
+    - job: x86_64-alpine-321-container
       optional: true
   allow_failure: false
   variables:
-    NAME: alpine-320
-    TARGET_BASE_IMAGE: docker.io/library/alpine:3.20
+    NAME: alpine-321
+    TARGET_BASE_IMAGE: docker.io/library/alpine:3.21
 
 
-x86_64-alpine-321:
+x86_64-alpine-322:
   extends: .native_build_job
   needs:
-    - job: x86_64-alpine-321-container
+    - job: x86_64-alpine-322-container
       optional: true
   allow_failure: false
   variables:
-    NAME: alpine-321
-    TARGET_BASE_IMAGE: docker.io/library/alpine:3.21
+    NAME: alpine-322
+    TARGET_BASE_IMAGE: docker.io/library/alpine:3.22
 
 
 x86_64-alpine-edge:
@@ -95,26 +95,26 @@
     TARGET_BASE_IMAGE: docker.io/library/debian:sid-slim
 
 
-x86_64-fedora-40:
+x86_64-fedora-41:
   extends: .native_build_job
   needs:
-    - job: x86_64-fedora-40-container
+    - job: x86_64-fedora-41-container
       optional: true
   allow_failure: false
   variables:
-    NAME: fedora-40
-    TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:40
+    NAME: fedora-41
+    TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:41
 
 
-x86_64-fedora-41:
+x86_64-fedora-42:
   extends: .native_build_job
   needs:
-    - job: x86_64-fedora-41-container
+    - job: x86_64-fedora-42-container
       optional: true
   allow_failure: false
   variables:
-    NAME: fedora-41
-    TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:41
+    NAME: fedora-42
+    TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:42
 
 
 x86_64-fedora-rawhide:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/gitlab/containers.yml 
new/libnbd-1.22.4/ci/gitlab/containers.yml
--- old/libnbd-1.22.3/ci/gitlab/containers.yml  2025-07-17 15:05:46.000000000 
+0200
+++ new/libnbd-1.22.4/ci/gitlab/containers.yml  2025-08-23 18:09:41.000000000 
+0200
@@ -7,18 +7,18 @@
 
 # Native container jobs
 
-x86_64-alpine-320-container:
+x86_64-alpine-321-container:
   extends: .container_job
   allow_failure: false
   variables:
-    NAME: alpine-320
+    NAME: alpine-321
 
 
-x86_64-alpine-321-container:
+x86_64-alpine-322-container:
   extends: .container_job
   allow_failure: false
   variables:
-    NAME: alpine-321
+    NAME: alpine-322
 
 
 x86_64-alpine-edge-container:
@@ -63,18 +63,18 @@
     NAME: debian-sid
 
 
-x86_64-fedora-40-container:
+x86_64-fedora-41-container:
   extends: .container_job
   allow_failure: false
   variables:
-    NAME: fedora-40
+    NAME: fedora-41
 
 
-x86_64-fedora-41-container:
+x86_64-fedora-42-container:
   extends: .container_job
   allow_failure: false
   variables:
-    NAME: fedora-41
+    NAME: fedora-42
 
 
 x86_64-fedora-rawhide-container:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/ci/manifest.yml 
new/libnbd-1.22.4/ci/manifest.yml
--- old/libnbd-1.22.3/ci/manifest.yml   2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/ci/manifest.yml   2025-08-23 18:09:41.000000000 +0200
@@ -8,10 +8,10 @@
     check-dco: false
 
 targets:
-  alpine-320: x86_64
-
   alpine-321: x86_64
 
+  alpine-322: x86_64
+
   alpine-edge: x86_64
 
   almalinux-9: x86_64
@@ -30,10 +30,10 @@
 
   debian-sid: x86_64
 
-  fedora-40: x86_64
-
   fedora-41: x86_64
 
+  fedora-42: x86_64
+
   fedora-rawhide:
     jobs:
       - arch: x86_64
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/common/utils/Makefile.am 
new/libnbd-1.22.4/common/utils/Makefile.am
--- old/libnbd-1.22.3/common/utils/Makefile.am  2025-07-17 15:05:46.000000000 
+0200
+++ new/libnbd-1.22.4/common/utils/Makefile.am  2025-08-23 18:09:41.000000000 
+0200
@@ -38,6 +38,7 @@
        device-size.c \
        device-size.h \
        nbdkit-string.h \
+       string.c \
        string-vector.h \
        vector.c \
        vector.h \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/common/utils/nbdkit-string.h 
new/libnbd-1.22.4/common/utils/nbdkit-string.h
--- old/libnbd-1.22.3/common/utils/nbdkit-string.h      2025-07-17 
15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/common/utils/nbdkit-string.h      2025-08-23 
18:09:41.000000000 +0200
@@ -39,4 +39,9 @@
 
 DEFINE_VECTOR_TYPE (string, char);
 
+/* Append a formatted string to the end of string 's'.  Returns the
+ * new length of 's'.  On error, returns -1.
+ */
+extern ssize_t string_append_format (string *s, const char *fs, ...);
+
 #endif /* NBDKIT_STRING_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/common/utils/string.c 
new/libnbd-1.22.4/common/utils/string.c
--- old/libnbd-1.22.3/common/utils/string.c     1970-01-01 01:00:00.000000000 
+0100
+++ new/libnbd-1.22.4/common/utils/string.c     2025-08-23 18:09:41.000000000 
+0200
@@ -0,0 +1,77 @@
+/* nbdkit
+ * Copyright Red Hat
+ *
+ * This is based on code from util-linux/lib/blkdev.c which is
+ * distributed under a compatible license.
+ *
+ * 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 <stdarg.h>
+
+#include "nbdkit-string.h"
+
+ssize_t
+string_append_format (string *s, const char *fs, ...)
+{
+  char *s2;
+  va_list ap;
+  size_t len;
+  ssize_t need;
+  int r;
+
+  va_start (ap, fs);
+  r = vasprintf (&s2, fs, ap);
+  va_end (ap);
+  if (r == -1) return -1;
+
+  /* Make sure the string is always \0-terminated by ensuring the
+   * reservation is 1 byte longer than we need.
+   */
+  len = strlen (s2);
+  need = s->len + len + 1 - s->cap;
+  if (need > 0 && string_reserve (s, need) == -1) {
+    free (s2);
+    return -1;
+  }
+
+  string_append_array (s, s2, len);
+  free (s2);
+
+  /* Make sure the string is \0-terminated in the byte of space
+   * reserved after the string.
+   */
+  s->ptr[s->len] = '\0';
+
+  return s->len;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/common/utils/test-vector.c 
new/libnbd-1.22.4/common/utils/test-vector.c
--- old/libnbd-1.22.3/common/utils/test-vector.c        2025-07-17 
15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/common/utils/test-vector.c        2025-08-23 
18:09:41.000000000 +0200
@@ -42,6 +42,7 @@
 #undef NDEBUG /* Keep test strong even for nbdkit built without assertions */
 #include <assert.h>
 
+#include "array-size.h"
 #include "bench.h"
 #include "const-string-vector.h"
 #include "nbdkit-string.h"
@@ -50,11 +51,46 @@
 
 #define APPENDS 1000000
 
+DEFINE_VECTOR_TYPE (int_vector, int);
 DEFINE_VECTOR_TYPE (int64_vector, int64_t);
 DEFINE_VECTOR_TYPE (uint32_vector, uint32_t);
 
+static void
+test_int_vector (void)
+{
+  int_vector v = empty_vector;
+  int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+  int r;
+  size_t i;
+
+  r = int_vector_append_array (&v, data, ARRAY_SIZE (data));
+  assert (r == 0);
+
+  assert (v.len == 10);
+  for (i = 0; i < 10; ++i)
+    assert (v.ptr[i] == i);
+
+  int_vector_remove_range (&v, 5, 3); /* remove elements [3..7] */
+
+  assert (v.len == 5);
+  assert (v.ptr[0] == 0);
+  assert (v.ptr[1] == 1);
+  assert (v.ptr[2] == 2);
+  assert (v.ptr[3] == 8);
+  assert (v.ptr[4] == 9);
+
+  r = int_vector_insert_array (&v, &data[3], 5, 3);
+  assert (r == 0);
+
+  assert (v.len == 10);
+  for (i = 0; i < 10; ++i)
+    assert (v.ptr[i] == i);
+
+  int_vector_reset (&v);
+}
+
 static int
-compare (const int64_t *a, const int64_t *b)
+compare_int64 (const int64_t *a, const int64_t *b)
 {
   return (*a > *b) - (*a < *b);
 }
@@ -73,7 +109,7 @@
 
   for (i = 0; i < 10; ++i)
     assert (v.ptr[i] == 9 - i);
-  int64_vector_sort (&v, compare);
+  int64_vector_sort (&v, compare_int64);
   for (i = 0; i < 10; ++i)
     assert (v.ptr[i] == i);
 
@@ -82,13 +118,13 @@
   assert (v.ptr[1] == 2);
 
   tmp = 10;
-  p = int64_vector_search (&v, &tmp, (void *)compare);
+  p = int64_vector_search (&v, &tmp, (void*) compare_int64);
   assert (p == NULL);
   tmp = 8;
-  p = int64_vector_search (&v, &tmp, (void *)compare);
+  p = int64_vector_search (&v, &tmp, (void*) compare_int64);
   assert (p == &v.ptr[7]);
 
-  free (v.ptr);
+  int64_vector_reset (&v);
 }
 
 static void
@@ -124,7 +160,7 @@
 
   assert (strcmp (s.ptr, "hello world") == 0);
   assert (s.len == 12); /* hello + space + world + \0 */
-  free (s.ptr);
+  string_reset (&s);
 }
 
 /* Same as above, but using string_reserve_exactly. */
@@ -161,7 +197,7 @@
 
   assert (strcmp (s.ptr, "hello world") == 0);
   assert (s.len == 12); /* hello + space + world + \0 */
-  free (s.ptr);
+  string_reset (&s);
 }
 
 static void
@@ -232,6 +268,45 @@
   assert (errno == ENOMEM);
 }
 
+/* Test vector_uniq function. */
+static int
+compare_int (const int *a, const int *b)
+{
+  return (*a > *b) - (*a < *b);
+}
+
+static void
+test_uniq (void)
+{
+  int_vector v = empty_vector;
+  int r;
+
+  int data1[] = { 1, 2, 2, 2, 3, 1, 1, 1, 4, 4 };
+  r = int_vector_append_array (&v, data1, ARRAY_SIZE (data1));
+  assert (r == 0);
+  int_vector_uniq (&v, compare_int);
+  assert (v.len == 5);
+  assert (v.ptr[0] == 1);
+  assert (v.ptr[1] == 2);
+  assert (v.ptr[2] == 3);
+  assert (v.ptr[3] == 1);
+  assert (v.ptr[4] == 4);
+  int_vector_reset (&v);
+
+  int data2[] = { 1, 2, 1, 2, 2, 2, 3, 1, 1, 1 };
+  r = int_vector_append_array (&v, data2, ARRAY_SIZE (data2));
+  assert (r == 0);
+  int_vector_uniq (&v, compare_int);
+  assert (v.len == 6);
+  assert (v.ptr[0] == 1);
+  assert (v.ptr[1] == 2);
+  assert (v.ptr[2] == 1);
+  assert (v.ptr[3] == 2);
+  assert (v.ptr[4] == 3);
+  assert (v.ptr[5] == 1);
+  int_vector_reset (&v);
+}
+
 static void
 bench_reserve (void)
 {
@@ -287,12 +362,14 @@
 
   if (!bench) {
     /* Do normal tests. */
+    test_int_vector ();
     test_int64_vector ();
     test_string ();
     test_string_exactly ();
     test_string_vector ();
     test_const_string_vector ();
     test_overflow ();
+    test_uniq ();
   }
 
   else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/common/utils/vector.h 
new/libnbd-1.22.4/common/utils/vector.h
--- old/libnbd-1.22.3/common/utils/vector.h     2025-07-17 15:05:46.000000000 
+0200
+++ new/libnbd-1.22.4/common/utils/vector.h     2025-08-23 18:09:41.000000000 
+0200
@@ -132,20 +132,28 @@
                                                 n, sizeof (type));      \
   }                                                                     \
                                                                         \
-  /* Insert at i'th element.  i=0 => beginning  i=len => append */      \
+  /* Insert list at i'th element.  i=0 => beginning  i=len => append */ \
   static inline int __attribute__ ((__unused__))                        \
-  name##_insert (name *v, type elem, size_t i)                          \
+  name##_insert_array (name *v, type *elems, size_t nr_elems, size_t i) \
   {                                                                     \
     assert (i <= v->len);                                               \
-    if (v->len >= v->cap) {                                             \
-      if (name##_reserve (v, 1) == -1) return -1;                       \
+    if (v->len+nr_elems > v->cap) {                                     \
+      if (name##_reserve (v, nr_elems) == -1) return -1;                \
     }                                                                   \
-    memmove (&v->ptr[i+1], &v->ptr[i], (v->len-i) * sizeof (elem));     \
-    v->ptr[i] = elem;                                                   \
-    v->len++;                                                           \
+    memmove (&v->ptr[i+nr_elems], &v->ptr[i],                           \
+             (v->len-i) * sizeof (elems[0]));                           \
+    memcpy (&v->ptr[i], elems, nr_elems * sizeof (elems[0]));           \
+    v->len += nr_elems;                                                 \
     return 0;                                                           \
   }                                                                     \
                                                                         \
+  /* Insert at i'th element.  i=0 => beginning  i=len => append */      \
+  static inline int __attribute__ ((__unused__))                        \
+  name##_insert (name *v, type elem, size_t i)                          \
+  {                                                                     \
+    return name##_insert_array (v, &elem, 1, i);                        \
+  }                                                                     \
+                                                                        \
   /* Append a new element to the end of the vector. */                  \
   static inline int __attribute__ ((__unused__))                        \
   name##_append (name *v, type elem)                                    \
@@ -153,13 +161,27 @@
     return name##_insert (v, elem, v->len);                             \
   }                                                                     \
                                                                         \
+  /* Append list of new elements to the end of the vector. */           \
+  static inline int __attribute__ ((__unused__))                        \
+  name##_append_array (name *v, type *elems, size_t nr_elems)           \
+  {                                                                     \
+    return name##_insert_array (v, elems, nr_elems, v->len);            \
+  }                                                                     \
+                                                                        \
+  /* Remove [i..i+nr-1] elements.  i=0 => beginning  i=len-1 => end */  \
+  static inline void __attribute__ ((__unused__))                       \
+  name##_remove_range (name *v, size_t nr, size_t i)                    \
+  {                                                                     \
+    assert (i < v->len);                                                \
+    memmove (&v->ptr[i], &v->ptr[i+nr], (v->len-i-nr) * sizeof (type)); \
+    v->len -= nr;                                                       \
+  }                                                                     \
+                                                                        \
   /* Remove i'th element.  i=0 => beginning  i=len-1 => end */          \
   static inline void __attribute__ ((__unused__))                       \
   name##_remove (name *v, size_t i)                                     \
   {                                                                     \
-    assert (i < v->len);                                                \
-    memmove (&v->ptr[i], &v->ptr[i+1], (v->len-i-1) * sizeof (type));   \
-    v->len--;                                                           \
+    name##_remove_range (v, 1, i);                                      \
   }                                                                     \
                                                                         \
   /* Remove all elements and deallocate the vector. */                  \
@@ -188,6 +210,20 @@
     qsort (v->ptr, v->len, sizeof (type), (void *)compare);             \
   }                                                                     \
                                                                         \
+  /* Remove duplicate adjacent elements (uniq). */                      \
+  static inline void __attribute__ ((__unused__))                       \
+  name##_uniq (name *v,                                                 \
+               int (*compare) (type const *p1, type const *p2))         \
+  {                                                                     \
+    size_t i;                                                           \
+    for (i = 0; i < v->len - 1; ++i) {                                  \
+      if (compare (&v->ptr[i], &v->ptr[i+1]) == 0) {                    \
+        name##_remove (v, i);                                           \
+        i--;                                                            \
+      }                                                                 \
+    }                                                                   \
+  }                                                                     \
+                                                                        \
   /* Search for an exactly matching element in the vector using a       \
    * binary search.  Returns a pointer to the element or NULL.          \
    */                                                                   \
@@ -204,9 +240,9 @@
   name##_duplicate (name *v, name *copy)                                \
   {                                                                     \
     /* Note it's allowed for v and copy to be the same pointer. */      \
-    type *vptr = v->ptr;                                                \
+    type const *vptr = v->ptr;                                          \
     type *newptr;                                                       \
-    size_t len = v->len * sizeof (type);                                \
+    const size_t len = v->len * sizeof (type);                          \
                                                                         \
     newptr = malloc (len);                                              \
     if (newptr == NULL) return -1;                                      \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/configure.ac 
new/libnbd-1.22.4/configure.ac
--- old/libnbd-1.22.3/configure.ac      2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/configure.ac      2025-08-23 18:09:41.000000000 +0200
@@ -15,7 +15,7 @@
 # License along with this library; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
-AC_INIT([libnbd],[1.22.3])
+AC_INIT([libnbd],[1.22.4])
 
 AC_CONFIG_MACRO_DIR([m4])
 m4_ifdef([AC_USE_SYSTEM_EXTENSIONS],[],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/copy/nbd-ops.c 
new/libnbd-1.22.4/copy/nbd-ops.c
--- old/libnbd-1.22.3/copy/nbd-ops.c    2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/copy/nbd-ops.c    2025-08-23 18:09:41.000000000 +0200
@@ -161,7 +161,6 @@
 struct rw *
 nbd_rw_create_subprocess (const char **argv, size_t argc, direction d)
 {
-  size_t i;
   struct rw_nbd *rwn = calloc (1, sizeof *rwn);
   if (rwn == NULL) { perror ("calloc"); exit (EXIT_FAILURE); }
 
@@ -171,10 +170,8 @@
   rwn->d = d;
 
   /* We have to copy the args so we can null-terminate them. */
-  for (i = 0; i < argc; ++i) {
-    if (const_string_vector_append (&rwn->argv, argv[i]) == -1)
-      goto error;
-  }
+  if (const_string_vector_append_array (&rwn->argv, argv, argc) == -1)
+    goto error;
   if (const_string_vector_append (&rwn->argv, NULL) == -1)
     goto error;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/generator/API.ml 
new/libnbd-1.22.4/generator/API.ml
--- old/libnbd-1.22.3/generator/API.ml  2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/generator/API.ml  2025-08-23 18:09:41.000000000 +0200
@@ -434,15 +434,17 @@
     shortdesc = "set the per-handle private data";
     longdesc = "\
 Handles contain a private data field for applications to use
-for any purpose.
+for any purpose.  This function sets the value of this field
+and returns the old value (or 0 if it was not previously set).
 
 When calling libnbd from C, the type of this field is C<uintptr_t> so
 it can be used to store an unsigned integer or a pointer.
 
 In non-C bindings it can be used to store an unsigned integer.
 
-This function sets the value of this field and returns the old value
-(or 0 if it was not previously set).";
+Libnbd does not use or interpret the value at all (except to return
+it when you call L<nbd_get_private_data(3)>).  In particular, if the
+value is a pointer then it is not freed when the handle is closed.";
     see_also = [Link "get_private_data"];
   };
 
@@ -1976,10 +1978,10 @@
 
 =back
 
-=head2 Supported URI formats
+=head2 URI scheme
 
-The following schemes are supported in the current version
-of libnbd:
+The scheme is the part before the first C<:>.  The following schemes
+are supported in the current version of libnbd:
 
 =over 4
 
@@ -2019,7 +2021,9 @@
 
 =back
 
-The authority part of the URI (C<[username@][servername][:port]>)
+=head2 URI authority
+
+The authority part of the URI C<[username@][servername][:port]>
 is parsed depending on the transport.  For TCP it specifies the
 server to connect to and optional port number.  For C<+unix>
 it should not be present.  For C<+vsock> the server name is the
@@ -2028,8 +2032,22 @@
 and optional port.  If the C<username> is present it
 is used for TLS authentication.
 
+=head2 URI export name
+
 For all transports, an export name may be present, parsed in
-accordance with the NBD URI specification.
+accordance with the NBD URI specification.  Note that the initial
+C</> character is not part of the export name:
+
+ URI                    export name
+ nbd://localhost/       \"\"        (empty string)
+ nbd://localhost/export \"export\"
+
+It is possible to override the export name programmatically
+by using L<nbd_set_opt_mode(3)> to enable option mode,
+then using L<nbd_set_export_name(3)> and L<nbd_opt_go(3)>
+as part of subsequent negotiation.
+
+=head2 URI query
 
 Finally the query part of the URI can contain:
 
@@ -2062,7 +2080,7 @@
 
 =back
 
-=head2 Disable URI features
+=head2 Disabling URI features
 
 For security reasons you might want to disable certain URI
 features.  Pre-filtering URIs is error-prone and should not
@@ -2104,13 +2122,6 @@
 
 =back
 
-=head2 Overriding the export name
-
-It is possible to override the export name portion of a URI
-by using L<nbd_set_opt_mode(3)> to enable option mode,
-then using L<nbd_set_export_name(3)> and L<nbd_opt_go(3)>
-as part of subsequent negotiation.
-
 =head2 Optional features
 
 This call will fail if libnbd was not compiled with libxml2; you can
@@ -2131,8 +2142,8 @@
 =head2 Differences from qemu and glib parsing of NBD URIs
 
 L<qemu(1)> also supports NBD URIs and has a separate URI parser.  In
-qemu E<le> 9.0 this was done using their own parser.
-In qemu E<ge> 9.1 this is done using glib C<g_uri> functions.
+S<qemu E<le> 9.0> this was done using their own parser.
+In S<qemu E<ge> 9.1> this is done using glib C<g_uri> functions.
 The current (glib-based) parser does not parse the export name part
 of the URI in exactly the same way as libnbd, which may cause URIs
 to work in libnbd but not in qemu or I<vice versa>.  Only URIs using
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/generator/OCaml.ml 
new/libnbd-1.22.4/generator/OCaml.ml
--- old/libnbd-1.22.3/generator/OCaml.ml        2025-07-17 15:05:46.000000000 
+0200
+++ new/libnbd-1.22.4/generator/OCaml.ml        2025-08-23 18:09:41.000000000 
+0200
@@ -252,10 +252,10 @@
     can be used in callbacks to update the [int ref] parameter. *)
 
 type t
-(** The handle. *)
+(** The libnbd handle, equivalent to the C type [struct nbd_handle *]. *)
 
 val create : unit -> t
-(** Create a new handle. *)
+(** Create a new libnbd handle. *)
 
 val close : t -> unit
 (** Close a handle.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/generator/Rust.ml 
new/libnbd-1.22.4/generator/Rust.ml
--- old/libnbd-1.22.3/generator/Rust.ml 2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/generator/Rust.ml 2025-08-23 18:09:41.000000000 +0200
@@ -491,37 +491,7 @@
 
 (* Convert POD to rustdoc markdown. *)
 and longdesc_to_markdown name longdesc =
-  (* Replace any POD <> expression *)
-  let content =
-    Str.global_substitute (Str.regexp {|[A-Z]<[^>]+?>|})
-      (fun s ->
-        let expr = Str.matched_string s in
-        let len = String.length expr in
-        let c = expr.[0] and content = String.sub expr 2 (len-3) in
-        match c with
-        | 'C' -> sprintf "`%s`" content (* C<...> becomes `...` *)
-        | 'B' -> sprintf "<b>%s</b>" content
-        | 'I' | 'F' -> sprintf "<i>%s</i>" content
-        | 'E' -> sprintf "&%s;" content
-        | 'L' ->
-           let len = String.length content in
-           if string_starts_with ~prefix:"nbd_" content then (
-             let n = String.sub content 4 (len - 7) in
-             if n <> "get_error" && n <> "get_errno" && n <> "close" then
-               sprintf "[%s](Handle::%s)" n n
-             else
-               sprintf "`%s`" n
-           )
-           else if string_starts_with ~prefix:"http://"; content ||
-                     string_starts_with ~prefix:"https://"; content then
-             sprintf "[%s](%s)" content content
-           else (* external manual page - how to link XXX *)
-             sprintf "<i>%s</i>" content
-        | _ ->
-           failwithf "rust: API documentation for %s contains '%s' which
-                      cannot be converted to Rust markdown" name expr
-      )
-      longdesc in
+  let content = replace_pod_expr name longdesc in
 
   (* Split input into lines for rest of the processing. *)
   let lines = nsplit "\n" content in
@@ -562,6 +532,73 @@
         Some s
   ) lines
 
+(* Replace any POD X<> expressions.
+ * JWZ's rule applies here so we cannot use regexps to parse this.
+ *)
+and replace_pod_expr name s =
+  (* Split string s into the part before "X<", the operator 'X', and
+   * the remainder of the string.
+   *)
+  let before, op, after =
+    try
+      let i = Str.search_forward (Str.regexp {|[A-Z]<|}) s 0 in
+      let op = Some s.[i] in
+      let before = String.sub s 0 i in
+      let after = String.sub s (i+2) (String.length s - i - 2) in
+      before, op, after
+    with Not_found -> s, None, "" in
+
+  match op with
+  | None -> before
+  | Some op ->
+     (* Find the content inside the X<...> operator. *)
+     let content, rest =
+       let n = String.length after in
+       let rec loop i depth =
+         if i > n then
+           failwithf "rust: API documentation for %s contains unclosed %c<...>"
+             name op;
+         let c = after.[i] in
+         match c, depth with
+         | '<', _ -> loop (i+1) (depth+1)
+         | '>', 0 -> i
+         | '>', _ -> loop (i+1) (depth-1)
+         | _ -> loop (i+1) depth
+       in
+       let i = loop 0 0 in
+       String.sub after 0 i, String.sub after (i+1) (n-i-1) in
+
+     (* Process the operator. *)
+     let new_content =
+       let content = replace_pod_expr name content in
+       match op with
+       | 'C' -> sprintf "`%s`" content (* C<...> becomes `...` *)
+       | 'B' -> sprintf "<b>%s</b>" content
+       | 'I' | 'F' -> sprintf "<i>%s</i>" content
+       | 'E' -> sprintf "&%s;" content
+       | 'S' -> (* non-breaking spaces *)
+          Str.global_replace (Str.regexp {| \|\t|}) "&nbsp;" content
+       | 'L' ->
+          let len = String.length content in
+          if string_starts_with ~prefix:"nbd_" content then (
+            let n = String.sub content 4 (len - 7) in
+            if n <> "get_error" && n <> "get_errno" && n <> "close" then
+              sprintf "[%s](Handle::%s)" n n
+            else
+              sprintf "`%s`" n
+          )
+          else if string_starts_with ~prefix:"http://"; content ||
+                    string_starts_with ~prefix:"https://"; content then
+            sprintf "[%s](%s)" content content
+          else (* external manual page - how to link XXX *)
+            sprintf "<i>%s</i>" content
+       | _ ->
+          failwithf "rust: API documentation for %s contains '%c<...>' which
+                     cannot be converted to Rust markdown" name op in
+
+     (* Assemble the output. *)
+     before ^ new_content ^ replace_pod_expr name rest
+
 (* Print a Rust expression which converts Rust like arguments to FFI like
    arguments, makes a call on the raw FFI handle, and converts the return
    value to a Rusty type. The expression assumes that variables with name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/generator/docs.ml 
new/libnbd-1.22.4/generator/docs.ml
--- old/libnbd-1.22.3/generator/docs.ml 2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/generator/docs.ml 2025-08-23 18:09:41.000000000 +0200
@@ -59,7 +59,8 @@
   let pages =
     filter_map (
       fun (name, _) ->
-        if is_prefix name "is_" || is_prefix name "can_" then
+        if (is_prefix name "is_" && name <> "is_uri") ||
+             is_prefix name "can_" then
           Some (sprintf "nbd_%s(3)" name)
         else
           None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/info/map.c new/libnbd-1.22.4/info/map.c
--- old/libnbd-1.22.3/info/map.c        2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/info/map.c        2025-08-23 18:09:41.000000000 +0200
@@ -129,7 +129,6 @@
                  int *error)
 {
   extent_vector *list = user_data;
-  size_t i;
 
   if (strcmp (metacontext, map) != 0)
     return 0;
@@ -137,11 +136,9 @@
   /* Just append the entries we got to the list.  They are printed in
    * print_extents below.
    */
-  for (i = 0; i < nr_entries; ++i) {
-    if (extent_vector_append (list, entries[i]) == -1) {
-      perror ("realloc");
-      exit (EXIT_FAILURE);
-    }
+  if (extent_vector_append_array (list, entries, nr_entries) == -1) {
+    perror ("realloc");
+    exit (EXIT_FAILURE);
   }
   return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libnbd-1.22.3/lib/uri.c new/libnbd-1.22.4/lib/uri.c
--- old/libnbd-1.22.3/lib/uri.c 2025-07-17 15:05:46.000000000 +0200
+++ new/libnbd-1.22.4/lib/uri.c 2025-08-23 18:09:41.000000000 +0200
@@ -63,6 +63,13 @@
 
 DEFINE_VECTOR_TYPE (uri_query_list, struct uri_query);
 
+static void
+free_uri_query (struct uri_query q)
+{
+  free (q.name);
+  free (q.value);
+}
+
 /* Parse the query_raw substring of a URI into a list of decoded queries.
  * Return 0 on success or -1 on error.
  */
@@ -154,7 +161,7 @@
 }
 
 /* Similar to nbdkit_parse_bool */
-int
+static int
 parse_bool (const char *param, const char *value)
 {
   if (!strcmp (value, "1") ||
@@ -477,11 +484,8 @@
   ret = 0;
 
 cleanup:
-  for (i = 0; i < queries.len; ++i) {
-    free (queries.ptr[i].name);
-    free (queries.ptr[i].value);
-  }
-  free (queries.ptr);
+  uri_query_list_iter (&queries, free_uri_query);
+  uri_query_list_reset (&queries);
   xmlFreeURI (uri);
   return ret;
 }

Reply via email to