Compare commits

...

30 Commits

Author SHA1 Message Date
Richard W.M. Jones
5011bea96d Version 1.59.4. 2026-03-17 19:28:37 +00:00
Richard W.M. Jones
31740229dc lua: Add test files to EXTRA_DIST even if --disable-lua
Ensure that 'make dist' adds the Lua test files to the tarball even if
Lua support was configured out.
2026-03-17 19:25:02 +00:00
Richard W.M. Jones
69305ca07b build: Remove qemu test and --with-qemu option
We will no longer support overriding the qemu binary at compile time.
Instead we will pick a suitable default qemu at runtime (see other
commits) or allow the user to override qemu at runtime by calling
guestfs_set_hv() or setting LIBGUESTFS_HV.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
77e447a516 lib: Remove configure-time QEMU
Remove the configure-time QEMU definition.  No longer initialize g->hv
= QEMU.  g->hv may now be NULL if the user does not explicitly either
call guestfs_set_hv or set LIBGUESTFS_HV.

Remove any assumptions in the code that g->hv is always non-NULL.

Fix one test that relied on the QEMU definition.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
39d4437e29 lib: libvirt: Remove assumptions that g->hv != NULL
For the libvirt backend we no longer need to determine if we're using
a custom hypervisor using black magic.  Instead we can simply check if
g->hv is non-NULL.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
503e9fde5a lib: direct: Remove assumptions that g->hv != NULL
In a following commit, g->hv may now be NULL if the user does not
explicitly either call guestfs_set_hv or set LIBGUESTFS_HV.

There were multiple places in the code that assumed g->hv was not
NULL, so they were all revised so that now g->hv is only not NULL if
set by the user and (in the normal case) is NULL meaning "use the
default hypervisor".

For the direct backend we call get_default_hv_direct early on and set
data->qemu in the handle.  We need to modify the KVM test so that the
current qemu binary is passed along.

We also have to change execve to execvpe since the path to qemu is not
absolute.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
0818f31960 generator: Remove test of deprecated guestfs_get_qemu
With the libvirt backend this test will fail since we don't (and
can't) know the default qemu until the appliance has launched.

Since this is a deprecated API, delete the test.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
fd6263df75 lib: Change guestfs_get_hv to report backend default hypervisor
Change the implementation of guestfs_get_hv so that if a custom
hypervisor was not set (eg. by an earlier call to guestfs_set_hv) then
we will return the default hypervisor reported by the backend.

This changes the API slightly because we can now return an error here
in the libvirt backend case if the appliance has not been launched
yet.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
ce4bfa5d08 lib: Add get_default_hv to backend operations
Add a generic way for backends to report the default hypervisor
(ie. QEMU) back to the main code.

The direct implemention reflects the current way that the hypervisor
is chosen at configure time (see m4/guestfs-qemu.m4).

For the libvirt backend, we are already getting this from libvirt
domcapabilities, so we can just return that field.

Note this may return NULL (roughly "no data"), particularly in the
libvirt case because that requires us to have launched the appliance
already.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
389c6b7583 m4/guestfs-qemu.m4: Remove virtio-serial test
I'm not sure what versions of qemu lack virtio-serial support, but
it's not ones that we have ever seen, so remove this test.  Also
virtio-serial doesn't work without kernel support, but we never tested
that.

If qemu or the guest kernel really lacks virtio-serial (likely it has
been compiled out) then we'll see it as soon as someone uses
libguestfs.

This also removes QEMU_OPTIONS_FOR_CONFIGURE, and the test of the qemu
version, since both are no longer used after we remove this test.
2026-03-17 19:07:32 +00:00
Richard W.M. Jones
48607d9d15 m4/guestfs-ocaml.m4: Check for caml_unix_error
In OCaml 5.0, unix_error was renamed caml_unix_error.

