diff options
author | Yonghee Han <onstudy@samsung.com> | 2016-07-27 16:39:12 +0900 |
---|---|---|
committer | Yonghee Han <onstudy@samsung.com> | 2016-07-27 16:47:03 +0900 |
commit | a3b133b0ea0696e42fd876b9a803e28bc6ef5299 (patch) | |
tree | 68d7537fb9ede28b2e4d2b9f44eb70988279b8ba /util | |
parent | 0d6a2f7e595218b5632ba7005128470e65138951 (diff) | |
download | qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.tar.gz qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.tar.bz2 qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.zip |
Imported Upstream version 2.3.1upstream/2.3.1
Change-Id: I2161522ea1d7ff10cd1d697609d473243c05e1df
Diffstat (limited to 'util')
-rw-r--r-- | util/Makefile.objs | 1 | ||||
-rw-r--r-- | util/aes.c | 2 | ||||
-rw-r--r-- | util/cutils.c | 19 | ||||
-rw-r--r-- | util/envlist.c | 32 | ||||
-rw-r--r-- | util/error.c | 14 | ||||
-rw-r--r-- | util/hbitmap.c | 4 | ||||
-rw-r--r-- | util/iov.c | 4 | ||||
-rw-r--r-- | util/oslib-posix.c | 4 | ||||
-rw-r--r-- | util/qemu-config.c | 99 | ||||
-rw-r--r-- | util/qemu-option.c | 118 | ||||
-rw-r--r-- | util/qemu-sockets.c | 68 | ||||
-rw-r--r-- | util/qemu-thread-posix.c | 45 | ||||
-rw-r--r-- | util/qemu-thread-win32.c | 48 | ||||
-rw-r--r-- | util/rcu.c | 328 | ||||
-rw-r--r-- | util/uri.c | 179 |
15 files changed, 714 insertions, 251 deletions
diff --git a/util/Makefile.objs b/util/Makefile.objs index 93007e2f5..ceaba3093 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -17,3 +17,4 @@ util-obj-y += throttle.o util-obj-y += getauxval.o util-obj-y += readline.o util-obj-y += rfifolock.o +util-obj-y += rcu.o diff --git a/util/aes.c b/util/aes.c index 6058f1950..3d7c4be9b 100644 --- a/util/aes.c +++ b/util/aes.c @@ -1161,7 +1161,7 @@ int AES_set_encrypt_key(const unsigned char *userKey, const int bits, rk += 8; } } - return 0; + abort(); } /** diff --git a/util/cutils.c b/util/cutils.c index dbe7412bd..144b25c05 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -483,6 +483,20 @@ int64_t pow2floor(int64_t value) return value; } +/* round up to the nearest power of 2 (0 if overflow) */ +uint64_t pow2ceil(uint64_t value) +{ + uint8_t nlz = clz64(value); + + if (is_power_of_2(value)) { + return value; + } + if (!nlz) { + return 0; + } + return 1ULL << (64 - nlz); +} + /* * Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128) * Input is limited to 14-bit numbers @@ -523,16 +537,17 @@ int parse_debug_env(const char *name, int max, int initial) { char *debug_env = getenv(name); char *inv = NULL; - int debug; + long debug; if (!debug_env) { return initial; } + errno = 0; debug = strtol(debug_env, &inv, 10); if (inv == debug_env) { return initial; } - if (debug < 0 || debug > max) { + if (debug < 0 || debug > max || errno != 0) { fprintf(stderr, "warning: %s not in [0, %d]", name, max); return initial; } diff --git a/util/envlist.c b/util/envlist.c index ebc06cf0f..099a544a4 100644 --- a/util/envlist.c +++ b/util/envlist.c @@ -94,30 +94,30 @@ envlist_parse(envlist_t *envlist, const char *env, { char *tmpenv, *envvar; char *envsave = NULL; - - assert(callback != NULL); + int ret = 0; + assert(callback != NULL); if ((envlist == NULL) || (env == NULL)) return (EINVAL); - /* - * We need to make temporary copy of the env string - * as strtok_r(3) modifies it while it tokenizes. - */ if ((tmpenv = strdup(env)) == NULL) return (errno); - - envvar = strtok_r(tmpenv, ",", &envsave); - while (envvar != NULL) { - if ((*callback)(envlist, envvar) != 0) { - free(tmpenv); - return (errno); + envsave = tmpenv; + + do { + envvar = strchr(tmpenv, ','); + if (envvar != NULL) { + *envvar = '\0'; + } + if ((*callback)(envlist, tmpenv) != 0) { + ret = errno; + break; } - envvar = strtok_r(NULL, ",", &envsave); - } + tmpenv = envvar + 1; + } while (envvar != NULL); - free(tmpenv); - return (0); + free(envsave); + return ret; } /* diff --git a/util/error.c b/util/error.c index 2ace0d8dd..14f435187 100644 --- a/util/error.c +++ b/util/error.c @@ -41,7 +41,7 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) err->err_class = err_class; if (errp == &error_abort) { - error_report("%s", error_get_pretty(err)); + error_report_err(err); abort(); } @@ -77,7 +77,7 @@ void error_set_errno(Error **errp, int os_errno, ErrorClass err_class, err->err_class = err_class; if (errp == &error_abort) { - error_report("%s", error_get_pretty(err)); + error_report_err(err); abort(); } @@ -122,7 +122,7 @@ void error_set_win32(Error **errp, int win32_err, ErrorClass err_class, err->err_class = err_class; if (errp == &error_abort) { - error_report("%s", error_get_pretty(err)); + error_report_err(err); abort(); } @@ -152,6 +152,12 @@ const char *error_get_pretty(Error *err) return err->msg; } +void error_report_err(Error *err) +{ + error_report("%s", error_get_pretty(err)); + error_free(err); +} + void error_free(Error *err) { if (err) { @@ -163,7 +169,7 @@ void error_free(Error *err) void error_propagate(Error **dst_errp, Error *local_err) { if (local_err && dst_errp == &error_abort) { - error_report("%s", error_get_pretty(local_err)); + error_report_err(local_err); abort(); } else if (dst_errp && !*dst_errp) { *dst_errp = local_err; diff --git a/util/hbitmap.c b/util/hbitmap.c index b3060e697..ab139717f 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -373,7 +373,7 @@ void hbitmap_free(HBitmap *hb) HBitmap *hbitmap_alloc(uint64_t size, int granularity) { - HBitmap *hb = g_malloc0(sizeof (struct HBitmap)); + HBitmap *hb = g_new0(struct HBitmap, 1); unsigned i; assert(granularity >= 0 && granularity < 64); @@ -384,7 +384,7 @@ HBitmap *hbitmap_alloc(uint64_t size, int granularity) hb->granularity = granularity; for (i = HBITMAP_LEVELS; i-- > 0; ) { size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1); - hb->levels[i] = g_malloc0(size * sizeof(unsigned long)); + hb->levels[i] = g_new0(unsigned long, size); } /* We necessarily have free bits in level 0 due to the definition diff --git a/util/iov.c b/util/iov.c index 24566c878..2fb18e665 100644 --- a/util/iov.c +++ b/util/iov.c @@ -253,7 +253,7 @@ unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt, void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint) { - qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec)); + qiov->iov = g_new(struct iovec, alloc_hint); qiov->niov = 0; qiov->nalloc = alloc_hint; qiov->size = 0; @@ -277,7 +277,7 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len) if (qiov->niov == qiov->nalloc) { qiov->nalloc = 2 * qiov->nalloc + 1; - qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec)); + qiov->iov = g_renew(struct iovec, qiov->iov, qiov->nalloc); } qiov->iov[qiov->niov].iov_base = base; qiov->iov[qiov->niov].iov_len = len; diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 16fcec2f3..37ffd9624 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -399,10 +399,10 @@ void os_mem_prealloc(int fd, char *area, size_t memory) } else { int i; size_t hpagesize = fd_getpagesize(fd); + size_t numpages = DIV_ROUND_UP(memory, hpagesize); /* MAP_POPULATE silently ignores failures */ - memory = (memory + hpagesize - 1) & -hpagesize; - for (i = 0; i < (memory / hpagesize); i++) { + for (i = 0; i < numpages; i++) { memset(area + (hpagesize * i), 0, 1); } diff --git a/util/qemu-config.c b/util/qemu-config.c index ba375c014..2d32ce7e9 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -6,6 +6,7 @@ #include "hw/qdev.h" #include "qapi/error.h" #include "qmp-commands.h" +#include "hw/i386/pc.h" static QemuOptsList *vm_config_groups[32]; static QemuOptsList *drive_config_groups[4]; @@ -32,8 +33,7 @@ QemuOptsList *qemu_find_opts(const char *group) ret = find_list(vm_config_groups, group, &local_err); if (local_err) { - error_report("%s", error_get_pretty(local_err)); - error_free(local_err); + error_report_err(local_err); } return ret; @@ -149,6 +149,84 @@ static CommandLineParameterInfoList *get_drive_infolist(void) return head; } +/* restore machine options that are now machine's properties */ +static QemuOptsList machine_opts = { + .merge_lists = true, + .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head), + .desc = { + { + .name = "type", + .type = QEMU_OPT_STRING, + .help = "emulated machine" + },{ + .name = "accel", + .type = QEMU_OPT_STRING, + .help = "accelerator list", + },{ + .name = "kernel_irqchip", + .type = QEMU_OPT_BOOL, + .help = "use KVM in-kernel irqchip", + },{ + .name = "kvm_shadow_mem", + .type = QEMU_OPT_SIZE, + .help = "KVM shadow MMU size", + },{ + .name = "kernel", + .type = QEMU_OPT_STRING, + .help = "Linux kernel image file", + },{ + .name = "initrd", + .type = QEMU_OPT_STRING, + .help = "Linux initial ramdisk file", + },{ + .name = "append", + .type = QEMU_OPT_STRING, + .help = "Linux kernel command line", + },{ + .name = "dtb", + .type = QEMU_OPT_STRING, + .help = "Linux kernel device tree file", + },{ + .name = "dumpdtb", + .type = QEMU_OPT_STRING, + .help = "Dump current dtb to a file and quit", + },{ + .name = "phandle_start", + .type = QEMU_OPT_NUMBER, + .help = "The first phandle ID we may generate dynamically", + },{ + .name = "dt_compatible", + .type = QEMU_OPT_STRING, + .help = "Overrides the \"compatible\" property of the dt root node", + },{ + .name = "dump-guest-core", + .type = QEMU_OPT_BOOL, + .help = "Include guest memory in a core dump", + },{ + .name = "mem-merge", + .type = QEMU_OPT_BOOL, + .help = "enable/disable memory merge support", + },{ + .name = "usb", + .type = QEMU_OPT_BOOL, + .help = "Set on/off to enable/disable usb", + },{ + .name = "firmware", + .type = QEMU_OPT_STRING, + .help = "firmware image", + },{ + .name = "iommu", + .type = QEMU_OPT_BOOL, + .help = "Set on/off to enable/disable Intel IOMMU (VT-d)", + },{ + .name = "suppress-vmdesc", + .type = QEMU_OPT_BOOL, + .help = "Set on to disable self-describing migration", + }, + { /* End of list */ } + } +}; + CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, const char *option, Error **errp) @@ -163,6 +241,8 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, info->option = g_strdup(vm_config_groups[i]->name); if (!strcmp("drive", vm_config_groups[i]->name)) { info->parameters = get_drive_infolist(); + } else if (!strcmp("machine", vm_config_groups[i]->name)) { + info->parameters = query_option_descs(machine_opts.desc); } else { info->parameters = query_option_descs(vm_config_groups[i]->desc); @@ -220,6 +300,7 @@ void qemu_add_opts(QemuOptsList *list) int qemu_set_option(const char *str) { + Error *local_err = NULL; char group[64], id[64], arg[64]; QemuOptsList *list; QemuOpts *opts; @@ -243,7 +324,9 @@ int qemu_set_option(const char *str) return -1; } - if (qemu_opt_set(opts, arg, str+offset+1) == -1) { + qemu_opt_set(opts, arg, str + offset + 1, &local_err); + if (local_err) { + error_report_err(local_err); return -1; } return 0; @@ -314,8 +397,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) /* group with id */ list = find_list(lists, group, &local_err); if (local_err) { - error_report("%s", error_get_pretty(local_err)); - error_free(local_err); + error_report_err(local_err); goto out; } opts = qemu_opts_create(list, id, 1, NULL); @@ -325,8 +407,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) /* group without id */ list = find_list(lists, group, &local_err); if (local_err) { - error_report("%s", error_get_pretty(local_err)); - error_free(local_err); + error_report_err(local_err); goto out; } opts = qemu_opts_create(list, NULL, 0, &error_abort); @@ -338,7 +419,9 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) error_report("no group defined"); goto out; } - if (qemu_opt_set(opts, arg, value) != 0) { + qemu_opt_set(opts, arg, value, &local_err); + if (local_err) { + error_report_err(local_err); goto out; } continue; diff --git a/util/qemu-option.c b/util/qemu-option.c index 5d106959c..fda4e5fcb 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -213,7 +213,7 @@ void parse_option_size(const char *name, const char *value, bool has_help_option(const char *param) { size_t buflen = strlen(param) + 1; - char *buf = g_malloc0(buflen); + char *buf = g_malloc(buflen); const char *p = param; bool result = false; @@ -230,14 +230,14 @@ bool has_help_option(const char *param) } out: - free(buf); + g_free(buf); return result; } bool is_valid_option_list(const char *param) { size_t buflen = strlen(param) + 1; - char *buf = g_malloc0(buflen); + char *buf = g_malloc(buflen); const char *p = param; bool result = true; @@ -255,7 +255,7 @@ bool is_valid_option_list(const char *param) } out: - free(buf); + g_free(buf); return result; } @@ -548,27 +548,14 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value, } } -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 (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; - } - - return 0; -} - -void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, - Error **errp) +void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, + Error **errp) { opt_set(opts, name, value, false, errp); } -int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val) +void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, + Error **errp) { QemuOpt *opt; const QemuOptDesc *desc = opts->list->desc; @@ -576,9 +563,9 @@ int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val) opt = g_malloc0(sizeof(*opt)); opt->desc = find_desc_by_name(desc, name); if (!opt->desc && !opts_accepts_any(opts)) { - qerror_report(QERR_INVALID_PARAMETER, name); + error_set(errp, QERR_INVALID_PARAMETER, name); g_free(opt); - return -1; + return; } opt->name = g_strdup(name); @@ -586,11 +573,10 @@ int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val) opt->value.boolean = !!val; opt->str = g_strdup(val ? "on" : "off"); QTAILQ_INSERT_TAIL(&opts->head, opt, next); - - return 0; } -int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val) +void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, + Error **errp) { QemuOpt *opt; const QemuOptDesc *desc = opts->list->desc; @@ -598,9 +584,9 @@ int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val) opt = g_malloc0(sizeof(*opt)); opt->desc = find_desc_by_name(desc, name); if (!opt->desc && !opts_accepts_any(opts)) { - qerror_report(QERR_INVALID_PARAMETER, name); + error_set(errp, QERR_INVALID_PARAMETER, name); g_free(opt); - return -1; + return; } opt->name = g_strdup(name); @@ -608,8 +594,6 @@ int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val) opt->value.uint = val; opt->str = g_strdup_printf("%" PRId64, val); QTAILQ_INSERT_TAIL(&opts->head, opt, next); - - return 0; } int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, @@ -692,19 +676,18 @@ void qemu_opts_loc_restore(QemuOpts *opts) loc_restore(&opts->loc); } -int qemu_opts_set(QemuOptsList *list, const char *id, - const char *name, const char *value) +void qemu_opts_set(QemuOptsList *list, const char *id, + const char *name, const char *value, Error **errp) { QemuOpts *opts; Error *local_err = NULL; opts = qemu_opts_create(list, id, 1, &local_err); if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; + error_propagate(errp, local_err); + return; } - return qemu_opt_set(opts, name, value); + qemu_opt_set(opts, name, value, errp); } const char *qemu_opts_id(QemuOpts *opts) @@ -737,14 +720,14 @@ void qemu_opts_del(QemuOpts *opts) g_free(opts); } -void qemu_opts_print(QemuOpts *opts) +void qemu_opts_print(QemuOpts *opts, const char *sep) { QemuOpt *opt; QemuOptDesc *desc = opts->list->desc; if (desc[0].name == NULL) { QTAILQ_FOREACH(opt, &opts->head, next) { - printf("%s=\"%s\" ", opt->name, opt->str); + printf("%s%s=\"%s\"", sep, opt->name, opt->str); } return; } @@ -757,18 +740,18 @@ void qemu_opts_print(QemuOpts *opts) continue; } if (desc->type == QEMU_OPT_STRING) { - printf("%s='%s' ", desc->name, value); + printf("%s%s='%s'", sep, desc->name, value); } else if ((desc->type == QEMU_OPT_SIZE || desc->type == QEMU_OPT_NUMBER) && opt) { - printf("%s=%" PRId64 " ", desc->name, opt->value.uint); + printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint); } else { - printf("%s=%s ", desc->name, value); + printf("%s%s=%s", sep, desc->name, value); } } } -static int opts_do_parse(QemuOpts *opts, const char *params, - const char *firstname, bool prepend) +static void opts_do_parse(QemuOpts *opts, const char *params, + const char *firstname, bool prepend, Error **errp) { char option[128], value[1024]; const char *p,*pe,*pc; @@ -806,25 +789,30 @@ static int opts_do_parse(QemuOpts *opts, const char *params, /* store and parse */ opt_set(opts, option, value, prepend, &local_err); if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; + error_propagate(errp, local_err); + return; } } if (*p != ',') { break; } } - return 0; } -int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname) +/** + * Store options parsed from @params into @opts. + * If @firstname is non-null, the first key=value in @params may omit + * key=, and is treated as if key was @firstname. + * On error, store an error object through @errp if non-null. + */ +void qemu_opts_do_parse(QemuOpts *opts, const char *params, + const char *firstname, Error **errp) { - return opts_do_parse(opts, params, firstname, false); + opts_do_parse(opts, params, firstname, false, errp); } static QemuOpts *opts_parse(QemuOptsList *list, const char *params, - int permit_abbrev, bool defaults) + int permit_abbrev, bool defaults, Error **errp) { const char *firstname; char value[1024], *id = NULL; @@ -853,14 +841,13 @@ 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 (local_err) { - qerror_report_err(local_err); - error_free(local_err); - } + error_propagate(errp, local_err); return NULL; } - if (opts_do_parse(opts, params, firstname, defaults) != 0) { + opts_do_parse(opts, params, firstname, defaults, &local_err); + if (local_err) { + error_propagate(errp, local_err); qemu_opts_del(opts); return NULL; } @@ -868,10 +855,25 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, return opts; } +/** + * Create a QemuOpts in @list and with options parsed from @params. + * If @permit_abbrev, the first key=value in @params may omit key=, + * and is treated as if key was @list->implied_opt_name. + * Report errors with qerror_report_err(). + * Return the new QemuOpts on success, null pointer on error. + */ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev) { - return opts_parse(list, params, permit_abbrev, false); + Error *err = NULL; + QemuOpts *opts; + + opts = opts_parse(list, params, permit_abbrev, false, &err); + if (!opts) { + qerror_report_err(err); + error_free(err); + } + return opts; } void qemu_opts_set_defaults(QemuOptsList *list, const char *params, @@ -879,7 +881,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, { QemuOpts *opts; - opts = opts_parse(list, params, permit_abbrev, true); + opts = opts_parse(list, params, permit_abbrev, true, NULL); assert(opts); } @@ -924,7 +926,7 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) return; } - qemu_opt_set_err(state->opts, key, value, state->errp); + qemu_opt_set(state->opts, key, value, state->errp); } /* diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index a76bb3c91..87c9bc6c6 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -199,11 +199,13 @@ listen: freeaddrinfo(res); return -1; } - snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset); - qemu_opt_set(opts, "host", uaddr); - qemu_opt_set(opts, "port", uport); - qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off"); - qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off"); + qemu_opt_set(opts, "host", uaddr, &error_abort); + qemu_opt_set_number(opts, "port", inet_getport(e) - port_offset, + &error_abort); + qemu_opt_set_bool(opts, "ipv6", e->ai_family == PF_INET6, + &error_abort); + qemu_opt_set_bool(opts, "ipv4", e->ai_family != PF_INET6, + &error_abort); freeaddrinfo(res); return slisten; } @@ -512,7 +514,7 @@ InetSocketAddress *inet_parse(const char *str, Error **errp) { InetSocketAddress *addr; const char *optstr, *h; - char host[64]; + char host[65]; char port[33]; int to; int pos; @@ -580,16 +582,14 @@ static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr) bool ipv6 = addr->ipv6 || !addr->has_ipv6; if (!ipv4 || !ipv6) { - qemu_opt_set_bool(opts, "ipv4", ipv4); - qemu_opt_set_bool(opts, "ipv6", ipv6); + qemu_opt_set_bool(opts, "ipv4", ipv4, &error_abort); + qemu_opt_set_bool(opts, "ipv6", ipv6, &error_abort); } if (addr->has_to) { - char to[20]; - snprintf(to, sizeof(to), "%d", addr->to); - qemu_opt_set(opts, "to", to); + qemu_opt_set_number(opts, "to", addr->to, &error_abort); } - qemu_opt_set(opts, "host", addr->host); - qemu_opt_set(opts, "port", addr->port); + qemu_opt_set(opts, "host", addr->host, &error_abort); + qemu_opt_set(opts, "port", addr->port, &error_abort); } int inet_listen(const char *str, char *ostr, int olen, @@ -694,7 +694,7 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - error_setg_errno(errp, errno, "Failed to create socket"); + error_setg_errno(errp, errno, "Failed to create Unix socket"); return -1; } @@ -703,9 +703,15 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) if (path && strlen(path)) { snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); } else { - char *tmpdir = getenv("TMPDIR"); - snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", - tmpdir ? tmpdir : "/tmp"); + const char *tmpdir = getenv("TMPDIR"); + tmpdir = tmpdir ? tmpdir : "/tmp"; + if (snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", + tmpdir) >= sizeof(un.sun_path)) { + error_setg_errno(errp, errno, + "TMPDIR environment variable (%s) too large", tmpdir); + goto err; + } + /* * This dummy fd usage silences the mktemp() unsecure warning. * Using mkstemp() doesn't make things more secure here @@ -713,13 +719,19 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) * to unlink first and thus re-open the race window. The * worst case possible is bind() failing, i.e. a DoS attack. */ - fd = mkstemp(un.sun_path); close(fd); - qemu_opt_set(opts, "path", un.sun_path); + fd = mkstemp(un.sun_path); + if (fd < 0) { + error_setg_errno(errp, errno, + "Failed to make a temporary socket name in %s", tmpdir); + goto err; + } + close(fd); + qemu_opt_set(opts, "path", un.sun_path, &error_abort); } unlink(un.sun_path); if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { - error_setg_errno(errp, errno, "Failed to bind socket"); + error_setg_errno(errp, errno, "Failed to bind socket to %s", un.sun_path); goto err; } if (listen(sock, 1) < 0) { @@ -826,11 +838,11 @@ int unix_listen(const char *str, char *ostr, int olen, Error **errp) if (len) { path = g_malloc(len+1); snprintf(path, len+1, "%.*s", len, str); - qemu_opt_set(opts, "path", path); + qemu_opt_set(opts, "path", path, &error_abort); g_free(path); } } else { - qemu_opt_set(opts, "path", str); + qemu_opt_set(opts, "path", str, &error_abort); } sock = unix_listen_opts(opts, errp); @@ -847,7 +859,7 @@ int unix_connect(const char *path, Error **errp) int sock; opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - qemu_opt_set(opts, "path", path); + qemu_opt_set(opts, "path", path, &error_abort); sock = unix_connect_opts(opts, errp, NULL, NULL); qemu_opts_del(opts); return sock; @@ -864,7 +876,7 @@ int unix_nonblocking_connect(const char *path, g_assert(callback != NULL); opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - qemu_opt_set(opts, "path", path); + qemu_opt_set(opts, "path", path, &error_abort); sock = unix_connect_opts(opts, errp, callback, opaque); qemu_opts_del(opts); return sock; @@ -921,7 +933,7 @@ int socket_connect(SocketAddress *addr, Error **errp, break; case SOCKET_ADDRESS_KIND_UNIX: - qemu_opt_set(opts, "path", addr->q_unix->path); + qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort); fd = unix_connect_opts(opts, errp, callback, opaque); break; @@ -953,7 +965,7 @@ int socket_listen(SocketAddress *addr, Error **errp) break; case SOCKET_ADDRESS_KIND_UNIX: - qemu_opt_set(opts, "path", addr->q_unix->path); + qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort); fd = unix_listen_opts(opts, errp); break; @@ -978,8 +990,8 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) case SOCKET_ADDRESS_KIND_INET: inet_addr_to_opts(opts, remote->inet); if (local) { - qemu_opt_set(opts, "localaddr", local->inet->host); - qemu_opt_set(opts, "localport", local->inet->port); + qemu_opt_set(opts, "localaddr", local->inet->host, &error_abort); + qemu_opt_set(opts, "localport", local->inet->port, &error_abort); } fd = inet_dgram_opts(opts, errp); break; diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index d05a6497e..ba67cec62 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -26,6 +26,7 @@ #endif #include "qemu/thread.h" #include "qemu/atomic.h" +#include "qemu/notify.h" static bool name_threads; @@ -50,12 +51,8 @@ static void error_exit(int err, const char *msg) void qemu_mutex_init(QemuMutex *mutex) { int err; - pthread_mutexattr_t mutexattr; - pthread_mutexattr_init(&mutexattr); - pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); - err = pthread_mutex_init(&mutex->lock, &mutexattr); - pthread_mutexattr_destroy(&mutexattr); + err = pthread_mutex_init(&mutex->lock, NULL); if (err) error_exit(err, __func__); } @@ -306,11 +303,13 @@ static inline void futex_wait(QemuEvent *ev, unsigned val) #else static inline void futex_wake(QemuEvent *ev, int n) { + pthread_mutex_lock(&ev->lock); if (n == 1) { pthread_cond_signal(&ev->cond); } else { pthread_cond_broadcast(&ev->cond); } + pthread_mutex_unlock(&ev->lock); } static inline void futex_wait(QemuEvent *ev, unsigned val) @@ -401,6 +400,42 @@ void qemu_event_wait(QemuEvent *ev) } } +static pthread_key_t exit_key; + +union NotifierThreadData { + void *ptr; + NotifierList list; +}; +QEMU_BUILD_BUG_ON(sizeof(union NotifierThreadData) != sizeof(void *)); + +void qemu_thread_atexit_add(Notifier *notifier) +{ + union NotifierThreadData ntd; + ntd.ptr = pthread_getspecific(exit_key); + notifier_list_add(&ntd.list, notifier); + pthread_setspecific(exit_key, ntd.ptr); +} + +void qemu_thread_atexit_remove(Notifier *notifier) +{ + union NotifierThreadData ntd; + ntd.ptr = pthread_getspecific(exit_key); + notifier_remove(notifier); + pthread_setspecific(exit_key, ntd.ptr); +} + +static void qemu_thread_atexit_run(void *arg) +{ + union NotifierThreadData ntd = { .ptr = arg }; + notifier_list_notify(&ntd.list, NULL); +} + +static void __attribute__((constructor)) qemu_thread_atexit_init(void) +{ + pthread_key_create(&exit_key, qemu_thread_atexit_run); +} + + /* Attempt to set the threads name; note that this is for debug, so * we're not going to fail if we can't set it. */ diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c index c405c9bef..406b52f91 100644 --- a/util/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c @@ -12,6 +12,7 @@ */ #include "qemu-common.h" #include "qemu/thread.h" +#include "qemu/notify.h" #include <process.h> #include <assert.h> #include <limits.h> @@ -268,6 +269,7 @@ struct QemuThreadData { void *(*start_routine)(void *); void *arg; short mode; + NotifierList exit; /* Only used for joinable threads. */ bool exited; @@ -275,18 +277,40 @@ struct QemuThreadData { CRITICAL_SECTION cs; }; +static bool atexit_registered; +static NotifierList main_thread_exit; + static __thread QemuThreadData *qemu_thread_data; +static void run_main_thread_exit(void) +{ + notifier_list_notify(&main_thread_exit, NULL); +} + +void qemu_thread_atexit_add(Notifier *notifier) +{ + if (!qemu_thread_data) { + if (!atexit_registered) { + atexit_registered = true; + atexit(run_main_thread_exit); + } + notifier_list_add(&main_thread_exit, notifier); + } else { + notifier_list_add(&qemu_thread_data->exit, notifier); + } +} + +void qemu_thread_atexit_remove(Notifier *notifier) +{ + notifier_remove(notifier); +} + static unsigned __stdcall win32_start_routine(void *arg) { QemuThreadData *data = (QemuThreadData *) arg; void *(*start_routine)(void *) = data->start_routine; void *thread_arg = data->arg; - if (data->mode == QEMU_THREAD_DETACHED) { - g_free(data); - data = NULL; - } qemu_thread_data = data; qemu_thread_exit(start_routine(thread_arg)); abort(); @@ -296,12 +320,14 @@ void qemu_thread_exit(void *arg) { QemuThreadData *data = qemu_thread_data; - if (data) { - assert(data->mode != QEMU_THREAD_DETACHED); + notifier_list_notify(&data->exit, NULL); + if (data->mode == QEMU_THREAD_JOINABLE) { data->ret = arg; EnterCriticalSection(&data->cs); data->exited = true; LeaveCriticalSection(&data->cs); + } else { + g_free(data); } _endthreadex(0); } @@ -313,9 +339,10 @@ void *qemu_thread_join(QemuThread *thread) HANDLE handle; data = thread->data; - if (!data) { + if (data->mode == QEMU_THREAD_DETACHED) { return NULL; } + /* * Because multiple copies of the QemuThread can exist via * qemu_thread_get_self, we need to store a value that cannot @@ -329,7 +356,6 @@ void *qemu_thread_join(QemuThread *thread) CloseHandle(handle); } ret = data->ret; - assert(data->mode != QEMU_THREAD_DETACHED); DeleteCriticalSection(&data->cs); g_free(data); return ret; @@ -347,6 +373,7 @@ void qemu_thread_create(QemuThread *thread, const char *name, data->arg = arg; data->mode = mode; data->exited = false; + notifier_list_init(&data->exit); if (data->mode != QEMU_THREAD_DETACHED) { InitializeCriticalSection(&data->cs); @@ -358,7 +385,7 @@ void qemu_thread_create(QemuThread *thread, const char *name, error_exit(GetLastError(), __func__); } CloseHandle(hThread); - thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data; + thread->data = data; } void qemu_thread_get_self(QemuThread *thread) @@ -373,11 +400,10 @@ HANDLE qemu_thread_get_handle(QemuThread *thread) HANDLE handle; data = thread->data; - if (!data) { + if (data->mode == QEMU_THREAD_DETACHED) { return NULL; } - assert(data->mode != QEMU_THREAD_DETACHED); EnterCriticalSection(&data->cs); if (!data->exited) { handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE, diff --git a/util/rcu.c b/util/rcu.c new file mode 100644 index 000000000..7270151be --- /dev/null +++ b/util/rcu.c @@ -0,0 +1,328 @@ +/* + * urcu-mb.c + * + * Userspace RCU library with explicit memory barriers + * + * Copyright (c) 2009 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> + * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. + * Copyright 2015 Red Hat, Inc. + * + * Ported to QEMU by Paolo Bonzini <pbonzini@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * IBM's contributions to this file may be relicensed under LGPLv2 or later. + */ + +#include "qemu-common.h" +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <stdint.h> +#include <errno.h> +#include "qemu/rcu.h" +#include "qemu/atomic.h" +#include "qemu/thread.h" +#include "qemu/main-loop.h" + +/* + * Global grace period counter. Bit 0 is always one in rcu_gp_ctr. + * Bits 1 and above are defined in synchronize_rcu. + */ +#define RCU_GP_LOCKED (1UL << 0) +#define RCU_GP_CTR (1UL << 1) + +unsigned long rcu_gp_ctr = RCU_GP_LOCKED; + +QemuEvent rcu_gp_event; +static QemuMutex rcu_gp_lock; + +/* + * Check whether a quiescent state was crossed between the beginning of + * update_counter_and_wait and now. + */ +static inline int rcu_gp_ongoing(unsigned long *ctr) +{ + unsigned long v; + + v = atomic_read(ctr); + return v && (v != rcu_gp_ctr); +} + +/* Written to only by each individual reader. Read by both the reader and the + * writers. + */ +__thread struct rcu_reader_data rcu_reader; + +/* Protected by rcu_gp_lock. */ +typedef QLIST_HEAD(, rcu_reader_data) ThreadList; +static ThreadList registry = QLIST_HEAD_INITIALIZER(registry); + +/* Wait for previous parity/grace period to be empty of readers. */ +static void wait_for_readers(void) +{ + ThreadList qsreaders = QLIST_HEAD_INITIALIZER(qsreaders); + struct rcu_reader_data *index, *tmp; + + for (;;) { + /* We want to be notified of changes made to rcu_gp_ongoing + * while we walk the list. + */ + qemu_event_reset(&rcu_gp_event); + + /* Instead of using atomic_mb_set for index->waiting, and + * atomic_mb_read for index->ctr, memory barriers are placed + * manually since writes to different threads are independent. + * atomic_mb_set has a smp_wmb before... + */ + smp_wmb(); + QLIST_FOREACH(index, ®istry, node) { + atomic_set(&index->waiting, true); + } + + /* ... and a smp_mb after. */ + smp_mb(); + + QLIST_FOREACH_SAFE(index, ®istry, node, tmp) { + if (!rcu_gp_ongoing(&index->ctr)) { + QLIST_REMOVE(index, node); + QLIST_INSERT_HEAD(&qsreaders, index, node); + + /* No need for mb_set here, worst of all we + * get some extra futex wakeups. + */ + atomic_set(&index->waiting, false); + } + } + + /* atomic_mb_read has smp_rmb after. */ + smp_rmb(); + + if (QLIST_EMPTY(®istry)) { + break; + } + + /* Wait for one thread to report a quiescent state and + * try again. + */ + qemu_event_wait(&rcu_gp_event); + } + + /* put back the reader list in the registry */ + QLIST_SWAP(®istry, &qsreaders, node); +} + +void synchronize_rcu(void) +{ + qemu_mutex_lock(&rcu_gp_lock); + + if (!QLIST_EMPTY(®istry)) { + /* In either case, the atomic_mb_set below blocks stores that free + * old RCU-protected pointers. + */ + if (sizeof(rcu_gp_ctr) < 8) { + /* For architectures with 32-bit longs, a two-subphases algorithm + * ensures we do not encounter overflow bugs. + * + * Switch parity: 0 -> 1, 1 -> 0. + */ + atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); + wait_for_readers(); + atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); + } else { + /* Increment current grace period. */ + atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr + RCU_GP_CTR); + } + + wait_for_readers(); + } + + qemu_mutex_unlock(&rcu_gp_lock); +} + + +#define RCU_CALL_MIN_SIZE 30 + +/* Multi-producer, single-consumer queue based on urcu/static/wfqueue.h + * from liburcu. Note that head is only used by the consumer. + */ +static struct rcu_head dummy; +static struct rcu_head *head = &dummy, **tail = &dummy.next; +static int rcu_call_count; +static QemuEvent rcu_call_ready_event; + +static void enqueue(struct rcu_head *node) +{ + struct rcu_head **old_tail; + + node->next = NULL; + old_tail = atomic_xchg(&tail, &node->next); + atomic_mb_set(old_tail, node); +} + +static struct rcu_head *try_dequeue(void) +{ + struct rcu_head *node, *next; + +retry: + /* Test for an empty list, which we do not expect. Note that for + * the consumer head and tail are always consistent. The head + * is consistent because only the consumer reads/writes it. + * The tail, because it is the first step in the enqueuing. + * It is only the next pointers that might be inconsistent. + */ + if (head == &dummy && atomic_mb_read(&tail) == &dummy.next) { + abort(); + } + + /* If the head node has NULL in its next pointer, the value is + * wrong and we need to wait until its enqueuer finishes the update. + */ + node = head; + next = atomic_mb_read(&head->next); + if (!next) { + return NULL; + } + + /* Since we are the sole consumer, and we excluded the empty case + * above, the queue will always have at least two nodes: the + * dummy node, and the one being removed. So we do not need to update + * the tail pointer. + */ + head = next; + + /* If we dequeued the dummy node, add it back at the end and retry. */ + if (node == &dummy) { + enqueue(node); + goto retry; + } + + return node; +} + +static void *call_rcu_thread(void *opaque) +{ + struct rcu_head *node; + + for (;;) { + int tries = 0; + int n = atomic_read(&rcu_call_count); + + /* Heuristically wait for a decent number of callbacks to pile up. + * Fetch rcu_call_count now, we only must process elements that were + * added before synchronize_rcu() starts. + */ + while (n == 0 || (n < RCU_CALL_MIN_SIZE && ++tries <= 5)) { + g_usleep(10000); + if (n == 0) { + qemu_event_reset(&rcu_call_ready_event); + n = atomic_read(&rcu_call_count); + if (n == 0) { + qemu_event_wait(&rcu_call_ready_event); + } + } + n = atomic_read(&rcu_call_count); + } + + atomic_sub(&rcu_call_count, n); + synchronize_rcu(); + qemu_mutex_lock_iothread(); + while (n > 0) { + node = try_dequeue(); + while (!node) { + qemu_mutex_unlock_iothread(); + qemu_event_reset(&rcu_call_ready_event); + node = try_dequeue(); + if (!node) { + qemu_event_wait(&rcu_call_ready_event); + node = try_dequeue(); + } + qemu_mutex_lock_iothread(); + } + + n--; + node->func(node); + } + qemu_mutex_unlock_iothread(); + } + abort(); +} + +void call_rcu1(struct rcu_head *node, void (*func)(struct rcu_head *node)) +{ + node->func = func; + enqueue(node); + atomic_inc(&rcu_call_count); + qemu_event_set(&rcu_call_ready_event); +} + +void rcu_register_thread(void) +{ + assert(rcu_reader.ctr == 0); + qemu_mutex_lock(&rcu_gp_lock); + QLIST_INSERT_HEAD(®istry, &rcu_reader, node); + qemu_mutex_unlock(&rcu_gp_lock); +} + +void rcu_unregister_thread(void) +{ + qemu_mutex_lock(&rcu_gp_lock); + QLIST_REMOVE(&rcu_reader, node); + qemu_mutex_unlock(&rcu_gp_lock); +} + +static void rcu_init_complete(void) +{ + QemuThread thread; + + qemu_mutex_init(&rcu_gp_lock); + qemu_event_init(&rcu_gp_event, true); + + qemu_event_init(&rcu_call_ready_event, false); + + /* The caller is assumed to have iothread lock, so the call_rcu thread + * must have been quiescent even after forking, just recreate it. + */ + qemu_thread_create(&thread, "call_rcu", call_rcu_thread, + NULL, QEMU_THREAD_DETACHED); + + rcu_register_thread(); +} + +#ifdef CONFIG_POSIX +static void rcu_init_lock(void) +{ + qemu_mutex_lock(&rcu_gp_lock); +} + +static void rcu_init_unlock(void) +{ + qemu_mutex_unlock(&rcu_gp_lock); +} +#endif + +void rcu_after_fork(void) +{ + memset(®istry, 0, sizeof(registry)); + rcu_init_complete(); +} + +static void __attribute__((__constructor__)) rcu_init(void) +{ +#ifdef CONFIG_POSIX + pthread_atfork(rcu_init_lock, rcu_init_unlock, rcu_init_unlock); +#endif + rcu_init_complete(); +} diff --git a/util/uri.c b/util/uri.c index e348c1768..550b98458 100644 --- a/util/uri.c +++ b/util/uri.c @@ -225,7 +225,7 @@ rfc3986_parse_scheme(URI *uri, const char **str) { while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++; if (uri != NULL) { - if (uri->scheme != NULL) g_free(uri->scheme); + g_free(uri->scheme); uri->scheme = g_strndup(*str, cur - *str); } *str = cur; @@ -262,8 +262,7 @@ rfc3986_parse_fragment(URI *uri, const char **str) ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) NEXT(cur); if (uri != NULL) { - if (uri->fragment != NULL) - g_free(uri->fragment); + g_free(uri->fragment); if (uri->cleanup & 2) uri->fragment = g_strndup(*str, cur - *str); else @@ -298,8 +297,7 @@ rfc3986_parse_query(URI *uri, const char **str) ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) NEXT(cur); if (uri != NULL) { - if (uri->query != NULL) - g_free (uri->query); + g_free(uri->query); uri->query = g_strndup (*str, cur - *str); } *str = cur; @@ -322,19 +320,23 @@ static int rfc3986_parse_port(URI *uri, const char **str) { const char *cur = *str; + int port = 0; if (ISA_DIGIT(cur)) { - if (uri != NULL) - uri->port = 0; - while (ISA_DIGIT(cur)) { - if (uri != NULL) - uri->port = uri->port * 10 + (*cur - '0'); - cur++; - } - *str = cur; - return(0); + while (ISA_DIGIT(cur)) { + port = port * 10 + (*cur - '0'); + if (port > 65535) { + return 1; + } + cur++; + } + if (uri) { + uri->port = port; + } + *str = cur; + return 0; } - return(1); + return 1; } /** @@ -360,7 +362,7 @@ rfc3986_parse_user_info(URI *uri, const char **str) NEXT(cur); if (*cur == '@') { if (uri != NULL) { - if (uri->user != NULL) g_free(uri->user); + g_free(uri->user); if (uri->cleanup & 2) uri->user = g_strndup(*str, cur - *str); else @@ -473,9 +475,9 @@ not_ipv4: NEXT(cur); found: if (uri != NULL) { - if (uri->authority != NULL) g_free(uri->authority); + g_free(uri->authority); uri->authority = NULL; - if (uri->server != NULL) g_free(uri->server); + g_free(uri->server); if (cur != host) { if (uri->cleanup & 2) uri->server = g_strndup(host, cur - host); @@ -585,7 +587,7 @@ rfc3986_parse_path_ab_empty(URI *uri, const char **str) if (ret != 0) return(ret); } if (uri != NULL) { - if (uri->path != NULL) g_free(uri->path); + g_free(uri->path); if (*str != cur) { if (uri->cleanup & 2) uri->path = g_strndup(*str, cur - *str); @@ -631,7 +633,7 @@ rfc3986_parse_path_absolute(URI *uri, const char **str) } } if (uri != NULL) { - if (uri->path != NULL) g_free(uri->path); + g_free(uri->path); if (cur != *str) { if (uri->cleanup & 2) uri->path = g_strndup(*str, cur - *str); @@ -673,7 +675,7 @@ rfc3986_parse_path_rootless(URI *uri, const char **str) if (ret != 0) return(ret); } if (uri != NULL) { - if (uri->path != NULL) g_free(uri->path); + g_free(uri->path); if (cur != *str) { if (uri->cleanup & 2) uri->path = g_strndup(*str, cur - *str); @@ -715,7 +717,7 @@ rfc3986_parse_path_no_scheme(URI *uri, const char **str) if (ret != 0) return(ret); } if (uri != NULL) { - if (uri->path != NULL) g_free(uri->path); + g_free(uri->path); if (cur != *str) { if (uri->cleanup & 2) uri->path = g_strndup(*str, cur - *str); @@ -769,7 +771,7 @@ rfc3986_parse_hier_part(URI *uri, const char **str) } else { /* path-empty is effectively empty */ if (uri != NULL) { - if (uri->path != NULL) g_free(uri->path); + g_free(uri->path); uri->path = NULL; } } @@ -812,7 +814,7 @@ rfc3986_parse_relative_ref(URI *uri, const char *str) { } else { /* path-empty is effectively empty */ if (uri != NULL) { - if (uri->path != NULL) g_free(uri->path); + g_free(uri->path); uri->path = NULL; } } @@ -930,12 +932,10 @@ uri_parse(const char *str) { if (str == NULL) return(NULL); uri = uri_new(); - if (uri != NULL) { - ret = rfc3986_parse_uri_reference(uri, str); - if (ret) { - uri_free(uri); - return(NULL); - } + ret = rfc3986_parse_uri_reference(uri, str); + if (ret) { + uri_free(uri); + return(NULL); } return(uri); } @@ -976,15 +976,13 @@ uri_parse_raw(const char *str, int raw) { if (str == NULL) return(NULL); uri = uri_new(); - if (uri != NULL) { - if (raw) { - uri->cleanup |= 2; - } - ret = uri_parse_into(uri, str); - if (ret) { - uri_free(uri); - return(NULL); - } + if (raw) { + uri->cleanup |= 2; + } + ret = uri_parse_into(uri, str); + if (ret) { + uri_free(uri); + return(NULL); } return(uri); } @@ -1006,8 +1004,7 @@ URI * uri_new(void) { URI *ret; - ret = (URI *) g_malloc(sizeof(URI)); - memset(ret, 0, sizeof(URI)); + ret = g_new0(URI, 1); return(ret); } @@ -1056,14 +1053,12 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = *p++; } if (len >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = ':'; @@ -1073,7 +1068,6 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p))) @@ -1090,7 +1084,6 @@ uri_to_string(URI *uri) { if (uri->server != NULL) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = '/'; @@ -1100,7 +1093,6 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } if ((IS_UNRESERVED(*(p))) || @@ -1119,7 +1111,6 @@ uri_to_string(URI *uri) { } if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = '@'; @@ -1128,7 +1119,6 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = *p++; @@ -1136,7 +1126,6 @@ uri_to_string(URI *uri) { if (uri->port > 0) { if (len + 10 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } len += snprintf(&ret[len], max - len, ":%d", uri->port); @@ -1144,7 +1133,6 @@ uri_to_string(URI *uri) { } else if (uri->authority != NULL) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = '/'; @@ -1153,7 +1141,6 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } if ((IS_UNRESERVED(*(p))) || @@ -1172,7 +1159,6 @@ uri_to_string(URI *uri) { } else if (uri->scheme != NULL) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = '/'; @@ -1192,7 +1178,6 @@ uri_to_string(URI *uri) { (!strcmp(uri->scheme, "file"))) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = *p++; @@ -1202,7 +1187,6 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) || @@ -1222,7 +1206,6 @@ uri_to_string(URI *uri) { if (uri->query != NULL) { if (len + 1 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = '?'; @@ -1230,7 +1213,6 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len + 1 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = *p++; @@ -1240,7 +1222,6 @@ uri_to_string(URI *uri) { if (uri->fragment != NULL) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len++] = '#'; @@ -1248,7 +1229,6 @@ uri_to_string(URI *uri) { while (*p != 0) { if (len + 3 >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) @@ -1264,15 +1244,10 @@ uri_to_string(URI *uri) { } if (len >= max) { temp = realloc2n(ret, &max); - if (temp == NULL) goto mem_error; ret = temp; } ret[len] = 0; return(ret); - -mem_error: - g_free(ret); - return(NULL); } /** @@ -1285,21 +1260,21 @@ static void uri_clean(URI *uri) { if (uri == NULL) return; - if (uri->scheme != NULL) g_free(uri->scheme); + g_free(uri->scheme); uri->scheme = NULL; - if (uri->server != NULL) g_free(uri->server); + g_free(uri->server); uri->server = NULL; - if (uri->user != NULL) g_free(uri->user); + g_free(uri->user); uri->user = NULL; - if (uri->path != NULL) g_free(uri->path); + g_free(uri->path); uri->path = NULL; - if (uri->fragment != NULL) g_free(uri->fragment); + g_free(uri->fragment); uri->fragment = NULL; - if (uri->opaque != NULL) g_free(uri->opaque); + g_free(uri->opaque); uri->opaque = NULL; - if (uri->authority != NULL) g_free(uri->authority); + g_free(uri->authority); uri->authority = NULL; - if (uri->query != NULL) g_free(uri->query); + g_free(uri->query); uri->query = NULL; } @@ -1678,8 +1653,6 @@ uri_resolve(const char *uri, const char *base) { else { if (*uri) { ref = uri_new(); - if (ref == NULL) - goto done; ret = uri_parse_into(ref, uri); } else @@ -1698,8 +1671,6 @@ uri_resolve(const char *uri, const char *base) { ret = -1; else { bas = uri_new(); - if (bas == NULL) - goto done; ret = uri_parse_into(bas, base); } if (ret != 0) { @@ -1711,10 +1682,8 @@ uri_resolve(const char *uri, const char *base) { /* * the base fragment must be ignored */ - if (bas->fragment != NULL) { - g_free(bas->fragment); - bas->fragment = NULL; - } + g_free(bas->fragment); + bas->fragment = NULL; val = uri_to_string(bas); goto done; } @@ -1732,28 +1701,23 @@ uri_resolve(const char *uri, const char *base) { * document. */ res = uri_new(); - if (res == NULL) - goto done; if ((ref->scheme == NULL) && (ref->path == NULL) && ((ref->authority == NULL) && (ref->server == NULL))) { - if (bas->scheme != NULL) - res->scheme = g_strdup(bas->scheme); + res->scheme = g_strdup(bas->scheme); if (bas->authority != NULL) res->authority = g_strdup(bas->authority); else if (bas->server != NULL) { - res->server = g_strdup(bas->server); - if (bas->user != NULL) - res->user = g_strdup(bas->user); - res->port = bas->port; + res->server = g_strdup(bas->server); + res->user = g_strdup(bas->user); + res->port = bas->port; } - if (bas->path != NULL) - res->path = g_strdup(bas->path); - if (ref->query != NULL) + res->path = g_strdup(bas->path); + if (ref->query != NULL) { res->query = g_strdup (ref->query); - else if (bas->query != NULL) - res->query = g_strdup(bas->query); - if (ref->fragment != NULL) - res->fragment = g_strdup(ref->fragment); + } else { + res->query = g_strdup(bas->query); + } + res->fragment = g_strdup(ref->fragment); goto step_7; } @@ -1767,13 +1731,10 @@ uri_resolve(const char *uri, const char *base) { val = uri_to_string(ref); goto done; } - if (bas->scheme != NULL) - res->scheme = g_strdup(bas->scheme); + res->scheme = g_strdup(bas->scheme); - if (ref->query != NULL) - res->query = g_strdup(ref->query); - if (ref->fragment != NULL) - res->fragment = g_strdup(ref->fragment); + res->query = g_strdup(ref->query); + res->fragment = g_strdup(ref->fragment); /* * 4) If the authority component is defined, then the reference is a @@ -1787,20 +1748,17 @@ uri_resolve(const char *uri, const char *base) { res->authority = g_strdup(ref->authority); else { res->server = g_strdup(ref->server); - if (ref->user != NULL) - res->user = g_strdup(ref->user); + res->user = g_strdup(ref->user); res->port = ref->port; } - if (ref->path != NULL) - res->path = g_strdup(ref->path); + res->path = g_strdup(ref->path); goto step_7; } if (bas->authority != NULL) res->authority = g_strdup(bas->authority); else if (bas->server != NULL) { - res->server = g_strdup(bas->server); - if (bas->user != NULL) - res->user = g_strdup(bas->user); + res->server = g_strdup(bas->server); + res->user = g_strdup(bas->user); res->port = bas->port; } @@ -1947,8 +1905,6 @@ uri_resolve_relative (const char *uri, const char * base) * First parse URI into a standard form */ ref = uri_new (); - if (ref == NULL) - return NULL; /* If URI not already in "relative" form */ if (uri[0] != '.') { ret = uri_parse_into (ref, uri); @@ -1965,8 +1921,6 @@ uri_resolve_relative (const char *uri, const char * base) goto done; } bas = uri_new (); - if (bas == NULL) - goto done; if (base[0] != '.') { ret = uri_parse_into (bas, base); if (ret != 0) @@ -1985,7 +1939,8 @@ uri_resolve_relative (const char *uri, const char * base) val = g_strdup (uri); goto done; } - if (!strcmp(bas->path, ref->path)) { + if (bas->path == ref->path || + (bas->path && ref->path && !strcmp(bas->path, ref->path))) { val = g_strdup(""); goto done; } |