diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/fifo8.c | 47 | ||||
-rw-r--r-- | util/iov.c | 106 | ||||
-rw-r--r-- | util/module.c | 147 | ||||
-rw-r--r-- | util/osdep.c | 1 | ||||
-rw-r--r-- | util/oslib-posix.c | 54 | ||||
-rw-r--r-- | util/oslib-win32.c | 30 | ||||
-rw-r--r-- | util/qemu-config.c | 22 | ||||
-rw-r--r-- | util/qemu-option.c | 71 |
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; } |