If it's not available, define as unix_error, the old symbol name.
2026-03-17 16:13:05 +00:00
Richard W.M. Jones
3bff5a6f79 Update common submodule
Pulls in the following commits:

  Cole Robinson (2):
      virtio-win: Install blnsvr.exe to C:\Windows\Drivers\VirtIO
      build: mark some ocaml commands with $(AM_V_GEN)

  Richard W.M. Jones (6):
      mlstdutils: Export List.assoc_opt
      mlcustomize/firstboot.ml: Be more careful about quoting
      mlcustomize: Create a sentinel file when firstboot completes
      mlutils/c_utils-c.c: Throw Unix_error on failure
      Use caml_unix_error instead of unix_error
      mlutils/unix_utils.ml: statvfs_is_network_filesystem should not be noalloc

  grass-lu (1):
      Add support for Kylin, NeoKylin and Anolis Linux

  shivanayak (5):
      common: fix FILE stream leak in worker_thread on guestfs_create failure (#27)
      options: fix memory leak in read_key on getline failure (#30)
      edit: check WIFEXITED before WEXITSTATUS in edit_file_editor and edit_file_perl (#31)
      mlutils: fix pattern leak in mkdtemp wrapper on failure
      qemuopts: check for write errors in qemuopts_to_channel and qemuopts_to_config_channel (#33)
2026-03-16 09:17:48 +00:00
Richard W.M. Jones
2d2eba643d lib/proto.c: Avoid generating events for incorrect progress messages
If xdr_guestfs_progress fails to decode the progress message, don't
generate an event callback.

Closes: https://github.com/libguestfs/libguestfs/pull/329
2026-03-16 09:13:56 +00:00
shivanayak
8d4d35c604 ocaml: fix memory leak in guestfs_int_ocaml_strings_val on strdup failure (#324)
When strdup() fails partway through the loop, caml_raise_out_of_memory()
longjmps without freeing the previously allocated strings or the array.
Free all prior allocations before raising the exception.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-15 09:55:02 +00:00
shivanayak
92c2e1e79e lib: fix drive struct leak on hotplug error in guestfs_impl_add_drive_opts (#318)
When guestfs_impl_add_drive_opts is called outside CONFIG state, the
hotplug error path returns -1 without freeing the already-allocated
drv structure.

Co-authored-by: Claude Local LLM <noreply@anthropic.com>
2026-03-11 09:56:16 +00:00
shivanayak
2bc54b40f7 lib: fix realpath memory leak on error paths in set_abs_path (#317)
When realpath() succeeds but subsequent operations fail, the
allocated path is leaked. Add free(ret) before returning -1
on both error paths.

Co-authored-by: Claude <norep@anthropic.com>
2026-03-11 09:37:00 +00:00
Richard W.M. Jones
47c2233026 daemon/blkid.c: Fix compilation error introduced by earlier change
blkid.c: In function ‘test_blkid_p_i_opt’:
  blkid.c:105:3: error: label ‘command_failed’ defined but not used [-Werror=unused-label]
    105 |   command_failed:
        |   ^~~~~~~~~~~~~~

Fixes: https://github.com/libguestfs/libguestfs/pull/315
Fixes: commit ff4467a1a4
2026-03-10 08:31:27 +00:00
shivanayak
065c997f5b fish: fix fd leak and undefined behavior on fdopen failure in rc_listen (#320)
Add missing NULL check after fdopen in both rc_listen and rc_remote.
In rc_listen, fdopen failure on a valid fd indicates something
fundamentally broken, so abort. In rc_remote, return an error to
the caller.

Co-authored-by: Claude <nor@anthropic.com>
2026-03-10 08:21:35 +00:00
shivanayak
2fc54b8121 lib: fix ownership leaks in FUSE cache insert functions on malloc failure (#321)
In rlc_insert and xac_insert (lib/fuse.c), both functions take
ownership of a parameter (link and xattrs respectively) but fail to
free it when their own malloc calls fail. Under memory pressure in a
long-running FUSE process, each failed cache insertion leaks the
owned resource.

Co-authored-by: Claude <nore@anthro.com>
2026-03-09 18:29:54 +00:00
shivanayak
91578639c6 daemon: fix fd leak in do_inotify_files on error paths (#319)
When popen or do_inotify_read fails, the file descriptor created by
mkstemp is never closed before returning. Add close(fd) to both
error paths to prevent file descriptor leaks.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-09 18:15:38 +00:00
shivanayak
ff4467a1a4 daemon: fix low severity bugs in debug, file, and blkid (#315)
- debug.c: fix memory leak of out buffer on opendir failure in
  debug_fds. After fclose on open_memstream, the out buffer is
  allocated and must be freed.

- file.c: add missing reply_with_perror on strdup failure in
  do_zfile, so callers get a proper error message instead of
  silent NULL return.

- blkid.c: fix wrong error variable used at command_failed label
  in test_blkid_p_i_opt. The second commandr stores its error in
  err2, but goto command_failed would report err from the first
  command. Inline the error reporting with the correct variable.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-09 18:14:32 +00:00
shivanayak
a47c923b05 lib: fix memory leak of query_kvm in guestfs_int_platform_has_kvm (#316)
The string allocated by generic_qmp_test via safe_strdup is passed to
parse_has_kvm but never freed afterwards, leaking memory on every KVM
capability check. Use CLEANUP_FREE to ensure automatic cleanup.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-09 17:22:27 +00:00
shivanayak
25c321a8fd daemon: fix temp file leak in do_vgmeta on error paths (#314)
When vgcfgbackup fails or subsequent file operations fail, the
temporary file created by mkstemp is never unlinked. Add unlink(tmp)
to all error paths after mkstemp to prevent temp files accumulating
in /tmp.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:48:56 +00:00
shivanayak
cb233a73c6 daemon: fix memory leak in do_aug_match on realloc failure (#313)
When realloc fails, vp is NULL so free(vp) is a no-op. The original
matches array (and all r strings allocated by aug_match) is leaked.
Use free_stringslen to properly free the array and its contents.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:46:00 +00:00
Cole Robinson
9b890de878 po-docs: hide deprecation warnings
The build emits a lot of warnings like this:

po4a-translate is deprecated. The unified po4a(1) program is more convenient and less error prone. Once
configured, `po4a --no-update` can be used as a drop-in replacement to `po4a-translate`.
po4a::pod: A new SimplePod parser is now available.  Please consider using it instead of the current Pod
           module. If you encounter any bugs, your reports would be greatly appreciated.  To use it, add
           the following line at the top of your po4a configuration file: "[po4a_alias:Pod] SimplePod".
           You can disable this message by setting the no-warn-simple option.  Sorry for the noise, and
           thank you!

But we can suppress them with some options to the po4a tools.

Actually fixing it is tracked here:
https://github.com/libguestfs/libguestfs/issues/312

(cherry picked from virt-v2v commit
 865f1ced9fedd9c3121b44b2f3461727ce9dfadc)

Signed-off-by: Cole Robinson <crobinso@redhat.com>
2026-02-20 10:26:11 -05:00
Cole Robinson
08503c2482 build: fix make dist with java disabled
Fails for me with:

  No rule to make target 'com_redhat_et_libguestfs_GuestFS.h'

libguestfs_jni_la_SOURCES is inside the `HAVE_JAVA` conditional,
but apparently with automake that doesn't matter, and _SOURCES
will always be copied into Makefile.in, making `make dist` fail
even if we never built anything in the java/ directory.

That header is in BUILT_SOURCES already which apparently does
what we want (and is _not_ copied unconditionally to Makefile.in).
So just drop the offending line

Signed-off-by: Cole Robinson <crobinso@redhat.com>
2026-02-19 09:09:02 -05:00
Cole Robinson
9451c1a2ef ci: make it easier to test in forked branches
+ start branch names with `ci/` to easily test in a fork
+ add `workflow_dispatch` to allow manually triggering jobs on
  any branch

Signed-off-by: Cole Robinson <crobinso@redhat.com>
(cherry picked from commit v2v
 df23b503c22579468d7c544c1724507ede84948d)
2026-02-18 12:07:04 -05:00
Hilko Bengen
5a4977fc66 lib/qemu.c: Dump qemu's stderr if QMP test fails
Qemu will refuse to start on some (all?) architectures if firmware
files are missing, or for other reasons, and complain to stderr. Those
messages should be made visible to the user as part of the error message.
2026-02-17 07:05:56 +00:00
Cole Robinson
50701c8325 ci: More fixes and tweaks
+ ubuntu
  + fix build by adding --disable-ruby
  + fix a test failure due to missing python libvirt import

+ fedora
  + use `--privileged` docker flag which also handles seccomp disable
    + this makes some network tests work, so enable them

  + exclude a flakey test
  + better document remaining disabled tests

Signed-off-by: Cole Robinson <crobinso@redhat.com>
2026-02-16 08:53:27 +00:00
Cole Robinson
358d17dea1 ci: Drop su -c usage
The `su -c` usage seems to be leftover from someone else's
CI config that was used for inspiration. Drop it. Test suite
in containers now run as root.

The libvirt pieces and new test exclusions were what I needed
to get the test suite working under root

Signed-off-by: Cole Robinson <crobinso@redhat.com>
2026-02-12 13:45:54 -05:00
32 changed files with 6035 additions and 6076 deletions

View File

@@ -3,9 +3,11 @@ on:
push:
branches:
- master
- 'ci/**' # Allow automatic CI testing on ci/* branches
pull_request:
branches:
- master
workflow_dispatch: # Allow manual triggering on any branch
# Runs basic configure, make and make check.
jobs:
@@ -38,7 +40,8 @@ jobs:
run: |
# Git is needed to run git submodule command.
# json-c is missing from the Ubuntu package deps.
sudo apt-get -y install git libjson-c-dev
# python libvirt module used unconditionally in a python test
sudo apt-get -y install git libjson-c-dev python3-libvirt
- name: Fix broken Ubuntu kernel permissions
run: |
@@ -59,7 +62,9 @@ jobs:
- name: Compile the code
run: |
autoreconf -fiv
./configure --enable-werror
# --disable-ruby needed for
# https://github.com/libguestfs/libguestfs/issues/309
./configure --enable-werror --disable-ruby
make -j
- name: Run the quick test
@@ -99,7 +104,7 @@ jobs:
container:
image: quay.io/fedora/fedora:${{ matrix.release }}
options: --security-opt seccomp=unconfined
options: --privileged
steps:
- name: Identify the system
@@ -119,43 +124,41 @@ jobs:
- name: Checkout sources
uses: actions/checkout@v5
- name: Create user
run: |
useradd -m -s /bin/bash -G wheel guestfs
tail /etc/passwd
- name: Make checkout directory editable by the sscg user
run: |
chown -R guestfs:wheel ${GITHUB_WORKSPACE}
- name: Checkout submodule
run: |
su -c 'git submodule update --init' guestfs
git config --global --add safe.directory $PWD
git submodule update --init
- name: Compile the code
run: |
su -c '
autoreconf -fiv &&
./configure CFLAGS="-fPIC -g -O2" --enable-werror &&
make -j
' guestfs
- name: Run the quick test
run: |
su -c 'make quickcheck' guestfs
make quickcheck
- name: Sanity check libvirt connection
run: |
virtqemud --daemon
virsh uri
- name: Run the full tests
run: |
# error: passt exited with status 1
export SKIP_TEST_NETWORK_SH=1
# error: passt exited with status 1
# guestunmount exit(3) doesn't trigger for root user
# https://github.com/libguestfs/libguestfs/issues/307
export SKIP_TEST_GUESTUNMOUNT_FD=1
# test-fuse-unmount-race.sh is flakey:
# ./test-fuse-umount-race.sh: wait for guestmount to exit failed after 10 seconds
export SKIP_TEST_FUSE_UMOUNT_RACE_SH=1
# test-rsync.sh is busted for root user
# rsync_out: '/dir2/' to 'rsync://root@169.254.2.2:65257/dest/': rsync: [generator] failed to set times on "." (in dest): Operation not permitted (1)
export SKIP_TEST_RSYNC_SH=1
# error: internal_autosync: umount: /sysroot: umount: /sysroot:
# target is busy
export SKIP_RHBZ1011907_1165785_SH=1
# We have to set $HOME since su -p won't set it below.
export HOME=/home/guestfs
if ! su -p -c 'make check' guestfs; then
if ! make check; then
find -name test-suite.log -exec cat {} \;
exit 1
fi

2
common

Submodule common updated: 3ac5d18419...30d3e92130

View File

@@ -1,5 +1,5 @@
# libguestfs
# Copyright (C) 2009-2025 Red Hat Inc.
# Copyright (C) 2009-2026 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -20,8 +20,8 @@
# freeform string.
m4_define([libguestfs_major], [1])
m4_define([libguestfs_minor], [59])
m4_define([libguestfs_release], [3])
m4_define([release_date], [2026-02-11])
m4_define([libguestfs_release], [4])
m4_define([release_date], [2026-03-17])
AC_INIT([libguestfs],libguestfs_major.libguestfs_minor.libguestfs_release)
AC_SUBST([RELEASE_DATE],release_date)
@@ -127,10 +127,6 @@ dnl The appliance and any dependencies.
HEADING([Checking the appliance and its dependencies])
m4_include([m4/guestfs-appliance.m4])
dnl Check for QEMU.
HEADING([Checking for QEMU])
m4_include([m4/guestfs-qemu.m4])
dnl Miscellaneous libraries used by other programs.
HEADING([Checking for other libraries])
m4_include([m4/guestfs-misc-libraries.m4])
@@ -312,7 +308,6 @@ feature ()
feature "Daemon" test "x$enable_daemon" = "xyes"
feature "Appliance" test "x$ENABLE_APPLIANCE" = "xyes"
print "QEMU" "$QEMU"
feature "guestfish" true ;# always enabled
feature "FUSE filesystem" test "x$enable_fuse" = "xyes"
print "Default backend" "$DEFAULT_BACKEND"

View File

@@ -342,7 +342,7 @@ do_aug_match (const char *path)
vp = realloc (matches, sizeof (char *) * (r+1));
if (vp == NULL) {
reply_with_perror ("realloc");
free (vp);
free_stringslen (matches, r);
return NULL;
}
matches = vp;

View File

@@ -102,7 +102,6 @@ test_blkid_p_i_opt (void)
r = commandr (NULL, &err, "blkid", "-p", "/dev/null", NULL);
if (r == -1) {
/* This means we couldn't run the blkid command at all. */
command_failed:
reply_with_error ("could not run 'blkid' command: %s", err);
return -1;
}
@@ -112,8 +111,10 @@ test_blkid_p_i_opt (void)
}
r = commandr (NULL, &err2, "blkid", "-i", NULL);
if (r == -1)
goto command_failed;
if (r == -1) {
reply_with_error ("could not run 'blkid' command: %s", err2);
return -1;
}
if (strstr (err2, "invalid option --")) {
return 0;

View File

@@ -164,6 +164,7 @@ debug_fds (const char *subcmd, size_t argc, char *const *const argv)
if (!dir) {
reply_with_perror ("opendir: /proc/self/fd");
fclose (fp);
free (out);
return NULL;
}

View File

@@ -501,7 +501,10 @@ do_zfile (const char *method, const char *path)
if (len > 0 && line[len-1] == '\n')
line[len-1] = '\0';
return strdup (line);
char *ret = strdup (line);
if (ret == NULL)
reply_with_perror ("strdup");
return ret;
}
int64_t

View File

@@ -331,6 +331,7 @@ do_inotify_files (void)
pp = popen (cmd, "w");
if (pp == NULL) {
reply_with_perror ("sort");
close (fd);
unlink (tempfile);
return NULL;
}
@@ -339,6 +340,7 @@ do_inotify_files (void)
events = do_inotify_read ();
if (events == NULL) {
pclose (pp);
close (fd);
unlink (tempfile);
return NULL;
}

View File

@@ -771,6 +771,7 @@ do_vgmeta (const char *vg, size_t *size_r)
r = command (NULL, &err, "lvm", "vgcfgbackup", "-f", tmp, vg, NULL);
if (r == -1) {
reply_with_error ("vgcfgbackup: %s", err);
unlink (tmp);
return NULL;
}
@@ -778,6 +779,7 @@ do_vgmeta (const char *vg, size_t *size_r)
fd = open (tmp, O_RDONLY|O_CLOEXEC);
if (fd == -1) {
reply_with_error ("%s", tmp);
unlink (tmp);
return NULL;
}
@@ -796,6 +798,7 @@ do_vgmeta (const char *vg, size_t *size_r)
reply_with_error ("metadata is too large for message buffer");
free (buf);
close (fd);
unlink (tmp);
return NULL;
}
buf2 = realloc (buf, alloc);
@@ -803,6 +806,7 @@ do_vgmeta (const char *vg, size_t *size_r)
reply_with_perror ("realloc");
free (buf);
close (fd);
unlink (tmp);
return NULL;
}
buf = buf2;
@@ -813,6 +817,7 @@ do_vgmeta (const char *vg, size_t *size_r)
reply_with_perror ("read: %s", tmp);
free (buf);
close (fd);
unlink (tmp);
return NULL;
}
if (rs == 0)
@@ -824,6 +829,7 @@ do_vgmeta (const char *vg, size_t *size_r)
if (close (fd) == -1) {
reply_with_perror ("close: %s", tmp);
free (buf);
unlink (tmp);
return NULL;
}

View File

@@ -277,6 +277,11 @@ rc_listen (void)
receive_stdout (s);
fp = fdopen (s, "r+");
if (fp == NULL) {
perror ("fdopen");
close (s);
abort ();
}
xdrstdio_create (&xdr, fp, XDR_DECODE);
if (!xdr_guestfish_hello (&xdr, &hello)) {
@@ -393,6 +398,11 @@ rc_remote (int pid, const char *cmd, size_t argc, char *argv[],
/* Send the greeting. */
fp = fdopen (sock, "r+");
if (fp == NULL) {
perror ("fdopen");
close (sock);
return -1;
}
xdrstdio_create (&xdr, fp, XDR_ENCODE);
if (!xdr_guestfish_hello (&xdr, &hello)) {

View File

@@ -33,9 +33,6 @@ let non_daemon_functions = [
depends on the backend, but is usually the location of the
qemu/KVM hypervisor.
The default is chosen when the library was compiled by the
configure script.
You can also override this by setting the C<LIBGUESTFS_HV>
environment variable.
@@ -59,8 +56,12 @@ the qemu binary at the same time as the handle is created.|} };
longdesc = "\
Return the current hypervisor binary.
This is always non-NULL. If it wasn't set already, then this will
return the default qemu binary name." };
If it wasn't set already, then this will return the default
qemu binary name.
For some backends this may return an error if called before
launch since it may not be possible to get the default hypervisor
before the appliance is launched." };
{ defaults with
name = "set_path"; added = (0, 0, 3);

View File

@@ -34,9 +34,6 @@ let non_daemon_functions = [
shortdesc = "set the hypervisor binary (usually qemu)";
longdesc = {|Set the hypervisor binary (usually qemu) that we will use.
The default is chosen when the library was compiled by the
configure script.
You can also override this by setting the C<LIBGUESTFS_HV>
environment variable.
@@ -55,10 +52,6 @@ the qemu binary at the same time as the handle is created.|} };
style = RConstString "hv", [], [];
blocking = false;
deprecated_by = Replaced_by "get_hv";
tests = [
InitNone, Always, TestRun (
[["get_qemu"]]), []
];
shortdesc = "get the hypervisor binary (usually qemu)";
longdesc = "\
Return the current hypervisor binary (usually qemu).

View File

@@ -99,7 +99,6 @@ jnilib_LTLIBRARIES = libguestfs_jni.la
jnilibdir = $(JNI_INSTALL_DIR)
libguestfs_jni_la_SOURCES = \
com_redhat_et_libguestfs_GuestFS.h \
actions-0.c \
actions-1.c \
actions-2.c \

View File

@@ -820,6 +820,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g,
/* ... else the old hotplugging case */
error (g, _("hotplugging support was removed in libguestfs 1.48"));
free_drive_struct (drv);
return -1;
}

View File

@@ -1385,6 +1385,7 @@ xac_insert (guestfs_h *g,
entry = malloc (sizeof *entry);
if (entry == NULL) {
perrorf (g, "malloc");
guestfs_free_xattr_list (xattrs);
return -1;
}
@@ -1393,6 +1394,7 @@ xac_insert (guestfs_h *g,
if (entry->c.pathname == NULL) {
perrorf (g, "malloc");
free (entry);
guestfs_free_xattr_list (xattrs);
return -1;
}
if (STREQ (path, "/"))
@@ -1418,6 +1420,7 @@ rlc_insert (guestfs_h *g,
entry = malloc (sizeof *entry);
if (entry == NULL) {
perrorf (g, "malloc");
free (link);
return -1;
}
@@ -1426,6 +1429,7 @@ rlc_insert (guestfs_h *g,
if (entry->c.pathname == NULL) {
perrorf (g, "malloc");
free (entry);
free (link);
return -1;
}
if (STREQ (path, "/"))

View File

@@ -164,4 +164,9 @@ extern int accept4 (int sockfd, struct sockaddr *__restrict__ addr,
extern int pipe2 (int pipefd[2], int flags);
#endif
#ifndef HAVE_CAML_UNIX_ERROR
/* For backwards compatibility with OCaml < 5.0 */
#define caml_unix_error unix_error
#endif
#endif /* GUESTFS_INTERNAL_ALL_H_ */

View File

@@ -331,6 +331,11 @@ struct backend_ops {
*/
char *(*create_cow_overlay) (guestfs_h *g, void *data, struct drive *drv);
/* Get the default hypervisor (qemu), if the user does not override
* this by calling guestfs_set_hv or setting LIBGUESTFS_HV.
*/
const char *(*get_default_hv) (guestfs_h *g, void *data);
/* Launch and shut down. */
int (*launch) (guestfs_h *g, void *data, const char *arg);
int (*shutdown) (guestfs_h *g, void *data, int check_for_errors);
@@ -791,7 +796,7 @@ void guestfs_int_init_libvirt_backend (void) __attribute__((constructor));
#endif
/* qemu.c */
extern int guestfs_int_platform_has_kvm (guestfs_h *g);
extern int guestfs_int_platform_has_kvm (guestfs_h *g, const char *qemu);
extern char *guestfs_int_drive_source_qemu_param (guestfs_h *g, const struct drive_source *src);
extern bool guestfs_int_discard_possible (guestfs_h *g, struct drive *drv);
extern char *guestfs_int_qemu_escape_param (guestfs_h *g, const char *param);

View File

@@ -118,17 +118,6 @@ guestfs_create_flags (unsigned flags, ...)
g->path = strdup (GUESTFS_DEFAULT_PATH);
if (!g->path) goto error;
#ifdef QEMU
g->hv = strdup (QEMU);
#else
/* configure --without-qemu, so set QEMU to something which will
* definitely fail. The user is expected to override the hypervisor
* by setting an environment variable or calling set_hv.
*/
g->hv = strdup ("false");
#endif
if (!g->hv) goto error;
/* Get program name. */
if (STRPREFIX (getprogname (), "lt-"))
/* Remove libtool (lt-*) prefix from short name. */
@@ -535,27 +524,17 @@ guestfs_impl_get_path (guestfs_h *g)
int
guestfs_impl_set_qemu (guestfs_h *g, const char *qemu)
{
char *new_hv;
/* Only this deprecated set_qemu API supports using NULL as a
* parameter, to mean set it back to the default QEMU. The new
* set_hv API does not allow callers to do this.
/* This deprecated API let you set qemu == NULL to mean "use the
* default qemu". set_hv doesn't allow this, although maybe it
* should.
*/
if (qemu == NULL) {
#ifdef QEMU
new_hv = safe_strdup (g, QEMU);
#else
error (g, _("configured --without-qemu so calling guestfs_set_qemu with qemu == NULL is an error"));
return -1;
#endif
free (g->hv);
g->hv = NULL;
return 0;
}
else
new_hv = safe_strdup (g, qemu);
free (g->hv);
g->hv = new_hv;
return 0;
return guestfs_impl_set_hv (g, qemu);
}
const char *
@@ -575,7 +554,21 @@ guestfs_impl_set_hv (guestfs_h *g, const char *hv)
char *
guestfs_impl_get_hv (guestfs_h *g)
{
return safe_strdup (g, g->hv);
if (g->hv)
return safe_strdup (g, g->hv);
else {
/* Try to return the default hypervisor. */
const char *default_hv;
if (g->backend_ops && g->backend_data &&
(default_hv = g->backend_ops->get_default_hv (g, g->backend_data))
!= NULL)
return safe_strdup (g, default_hv);
else {
error (g, _("cannot get default hypervisor"));
return NULL;
}
}
}
int

View File

@@ -53,6 +53,7 @@
/* Per-handle data. */
struct backend_direct_data {
const char *qemu; /* Qemu binary name. */
pid_t pid; /* Qemu PID. */
pid_t recoverypid; /* Recovery process PID. */
@@ -441,6 +442,23 @@ free_pid_path:
return rc;
}
/* Pick a default, arch-specific qemu. */
static const char *
get_default_hv_direct (guestfs_h *g, void *datav)
{
if (host_cpu[0] == 'i' && strchr ("3456", host_cpu[1]) &&
host_cpu[2] == '8' && host_cpu[3] == '6' && host_cpu[4] == '\0')
return "qemu-system-i386";
else if (STRPREFIX (host_cpu, "arm"))
return "qemu-system-arm";
else if (STREQ (host_cpu, "powerpc64") ||
STREQ (host_cpu, "powerpc64le") ||
STREQ (host_cpu, "ppc64le"))
return "qemu-system-ppc64";
else
return "qemu-system-" host_cpu;
}
static int
launch_direct (guestfs_h *g, void *datav, const char *arg)
{
@@ -482,20 +500,23 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
guestfs_int_launch_send_progress (g, 3);
data->qemu = g->hv ? : get_default_hv_direct (g, data);
debug (g, "chosen qemu: %s", data->qemu);
debug (g, "begin testing qemu features");
/* If debugging, print the qemu version. */
if (g->verbose) {
CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g);
guestfs_int_cmd_add_arg (cmd, g->hv);
guestfs_int_cmd_add_arg (cmd, data->qemu);
guestfs_int_cmd_add_arg (cmd, "-version");
guestfs_int_cmd_set_stdout_callback (cmd, debug_lines, NULL, 0);
guestfs_int_cmd_run (cmd);
}
/* Work out if KVM is supported or if the user wants to force TCG. */
if ((has_kvm = guestfs_int_platform_has_kvm (g)) == -1)
if ((has_kvm = guestfs_int_platform_has_kvm (g, data->qemu)) == -1)
goto cleanup0;
debug (g, "qemu KVM: %s", has_kvm ? "enabled" : "disabled");
@@ -571,7 +592,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
perrorf (g, "qemuopts");
goto cleanup0;
}
if (qemuopts_set_binary (qopts, g->hv) == -1) goto qemuopts_error;
if (qemuopts_set_binary (qopts, data->qemu) == -1) goto qemuopts_error;
/* CVE-2011-4127 mitigation: Disable SCSI ioctls on virtio-blk
* devices.
@@ -857,8 +878,8 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
if (g->pgroup)
setpgid (0, 0);
execve (g->hv, argv, env); /* Run qemu. */
perror (g->hv);
execvpe (data->qemu, argv, env); /* Run qemu. */
perror (data->qemu);
_exit (EXIT_FAILURE);
}
@@ -1061,7 +1082,7 @@ shutdown_direct (guestfs_h *g, void *datav, int check_for_errors)
if (guestfs_int_wait4 (g, data->pid, &status, &rusage, "qemu") == -1)
ret = -1;
else if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) {
guestfs_int_external_command_failed (g, status, g->hv, NULL);
guestfs_int_external_command_failed (g, status, data->qemu, NULL);
ret = -1;
}
else
@@ -1105,6 +1126,7 @@ max_disks_direct (guestfs_h *g, void *datav)
static struct backend_ops backend_direct_ops = {
.data_size = sizeof (struct backend_direct_data),
.create_cow_overlay = create_cow_overlay_direct,
.get_default_hv = get_default_hv_direct,
.launch = launch_direct,
.shutdown = shutdown_direct,
.get_pid = get_pid_direct,

View File

@@ -154,7 +154,6 @@ struct libvirt_xml_params {
size_t appliance_index; /* index of appliance */
bool enable_svirt; /* false if we decided to disable sVirt */
bool current_proc_is_root; /* true = euid is root */
bool is_custom; /* true if user sets non-default g->hv */
};
static int parse_capabilities (guestfs_h *g, const char *capabilities_xml, struct backend_libvirt_data *data);
@@ -167,7 +166,6 @@ static void debug_appliance_permissions (guestfs_h *g);
static void debug_socket_permissions (guestfs_h *g);
static void libvirt_error (guestfs_h *g, const char *fs, ...) __attribute__((format (printf,2,3)));
static void libvirt_debug (guestfs_h *g, const char *fs, ...) __attribute__((format (printf,2,3)));
static int is_custom_hv (guestfs_h *g, struct backend_libvirt_data *data);
static int is_blk (const char *path);
static void ignore_errors (void *ignore, virErrorPtr ignore2);
static void set_socket_create_context (guestfs_h *g);
@@ -305,6 +303,13 @@ create_cow_overlay_libvirt (guestfs_h *g, void *datav, struct drive *drv)
return overlay;
}
static const char *
get_default_hv_libvirt (guestfs_h *g, void *datav)
{
struct backend_libvirt_data *data = datav;
return data->default_qemu;
}
static int
launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
{
@@ -567,8 +572,12 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
params.appliance_index = g->nr_drives;
strcpy (params.appliance_dev, "/dev/sd");
guestfs_int_drive_name (params.appliance_index, &params.appliance_dev[7]);
params.is_custom = is_custom_hv (g, data);
params.enable_svirt = !params.is_custom;
/* Disable sVirt if the user set a custom hypervisor because SELinux
* rules probably refer to a specific qemu binary (or label) which a
* custom hypervisor probably doesn't have.
*/
params.enable_svirt = g->hv == NULL;
/* workaround a libvirt validation bug that rejects disabling selinux
* at domain level and also at disk level, as of libvirt 11.8.0
@@ -873,24 +882,6 @@ parse_domcapabilities (guestfs_h *g, const char *domcapabilities_xml,
return 0;
}
static int
is_custom_hv (guestfs_h *g, struct backend_libvirt_data *data)
{
CLEANUP_FREE char *rawpath = NULL;
if (STREQ (g->hv, data->default_qemu))
return 0;
/* ignore error here, let guest startup fail later */
rawpath = realpath(g->hv, NULL);
if (rawpath && STREQ (rawpath, data->default_qemu))
return 0;
debug (g, "user passed custom hv=%s (realpath=%s) libvirt default=%s",
g->hv, rawpath, data->default_qemu);
return 1;
}
#if HAVE_LIBSELINUX
/* Set sVirt (SELinux) socket create context. For details see:
@@ -1296,7 +1287,7 @@ construct_libvirt_xml_devices (guestfs_h *g,
/* Path to hypervisor. Only write this if the user has changed the
* default, otherwise allow libvirt to choose the best one.
*/
if (params->is_custom)
if (g->hv)
single_element ("emulator", g->hv);
/* Add a random number generator (backend for virtio-rng). */
@@ -2211,6 +2202,7 @@ max_disks_libvirt (guestfs_h *g, void *datav)
static struct backend_ops backend_libvirt_ops = {
.data_size = sizeof (struct backend_libvirt_data),
.create_cow_overlay = create_cow_overlay_libvirt,
.get_default_hv = get_default_hv_libvirt,
.launch = launch_libvirt,
.shutdown = shutdown_libvirt,
.max_disks = max_disks_libvirt,

View File

@@ -219,17 +219,19 @@ check_daemon_socket (guestfs_h *g)
/* Read and process progress messages that happen during FileIn. */
if (flag == GUESTFS_PROGRESS_FLAG) {
char mbuf[PROGRESS_MESSAGE_SIZE];
guestfs_progress message;
guestfs_progress message = { 0 };
n = g->conn->ops->read_data (g, g->conn, mbuf, PROGRESS_MESSAGE_SIZE);
if (n <= 0) /* 0 or -1 */
return n;
xdrmem_create (&xdr, mbuf, PROGRESS_MESSAGE_SIZE, XDR_DECODE);
xdr_guestfs_progress (&xdr, &message);
if (!xdr_guestfs_progress (&xdr, &message))
message.proc = 0;
xdr_destroy (&xdr);
guestfs_int_progress_message_callback (g, &message);
if (message.proc)
guestfs_int_progress_message_callback (g, &message);
goto again;
}
@@ -625,14 +627,16 @@ guestfs_int_recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
return -1;
if (*size_rtn == GUESTFS_PROGRESS_FLAG) {
guestfs_progress message;
guestfs_progress message = { 0 };
XDR xdr;
xdrmem_create (&xdr, *buf_rtn, PROGRESS_MESSAGE_SIZE, XDR_DECODE);
xdr_guestfs_progress (&xdr, &message);
if (!xdr_guestfs_progress (&xdr, &message))
message.proc = 0;
xdr_destroy (&xdr);
guestfs_int_progress_message_callback (g, &message);
if (message.proc)
guestfs_int_progress_message_callback (g, &message);
free (*buf_rtn);
*buf_rtn = NULL;

View File

@@ -59,7 +59,8 @@ cleanup_json_object_put (void *ptr)
* Run a generic QMP test on the QEMU binary.
*/
static int
generic_qmp_test (guestfs_h *g, const char *qmp_command, char **outp)
generic_qmp_test (guestfs_h *g,
const char *qemu, const char *qmp_command, char **outp)
{
CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g);
int r, fd;
@@ -68,6 +69,8 @@ generic_qmp_test (guestfs_h *g, const char *qmp_command, char **outp)
size_t allocsize = 0;
ssize_t len;
unsigned lineno;
const char *errmsg;
CLEANUP_FREE char *errors = NULL;
guestfs_int_cmd_add_string_unquoted (cmd, "echo ");
/* QMP is modal. You have to send the qmp_capabilities command first. */
@@ -79,7 +82,7 @@ generic_qmp_test (guestfs_h *g, const char *qmp_command, char **outp)
guestfs_int_cmd_add_string_unquoted (cmd, "'{ \"execute\": \"quit\" }' ");
guestfs_int_cmd_add_string_unquoted (cmd, " | ");
guestfs_int_cmd_add_string_unquoted (cmd, "QEMU_AUDIO_DRV=none ");
guestfs_int_cmd_add_string_quoted (cmd, g->hv);
guestfs_int_cmd_add_string_quoted (cmd, qemu);
guestfs_int_cmd_add_string_unquoted (cmd, " -display none");
guestfs_int_cmd_add_string_unquoted (cmd, " -machine none,accel=kvm:hvf:tcg");
guestfs_int_cmd_add_string_unquoted (cmd, " -qmp stdio");
@@ -108,8 +111,8 @@ generic_qmp_test (guestfs_h *g, const char *qmp_command, char **outp)
if (len >= 0) debug (g, "generic_qmp_test: %u: %s", lineno, line);
if (len == -1 || strstr (line, "\"QMP\"") == NULL) {
parse_failure:
error (g, "did not understand QMP monitor output from %s", g->hv);
return -1;
errmsg = "did not understand QMP monitor output";
goto err;
}
lineno++; /* line 2 */
@@ -133,11 +136,16 @@ generic_qmp_test (guestfs_h *g, const char *qmp_command, char **outp)
r = guestfs_int_cmd_pipe_wait (cmd);
/* QMP tests are optional, don't fail if the tests fail. */
if (r == -1 || !WIFEXITED (r) || WEXITSTATUS (r) != 0) {
error (g, "%s wait failed or unexpected exit status", g->hv);
return -1;
errmsg = "wait failed or unexpected exit status";
goto err;
}
return 0;
err:
errors = guestfs_int_cmd_get_pipe_errors (cmd);
error (g, "%s: %s\nError output of qemu: %s", qemu, errmsg, errors);
return -1;
}
/**
@@ -184,11 +192,11 @@ parse_has_kvm (guestfs_h *g, const char *json)
* that command.
*/
int
guestfs_int_platform_has_kvm (guestfs_h *g)
guestfs_int_platform_has_kvm (guestfs_h *g, const char *qemu)
{
char *query_kvm;
CLEANUP_FREE char *query_kvm = NULL;
if (generic_qmp_test (g, "query-kvm", &query_kvm) == -1)
if (generic_qmp_test (g, qemu, "query-kvm", &query_kvm) == -1)
return -1;
return parse_has_kvm (g, query_kvm);

View File

@@ -71,12 +71,14 @@ set_abs_path (guestfs_h *g, const char *ctxstr,
if (stat (ret, &statbuf) == -1) {
perrorf (g, "%s: %s: %s: stat",
_("setting temporary directory"), ctxstr, tmpdir);
free (ret);
return -1;
}
if (!S_ISDIR (statbuf.st_mode)) {
error (g, _("%s: %s: %s is not a directory"),
_("setting temporary directory"), ctxstr, tmpdir);
free (ret);
return -1;
}

View File

@@ -21,11 +21,25 @@ lualibdir = $(libdir)/lua/$(LUA_VERSION)
generator_built = \
bindtests.lua \
lua-guestfs.c
lua-guestfs.c \
$(NULL)
EXTRA_DIST = \
$(generator_built) \
run-bindtests
run-bindtests \
tests/010-load.lua \
tests/015-globals.lua \
tests/020-create.lua \
tests/025-create-flags.lua \
tests/027-create-multiple.lua \
tests/030-config.lua \
tests/050-lvcreate.lua \
tests/060-readdir.lua \
tests/070-optargs.lua \
tests/400-events.lua \
tests/400-progress.lua \
tests/900-errors.lua \
$(NULL)
CLEANFILES += \
guestfs.so
@@ -85,20 +99,6 @@ TESTS += \
tests/400-progress.lua
endif
EXTRA_DIST += \
tests/010-load.lua \
tests/015-globals.lua \
tests/020-create.lua \
tests/025-create-flags.lua \
tests/027-create-multiple.lua \
tests/030-config.lua \
tests/050-lvcreate.lua \
tests/060-readdir.lua \
tests/070-optargs.lua \
tests/400-events.lua \
tests/400-progress.lua \
tests/900-errors.lua
# Run the tests under valgrind.
# This doesn't work. Because Lua dlcloses the library on exit, the
# stack traces contain no useful information. The only way to make

View File

@@ -191,3 +191,19 @@ if test "x$INSTALL_OCAMLLIB" = "x"; then
INSTALL_OCAMLLIB=$OCAMLLIB
fi
AC_SUBST([INSTALL_OCAMLLIB])
dnl Check if OCaml has caml_unix_error (added 2022, OCaml 5.0).
AC_MSG_CHECKING([for caml_unix_error])
cat >conftest.c <<'EOF'
#include <caml/mlvalues.h>
#include <caml/unixsupport.h>
int main () { char *p = (void *) caml_unix_error; return 0; }
EOF
AS_IF([$OCAMLC conftest.c >&AS_MESSAGE_LOG_FD 2>&1],[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_CAML_UNIX_ERROR],[1],
[caml_unix_error found at compile time.])
],[
AC_MSG_RESULT([no])
])
rm -f conftest.c conftest.o

View File

@@ -1,133 +0,0 @@
# libguestfs
# Copyright (C) 2009-2025 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
dnl Check for QEMU for running binaries on this $host_cpu, fall
dnl back to basic 'qemu'. Allow the user to override it.
AS_CASE([$host_cpu],
[i@<:@456@:>@86],[qemu_cpu=i386],
[arm*],[qemu_cpu=arm],
[amd64],[qemu_cpu=x86_64],
[powerpc64 | ppc64le | powerpc64le],[qemu_cpu=ppc64],
[qemu_cpu=$host_cpu])
default_qemu="qemu-kvm kvm qemu-system-$qemu_cpu qemu"
AC_ARG_WITH([qemu],
[AS_HELP_STRING([--with-qemu="bin1 bin2 ..."],
[set default QEMU binary @<:@default="[qemu-kvm] qemu-system-<host> qemu"@:>@])],
dnl --with-qemu or --without-qemu:
[],
dnl neither option was given:
[with_qemu="$default_qemu"]
)
AS_IF([test "x$with_qemu" = "xno"],[
AC_MSG_WARN([qemu was disabled, libguestfs may not work at all])
QEMU=no
],[
AC_PATH_PROGS([QEMU],[$with_qemu],[no],
[$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin$PATH_SEPARATOR/usr/libexec])
test "x$QEMU" = "xno" && AC_MSG_ERROR([qemu must be installed])
AC_DEFINE_UNQUOTED([QEMU],["$QEMU"],[Location of qemu binary.])
dnl Check that the chosen qemu has virtio-serial support.
dnl For historical reasons this can be disabled by setting
dnl vmchannel_test=no.
if test "x$vmchannel_test" != "xno"; then
AC_MSG_CHECKING([that $QEMU -help works])
if $QEMU -help >&AS_MESSAGE_LOG_FD 2>&1; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_FAILURE(
[$QEMU -help: command failed.
This could be a very old version of qemu, or qemu might not be
working.
])
fi
AC_MSG_CHECKING([that $QEMU -version works])
if $QEMU -version >&AS_MESSAGE_LOG_FD 2>&1; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_FAILURE(
[$QEMU -version: command failed.
This could be a very old version of qemu, or qemu might not be
working.
])
fi
AC_MSG_CHECKING([for $QEMU version >= 1])
if $QEMU -version | grep -sq 'version @<:@1-9@:>@'; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_FAILURE([$QEMU version must be >= 1.0.])
fi
dnl Unfortunately $QEMU -device \? won't just work. We probably
dnl need to add a cocktail of different arguments which differ
dnl on the various emulators. Thanks, qemu.
AC_MSG_CHECKING([what extra options we need to use for qemu feature tests])
QEMU_OPTIONS_FOR_CONFIGURE=
# Note: the order we test these matters.
for opt in "-machine virt" "-machine accel=kvm:tcg" "-display none"; do
if $QEMU $QEMU_OPTIONS_FOR_CONFIGURE $opt -device \? >&AS_MESSAGE_LOG_FD 2>&1; then
QEMU_OPTIONS_FOR_CONFIGURE="$QEMU_OPTIONS_FOR_CONFIGURE $opt"
fi
done
AC_MSG_RESULT([$QEMU_OPTIONS_FOR_CONFIGURE])
AC_MSG_CHECKING([that $QEMU $QEMU_OPTIONS_FOR_CONFIGURE -device ? works])
if $QEMU $QEMU_OPTIONS_FOR_CONFIGURE -device \? >&AS_MESSAGE_LOG_FD 2>&1; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_FAILURE([$QEMU $QEMU_OPTIONS_FOR_CONFIGURE -device ? doesn't work.])
fi
AC_MSG_CHECKING([for virtio-serial support in $QEMU])
if $QEMU $QEMU_OPTIONS_FOR_CONFIGURE -device \? 2>&1 | grep -sq virtio-serial; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_FAILURE(
[I did not find virtio-serial support in
$QEMU.
virtio-serial support in qemu or KVM is essential for libguestfs
to operate.
Usually this means that you have to install a newer version of qemu
and/or KVM. Please read the relevant section in the README file for
more information about this.
You can override this test by setting the environment variable
vmchannel_test=no
However if you don't have the right support in your qemu, then this
just delays the pain.
If I am using the wrong qemu or you want to compile qemu from source
and install it in another location, then you should configure with
the --with-qemu option.
])
fi
fi
])

View File

@@ -193,7 +193,13 @@ guestfs_int_ocaml_strings_val (guestfs_h *g, value sv)
if (r == NULL) caml_raise_out_of_memory ();
for (i = 0; i < Wosize_val (sv); ++i) {
r[i] = strdup (String_val (Field (sv, i)));
if (r[i] == NULL) caml_raise_out_of_memory ();
if (r[i] == NULL) {
size_t j;
for (j = 0; j < i; ++j)
free (r[j]);
free (r);
caml_raise_out_of_memory ();
}
}
r[i] = NULL;

View File

@@ -42,6 +42,8 @@ SUBDIRS = $(linguas_translated)
libguestfs-docs.pot:
cd $(top_srcdir) && $(PO4A_UPDATEPO) \
--no-deprecation \
-o no-warn-simple \
-f pod \
-M utf-8 \
--package-name $(PACKAGE_NAME) \

View File

@@ -188,6 +188,8 @@ virt-p2v.1: virt-p2v.pod virt-p2v-kernel-config.pod
%.pod: $(srcdir)/../$(LINGUA).po
rm -f $@ $@-t
$(guestfs_am_v_po4a_translate)$(PO4A_TRANSLATE) \
--no-deprecation \
-o no-warn-simple \
-f pod \
-M utf-8 -L utf-8 \
-k 0 \

File diff suppressed because it is too large Load Diff

View File

@@ -6,10 +6,10 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: libguestfs 1.59.3\n"
"Project-Id-Version: libguestfs 1.59.4\n"
"Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?"
"component=libguestfs&product=Virtualization+Tools\n"
"POT-Creation-Date: 2026-02-11 12:07+0000\n"
"POT-Creation-Date: 2026-03-17 19:07+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -103,42 +103,42 @@ msgstr ""
msgid "Enter key or passphrase (\"%s\"): "
msgstr ""
#: common/options/keys.c:145
#: common/options/keys.c:146
#, c-format
msgid "size_t overflow"
msgstr ""
#: common/options/keys.c:192
#: common/options/keys.c:193
#, c-format
msgid "could not read key from user"
msgstr ""
#: common/options/keys.c:231
#: common/options/keys.c:232
#, c-format
msgid "selector '%s': missing ID"
msgstr ""
#: common/options/keys.c:238
#: common/options/keys.c:239
#, c-format
msgid "selector '%s': missing TYPE"
msgstr ""
#: common/options/keys.c:244
#: common/options/keys.c:245
#, c-format
msgid "selector '%s': missing KEY_STRING, or too many fields"
msgstr ""
#: common/options/keys.c:253
#: common/options/keys.c:254
#, c-format
msgid "selector '%s': missing FILENAME, or too many fields"
msgstr ""
#: common/options/keys.c:261
#: common/options/keys.c:262
#, c-format
msgid "selector '%s': too many fields"
msgstr ""
#: common/options/keys.c:263
#: common/options/keys.c:264
#, c-format
msgid "selector '%s': invalid TYPE"
msgstr ""
@@ -3063,29 +3063,29 @@ msgstr ""
msgid "%s is not a directory or has insecure owner or permissions"
msgstr ""
#: fish/rc.c:283
#: fish/rc.c:288
#, c-format
msgid "guestfish: protocol error: could not read hello message\n"
msgstr ""
#: fish/rc.c:288
#: fish/rc.c:293
#, c-format
msgid ""
"guestfish: protocol error: version mismatch, server version %s does not "
"match client version %s. The two versions must match exactly.\n"
msgstr ""
#: fish/rc.c:373 fish/rc.c:387
#: fish/rc.c:378 fish/rc.c:392
#, c-format
msgid "guestfish: remote: looks like the server is not running\n"
msgstr ""
#: fish/rc.c:399 fish/rc.c:413
#: fish/rc.c:409 fish/rc.c:423
#, c-format
msgid "guestfish: protocol error: could not send initial greeting to server\n"
msgstr ""
#: fish/rc.c:424
#: fish/rc.c:434
#, c-format
msgid "guestfish: protocol error: could not decode reply from server\n"
msgstr ""
@@ -3700,16 +3700,16 @@ msgstr ""
msgid "unknown protocol %s"
msgstr ""
#: lib/drives.c:822 lib/drives.c:908
#: lib/drives.c:822 lib/drives.c:909
msgid "hotplugging support was removed in libguestfs 1.48"
msgstr ""
#: lib/drives.c:979
#: lib/drives.c:980
#, c-format
msgid "%s: device not found"
msgstr ""
#: lib/drives.c:989
#: lib/drives.c:990
msgid "drive index out of range"
msgstr ""
@@ -3821,53 +3821,51 @@ msgstr ""
msgid "could not initialize dir cache hashtables"
msgstr ""
#: lib/fuse.c:1513
#: lib/fuse.c:1517
msgid ""
"FUSE is not supported in this build of libguestfs because libfuse was not "
"found when libguestfs was compiled"
msgstr ""
#: lib/handle.c:144
#: lib/handle.c:133
msgid ""
"libguestfs was built with an invalid default backend, using direct instead"
msgstr ""
#: lib/handle.c:146
#: lib/handle.c:135
msgid "direct backend does not work"
msgstr ""
#: lib/handle.c:204 lib/handle.c:214
#: lib/handle.c:193 lib/handle.c:203
#, c-format
msgid "%s=%s: non-boolean value"
msgstr ""
#: lib/handle.c:256
#: lib/handle.c:245
msgid "non-numeric value for LIBGUESTFS_MEMSIZE"
msgstr ""
#: lib/handle.c:337
#: lib/handle.c:326
#, c-format
msgid "guestfs_close: called twice on the same handle\n"
msgstr ""
#: lib/handle.c:548
msgid ""
"configured --without-qemu so calling guestfs_set_qemu with qemu == NULL is "
"an error"
#: lib/handle.c:568
msgid "cannot get default hypervisor"
msgstr ""
#: lib/handle.c:601
#: lib/handle.c:594
#, c-format
msgid "too small value for memsize (must be at least %d)"
msgstr ""
#: lib/handle.c:718
#: lib/handle.c:711
msgid ""
"identifier must contain only alphanumeric characters, underscore or minus "
"sign"
msgstr ""
#: lib/handle.c:824
#: lib/handle.c:817
msgid "setting not found"
msgstr ""
@@ -3899,7 +3897,7 @@ msgstr ""
msgid "size of %s is unreasonably large (%<PRIi64> bytes)"
msgstr ""
#: lib/launch-direct.c:154
#: lib/launch-direct.c:155
#, c-format
msgid ""
"current user is not a member of the KVM group (group ID %d). This user "
@@ -3908,31 +3906,31 @@ msgid ""
"might need to log out and log in again)."
msgstr ""
#: lib/launch-direct.c:390
#: lib/launch-direct.c:391
#, c-format
msgid "passt was killed with signal %d"
msgstr ""
#: lib/launch-direct.c:395
#: lib/launch-direct.c:396
#, c-format
msgid "internal error: unexpected exit status from passt (%d)"
msgstr ""
#: lib/launch-direct.c:402
#: lib/launch-direct.c:403
#, c-format
msgid "passt exited with status %d"
msgstr ""
#: lib/launch-direct.c:423
#: lib/launch-direct.c:424
#, c-format
msgid "failed to parse passt PID from '%s'"
msgstr ""
#: lib/launch-direct.c:472
#: lib/launch-direct.c:490
msgid "you must call guestfs_add_drive before guestfs_launch"
msgstr ""
#: lib/launch-direct.c:1005 lib/launch-libvirt.c:663
#: lib/launch-direct.c:1026 lib/launch-libvirt.c:672
msgid "qemu launched and contacted daemon, but state != READY"
msgstr ""
@@ -3941,56 +3939,56 @@ msgstr ""
msgid "%s:%d: error constructing libvirt XML near call to \"%s\""
msgstr ""
#: lib/launch-libvirt.c:212
#: lib/launch-libvirt.c:210
msgid ""
"could not auto-detect the format.\n"
"If the format is known, pass the format to libguestfs, eg. using the\n"
"--format option, or via the optional format argument to add-drive."
msgstr ""
#: lib/launch-libvirt.c:223
#: lib/launch-libvirt.c:221
msgid ""
"could not auto-detect the format when using a non-file protocol.\n"
"If the format is known, pass the format to libguestfs, eg. using the\n"
"--format option, or via the optional format argument to add-drive."
msgstr ""
#: lib/launch-libvirt.c:338
#: lib/launch-libvirt.c:343
msgid "direct mode flag is not supported yet for libvirt backend"
msgstr ""
#: lib/launch-libvirt.c:372
#: lib/launch-libvirt.c:377
#, c-format
msgid "could not connect to libvirt (URI = %s)"
msgstr ""
#: lib/launch-libvirt.c:393
#: lib/launch-libvirt.c:398
msgid "could not get libvirt capabilities"
msgstr ""
#: lib/launch-libvirt.c:414
#: lib/launch-libvirt.c:419
msgid "could not get libvirt domain capabilities"
msgstr ""
#: lib/launch-libvirt.c:596
#: lib/launch-libvirt.c:605
msgid "could not create appliance through libvirt. Original error from libvirt"
msgstr ""
#: lib/launch-libvirt.c:728
#: lib/launch-libvirt.c:737
msgid "unable to parse capabilities XML returned by libvirt"
msgstr ""
#: lib/launch-libvirt.c:734 lib/launch-libvirt.c:836 lib/libvirt-domain.c:397
#: lib/launch-libvirt.c:743 lib/launch-libvirt.c:845 lib/libvirt-domain.c:397
#: lib/libvirt-domain.c:481
msgid "unable to create new XPath context"
msgstr ""
#: lib/launch-libvirt.c:744 lib/launch-libvirt.c:844 lib/launch-libvirt.c:860
#: lib/launch-libvirt.c:753 lib/launch-libvirt.c:853 lib/launch-libvirt.c:869
#, c-format
msgid "unable to evaluate XPath expression: %s"
msgstr ""
#: lib/launch-libvirt.c:783
#: lib/launch-libvirt.c:792
#, c-format
msgid ""
"libvirt hypervisor doesnt support qemu or KVM,\n"
@@ -4005,47 +4003,47 @@ msgid ""
"For further help, read the guestfs(3) man page and libguestfs FAQ."
msgstr ""
#: lib/launch-libvirt.c:830
#: lib/launch-libvirt.c:839
msgid "unable to parse domain capabilities XML returned by libvirt"
msgstr ""
#: lib/launch-libvirt.c:1461 lib/launch-libvirt.c:1709 lib/qemu.c:289
#: lib/launch-libvirt.c:1452 lib/launch-libvirt.c:1700 lib/qemu.c:297
#, c-format
msgid "realpath: could not convert %s to absolute path"
msgstr ""
#: lib/launch-libvirt.c:1539
#: lib/launch-libvirt.c:1530
msgid ""
"libvirt does not support the qemu curl driver protocols (ftp, http, etc.); "
"try setting LIBGUESTFS_BACKEND=direct"
msgstr ""
#: lib/launch-libvirt.c:1899
#: lib/launch-libvirt.c:1890
msgid "could not define libvirt secret"
msgstr ""
#: lib/launch-libvirt.c:1910
#: lib/launch-libvirt.c:1901
msgid "rbd protocol secret must be base64 encoded"
msgstr ""
#: lib/launch-libvirt.c:1914
#: lib/launch-libvirt.c:1905
#, c-format
msgid "base64_decode_alloc: %m"
msgstr ""
#: lib/launch-libvirt.c:1932
#: lib/launch-libvirt.c:1923
msgid "could not set libvirt secret value"
msgstr ""
#: lib/launch-libvirt.c:1945
#: lib/launch-libvirt.c:1936
msgid "could not get UUID from libvirt secret"
msgstr ""
#: lib/launch-libvirt.c:2121
#: lib/launch-libvirt.c:2112
msgid "could not destroy libvirt domain"
msgstr ""
#: lib/launch-libvirt.c:2142 lib/launch-libvirt.c:2175
#: lib/launch-libvirt.c:2133 lib/launch-libvirt.c:2166
#, c-format
msgid "%s: internal error forming error message"
msgstr ""
@@ -4211,75 +4209,75 @@ msgid ""
"without libvirt"
msgstr ""
#: lib/proto.c:238
#: lib/proto.c:240
#, c-format
msgid ""
"check_daemon_socket: read 0x%x from daemon, expected 0x%x. Lost protocol "
"synchronization (bad!)\n"
msgstr ""
#: lib/proto.c:284
#: lib/proto.c:286
msgid "xdr_guestfs_message_header failed"
msgstr ""
#: lib/proto.c:293
#: lib/proto.c:295
msgid "dispatch failed to marshal args"
msgstr ""
#: lib/proto.c:387 lib/proto.c:891
#: lib/proto.c:389 lib/proto.c:895
msgid "operation cancelled by user"
msgstr ""
#: lib/proto.c:462
#: lib/proto.c:464
#, c-format
msgid "xdr_guestfs_chunk failed (buf = %p, buflen = %zu)"
msgstr ""
#: lib/proto.c:560
#: lib/proto.c:562
#, c-format
msgid "received magic signature from guestfsd, but in state %d"
msgstr ""
#: lib/proto.c:579
#: lib/proto.c:581
#, c-format
msgid "message length (%u) > maximum possible size (%d)"
msgstr ""
#: lib/proto.c:847
#: lib/proto.c:851
msgid "write to daemon socket"
msgstr ""
#: lib/proto.c:876
#: lib/proto.c:880
msgid "receive_file_data: unexpected flag received when reading file chunks"
msgstr ""
#: lib/proto.c:884
#: lib/proto.c:888
msgid "failed to parse file chunk"
msgstr ""
#: lib/proto.c:893
#: lib/proto.c:897
msgid "file receive cancelled by daemon"
msgstr ""
#: lib/qemu.c:426
#: lib/qemu.c:434
msgid ""
"discard cannot be enabled on this drive: the drive has a read-only overlay"
msgstr ""
#: lib/qemu.c:433
#: lib/qemu.c:441
msgid ""
"discard cannot be enabled on this drive: you have to specify the format of "
"the file"
msgstr ""
#: lib/qemu.c:443
#: lib/qemu.c:451
#, c-format
msgid ""
"discard cannot be enabled on this drive: qemu does not support discard for "
"%s format files"
msgstr ""
#: lib/qemu.c:463
#: lib/qemu.c:471
#, c-format
msgid ""
"discard cannot be enabled on this drive: protocol %s does not support "
@@ -4299,22 +4297,22 @@ msgstr ""
msgid "converting path to absolute path: %s: %s: realpath"
msgstr ""
#: lib/tmpdirs.c:73 lib/tmpdirs.c:79
#: lib/tmpdirs.c:73 lib/tmpdirs.c:80
#, c-format
msgid "setting temporary directory"
msgstr ""
#: lib/tmpdirs.c:78
#: lib/tmpdirs.c:79
#, c-format
msgid "%s: %s: %s is not a directory"
msgstr ""
#: lib/tmpdirs.c:195
#: lib/tmpdirs.c:197
#, c-format
msgid "%s: cannot create temporary directory"
msgstr ""
#: lib/tmpdirs.c:197
#: lib/tmpdirs.c:199
#, c-format
msgid ""
"%s: cannot create temporary directory. It may be that $XDG_RUNTIME_DIR is "
@@ -4324,32 +4322,32 @@ msgid ""
"creating /run/user/%d with the right ownership."
msgstr ""
#: lib/tmpdirs.c:271
#: lib/tmpdirs.c:273
#, c-format
msgid "socket path too long: %s/%s"
msgstr ""
#: lib/tmpdirs.c:275
#: lib/tmpdirs.c:277
#, c-format
msgid "%s"
msgstr ""
#: lib/tmpdirs.c:323
#: lib/tmpdirs.c:325
#, c-format
msgid "stat: %s"
msgstr ""
#: lib/tmpdirs.c:328
#: lib/tmpdirs.c:330
#, c-format
msgid "security: cached appliance %s is not owned by UID %ju"
msgstr ""
#: lib/tmpdirs.c:334
#: lib/tmpdirs.c:336
#, c-format
msgid "security: cached appliance %s is not a directory (mode %o)"
msgstr ""
#: lib/tmpdirs.c:340
#: lib/tmpdirs.c:342
#, c-format
msgid "security: cached appliance %s is writable by group or other (mode %o)"
msgstr ""

View File

@@ -50,9 +50,7 @@ main (int argc, char *argv[])
assert (guestfs_set_path (g, NULL) == 0);
assert (guestfs_set_append (g, NULL) == 0);
#ifdef QEMU
assert (guestfs_set_qemu (g, NULL) == 0);
#endif
guestfs_close (g);
exit (EXIT_SUCCESS);