Misc cleanups

Mostly qemu-ga related cleanups.
 -----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmKT+IccHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5SGgD/97YXkEQHHQNCiKwFub
 c3RpunfM2ww/492fwBqRYt/QZgnl1esR3gNkMLcEtR8dtWoGja98XNcTBSGcbZGj
 ydGlMZ5kfe/+7mJd5xu45egfEbWICXySstohWU6MzpddBQ1tTgq0iTsU738CsPY7
 kreQgnbYjvfPux0/xhLbYmuLZgBeLX3ser4tzaDA5ExvHjdMSkzjV6qQI5j2BZbZ
 7jCEfOJJ++Rht71A+FN98HGF9WG6LhV0e6AUnc52XhhldnnhJ3hSU6vcrrvHfYFk
 31awe1R2agWb4RMfhV2Nfn1uwsc3E+2cNPYbTvm3v/wX00Zc0gE4Z2e1/nXYU8OZ
 +kjJeiVBCgt8DNfJDYnqRWnrYSyhMmc/UIysl0SKLVVOymPDotqHjkEanDNwPUsK
 sgGNkZz2KsBkW9+PoIXh9nxowT5gG/v2oBQuLZQ+2iHgrfNVTKUweO8vHDv+A5lj
 2hEjx7IhUTNlclSHjggj2Uig7cfSgPVw27ephij0pi5pclsS8wLDs3XlVX+GSyW9
 P+2DWcsi7sBx1Gt6VcwWO07McS+NrqwwhR7rT0ioNhmS1TE0mt0YWhkCg5iabVFo
 yzweA0urN8AF0Js5IKZdNk0/z83nr8Qu8dRmGjciaYo7abBetmIdqdzuv1mIkV2H
 Sqi0mv7yPf7uYHk0U1lb2RNtJQ==
 =L0lG
 -----END PGP SIGNATURE-----

Merge tag 'misc-pull-request' of gitlab.com:marcandre.lureau/qemu into staging

Misc cleanups

Mostly qemu-ga related cleanups.

# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmKT+IccHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5SGgD/97YXkEQHHQNCiKwFub
# c3RpunfM2ww/492fwBqRYt/QZgnl1esR3gNkMLcEtR8dtWoGja98XNcTBSGcbZGj
# ydGlMZ5kfe/+7mJd5xu45egfEbWICXySstohWU6MzpddBQ1tTgq0iTsU738CsPY7
# kreQgnbYjvfPux0/xhLbYmuLZgBeLX3ser4tzaDA5ExvHjdMSkzjV6qQI5j2BZbZ
# 7jCEfOJJ++Rht71A+FN98HGF9WG6LhV0e6AUnc52XhhldnnhJ3hSU6vcrrvHfYFk
# 31awe1R2agWb4RMfhV2Nfn1uwsc3E+2cNPYbTvm3v/wX00Zc0gE4Z2e1/nXYU8OZ
# +kjJeiVBCgt8DNfJDYnqRWnrYSyhMmc/UIysl0SKLVVOymPDotqHjkEanDNwPUsK
# sgGNkZz2KsBkW9+PoIXh9nxowT5gG/v2oBQuLZQ+2iHgrfNVTKUweO8vHDv+A5lj
# 2hEjx7IhUTNlclSHjggj2Uig7cfSgPVw27ephij0pi5pclsS8wLDs3XlVX+GSyW9
# P+2DWcsi7sBx1Gt6VcwWO07McS+NrqwwhR7rT0ioNhmS1TE0mt0YWhkCg5iabVFo
# yzweA0urN8AF0Js5IKZdNk0/z83nr8Qu8dRmGjciaYo7abBetmIdqdzuv1mIkV2H
# Sqi0mv7yPf7uYHk0U1lb2RNtJQ==
# =L0lG
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 29 May 2022 03:49:43 PM PDT
# gpg:                using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5
# gpg:                issuer "marcandre.lureau@redhat.com"
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full]
# gpg:                 aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full]

* tag 'misc-pull-request' of gitlab.com:marcandre.lureau/qemu:
  test/qga: use g_auto wherever sensible
  qga/wixl: replace QEMU_GA_MSI_MINGW_BIN_PATH with glib bindir
  qga/wixl: simplify some pre-processing
  qga/wixl: require Mingw_bin
  qga/wixl: prefer variables over environment
  test/qga: use G_TEST_DIR to locate os-release test file
  qga: make build_fs_mount_list() return a bool
  qga: replace qemu_open_old() with qga_open_cloexec()
  qga: throw an Error in ga_channel_open()
  qga: use qga_open_cloexec() for safe_open_or_create()
  qga: add qga_open_cloexec() helper
  qga: flatten safe_open_or_create()
  tests: make libqmp buildable for win32
  util/win32: simplify qemu_get_local_state_dir()
  include: move qemu_*_exec_dir() to cutils

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-05-29 16:34:56 -07:00
commit f7a1ea403e
19 changed files with 398 additions and 405 deletions

9
configure vendored
View File

@ -1495,6 +1495,11 @@ for i in $glib_modules; do
fi
done
glib_bindir="$($pkg_config --variable=bindir glib-2.0)"
if test -z "$glib_bindir" ; then
glib_bindir="$($pkg_config --variable=prefix glib-2.0)"/bin
fi
# This workaround is required due to a bug in pkg-config file for glib as it
# doesn't define GLIB_STATIC_COMPILATION for pkg-config --static
@ -1860,8 +1865,6 @@ if test "$QEMU_GA_VERSION" = ""; then
QEMU_GA_VERSION=$(cat $source_path/VERSION)
fi
QEMU_GA_MSI_MINGW_BIN_PATH="$($pkg_config --variable=prefix glib-2.0)/bin"
# Mac OS X ships with a broken assembler
roms=
if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \
@ -1948,7 +1951,6 @@ if test "$debug_tcg" = "yes" ; then
fi
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=y" >> $config_host_mak
echo "QEMU_GA_MSI_MINGW_BIN_PATH=${QEMU_GA_MSI_MINGW_BIN_PATH}" >> $config_host_mak
echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER}" >> $config_host_mak
echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO}" >> $config_host_mak
echo "QEMU_GA_VERSION=${QEMU_GA_VERSION}" >> $config_host_mak
@ -2020,6 +2022,7 @@ echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak
echo "QEMU_OBJCFLAGS=$QEMU_OBJCFLAGS" >> $config_host_mak
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
echo "GLIB_LIBS=$glib_libs" >> $config_host_mak
echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak
echo "GLIB_VERSION=$(pkg-config --modversion glib-2.0)" >> $config_host_mak
echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak
echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak

