summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/fifo8.c47
-rw-r--r--util/iov.c106
-rw-r--r--util/module.c147
-rw-r--r--util/osdep.c1
-rw-r--r--util/oslib-posix.c54
-rw-r--r--util/oslib-win32.c30
-rw-r--r--util/qemu-config.c22
-rw-r--r--util/qemu-option.c71
8 files changed, 456 insertions, 22 deletions
diff --git a/util/fifo8.c b/util/fifo8.c
index 013e903c6e..6a43482c9e 100644
--- a/util/fifo8.c
+++ b/util/fifo8.c
@@ -37,6 +37,27 @@ void fifo8_push(Fifo8 *fifo, uint8_t data)
fifo->num++;
}
+void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num)
+{
+ uint32_t start, avail;
+
+ if (fifo->num + num > fifo->capacity) {
+ abort();
+ }
+
+ start = (fifo->head + fifo->num) % fifo->capacity;
+
+ if (start + num <= fifo->capacity) {
+ memcpy(&fifo->data[start], data, num);
+ } else {
+ avail = fifo->capacity - start;
+ memcpy(&fifo->data[start], data, avail);
+ memcpy(&fifo->data[0], &data[avail], num - avail);
+ }
+
+ fifo->num += num;
+}
+
uint8_t fifo8_pop(Fifo8 *fifo)
{
uint8_t ret;
@@ -50,9 +71,25 @@ uint8_t fifo8_pop(Fifo8 *fifo)
return ret;
}
+const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num)
+{
+ uint8_t *ret;
+
+ if (max == 0 || max > fifo->num) {
+ abort();
+ }
+ *num = MIN(fifo->capacity - fifo->head, max);
+ ret = &fifo->data[fifo->head];
+ fifo->head += *num;
+ fifo->head %= fifo->capacity;
+ fifo->num -= *num;
+ return ret;
+}
+
void fifo8_reset(Fifo8 *fifo)
{
fifo->num = 0;
+ fifo->head = 0;
}
bool fifo8_is_empty(Fifo8 *fifo)
@@ -65,6 +102,16 @@ bool fifo8_is_full(Fifo8 *fifo)
return (fifo->num == fifo->capacity);
}
+uint32_t fifo8_num_free(Fifo8 *fifo)
+{
+ return fifo->capacity - fifo->num;
+}
+
+uint32_t fifo8_num_used(Fifo8 *fifo)
+{
+ return fifo->num;
+}
+
const VMStateDescription vmstate_fifo8 = {
.name = "Fifo8",
.version_id = 1,
diff --git a/util/iov.c b/util/iov.c
index bb46c04e4d..03934da74d 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -378,6 +378,112 @@ size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes);
}
+/**
+ * Check that I/O vector contents are identical
+ *
+ * The IO vectors must have the same structure (same length of all parts).
+ * A typical usage is to compare vectors created with qemu_iovec_clone().
+ *
+ * @a: I/O vector
+ * @b: I/O vector
+ * @ret: Offset to first mismatching byte or -1 if match
+ */
+ssize_t qemu_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
+{
+ int i;
+ ssize_t offset = 0;
+
+ assert(a->niov == b->niov);
+ for (i = 0; i < a->niov; i++) {
+ size_t len = 0;
+ uint8_t *p = (uint8_t *)a->iov[i].iov_base;
+ uint8_t *q = (uint8_t *)b->iov[i].iov_base;
+
+ assert(a->iov[i].iov_len == b->iov[i].iov_len);
+ while (len < a->iov[i].iov_len && *p++ == *q++) {
+ len++;
+ }
+
+ offset += len;
+
+ if (len != a->iov[i].iov_len) {
+ return offset;
+ }
+ }
+ return -1;
+}
+
+typedef struct {
+ int src_index;
+ struct iovec *src_iov;
+ void *dest_base;
+} IOVectorSortElem;
+
+static int sortelem_cmp_src_base(const void *a, const void *b)
+{
+ const IOVectorSortElem *elem_a = a;
+ const IOVectorSortElem *elem_b = b;
+
+ /* Don't overflow */
+ if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
+ return -1;
+ } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int sortelem_cmp_src_index(const void *a, const void *b)
+{
+ const IOVectorSortElem *elem_a = a;
+ const IOVectorSortElem *elem_b = b;
+
+ return elem_a->src_index - elem_b->src_index;
+}
+
+/**
+ * Copy contents of I/O vector
+ *
+ * The relative relationships of overlapping iovecs are preserved. This is
+ * necessary to ensure identical semantics in the cloned I/O vector.
+ */
+void qemu_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, void *buf)
+{
+ IOVectorSortElem sortelems[src->niov];
+ void *last_end;
+ int i;
+
+ /* Sort by source iovecs by base address */
+ for (i = 0; i < src->niov; i++) {
+ sortelems[i].src_index = i;
+ sortelems[i].src_iov = &src->iov[i];
+ }
+ qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
+
+ /* Allocate buffer space taking into account overlapping iovecs */
+ last_end = NULL;
+ for (i = 0; i < src->niov; i++) {
+ struct iovec *cur = sortelems[i].src_iov;
+ ptrdiff_t rewind = 0;
+
+ /* Detect overlap */
+ if (last_end && last_end > cur->iov_base) {
+ rewind = last_end - cur->iov_base;
+ }
+
+ sortelems[i].dest_base = buf - rewind;
+ buf += cur->iov_len - MIN(rewind, cur->iov_len);
+ last_end = MAX(cur->iov_base + cur->iov_len, last_end);
+ }
+
+ /* Sort by source iovec index and build destination iovec */
+ qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
+ for (i = 0; i < src->niov; i++) {
+ qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
+ }
+}
+
size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt,
size_t bytes)
{
diff --git a/util/module.c b/util/module.c
index 7acc33d076..dc08c16111 100644
--- a/util/module.c
+++ b/util/module.c
@@ -13,6 +13,10 @@
* GNU GPL, version 2 or (at your option) any later version.
*/
+#include <stdlib.h>
+#ifdef CONFIG_MODULES
+#include <gmodule.h>
+#endif
#include "qemu-common.h"
#include "qemu/queue.h"
#include "qemu/module.h"
@@ -21,13 +25,16 @@ typedef struct ModuleEntry
{
void (*init)(void);
QTAILQ_ENTRY(ModuleEntry) node;
+ module_init_type type;
} ModuleEntry;
typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
static ModuleTypeList init_type_list[MODULE_INIT_MAX];
-static void init_types(void)
+static ModuleTypeList dso_init_list;
+
+static void init_lists(void)
{
static int inited;
int i;
@@ -40,6 +47,8 @@ static void init_types(void)
QTAILQ_INIT(&init_type_list[i]);
}
+ QTAILQ_INIT(&dso_init_list);
+
inited = 1;
}
@@ -48,7 +57,7 @@ static ModuleTypeList *find_type(module_init_type type)
{
ModuleTypeList *l;
- init_types();
+ init_lists();
l = &init_type_list[type];
@@ -62,20 +71,154 @@ void register_module_init(void (*fn)(void), module_init_type type)
e = g_malloc0(sizeof(*e));
e->init = fn;
+ e->type = type;
l = find_type(type);
QTAILQ_INSERT_TAIL(l, e, node);
}
+void register_dso_module_init(void (*fn)(void), module_init_type type)
+{
+ ModuleEntry *e;
+
+ init_lists();
+
+ e = g_malloc0(sizeof(*e));
+ e->init = fn;
+ e->type = type;
+
+ QTAILQ_INSERT_TAIL(&dso_init_list, e, node);
+}
+
+static void module_load(module_init_type type);
+
void module_call_init(module_init_type type)
{
ModuleTypeList *l;
ModuleEntry *e;
+ module_load(type);
l = find_type(type);
QTAILQ_FOREACH(e, l, node) {
e->init();
}
}
+
+#ifdef CONFIG_MODULES
+static int module_load_file(const char *fname)
+{
+ GModule *g_module;
+ void (*sym)(void);
+ const char *dsosuf = HOST_DSOSUF;
+ int len = strlen(fname);
+ int suf_len = strlen(dsosuf);
+ ModuleEntry *e, *next;
+ int ret;
+
+ if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) {
+ /* wrong suffix */
+ ret = -EINVAL;
+ goto out;
+ }
+ if (access(fname, F_OK)) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ assert(QTAILQ_EMPTY(&dso_init_list));
+
+ g_module = g_module_open(fname, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+ if (!g_module) {
+ fprintf(stderr, "Failed to open module: %s\n",
+ g_module_error());
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
+ fprintf(stderr, "Failed to initialize module: %s\n",
+ fname);
+ /* Print some info if this is a QEMU module (but from different build),
+ * this will make debugging user problems easier. */
+ if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
+ fprintf(stderr,
+ "Note: only modules from the same build can be loaded.\n");
+ }
+ g_module_close(g_module);
+ ret = -EINVAL;
+ } else {
+ QTAILQ_FOREACH(e, &dso_init_list, node) {
+ register_module_init(e->init, e->type);
+ }
+ ret = 0;
+ }
+
+ QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
+ QTAILQ_REMOVE(&dso_init_list, e, node);
+ g_free(e);
+ }
+out:
+ return ret;
+}
+#endif
+
+void module_load(module_init_type type)
+{
+#ifdef CONFIG_MODULES
+ char *fname = NULL;
+ const char **mp;
+ static const char *block_modules[] = {
+ CONFIG_BLOCK_MODULES
+ };
+ char *exec_dir;
+ char *dirs[3];
+ int i = 0;
+ int ret;
+
+ if (!g_module_supported()) {
+ fprintf(stderr, "Module is not supported by system.\n");
+ return;
+ }
+
+ switch (type) {
+ case MODULE_INIT_BLOCK:
+ mp = block_modules;
+ break;
+ default:
+ /* no other types have dynamic modules for now*/
+ return;
+ }
+
+ exec_dir = qemu_get_exec_dir();
+ dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
+ dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : "");
+ dirs[i++] = g_strdup_printf("%s", exec_dir ? : "");
+ assert(i == ARRAY_SIZE(dirs));
+ g_free(exec_dir);
+ exec_dir = NULL;
+
+ for ( ; *mp; mp++) {
+ for (i = 0; i < ARRAY_SIZE(dirs); i++) {
+ fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF);
+ ret = module_load_file(fname);
+ /* Try loading until loaded a module file */
+ if (!ret) {
+ break;
+ }
+ g_free(fname);
+ fname = NULL;
+ }
+ if (ret == -ENOENT) {
+ fprintf(stderr, "Can't find module: %s\n", *mp);
+ }
+
+ g_free(fname);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dirs); i++) {
+ g_free(dirs[i]);
+ }
+
+#endif
+}
diff --git a/util/osdep.c b/util/osdep.c
index 62072b4be3..bd4f530ad1 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -46,7 +46,6 @@ extern int madvise(caddr_t, size_t, int);
#endif
#include "qemu-common.h"
-#include "trace.h"
#include "qemu/sockets.h"
#include "monitor/monitor.h"
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index d5dca4729a..c2eeb4fe40 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -57,6 +57,7 @@ extern int daemon(int, int);
#include "trace.h"
#include "qemu/sockets.h"
#include <sys/mman.h>
+#include <libgen.h>
#ifdef CONFIG_LINUX
#include <sys/syscall.h>
@@ -274,3 +275,56 @@ void qemu_set_tty_echo(int fd, bool echo)
tcsetattr(fd, TCSANOW, &tty);
}
+
+static char exec_dir[PATH_MAX];
+
+void qemu_init_exec_dir(const char *argv0)
+{
+ char *dir;
+ char *p = NULL;
+ char buf[PATH_MAX];
+
+ assert(!exec_dir[0]);
+
+#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__)
+ {
+ static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ 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;
+ }
+ }
+#endif
+ /* If we don't have any way of figuring out the actual executable
+ location then try argv[0]. */
+ if (!p) {
+ if (!argv0) {
+ return;
+ }
+ p = realpath(argv0, buf);
+ if (!p) {
+ return;
+ }
+ }
+ dir = dirname(p);
+
+ pstrcpy(exec_dir, sizeof(exec_dir), dir);
+}
+
+char *qemu_get_exec_dir(void)
+{
+ return g_strdup(exec_dir);
+}
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 50be0440f2..93f7d351d3 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -208,3 +208,33 @@ void qemu_set_tty_echo(int fd, bool echo)
dwMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
}
}
+
+static char exec_dir[PATH_MAX];
+
+void qemu_init_exec_dir(const char *argv0)
+{
+
+ char *p;
+ char buf[MAX_PATH];
+ DWORD len;
+
+ 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) {
+ pstrcpy(exec_dir, sizeof(exec_dir), buf);
+ }
+}
+
+char *qemu_get_exec_dir(void)
+{
+ return g_strdup(exec_dir);
+}
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 9298f55ecf..f6101012c0 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -31,7 +31,7 @@ QemuOptsList *qemu_find_opts(const char *group)
Error *local_err = NULL;
ret = find_list(vm_config_groups, group, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_report("%s", error_get_pretty(local_err));
error_free(local_err);
}
@@ -295,7 +295,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
/* group with id */
list = find_list(lists, group, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_report("%s", error_get_pretty(local_err));
error_free(local_err);
goto out;
@@ -306,7 +306,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
if (sscanf(line, "[%63[^]]]", group) == 1) {
/* group without id */
list = find_list(lists, group, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_report("%s", error_get_pretty(local_err));
error_free(local_err);
goto out;
@@ -376,13 +376,13 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
}
subopts = qemu_opts_create(opts, NULL, 0, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
goto out;
}
qemu_opts_absorb_qdict(subopts, subqdict, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
goto out;
}
@@ -413,16 +413,22 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry));
char *opt_name;
+ if (!section) {
+ error_setg(errp, "[%s] section (index %u) does not consist of "
+ "keys", opts->name, i);
+ goto out;
+ }
+
opt_name = g_strdup_printf("%s.%u", opts->name, i++);
subopts = qemu_opts_create(opts, opt_name, 1, &local_err);
g_free(opt_name);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
goto out;
}
qemu_opts_absorb_qdict(subopts, section, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
qemu_opts_del(subopts);
goto out;
@@ -450,7 +456,7 @@ void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
for (i = 0; lists[i]; i++) {
config_parse_qdict_section(options, lists[i], &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
return;
}
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 668e5d919f..9d898af443 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -246,7 +246,7 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name,
switch (list->type) {
case OPT_FLAG:
parse_option_bool(name, value, &flag, &local_err);
- if (!error_is_set(&local_err)) {
+ if (!local_err) {
list->value.n = flag;
}
break;
@@ -269,7 +269,7 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name,
return -1;
}
- if (error_is_set(&local_err)) {
+ if (local_err) {
qerror_report_err(local_err);
error_free(local_err);
return -1;
@@ -450,6 +450,55 @@ fail:
return NULL;
}
+bool has_help_option(const char *param)
+{
+ size_t buflen = strlen(param) + 1;
+ char *buf = g_malloc0(buflen);
+ const char *p = param;
+ bool result = false;
+
+ while (*p) {
+ p = get_opt_value(buf, buflen, p);
+ if (*p) {
+ p++;
+ }
+
+ if (is_help_option(buf)) {
+ result = true;
+ goto out;
+ }
+ }
+
+out:
+ free(buf);
+ return result;
+}
+
+bool is_valid_option_list(const char *param)
+{
+ size_t buflen = strlen(param) + 1;
+ char *buf = g_malloc0(buflen);
+ const char *p = param;
+ bool result = true;
+
+ while (*p) {
+ p = get_opt_value(buf, buflen, p);
+ if (*p && !*++p) {
+ result = false;
+ goto out;
+ }
+
+ if (!*buf || *buf == ',') {
+ result = false;
+ goto out;
+ }
+ }
+
+out:
+ free(buf);
+ return result;
+}
+
/*
* Prints all options of a list that have a value to stdout
*/
@@ -640,7 +689,7 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value,
opt->desc = desc;
opt->str = g_strdup(value);
qemu_opt_parse(opt, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
qemu_opt_del(opt);
}
@@ -651,7 +700,7 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
Error *local_err = NULL;
opt_set(opts, name, value, false, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
qerror_report_err(local_err);
error_free(local_err);
return -1;
@@ -812,7 +861,7 @@ int qemu_opts_set(QemuOptsList *list, const char *id,
Error *local_err = NULL;
opts = qemu_opts_create(list, id, 1, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
qerror_report_err(local_err);
error_free(local_err);
return -1;
@@ -897,7 +946,7 @@ static int opts_do_parse(QemuOpts *opts, const char *params,
if (strcmp(option, "id") != 0) {
/* store and parse */
opt_set(opts, option, value, prepend, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
qerror_report_err(local_err);
error_free(local_err);
return -1;
@@ -945,7 +994,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
assert(!defaults || list->merge_lists);
opts = qemu_opts_create(list, id, !defaults, &local_err);
if (opts == NULL) {
- if (error_is_set(&local_err)) {
+ if (local_err) {
qerror_report_err(local_err);
error_free(local_err);
}
@@ -1034,7 +1083,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1,
&local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
return NULL;
}
@@ -1044,7 +1093,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
state.errp = &local_err;
state.opts = opts;
qdict_iter(qdict, qemu_opts_from_qdict_1, &state);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
qemu_opts_del(opts);
return NULL;
@@ -1075,7 +1124,7 @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
if (find_desc_by_name(opts->list->desc, entry->key)) {
qemu_opts_from_qdict_1(entry->key, entry->value, &state);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
return;
} else {
@@ -1129,7 +1178,7 @@ void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
}
qemu_opt_parse(opt, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
return;
}