#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qstring.h"
#include "guest-agent-core.h"
#include "qga-qapi-init-commands.h"
#include "qapi/qmp/qerror.h"
#include "qapi/error.h"
#include "channel.h"
#include "qemu/bswap.h"
+#include "qemu/cutils.h"
#include "qemu/help_option.h"
#include "qemu/sockets.h"
#include "qemu/systemd.h"
" -p, --path device/socket path (the default for virtio-serial is:\n"
" %s,\n"
" the default for isa-serial is:\n"
-" %s)\n"
+" %s).\n"
+" Socket addresses for vsock-listen are written as\n"
+" <cid>:<port>.\n"
" -l, --logfile set logfile path, logs to stderr by default\n"
" -f, --pidfile specify pidfile (default is %s)\n"
#ifdef CONFIG_FSFREEZE
static const char *ga_log_level_str(GLogLevelFlags level)
{
switch (level & G_LOG_LEVEL_MASK) {
- case G_LOG_LEVEL_ERROR:
- return "error";
- case G_LOG_LEVEL_CRITICAL:
- return "critical";
- case G_LOG_LEVEL_WARNING:
- return "warning";
- case G_LOG_LEVEL_MESSAGE:
- return "message";
- case G_LOG_LEVEL_INFO:
- return "info";
- case G_LOG_LEVEL_DEBUG:
- return "debug";
- default:
- return "user";
+ case G_LOG_LEVEL_ERROR:
+ return "error";
+ case G_LOG_LEVEL_CRITICAL:
+ return "critical";
+ case G_LOG_LEVEL_WARNING:
+ return "warning";
+ case G_LOG_LEVEL_MESSAGE:
+ return "message";
+ case G_LOG_LEVEL_INFO:
+ return "info";
+ case G_LOG_LEVEL_DEBUG:
+ return "debug";
+ default:
+ return "user";
}
}
}
if (!whitelisted) {
g_debug("disabling command: %s", name);
- qmp_disable_command(&ga_commands, name);
+ qmp_disable_command(&ga_commands, name, "the agent is in frozen state");
}
}
static int send_response(GAState *s, const QDict *rsp)
{
- const char *buf;
- QString *payload_qstr, *response_qstr;
+ GString *response;
GIOStatus status;
- g_assert(rsp && s->channel);
+ g_assert(s->channel);
+
+ if (!rsp) {
+ return 0;
+ }
- payload_qstr = qobject_to_json(QOBJECT(rsp));
- if (!payload_qstr) {
+ response = qobject_to_json(QOBJECT(rsp));
+ if (!response) {
return -EINVAL;
}
if (s->delimit_response) {
s->delimit_response = false;
- response_qstr = qstring_new();
- qstring_append_chr(response_qstr, QGA_SENTINEL_BYTE);
- qstring_append(response_qstr, qstring_get_str(payload_qstr));
- qobject_unref(payload_qstr);
- } else {
- response_qstr = payload_qstr;
+ g_string_prepend_c(response, QGA_SENTINEL_BYTE);
}
- qstring_append_chr(response_qstr, '\n');
- buf = qstring_get_str(response_qstr);
- status = ga_channel_write_all(s->channel, buf, strlen(buf));
- qobject_unref(response_qstr);
+ g_string_append_c(response, '\n');
+ status = ga_channel_write_all(s->channel, response->str, response->len);
+ g_string_free(response, true);
if (status != G_IO_STATUS_NORMAL) {
return -EIO;
}
}
g_debug("processing command");
- rsp = qmp_dispatch(&ga_commands, obj, false);
+ rsp = qmp_dispatch(&ga_commands, obj, false, NULL);
end:
ret = send_response(s, rsp);
static gboolean channel_event_cb(GIOCondition condition, gpointer data)
{
GAState *s = data;
- gchar buf[QGA_READ_COUNT_DEFAULT+1];
+ gchar buf[QGA_READ_COUNT_DEFAULT + 1];
gsize count;
GIOStatus status = ga_channel_read(s->channel, buf, QGA_READ_COUNT_DEFAULT, &count);
switch (status) {
* host-side chardev. sleep a bit to mitigate this
*/
if (s->virtio) {
- usleep(100*1000);
+ usleep(100 * 1000);
}
return true;
default:
DWORD ret = NO_ERROR;
GAService *service = &ga_state->service;
- switch (ctrl)
- {
- case SERVICE_CONTROL_STOP:
- case SERVICE_CONTROL_SHUTDOWN:
- quit_handler(SIGTERM);
- SetEvent(ga_state->wakeup_event);
- service->status.dwCurrentState = SERVICE_STOP_PENDING;
- SetServiceStatus(service->status_handle, &service->status);
- break;
- case SERVICE_CONTROL_DEVICEEVENT:
- handle_serial_device_events(type, data);
- break;
+ switch (ctrl) {
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+ quit_handler(SIGTERM);
+ SetEvent(ga_state->wakeup_event);
+ service->status.dwCurrentState = SERVICE_STOP_PENDING;
+ SetServiceStatus(service->status_handle, &service->status);
+ break;
+ case SERVICE_CONTROL_DEVICEEVENT:
+ handle_serial_device_events(type, data);
+ break;
- default:
- ret = ERROR_CALL_NOT_IMPLEMENTED;
+ default:
+ ret = ERROR_CALL_NOT_IMPLEMENTED;
}
return ret;
}
{
GError *gerr = NULL;
GKeyFile *keyfile;
- const char *conf = g_getenv("QGA_CONF") ?: QGA_CONF_DEFAULT;
+ g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT);
/* read system config */
keyfile = g_key_file_new();
if (gerr &&
!(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT)) {
g_critical("error loading configuration from path: %s, %s",
- QGA_CONF_DEFAULT, gerr->message);
+ conf, gerr->message);
exit(EXIT_FAILURE);
}
g_clear_error(&gerr);
#ifdef CONFIG_FSFREEZE
case 'F':
g_free(config->fsfreeze_hook);
- config->fsfreeze_hook = g_strdup(optarg ?: QGA_FSFREEZE_HOOK_DEFAULT);
+ config->fsfreeze_hook = optarg ? g_strdup(optarg) : get_relocated_path(QGA_FSFREEZE_HOOK_DEFAULT);
break;
#endif
case 't':
s->blacklist = config->blacklist;
do {
g_debug("disabling command: %s", (char *)l->data);
- qmp_disable_command(&ga_commands, l->data);
+ qmp_disable_command(&ga_commands, l->data, NULL);
l = g_list_next(l);
} while (l);
}
config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
+ qemu_init_exec_dir(argv[0]);
qga_qmp_init_marshal(&ga_commands);
init_dfl_pathnames();