View File

@ -193,6 +193,13 @@ int uleb128_decode_small(const uint8_t *in, uint32_t *n);
*/
int qemu_pstrcmp0(const char **str1, const char **str2);
/* Find program directory, and save it for later usage with
* qemu_get_exec_dir().
* Try OS specific API first, if not working, parse from argv0. */
void qemu_init_exec_dir(const char *argv0);
/* Get the saved exec dir. */
const char *qemu_get_exec_dir(void);
/**
* get_relocated_path:

View File

@ -557,14 +557,6 @@ void qemu_set_cloexec(int fd);
*/
char *qemu_get_local_state_dir(void);
/* Find program directory, and save it for later usage with
* qemu_get_exec_dir().
* Try OS specific API first, if not working, parse from argv0. */
void qemu_init_exec_dir(const char *argv0);
/* Get the saved exec dir. */
const char *qemu_get_exec_dir(void);
/**
* qemu_getauxval:
* @type: the auxiliary vector key to lookup

View File

@ -466,7 +466,10 @@ add_project_arguments(config_host['GLIB_CFLAGS'].split(),
native: false, language: ['c', 'cpp', 'objc'])
glib = declare_dependency(compile_args: config_host['GLIB_CFLAGS'].split(),
link_args: config_host['GLIB_LIBS'].split(),
version: config_host['GLIB_VERSION'])
version: config_host['GLIB_VERSION'],
variables: {
'bindir': config_host['GLIB_BINDIR'],
})
# override glib dep with the configure results (for subprojects)
meson.override_dependency('glib-2.0', glib)

View File

@ -16,6 +16,7 @@
#endif
#include "qemu/help-texts.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qemu-io.h"
#include "qemu/error-report.h"

View File

@ -1,8 +1,10 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include <termios.h>
#include "qapi/error.h"
#include "qemu/sockets.h"
#include "channel.h"
#include "cutils.h"
#ifdef CONFIG_SOLARIS
#include <stropts.h>
@ -119,7 +121,7 @@ static int ga_channel_client_add(GAChannel *c, int fd)
}
static gboolean ga_channel_open(GAChannel *c, const gchar *path,
GAChannelMethod method, int fd)
GAChannelMethod method, int fd, Error **errp)
{
int ret;
c->method = method;
@ -127,27 +129,29 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path,
switch (c->method) {
case GA_CHANNEL_VIRTIO_SERIAL: {
assert(fd < 0);
fd = qemu_open_old(path, O_RDWR | O_NONBLOCK
fd = qga_open_cloexec(
path,
#ifndef CONFIG_SOLARIS
| O_ASYNC
O_ASYNC |
#endif
);
O_RDWR | O_NONBLOCK,
0
);
if (fd == -1) {
g_critical("error opening channel: %s", strerror(errno));
error_setg_errno(errp, errno, "error opening channel");
return false;
}
#ifdef CONFIG_SOLARIS
ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
if (ret == -1) {
g_critical("error setting event mask for channel: %s",
strerror(errno));
error_setg_errno(errp, errno, "error setting event mask for channel");
close(fd);
return false;
}
#endif
ret = ga_channel_client_add(c, fd);
if (ret) {
g_critical("error adding channel to main loop");
error_setg(errp, "error adding channel to main loop");
close(fd);
return false;
}
@ -157,9 +161,9 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path,
struct termios tio;
assert(fd < 0);
fd = qemu_open_old(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
fd = qga_open_cloexec(path, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
if (fd == -1) {
g_critical("error opening channel: %s", strerror(errno));
error_setg_errno(errp, errno, "error opening channel");
return false;
}
tcgetattr(fd, &tio);
@ -180,7 +184,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path,
tcsetattr(fd, TCSANOW, &tio);
ret = ga_channel_client_add(c, fd);
if (ret) {
g_critical("error adding channel to main loop");
error_setg(errp, "error adding channel to main loop");
close(fd);
return false;
}
@ -188,12 +192,8 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path,
}
case GA_CHANNEL_UNIX_LISTEN: {
if (fd < 0) {
Error *local_err = NULL;
fd = unix_listen(path, &local_err);
if (local_err != NULL) {
g_critical("%s", error_get_pretty(local_err));
error_free(local_err);
fd = unix_listen(path, errp);
if (fd < 0) {
return false;
}
}
@ -202,24 +202,19 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path,
}
case GA_CHANNEL_VSOCK_LISTEN: {
if (fd < 0) {
Error *local_err = NULL;
SocketAddress *addr;
char *addr_str;
addr_str = g_strdup_printf("vsock:%s", path);
addr = socket_parse(addr_str, &local_err);
addr = socket_parse(addr_str, errp);
g_free(addr_str);
if (local_err != NULL) {
g_critical("%s", error_get_pretty(local_err));
error_free(local_err);
if (!addr) {
return false;
}
fd = socket_listen(addr, 1, &local_err);
fd = socket_listen(addr, 1, errp);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
g_critical("%s", error_get_pretty(local_err));
error_free(local_err);
if (fd < 0) {
return false;
}
}
@ -227,7 +222,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path,
break;
}
default:
g_critical("error binding/listening to specified socket");
error_setg(errp, "error binding/listening to specified socket");
return false;
}
@ -272,12 +267,14 @@ GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
int listen_fd, GAChannelCallback cb, gpointer opaque)
{
Error *err = NULL;
GAChannel *c = g_new0(GAChannel, 1);
c->event_cb = cb;
c->user_data = opaque;
if (!ga_channel_open(c, path, method, listen_fd)) {
g_critical("error opening channel");
if (!ga_channel_open(c, path, method, listen_fd, &err)) {
g_critical("%s", error_get_pretty(err));
error_free(err);
ga_channel_free(c);
return NULL;
}

View File

@ -27,6 +27,7 @@
#include "qemu/cutils.h"
#include "commands-common.h"
#include "block/nvme.h"
#include "cutils.h"
#ifdef HAVE_UTMPX
#include <utmpx.h>
@ -339,73 +340,71 @@ find_open_flag(const char *mode_str, Error **errp)
static FILE *
safe_open_or_create(const char *path, const char *mode, Error **errp)
{
Error *local_err = NULL;
int oflag;
int fd = -1;
FILE *f = NULL;
oflag = find_open_flag(mode, &local_err);
if (local_err == NULL) {
int fd;
/* If the caller wants / allows creation of a new file, we implement it
* with a two step process: open() + (open() / fchmod()).
*
* First we insist on creating the file exclusively as a new file. If
* that succeeds, we're free to set any file-mode bits on it. (The
* motivation is that we want to set those file-mode bits independently
* of the current umask.)
*
* If the exclusive creation fails because the file already exists
* (EEXIST is not possible for any other reason), we just attempt to
* open the file, but in this case we won't be allowed to change the
* file-mode bits on the preexistent file.
*
* The pathname should never disappear between the two open()s in
* practice. If it happens, then someone very likely tried to race us.
* In this case just go ahead and report the ENOENT from the second
* open() to the caller.
*
* If the caller wants to open a preexistent file, then the first
* open() is decisive and its third argument is ignored, and the second
* open() and the fchmod() are never called.
*/
fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
if (fd == -1 && errno == EEXIST) {
oflag &= ~(unsigned)O_CREAT;
fd = open(path, oflag);
}
if (fd == -1) {
error_setg_errno(&local_err, errno, "failed to open file '%s' "
"(mode: '%s')", path, mode);
} else {
qemu_set_cloexec(fd);
if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
error_setg_errno(&local_err, errno, "failed to set permission "
"0%03o on new file '%s' (mode: '%s')",
(unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
} else {
FILE *f;
f = fdopen(fd, mode);
if (f == NULL) {
error_setg_errno(&local_err, errno, "failed to associate "
"stdio stream with file descriptor %d, "
"file '%s' (mode: '%s')", fd, path, mode);
} else {
return f;
}
}
close(fd);
if (oflag & O_CREAT) {
unlink(path);
}
}
oflag = find_open_flag(mode, errp);
if (oflag < 0) {
goto end;
}
error_propagate(errp, local_err);
return NULL;
/* If the caller wants / allows creation of a new file, we implement it
* with a two step process: open() + (open() / fchmod()).
*
* First we insist on creating the file exclusively as a new file. If
* that succeeds, we're free to set any file-mode bits on it. (The
* motivation is that we want to set those file-mode bits independently
* of the current umask.)
*
* If the exclusive creation fails because the file already exists
* (EEXIST is not possible for any other reason), we just attempt to
* open the file, but in this case we won't be allowed to change the
* file-mode bits on the preexistent file.
*
* The pathname should never disappear between the two open()s in
* practice. If it happens, then someone very likely tried to race us.
* In this case just go ahead and report the ENOENT from the second
* open() to the caller.
*
* If the caller wants to open a preexistent file, then the first
* open() is decisive and its third argument is ignored, and the second
* open() and the fchmod() are never called.
*/
fd = qga_open_cloexec(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
if (fd == -1 && errno == EEXIST) {
oflag &= ~(unsigned)O_CREAT;
fd = qga_open_cloexec(path, oflag, 0);
}
if (fd == -1) {
error_setg_errno(errp, errno,
"failed to open file '%s' (mode: '%s')",
path, mode);
goto end;
}
if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
error_setg_errno(errp, errno, "failed to set permission "
"0%03o on new file '%s' (mode: '%s')",
(unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
goto end;
}
f = fdopen(fd, mode);
if (f == NULL) {
error_setg_errno(errp, errno, "failed to associate stdio stream with "
"file descriptor %d, file '%s' (mode: '%s')",
fd, path, mode);
}
end:
if (f == NULL && fd != -1) {
close(fd);
if (oflag & O_CREAT) {
unlink(path);
}
}
return f;
}
int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
@ -674,7 +673,7 @@ static int dev_major_minor(const char *devpath,
/*
* Walk the mount table and build a list of local file systems
*/
static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
static bool build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
{
struct mntent *ment;
FsMount *mount;
@ -685,7 +684,7 @@ static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
fp = setmntent(mtab, "r");
if (!fp) {
error_setg(errp, "failed to open mtab file: '%s'", mtab);
return;
return false;
}
while ((ment = getmntent(fp))) {
@ -715,6 +714,7 @@ static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
}
endmntent(fp);
return true;
}
static void decode_mntname(char *name, int len)
@ -739,7 +739,7 @@ static void decode_mntname(char *name, int len)
}
}
static void build_fs_mount_list(FsMountList *mounts, Error **errp)
static bool build_fs_mount_list(FsMountList *mounts, Error **errp)
{
FsMount *mount;
char const *mountinfo = "/proc/self/mountinfo";
@ -752,8 +752,7 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp)
fp = fopen(mountinfo, "r");
if (!fp) {
build_fs_mount_list_from_mtab(mounts, errp);
return;
return build_fs_mount_list_from_mtab(mounts, errp);
}
while (getline(&line, &n, fp) != -1) {
@ -795,6 +794,7 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp)
free(line);
fclose(fp);
return true;
}
#endif
@ -1407,7 +1407,7 @@ static void get_nvme_smart(GuestDiskInfo *disk)
| (((sizeof(log) >> 2) - 1) << 16)
};
fd = qemu_open_old(disk->name, O_RDONLY);
fd = qga_open_cloexec(disk->name, O_RDONLY, 0);
if (fd == -1) {
g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno));
return;
@ -1593,8 +1593,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
Error *local_err = NULL;
QTAILQ_INIT(&mounts);
build_fs_mount_list(&mounts, &local_err);
if (local_err) {
if (!build_fs_mount_list(&mounts, &local_err)) {
error_propagate(errp, local_err);
return NULL;
}
@ -1717,8 +1716,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
}
QTAILQ_INIT(&mounts);
build_fs_mount_list(&mounts, &local_err);
if (local_err) {
if (!build_fs_mount_list(&mounts, &local_err)) {
error_propagate(errp, local_err);
return -1;
}
@ -1740,7 +1738,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
}
}
fd = qemu_open_old(mount->dirname, O_RDONLY);
fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0);
if (fd == -1) {
error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
goto error;
@ -1799,15 +1797,14 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
Error *local_err = NULL;
QTAILQ_INIT(&mounts);
build_fs_mount_list(&mounts, &local_err);
if (local_err) {
if (!build_fs_mount_list(&mounts, &local_err)) {
error_propagate(errp, local_err);
return 0;
}
QTAILQ_FOREACH(mount, &mounts, next) {
logged = false;
fd = qemu_open_old(mount->dirname, O_RDONLY);
fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0);
if (fd == -1) {
continue;
}
@ -1873,15 +1870,12 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
FsMountList mounts;
struct FsMount *mount;
int fd;
Error *local_err = NULL;
struct fstrim_range r;
slog("guest-fstrim called");
QTAILQ_INIT(&mounts);
build_fs_mount_list(&mounts, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (!build_fs_mount_list(&mounts, errp)) {
return NULL;
}
@ -1893,7 +1887,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
QAPI_LIST_PREPEND(response->paths, result);
fd = qemu_open_old(mount->dirname, O_RDONLY);
fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0);
if (fd == -1) {
result->error = g_strdup_printf("failed to open: %s",
strerror(errno));

33
qga/cutils.c Normal file
View File

@ -0,0 +1,33 @@
/*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "cutils.h"
#include "qapi/error.h"
/**
* qga_open_cloexec:
* @name: the pathname to open
* @flags: as in open()
* @mode: as in open()
*
* A wrapper for open() function which sets O_CLOEXEC.
*
* On error, -1 is returned.
*/
int qga_open_cloexec(const char *name, int flags, mode_t mode)
{
int ret;
#ifdef O_CLOEXEC
ret = open(name, flags | O_CLOEXEC, mode);
#else
ret = open(name, flags, mode);
if (ret >= 0) {
qemu_set_cloexec(ret);
}
#endif
return ret;
}

8
qga/cutils.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef CUTILS_H_
#define CUTILS_H_
#include "qemu/osdep.h"
int qga_open_cloexec(const char *name, int flags, mode_t mode);
#endif /* CUTILS_H_ */

View File

@ -1,62 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?ifndef env.QEMU_GA_VERSION ?>
<?error Environment variable QEMU_GA_VERSION undefined?>
<?endif?>
<?ifndef env.QEMU_GA_DISTRO ?>
<?error Environment variable QEMU_GA_DISTRO undefined?>
<?endif?>
<?ifndef env.QEMU_GA_MANUFACTURER ?>
<?error Environment variable QEMU_GA_MANUFACTURER undefined?>
<?endif?>
<?ifndef var.Arch?>
<?error Define Arch to 32 or 64?>
<?endif?>
<?ifndef var.Mingw_bin?>
<?if $(var.Arch) = "64"?>
<?define Mingw_bin=/usr/x86_64-w64-mingw32/sys-root/mingw/bin ?>
<?endif?>
<?if $(var.Arch) = "32"?>
<?define Mingw_bin=/usr/i686-w64-mingw32/sys-root/mingw/bin ?>
<?endif?>
<?endif?>
<?if $(var.Arch) = "64"?>
<?define ArchLib=libgcc_s_seh-1.dll?>
<?define GaProgramFilesFolder="ProgramFiles64Folder" ?>
<?endif?>
<?if $(var.Arch) = "32"?>
<?define ArchLib=libgcc_s_dw2-1.dll?>
<?define GaProgramFilesFolder="ProgramFilesFolder" ?>
<?endif?>
<?ifndef var.ArchLib ?>
<?error Unexpected Arch value $(var.Arch)?>
<?else?>
<?if $(var.Arch) = "32"?>
<?define ArchLib=libgcc_s_dw2-1.dll?>
<?define GaProgramFilesFolder="ProgramFilesFolder" ?>
<?else?>
<?error Unexpected Arch value $(var.Arch)?>
<?endif?>
<?endif?>
<Product
Name="QEMU guest agent"
Id="*"
UpgradeCode="{EB6B8302-C06E-4BEC-ADAC-932C68A3A98D}"
Manufacturer="$(env.QEMU_GA_MANUFACTURER)"
Version="$(env.QEMU_GA_VERSION)"
Manufacturer="$(var.QEMU_GA_MANUFACTURER)"
Version="$(var.QEMU_GA_VERSION)"
Language="1033">
<?if $(var.Arch) = 32 ?>
<Condition Message="Error: 32-bit version of Qemu GA can not be installed on 64-bit Windows.">NOT VersionNT64</Condition>
<?endif?>
<Package
Manufacturer="$(env.QEMU_GA_MANUFACTURER)"
Manufacturer="$(var.QEMU_GA_MANUFACTURER)"
InstallerVersion="200"
Languages="1033"
Compressed="yes"
InstallScope="perMachine"
/>
<Media Id="1" Cabinet="qemu_ga.$(env.QEMU_GA_VERSION).cab" EmbedCab="yes" />
<Media Id="1" Cabinet="qemu_ga.$(var.QEMU_GA_VERSION).cab" EmbedCab="yes" />
<Property Id="WHSLogo">1</Property>
<MajorUpgrade
DowngradeErrorMessage="Error: A newer version of QEMU guest agent is already installed."
@ -66,7 +39,7 @@
<Directory Id="$(var.GaProgramFilesFolder)" Name="QEMU Guest Agent">
<Directory Id="qemu_ga_directory" Name="Qemu-ga">
<Component Id="qemu_ga" Guid="{908B7199-DE2A-4DC6-A8D0-27A5AE444FEA}">
<File Id="qemu_ga.exe" Name="qemu-ga.exe" Source="$(env.BUILD_DIR)/qga/qemu-ga.exe" KeyPath="yes" DiskId="1"/>
<File Id="qemu_ga.exe" Name="qemu-ga.exe" Source="$(var.BUILD_DIR)/qga/qemu-ga.exe" KeyPath="yes" DiskId="1"/>
<ServiceInstall
Id="ServiceInstaller"
Type="ownProcess"
@ -85,57 +58,57 @@
</Component>
<?ifdef var.InstallVss?>
<Component Id="libstdc++_6_lib" Guid="{55E737B5-9127-4A11-9FC3-A29367714574}">
<File Id="libstdc++-6.lib" Name="libstdc++-6.dll" Source="$(var.Mingw_bin)/libstdc++-6.dll" KeyPath="yes" DiskId="1"/>
<File Id="libstdc++-6.lib" Name="libstdc++-6.dll" Source="$(var.BIN_DIR)/libstdc++-6.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="qga_vss_dll" Guid="{CB19C453-FABB-4BB1-ABAB-6B74F687BFBB}">
<File Id="qga_vss.dll" Name="qga-vss.dll" Source="$(env.BUILD_DIR)/qga/vss-win32/qga-vss.dll" KeyPath="yes" DiskId="1"/>
<File Id="qga_vss.dll" Name="qga-vss.dll" Source="$(var.BUILD_DIR)/qga/vss-win32/qga-vss.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="qga_vss_tlb" Guid="{D8D584B1-59C2-4FB7-A91F-636FF7BFA66E}">
<File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="$(env.BUILD_DIR)/qga/vss-win32/qga-vss.tlb" KeyPath="yes" DiskId="1"/>
<File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="$(var.BUILD_DIR)/qga/vss-win32/qga-vss.tlb" KeyPath="yes" DiskId="1"/>
</Component>
<?endif?>
<?if $(var.Arch) = "32"?>
<Component Id="gspawn-helper-console" Guid="{446185B3-87BE-43D2-96B8-0FEFD9E8696D}">
<File Id="gspawn-win32-helper-console.exe" Name="gspawn-win32-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper-console.exe" KeyPath="yes" DiskId="1"/>
<File Id="gspawn-win32-helper-console.exe" Name="gspawn-win32-helper-console.exe" Source="$(var.BIN_DIR)/gspawn-win32-helper-console.exe" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="gspawn-helper" Guid="{CD67A5A3-2DB1-4DA1-A67A-8D71E797B466}">
<File Id="gspawn-win32-helper.exe" Name="gspawn-win32-helper.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper-console.exe" KeyPath="yes" DiskId="1"/>
<File Id="gspawn-win32-helper.exe" Name="gspawn-win32-helper.exe" Source="$(var.BIN_DIR)/gspawn-win32-helper-console.exe" KeyPath="yes" DiskId="1"/>
</Component>
<?endif?>
<?if $(var.Arch) = "64"?>
<Component Id="gspawn-helper-console" Guid="{9E615A9F-349A-4992-A5C2-C10BAD173660}">
<File Id="gspawn-win64-helper-console.exe" Name="gspawn-win64-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper-console.exe" KeyPath="yes" DiskId="1"/>
<File Id="gspawn-win64-helper-console.exe" Name="gspawn-win64-helper-console.exe" Source="$(var.BIN_DIR)/gspawn-win64-helper-console.exe" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="gspawn-helper" Guid="{D201AD22-1846-4E4F-B6E1-C7A908ED2457}">
<File Id="gspawn-win64-helper.exe" Name="gspawn-win64-helper.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper-console.exe" KeyPath="yes" DiskId="1"/>
<File Id="gspawn-win64-helper.exe" Name="gspawn-win64-helper.exe" Source="$(var.BIN_DIR)/gspawn-win64-helper-console.exe" KeyPath="yes" DiskId="1"/>
</Component>
<?endif?>
<Component Id="iconv" Guid="{35EE3558-D34B-4F0A-B8BD-430FF0775246}">
<File Id="iconv.dll" Name="iconv.dll" Source="$(var.Mingw_bin)/iconv.dll" KeyPath="yes" DiskId="1"/>
<File Id="iconv.dll" Name="iconv.dll" Source="$(var.BIN_DIR)/iconv.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="libgcc_arch_lib" Guid="{ADD4D07D-4515-4AB6-AF3E-C904961B4BB0}">
<File Id="libgcc_arch_lib" Name="$(var.ArchLib)" Source="$(var.Mingw_bin)/$(var.ArchLib)" KeyPath="yes" DiskId="1"/>
<File Id="libgcc_arch_lib" Name="$(var.ArchLib)" Source="$(var.BIN_DIR)/$(var.ArchLib)" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="libglib" Guid="{D31BFD83-2773-4B65-B45A-E0D2ADA58679}">
<File Id="libglib_2.0_0.dll" Name="libglib-2.0-0.dll" Source="$(var.Mingw_bin)/libglib-2.0-0.dll" KeyPath="yes" DiskId="1"/>
<File Id="libglib_2.0_0.dll" Name="libglib-2.0-0.dll" Source="$(var.BIN_DIR)/libglib-2.0-0.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="libintl" Guid="{A641BC2D-A907-4A94-9149-F30ED430878F}">
<File Id="libintl_8.dll" Name="libintl-8.dll" Source="$(var.Mingw_bin)/libintl-8.dll" KeyPath="yes" DiskId="1"/>
<File Id="libintl_8.dll" Name="libintl-8.dll" Source="$(var.BIN_DIR)/libintl-8.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="libssp" Guid="{7880087B-02B4-4EF6-A5D3-D18F8E3D90E1}">
<File Id="libssp_0.dll" Name="libssp-0.dll" Source="$(var.Mingw_bin)/libssp-0.dll" KeyPath="yes" DiskId="1"/>
<File Id="libssp_0.dll" Name="libssp-0.dll" Source="$(var.BIN_DIR)/libssp-0.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="libwinpthread" Guid="{6C117C78-0F47-4B07-8F34-6BEE11643829}">
<File Id="libwinpthread_1.dll" Name="libwinpthread-1.dll" Source="$(var.Mingw_bin)/libwinpthread-1.dll" KeyPath="yes" DiskId="1"/>
<File Id="libwinpthread_1.dll" Name="libwinpthread-1.dll" Source="$(var.BIN_DIR)/libwinpthread-1.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="libpcre" Guid="{7A86B45E-A009-489A-A849-CE3BACF03CD0}">
<File Id="libpcre_1.dll" Name="libpcre-1.dll" Source="$(var.Mingw_bin)/libpcre-1.dll" KeyPath="yes" DiskId="1"/>
<File Id="libpcre_1.dll" Name="libpcre-1.dll" Source="$(var.BIN_DIR)/libpcre-1.dll" KeyPath="yes" DiskId="1"/>
</Component>
<Component Id="registry_entries" Guid="{D075D109-51CA-11E3-9F8B-000C29858960}">
<RegistryKey Root="HKLM"
Key="Software\$(env.QEMU_GA_MANUFACTURER)\$(env.QEMU_GA_DISTRO)\Tools\QemuGA">
Key="Software\$(var.QEMU_GA_MANUFACTURER)\$(var.QEMU_GA_DISTRO)\Tools\QemuGA">
<RegistryValue Type="string" Name="ProductID" Value="fb0a0d66-c7fb-4e2e-a16b-c4a3bfe8d13b" />
<RegistryValue Type="string" Name="Version" Value="$(env.QEMU_GA_VERSION)" />
<RegistryValue Type="string" Name="Version" Value="$(var.QEMU_GA_VERSION)" />
</RegistryKey>
</Component>
</Directory>

View File

@ -65,6 +65,7 @@ qga_ss.add(files(
'commands.c',
'guest-agent-command-state.c',
'main.c',
'cutils.c',
))
qga_ss.add(when: 'CONFIG_POSIX', if_true: files(
'channel-posix.c',
@ -121,15 +122,14 @@ if targetos == 'windows'
output: 'qemu-ga-@0@.msi'.format(host_arch),
depends: deps,
command: [
find_program('env'),
'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'],
'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'],
'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'],
'BUILD_DIR=' + meson.build_root(),
wixl, '-o', '@OUTPUT0@', '@INPUT0@',
qemu_ga_msi_arch[cpu],
qemu_ga_msi_vss,
'-D', 'Mingw_bin=' + config_host['QEMU_GA_MSI_MINGW_BIN_PATH'],
'-D', 'BUILD_DIR=' + meson.build_root(),
'-D', 'BIN_DIR=' + glib.get_variable('bindir'),
'-D', 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'],
'-D', 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'],
'-D', 'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'],
])
all_qga += [qga_msi]
alias_target('msi', qga_msi)

View File

@ -44,6 +44,7 @@
#include "qemu/help-texts.h"
#include "qemu-version.h"
#include "qemu/cutils.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "qemu/help_option.h"

View File

@ -15,6 +15,7 @@
#include <wordexp.h>
#include "qemu/cutils.h"
#include "qemu/datadir.h"
#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"

View File

@ -18,6 +18,11 @@
#include "libqmp.h"
#ifndef _WIN32
#include <sys/socket.h>
#endif
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/qjson.h"
@ -87,6 +92,7 @@ QDict *qmp_fd_receive(int fd)
return qmp.response;
}
#ifndef _WIN32
/* Sends a message and file descriptors to the socket.
* It's needed for qmp-commands like getfd/add-fd */
static void socket_send_fds(int socket_fd, int *fds, size_t fds_num,
@ -120,17 +126,23 @@ static void socket_send_fds(int socket_fd, int *fds, size_t fds_num,
} while (ret < 0 && errno == EINTR);
g_assert_cmpint(ret, >, 0);
}
#endif
/**
* Allow users to send a message without waiting for the reply,
* in the case that they choose to discard all replies up until
* a particular EVENT is received.
*/
void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
const char *fmt, va_list ap)
static void
_qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
const char *fmt, va_list ap)
{
QObject *qobj;
#ifdef _WIN32
assert(fds_num == 0);
#endif
/* Going through qobject ensures we escape strings properly */
qobj = qobject_from_vjsonf_nofail(fmt, ap);
@ -148,10 +160,14 @@ void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
if (log) {
fprintf(stderr, "%s", str->str);
}
#ifndef _WIN32
/* Send QMP request */
if (fds && fds_num > 0) {
socket_send_fds(fd, fds, fds_num, str->str, str->len);
} else {
} else
#endif
{
socket_send(fd, str->str, str->len);
}
@ -160,15 +176,23 @@ void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
}
}
#ifndef _WIN32
void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
const char *fmt, va_list ap)
{
_qmp_fd_vsend_fds(fd, fds, fds_num, fmt, ap);
}
#endif
void qmp_fd_vsend(int fd, const char *fmt, va_list ap)
{
qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
_qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
}
QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
{
qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
_qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
return qmp_fd_receive(fd);
}

View File

@ -21,8 +21,10 @@
#include "qapi/qmp/qdict.h"
QDict *qmp_fd_receive(int fd);
#ifndef _WIN32
void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
const char *fmt, va_list ap) G_GNUC_PRINTF(4, 0);
#endif
void qmp_fd_vsend(int fd, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0);
void qmp_fd_send(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
void qmp_fd_send_raw(int fd, const char *fmt, ...) G_GNUC_PRINTF(2, 3);

View File

@ -52,7 +52,10 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp)
{
const gchar *extra_arg = data;
GError *error = NULL;
gchar *cwd, *path, *cmd, **argv = NULL;
g_autofree char *cwd = NULL;
g_autofree char *path = NULL;
g_autofree char *cmd = NULL;
g_auto(GStrv) argv = NULL;
fixture->loop = g_main_loop_new(NULL, FALSE);
@ -78,17 +81,12 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp)
fixture->fd = connect_qga(path);
g_assert_cmpint(fixture->fd, !=, -1);
g_strfreev(argv);
g_free(cmd);
g_free(cwd);
g_free(path);
}
static void
fixture_tear_down(TestFixture *fixture, gconstpointer data)
{
gchar *tmp;
g_autofree char *tmp = NULL;
kill(fixture->pid, SIGTERM);
@ -107,7 +105,6 @@ fixture_tear_down(TestFixture *fixture, gconstpointer data)
tmp = g_build_filename(fixture->test_dir, "sock", NULL);
g_unlink(tmp);
g_free(tmp);
g_rmdir(fixture->test_dir);
g_free(fixture->test_dir);
@ -122,7 +119,7 @@ static void qmp_assertion_message_error(const char *domain,
QDict *dict)
{
const char *class, *desc;
char *s;
g_autofree char *s = NULL;
QDict *error;
error = qdict_get_qdict(dict, "error");
@ -131,7 +128,6 @@ static void qmp_assertion_message_error(const char *domain,
s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
g_assertion_message(domain, file, line, func, s);
g_free(s);
}
#define qmp_assert_no_error(err) do { \
@ -146,7 +142,7 @@ static void test_qga_sync_delimited(gconstpointer fix)
const TestFixture *fixture = fix;
guint32 v, r = g_test_rand_int();
unsigned char c;
QDict *ret;
g_autoptr(QDict) ret = NULL;
qmp_fd_send_raw(fixture->fd, "\xff");
qmp_fd_send(fixture->fd,
@ -180,15 +176,13 @@ static void test_qga_sync_delimited(gconstpointer fix)
v = qdict_get_int(ret, "return");
g_assert_cmpint(r, ==, v);
qobject_unref(ret);
}
static void test_qga_sync(gconstpointer fix)
{
const TestFixture *fixture = fix;
guint32 v, r = g_test_rand_int();
QDict *ret;
g_autoptr(QDict) ret = NULL;
/*
* TODO guest-sync is inherently limited: we cannot distinguish
@ -210,33 +204,27 @@ static void test_qga_sync(gconstpointer fix)
v = qdict_get_int(ret, "return");
g_assert_cmpint(r, ==, v);
qobject_unref(ret);
}
static void test_qga_ping(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
g_assert_nonnull(ret);
qmp_assert_no_error(ret);
qobject_unref(ret);
}
static void test_qga_id(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}");
g_assert_nonnull(ret);
qmp_assert_no_error(ret);
g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1);
qobject_unref(ret);
}
static void test_qga_invalid_oob(gconstpointer fix)
@ -253,7 +241,8 @@ static void test_qga_invalid_oob(gconstpointer fix)
static void test_qga_invalid_args(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *error;
g_autoptr(QDict) ret = NULL;
QDict *error;
const gchar *class, *desc;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', "
@ -266,14 +255,13 @@ static void test_qga_invalid_args(gconstpointer fix)
g_assert_cmpstr(class, ==, "GenericError");
g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected");
qobject_unref(ret);
}
static void test_qga_invalid_cmd(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *error;
g_autoptr(QDict) ret = NULL;
QDict *error;
const gchar *class, *desc;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
@ -285,14 +273,13 @@ static void test_qga_invalid_cmd(gconstpointer fix)
g_assert_cmpstr(class, ==, "CommandNotFound");
g_assert_cmpint(strlen(desc), >, 0);
qobject_unref(ret);
}
static void test_qga_info(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *val;
g_autoptr(QDict) ret = NULL;
QDict *val;
const gchar *version;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
@ -302,14 +289,12 @@ static void test_qga_info(gconstpointer fix)
val = qdict_get_qdict(ret, "return");
version = qdict_get_try_str(val, "version");
g_assert_cmpstr(version, ==, QEMU_VERSION);
qobject_unref(ret);
}
static void test_qga_get_vcpus(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
@ -322,14 +307,12 @@ static void test_qga_get_vcpus(gconstpointer fix)
entry = qlist_first(list);
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id"));
qobject_unref(ret);
}
static void test_qga_get_fsinfo(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
@ -346,14 +329,13 @@ static void test_qga_get_fsinfo(gconstpointer fix)
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type"));
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk"));
}
qobject_unref(ret);
}
static void test_qga_get_memory_block_info(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *val;
g_autoptr(QDict) ret = NULL;
QDict *val;
int64_t size;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
@ -366,14 +348,12 @@ static void test_qga_get_memory_block_info(gconstpointer fix)
size = qdict_get_int(val, "size");
g_assert_cmpint(size, >, 0);
}
qobject_unref(ret);
}
static void test_qga_get_memory_blocks(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
@ -391,14 +371,12 @@ static void test_qga_get_memory_blocks(gconstpointer fix)
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
}
}
qobject_unref(ret);
}
static void test_qga_network_get_interfaces(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
@ -410,8 +388,6 @@ static void test_qga_network_get_interfaces(gconstpointer fix)
list = qdict_get_qlist(ret, "return");
entry = qlist_first(list);
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
qobject_unref(ret);
}
static void test_qga_file_ops(gconstpointer fix)
@ -642,7 +618,7 @@ static void test_qga_file_write_read(gconstpointer fix)
static void test_qga_get_time(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
int64_t time;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
@ -651,8 +627,6 @@ static void test_qga_get_time(gconstpointer fix)
time = qdict_get_int(ret, "return");
g_assert_cmpint(time, >, 0);
qobject_unref(ret);
}
static void test_qga_blacklist(gconstpointer data)
@ -693,18 +667,22 @@ static void test_qga_blacklist(gconstpointer data)
static void test_qga_config(gconstpointer data)
{
GError *error = NULL;
char *cwd, *cmd, *out, *err, *str, **strv, **argv = NULL;
g_autofree char *out = NULL;
g_autofree char *err = NULL;
g_autofree char *cwd = NULL;
g_autofree char *cmd = NULL;
g_auto(GStrv) argv = NULL;
g_auto(GStrv) strv = NULL;
g_autoptr(GKeyFile) kf = NULL;
char *str;
char *env[2];
int status;
gsize n;
GKeyFile *kf;
cwd = g_get_current_dir();
cmd = g_strdup_printf("%s%cqga%cqemu-ga -D",
cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
g_free(cwd);
g_shell_parse_argv(cmd, NULL, &argv, &error);
g_free(cmd);
g_assert_no_error(error);
env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config",
@ -712,7 +690,6 @@ static void test_qga_config(gconstpointer data)
env[1] = NULL;
g_spawn_sync(NULL, argv, env, 0,
NULL, NULL, &out, &err, &status, &error);
g_strfreev(argv);
g_assert_no_error(error);
g_assert_cmpstr(err, ==, "");
@ -759,18 +736,14 @@ static void test_qga_config(gconstpointer data)
g_assert_true(g_strv_contains((const char * const *)strv,
"guest-get-time"));
g_assert_no_error(error);
g_strfreev(strv);
g_free(out);
g_free(err);
g_free(env[0]);
g_key_file_free(kf);
}
static void test_qga_fsfreeze_status(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
const gchar *status;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
@ -779,16 +752,15 @@ static void test_qga_fsfreeze_status(gconstpointer fix)
status = qdict_get_try_str(ret, "return");
g_assert_cmpstr(status, ==, "thawed");
qobject_unref(ret);
}
static void test_qga_guest_exec(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *val;
g_autoptr(QDict) ret = NULL;
QDict *val;
const gchar *out;
guchar *decoded;
g_autofree guchar *decoded = NULL;
int64_t pid, now, exitcode;
gsize len;
bool exited;
@ -827,14 +799,13 @@ static void test_qga_guest_exec(gconstpointer fix)
decoded = g_base64_decode(out, &len);
g_assert_cmpint(len, ==, 12);
g_assert_cmpstr((char *)decoded, ==, "\" test_str \"");
g_free(decoded);
qobject_unref(ret);
}
static void test_qga_guest_exec_invalid(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *error;
g_autoptr(QDict) ret = NULL;
QDict *error;
const gchar *class, *desc;
/* invalid command */
@ -859,13 +830,13 @@ static void test_qga_guest_exec_invalid(gconstpointer fix)
desc = qdict_get_str(error, "desc");
g_assert_cmpstr(class, ==, "GenericError");
g_assert_cmpint(strlen(desc), >, 0);
qobject_unref(ret);
}
static void test_qga_guest_get_host_name(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *val;
g_autoptr(QDict) ret = NULL;
QDict *val;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}");
g_assert_nonnull(ret);
@ -873,14 +844,13 @@ static void test_qga_guest_get_host_name(gconstpointer fix)
val = qdict_get_qdict(ret, "return");
g_assert(qdict_haskey(val, "host-name"));
qobject_unref(ret);
}
static void test_qga_guest_get_timezone(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret, *val;
g_autoptr(QDict) ret = NULL;
QDict *val;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}");
g_assert_nonnull(ret);
@ -889,14 +859,12 @@ static void test_qga_guest_get_timezone(gconstpointer fix)
/* Make sure there's at least offset */
val = qdict_get_qdict(ret, "return");
g_assert(qdict_haskey(val, "offset"));
qobject_unref(ret);
}
static void test_qga_guest_get_users(gconstpointer fix)
{
const TestFixture *fixture = fix;
QDict *ret;
g_autoptr(QDict) ret = NULL;
QList *val;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}");
@ -906,23 +874,20 @@ static void test_qga_guest_get_users(gconstpointer fix)
/* There is not much to test here */
val = qdict_get_qlist(ret, "return");
g_assert_nonnull(val);
qobject_unref(ret);
}
static void test_qga_guest_get_osinfo(gconstpointer data)
{
TestFixture fixture;
const gchar *str;
gchar *cwd, *env[2];
QDict *ret, *val;
g_autoptr(QDict) ret = NULL;
char *env[2];
QDict *val;
cwd = g_get_current_dir();
env[0] = g_strdup_printf(
"QGA_OS_RELEASE=%s%ctests%cdata%ctest-qga-os-release",
cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
"QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release",
g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
env[1] = NULL;
g_free(cwd);
fixture_setup(&fixture, NULL, env);
ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}");
@ -959,7 +924,6 @@ static void test_qga_guest_get_osinfo(gconstpointer data)
g_assert_nonnull(str);
g_assert_cmpstr(str, ==, "unit-test");
qobject_unref(ret);
g_free(env[0]);
fixture_tear_down(&fixture, NULL);
}

View File

@ -26,6 +26,15 @@
#include "qemu/host-utils.h"
#include <math.h>
#ifdef __FreeBSD__
#include <sys/sysctl.h>
#include <sys/user.h>
#endif
#ifdef __NetBSD__
#include <sys/sysctl.h>
#endif
#include "qemu/ctype.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
@ -931,6 +940,114 @@ static inline const char *next_component(const char *dir, int *p_len)
return dir;
}
static const char *exec_dir;
void qemu_init_exec_dir(const char *argv0)
{
#ifdef G_OS_WIN32
char *p;
char buf[MAX_PATH];
DWORD len;
if (exec_dir) {
return;
}
len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
if (len == 0) {
return;
}
buf[len] = 0;
p = buf + len - 1;
while (p != buf && *p != '\\') {
p--;
}
*p = 0;
if (access(buf, R_OK) == 0) {
exec_dir = g_strdup(buf);
} else {
exec_dir = CONFIG_BINDIR;
}
#else
char *p = NULL;
char buf[PATH_MAX];
if (exec_dir) {
return;
}
#if defined(__linux__)
{
int len;
len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (len > 0) {
buf[len] = 0;
p = buf;
}
}
#elif defined(__FreeBSD__) \
|| (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME))
{
#if defined(__FreeBSD__)
static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
#else
static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
#endif
size_t len = sizeof(buf) - 1;
*buf = '\0';
if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
*buf) {
buf[sizeof(buf) - 1] = '\0';
p = buf;
}
}
#elif defined(__APPLE__)
{
char fpath[PATH_MAX];
uint32_t len = sizeof(fpath);
if (_NSGetExecutablePath(fpath, &len) == 0) {
p = realpath(fpath, buf);
if (!p) {
return;
}
}
}
#elif defined(__HAIKU__)
{
image_info ii;
int32_t c = 0;
*buf = '\0';
while (get_next_image_info(0, &c, &ii) == B_OK) {
if (ii.type == B_APP_IMAGE) {
strncpy(buf, ii.name, sizeof(buf));
buf[sizeof(buf) - 1] = 0;
p = buf;
break;
}
}
}
#endif
/* If we don't have any way of figuring out the actual executable
location then try argv[0]. */
if (!p && argv0) {
p = realpath(argv0, buf);
}
if (p) {
exec_dir = g_path_get_dirname(p);
} else {
exec_dir = CONFIG_BINDIR;
}
#endif
}
const char *qemu_get_exec_dir(void)
{
return exec_dir;
}
char *get_relocated_path(const char *dir)
{
size_t prefix_len = strlen(CONFIG_PREFIX);

View File

@ -48,14 +48,13 @@
#endif
#ifdef __FreeBSD__
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/thr.h>
#include <sys/types.h>
#include <sys/user.h>
#include <libutil.h>
#endif
#ifdef __NetBSD__
#include <sys/sysctl.h>
#include <lwp.h>
#endif
@ -283,87 +282,6 @@ void qemu_set_tty_echo(int fd, bool echo)
tcsetattr(fd, TCSANOW, &tty);
}
static const char *exec_dir;
void qemu_init_exec_dir(const char *argv0)
{
char *p = NULL;
char buf[PATH_MAX];
if (exec_dir) {
return;
}
#if defined(__linux__)
{
int len;
len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (len > 0) {
buf[len] = 0;
p = buf;
}
}
#elif defined(__FreeBSD__) \
|| (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME))
{
#if defined(__FreeBSD__)
static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
#else
static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
#endif
size_t len = sizeof(buf) - 1;
*buf = '\0';
if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
*buf) {
buf[sizeof(buf) - 1] = '\0';
p = buf;
}
}
#elif defined(__APPLE__)
{
char fpath[PATH_MAX];
uint32_t len = sizeof(fpath);
if (_NSGetExecutablePath(fpath, &len) == 0) {
p = realpath(fpath, buf);
if (!p) {
return;
}
}
}
#elif defined(__HAIKU__)
{
image_info ii;
int32_t c = 0;
*buf = '\0';
while (get_next_image_info(0, &c, &ii) == B_OK) {
if (ii.type == B_APP_IMAGE) {
strncpy(buf, ii.name, sizeof(buf));
buf[sizeof(buf) - 1] = 0;
p = buf;
break;
}
}
}
#endif
/* If we don't have any way of figuring out the actual executable
location then try argv[0]. */
if (!p && argv0) {
p = realpath(argv0, buf);
}
if (p) {
exec_dir = g_path_get_dirname(p);
} else {
exec_dir = CONFIG_BINDIR;
}
}
const char *qemu_get_exec_dir(void)
{
return exec_dir;
}
#ifdef CONFIG_LINUX
static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx)
#else /* CONFIG_LINUX */

View File

@ -40,9 +40,6 @@
#include "qemu/error-report.h"
#include <malloc.h>
/* this must come after including "trace.h" */
#include <shlobj.h>
static int get_allocation_granularity(void)
{
SYSTEM_INFO system_info;
@ -237,17 +234,11 @@ int qemu_get_thread_id(void)
char *
qemu_get_local_state_dir(void)
{
HRESULT result;
char base_path[MAX_PATH+1] = "";
const char * const *data_dirs = g_get_system_data_dirs();
result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
/* SHGFP_TYPE_CURRENT */ 0, base_path);
if (result != S_OK) {
/* misconfigured environment */
g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result);
abort();
}
return g_strdup(base_path);
g_assert(data_dirs && data_dirs[0]);
return g_strdup(data_dirs[0]);
}
void qemu_set_tty_echo(int fd, bool echo)
@ -269,42 +260,6 @@ void qemu_set_tty_echo(int fd, bool echo)
}
}
static const char *exec_dir;
void qemu_init_exec_dir(const char *argv0)
{
char *p;
char buf[MAX_PATH];
DWORD len;
if (exec_dir) {
return;
}
len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
if (len == 0) {
return;
}
buf[len] = 0;
p = buf + len - 1;
while (p != buf && *p != '\\') {
p--;
}
*p = 0;
if (access(buf, R_OK) == 0) {
exec_dir = g_strdup(buf);
} else {
exec_dir = CONFIG_BINDIR;
}
}
const char *qemu_get_exec_dir(void)
{
return exec_dir;
}
int getpagesize(void)
{
SYSTEM_INFO system_info;