diff options
37 files changed, 384 insertions, 354 deletions
@@ -582,7 +582,6 @@ $(ROM_DIRS_RULES): .PHONY: recurse-all recurse-clean recurse-install recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS)) -recurse-fuzz: $(addsuffix /fuzz, $(TARGET_DIRS) $(ROM_DIRS)) recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS)) recurse-install: $(addsuffix /install, $(TARGET_DIRS)) $(addsuffix /install, $(TARGET_DIRS)): all diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c index c8ae3b9742..14316333fe 100644 --- a/backends/cryptodev-builtin.c +++ b/backends/cryptodev-builtin.c @@ -282,12 +282,7 @@ static int cryptodev_builtin_sym_close_session( CryptoDevBackendBuiltin *builtin = CRYPTODEV_BACKEND_BUILTIN(backend); - if (session_id >= MAX_NUM_SESSIONS || - builtin->sessions[session_id] == NULL) { - error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", - session_id); - return -1; - } + assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]); qcrypto_cipher_free(builtin->sessions[session_id]->cipher); g_free(builtin->sessions[session_id]); @@ -356,8 +351,7 @@ static void cryptodev_builtin_cleanup( for (i = 0; i < MAX_NUM_SESSIONS; i++) { if (builtin->sessions[i] != NULL) { - cryptodev_builtin_sym_close_session( - backend, i, 0, errp); + cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort); } } diff --git a/block/file-posix.c b/block/file-posix.c index 7e19bbff5f..094e3b0212 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2691,10 +2691,13 @@ static void check_cache_dropped(BlockDriverState *bs, Error **errp) vec_end = DIV_ROUND_UP(length, page_size); for (i = 0; i < vec_end; i++) { if (vec[i] & 0x1) { - error_setg(errp, "page cache still in use!"); break; } } + if (i < vec_end) { + error_setg(errp, "page cache still in use!"); + break; + } } if (window) { diff --git a/block/replication.c b/block/replication.c index da013c2041..971f0fe266 100644 --- a/block/replication.c +++ b/block/replication.c @@ -172,8 +172,8 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) { *nperm |= BLK_PERM_WRITE; } - *nshared = BLK_PERM_CONSISTENT_READ \ - | BLK_PERM_WRITE \ + *nshared = BLK_PERM_CONSISTENT_READ + | BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED; return; } diff --git a/block/vhdx.c b/block/vhdx.c index 33e57cd656..e16fdc2f2d 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -2206,20 +2206,20 @@ static QemuOptsList vhdx_create_opts = { .name = VHDX_BLOCK_OPT_BLOCK_SIZE, .type = QEMU_OPT_SIZE, .def_value_str = stringify(0), - .help = "Block Size; min 1MB, max 256MB. " \ + .help = "Block Size; min 1MB, max 256MB. " "0 means auto-calculate based on image size." }, { .name = BLOCK_OPT_SUBFMT, .type = QEMU_OPT_STRING, - .help = "VHDX format type, can be either 'dynamic' or 'fixed'. "\ + .help = "VHDX format type, can be either 'dynamic' or 'fixed'. " "Default is 'dynamic'." }, { .name = VHDX_BLOCK_OPT_ZERO, .type = QEMU_OPT_BOOL, - .help = "Force use of payload blocks of type 'ZERO'. "\ - "Non-standard, but default. Do not set to 'off' when "\ + .help = "Force use of payload blocks of type 'ZERO'. " + "Non-standard, but default. Do not set to 'off' when " "using 'qemu-img convert' with subformat=dynamic." }, { NULL } @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/config-file.h" +#include "qemu/cutils.h" #include "migration/vmstate.h" #include "monitor/monitor.h" #include "qapi/error.h" @@ -797,40 +798,47 @@ void cpu_ticks_init(void) void configure_icount(QemuOpts *opts, Error **errp) { - const char *option; - char *rem_str = NULL; + const char *option = qemu_opt_get(opts, "shift"); + bool sleep = qemu_opt_get_bool(opts, "sleep", true); + bool align = qemu_opt_get_bool(opts, "align", false); + long time_shift = -1; - option = qemu_opt_get(opts, "shift"); - if (!option) { - if (qemu_opt_get(opts, "align") != NULL) { - error_setg(errp, "Please specify shift option when using align"); - } + if (!option && qemu_opt_get(opts, "align")) { + error_setg(errp, "Please specify shift option when using align"); return; } - icount_sleep = qemu_opt_get_bool(opts, "sleep", true); - if (icount_sleep) { - timers_state.icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, - icount_timer_cb, NULL); - } - - icount_align_option = qemu_opt_get_bool(opts, "align", false); - - if (icount_align_option && !icount_sleep) { + if (align && !sleep) { error_setg(errp, "align=on and sleep=off are incompatible"); + return; } + if (strcmp(option, "auto") != 0) { - errno = 0; - timers_state.icount_time_shift = strtol(option, &rem_str, 0); - if (errno != 0 || *rem_str != '\0' || !strlen(option)) { + if (qemu_strtol(option, NULL, 0, &time_shift) < 0 + || time_shift < 0 || time_shift > MAX_ICOUNT_SHIFT) { error_setg(errp, "icount: Invalid shift value"); + return; } - use_icount = 1; - return; } else if (icount_align_option) { error_setg(errp, "shift=auto and align=on are incompatible"); + return; } else if (!icount_sleep) { error_setg(errp, "shift=auto and sleep=off are incompatible"); + return; + } + + icount_sleep = sleep; + if (icount_sleep) { + timers_state.icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, + icount_timer_cb, NULL); + } + + icount_align_option = align; + + if (time_shift >= 0) { + timers_state.icount_time_shift = time_shift; + use_icount = 1; + return; } use_icount = 2; diff --git a/dump/dump.c b/dump/dump.c index 22ed1d3b0d..248ea06370 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1892,7 +1892,7 @@ static void dump_process(DumpState *s, Error **errp) result = qmp_query_dump(NULL); /* should never fail */ assert(result); - qapi_event_send_dump_completed(result, !!local_err, (local_err ? \ + qapi_event_send_dump_completed(result, !!local_err, (local_err ? error_get_pretty(local_err) : NULL)); qapi_free_DumpQueryResult(result); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 7dc96abf72..cca5316256 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1186,7 +1186,7 @@ static void create_smmu(const VirtMachineState *vms, g_free(node); } -static void create_virtio_iommu_dt_bindings(VirtMachineState *vms, Error **errp) +static void create_virtio_iommu_dt_bindings(VirtMachineState *vms) { const char compat[] = "virtio,pci-iommu"; uint16_t bdf = vms->virtio_iommu_bdf; @@ -2118,7 +2118,7 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, vms->iommu = VIRT_IOMMU_VIRTIO; vms->virtio_iommu_bdf = pci_get_bdf(pdev); - create_virtio_iommu_dt_bindings(vms, errp); + create_virtio_iommu_dt_bindings(vms); } } diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 33bc9e2f92..9628cc171e 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2615,6 +2615,7 @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl, if (fdctrl->fallback == FLOPPY_DRIVE_TYPE_AUTO) { error_setg(errp, "Cannot choose a fallback FDrive type of 'auto'"); + return; } /* Fill 'command_to_handler' lookup table */ diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index 70eb619ef4..e763a0a72d 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -267,16 +267,18 @@ static void bochs_display_realize(PCIDevice *dev, Error **errp) Object *obj = OBJECT(dev); int ret; - s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s); - if (s->vgamem < 4 * MiB) { error_setg(errp, "bochs-display: video memory too small"); + return; } if (s->vgamem > 256 * MiB) { error_setg(errp, "bochs-display: video memory too big"); + return; } s->vgamem = pow2ceil(s->vgamem); + s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s); + memory_region_init_ram(&s->vram, obj, "bochs-display-vram", s->vgamem, &error_fatal); memory_region_init_io(&s->vbe, obj, &bochs_display_vbe_ops, s, diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index 5adf3b15b5..e199fc8678 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -195,8 +195,7 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, } /* Generate SDRAM SPD EEPROM data describing a module of type and size */ -uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size, - Error **errp) +uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size) { uint8_t *spd; uint8_t nbanks; @@ -222,39 +221,18 @@ uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size, g_assert_not_reached(); } size = ram_size >> 20; /* work in terms of megabytes */ - if (size < 4) { - error_setg(errp, "SDRAM size is too small"); - return NULL; - } sz_log2 = 31 - clz32(size); size = 1U << sz_log2; - if (ram_size > size * MiB) { - error_setg(errp, "SDRAM size 0x"RAM_ADDR_FMT" is not a power of 2, " - "truncating to %u MB", ram_size, size); - } - if (sz_log2 < min_log2) { - error_setg(errp, - "Memory size is too small for SDRAM type, adjusting type"); - if (size >= 32) { - type = DDR; - min_log2 = 5; - max_log2 = 12; - } else { - type = SDR; - min_log2 = 2; - max_log2 = 9; - } - } + assert(ram_size == size * MiB); + assert(sz_log2 >= min_log2); nbanks = 1; while (sz_log2 > max_log2 && nbanks < 8) { sz_log2--; - nbanks++; + nbanks *= 2; } - if (size > (1ULL << sz_log2) * nbanks) { - error_setg(errp, "Memory size is too big for SDRAM, truncating"); - } + assert(size == (1ULL << sz_log2) * nbanks); /* split to 2 banks if possible to avoid a bug in MIPS Malta firmware */ if (nbanks == 1 && sz_log2 > min_log2) { diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 5040afd581..ef02d54b33 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -297,7 +297,6 @@ static void mips_fulong2e_init(MachineState *machine) MemoryRegion *bios = g_new(MemoryRegion, 1); long bios_size; uint8_t *spd_data; - Error *err = NULL; int64_t kernel_entry; PCIBus *pci_bus; ISABus *isa_bus; @@ -377,13 +376,8 @@ static void mips_fulong2e_init(MachineState *machine) } /* Populate SPD eeprom data */ - spd_data = spd_data_generate(DDR, machine->ram_size, &err); - if (err) { - warn_report_err(err); - } - if (spd_data) { - smbus_eeprom_init_one(smbus, 0x50, spd_data); - } + spd_data = spd_data_generate(DDR, machine->ram_size); + smbus_eeprom_init_one(smbus, 0x50, spd_data); mc146818_rtc_init(isa_bus, 2000, NULL); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a46e3b37a7..65bb6886c7 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1526,7 +1526,7 @@ static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, + sizeof(struct eth_header)); unit->ip = ip6; unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); - unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\ + unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + sizeof(struct ip6_header)); unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; @@ -2947,6 +2947,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) n->net_conf.duplex = DUPLEX_FULL; } else { error_setg(errp, "'duplex' must be 'half' or 'full'"); + return; } n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); } else { @@ -2955,7 +2956,9 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) if (n->net_conf.speed < SPEED_UNKNOWN) { error_setg(errp, "'speed' must be between 0 and INT_MAX"); - } else if (n->net_conf.speed >= 0) { + return; + } + if (n->net_conf.speed >= 0) { n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); } diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 3376c43ff5..f1651e04d9 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -716,11 +716,11 @@ void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, for (i = 0; sdram_bank_sizes[i]; i++) { g_string_append_printf(s, "%" PRIi64 "%s", sdram_bank_sizes[i] / MiB, - sdram_bank_sizes[i + 1] ? " ," : ""); + sdram_bank_sizes[i + 1] ? ", " : ""); } - error_report("Max %d banks of %s MB DIMM/bank supported", - nr_banks, s->str); - error_report("Possible valid RAM size: %" PRIi64, + error_report("at most %d bank%s of %s MiB each supported", + nr_banks, nr_banks == 1 ? "" : "s", s->str); + error_printf("Possible valid RAM size: %" PRIi64 " MiB \n", used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB); g_string_free(s, true); diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 898453cf30..42a8c9fb7f 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -292,7 +292,6 @@ static void sam460ex_init(MachineState *machine) SysBusDevice *sbdev; struct boot_info *boot_info; uint8_t *spd_data; - Error *err = NULL; int success; cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); @@ -335,14 +334,10 @@ static void sam460ex_init(MachineState *machine) dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]); i2c = PPC4xx_I2C(dev)->bus; /* SPD EEPROM on RAM module */ - spd_data = spd_data_generate(DDR2, ram_sizes[0], &err); - if (err) { - warn_report_err(err); - } - if (spd_data) { - spd_data[20] = 4; /* SO-DIMM module */ - smbus_eeprom_init_one(i2c, 0x50, spd_data); - } + spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2, + ram_sizes[0]); + spd_data[20] = 4; /* SO-DIMM module */ + smbus_eeprom_init_one(i2c, 0x50, spd_data); /* RTC */ i2c_create_slave(i2c, "m41t80", 0x68); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 56351c4faa..998666c91f 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -465,7 +465,7 @@ static void riscv_sifive_u_machine_instance_init(Object *obj) object_property_add_bool(obj, "start-in-flash", sifive_u_get_start_in_flash, sifive_u_set_start_in_flash, NULL); object_property_set_description(obj, "start-in-flash", - "Set on to tell QEMU's ROM to jump to " \ + "Set on to tell QEMU's ROM to jump to " "flash. Otherwise QEMU will jump to DRAM", NULL); } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 1c0cb63a6f..e5bcd0baf8 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -3078,7 +3078,7 @@ static const TypeInfo scsi_cd_info = { #ifdef __linux__ static Property scsi_block_properties[] = { - DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \ + DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index de63ffb037..70531ad360 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1130,7 +1130,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) /* Limit block size to the maximum buffer size */ if (extract32(s->blksize, 0, 12) > s->buf_maxsz) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \ + qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " "the maximum buffer 0x%x", __func__, s->blksize, s->buf_maxsz); diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index b91082cb8b..81d5ad8da7 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -858,8 +858,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq); if (rc < 0) { - error_setg_errno(errp, errno, "Mapping machine irq %u to" - " pirq %i failed", machine_irq, pirq); + XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (err: %d)\n", + machine_irq, pirq, errno); /* Disable PCI intx assertion (turn on bit10 of devctl) */ cmd |= PCI_COMMAND_INTX_DISABLE; @@ -880,8 +880,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) PCI_SLOT(d->devfn), e_intx); if (rc < 0) { - error_setg_errno(errp, errno, "Binding of interrupt %u failed", - e_intx); + XEN_PT_ERR(d, "Binding of interrupt %i failed! (err: %d)\n", + e_intx, errno); /* Disable PCI intx assertion (turn on bit10 of devctl) */ cmd |= PCI_COMMAND_INTX_DISABLE; @@ -889,8 +889,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) if (xen_pt_mapped_machine_irq[machine_irq] == 0) { if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) { - error_setg_errno(errp, errno, "Unmapping of machine" - " interrupt %u failed", machine_irq); + XEN_PT_ERR(d, "Unmapping of machine interrupt %i failed!" + " (err: %d)\n", machine_irq, errno); } } s->machine_irq = 0; diff --git a/include/hw/i2c/smbus_eeprom.h b/include/hw/i2c/smbus_eeprom.h index 15e2151b50..68b0063ab6 100644 --- a/include/hw/i2c/smbus_eeprom.h +++ b/include/hw/i2c/smbus_eeprom.h @@ -31,6 +31,6 @@ void smbus_eeprom_init(I2CBus *bus, int nb_eeprom, const uint8_t *eeprom_spd, int size); enum sdram_type { SDR = 0x4, DDR = 0x7, DDR2 = 0x8 }; -uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t size, Error **errp); +uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t size); #endif diff --git a/include/qemu/option.h b/include/qemu/option.h index 844587cab3..eb4097889d 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -33,7 +33,6 @@ const char *get_opt_value(const char *p, char **value); void parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp); bool has_help_option(const char *param); -bool is_valid_option_list(const char *param); enum QemuOptType { QEMU_OPT_STRING = 0, /* no parsing (use string as-is) */ diff --git a/io/channel-socket.c b/io/channel-socket.c index b74f5b92a0..e1b4667087 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -704,6 +704,7 @@ qio_channel_socket_close(QIOChannel *ioc, { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); int rc = 0; + Error *err = NULL; if (sioc->fd != -1) { #ifdef WIN32 @@ -715,8 +716,8 @@ qio_channel_socket_close(QIOChannel *ioc, if (closesocket(sioc->fd) < 0) { sioc->fd = -1; - error_setg_errno(errp, errno, - "Unable to close socket"); + error_setg_errno(&err, errno, "Unable to close socket"); + error_propagate(errp, err); return -1; } sioc->fd = -1; diff --git a/migration/colo.c b/migration/colo.c index a54ac84f41..1b3493729b 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -263,7 +263,13 @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp) void qmp_xen_colo_do_checkpoint(Error **errp) { - replication_do_checkpoint_all(errp); + Error *err = NULL; + + replication_do_checkpoint_all(&err); + if (err) { + error_propagate(errp, err); + return; + } /* Notify all filters of all NIC to do checkpoint */ colo_notify_filters_event(COLO_EVENT_CHECKPOINT, errp); } diff --git a/qemu-img.c b/qemu-img.c index 821cbf610e..a2369766f0 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -223,6 +223,53 @@ static bool qemu_img_object_print_help(const char *type, QemuOpts *opts) return true; } +/* + * Is @optarg safe for accumulate_options()? + * It is when multiple of them can be joined together separated by ','. + * To make that work, @optarg must not start with ',' (or else a + * separating ',' preceding it gets escaped), and it must not end with + * an odd number of ',' (or else a separating ',' following it gets + * escaped), or be empty (or else a separating ',' preceding it can + * escape a separating ',' following it). + * + */ +static bool is_valid_option_list(const char *optarg) +{ + size_t len = strlen(optarg); + size_t i; + + if (!optarg[0] || optarg[0] == ',') { + return false; + } + + for (i = len; i > 0 && optarg[i - 1] == ','; i--) { + } + if ((len - i) % 2) { + return false; + } + + return true; +} + +static int accumulate_options(char **options, char *optarg) +{ + char *new_options; + + if (!is_valid_option_list(optarg)) { + error_report("Invalid option list: %s", optarg); + return -1; + } + + if (!*options) { + *options = g_strdup(optarg); + } else { + new_options = g_strdup_printf("%s,%s", *options, optarg); + g_free(*options); + *options = new_options; + } + return 0; +} + static QemuOptsList qemu_source_opts = { .name = "source", .implied_opt_name = "file", @@ -482,17 +529,9 @@ static int img_create(int argc, char **argv) fmt = optarg; break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { goto fail; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'q': quiet = true; @@ -2127,17 +2166,9 @@ static int img_convert(int argc, char **argv) s.compressed = true; break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { goto fail_getopt; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'l': if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { @@ -3953,18 +3984,10 @@ static int img_amend(int argc, char **argv) help(); break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { ret = -1; goto out_no_progress; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'f': fmt = optarg; @@ -4855,17 +4878,9 @@ static int img_measure(int argc, char **argv) out_fmt = optarg; break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { goto out; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'l': if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { diff --git a/qga/commands-posix.c b/qga/commands-posix.c index a52af0315f..ae1348dc8f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -2518,6 +2518,9 @@ GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp) mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10); mem_blk->has_can_offline = true; /* lolspeak ftw */ transfer_memory_block(mem_blk, true, NULL, &local_err); + if (local_err) { + break; + } entry = g_malloc0(sizeof *entry); entry->value = mem_blk; diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 9717a8d52d..5ba56327dd 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1322,9 +1322,16 @@ void qmp_guest_suspend_disk(Error **errp) *mode = GUEST_SUSPEND_MODE_DISK; check_suspend_mode(*mode, &local_err); + if (local_err) { + goto out; + } acquire_privilege(SE_SHUTDOWN_NAME, &local_err); + if (local_err) { + goto out; + } execute_async(do_suspend, mode, &local_err); +out: if (local_err) { error_propagate(errp, local_err); g_free(mode); @@ -1338,9 +1345,16 @@ void qmp_guest_suspend_ram(Error **errp) *mode = GUEST_SUSPEND_MODE_RAM; check_suspend_mode(*mode, &local_err); + if (local_err) { + goto out; + } acquire_privilege(SE_SHUTDOWN_NAME, &local_err); + if (local_err) { + goto out; + } execute_async(do_suspend, mode, &local_err); +out: if (local_err) { error_propagate(errp, local_err); g_free(mode); diff --git a/softmmu/vl.c b/softmmu/vl.c index 32c0047889..afd2615fb3 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3059,19 +3059,19 @@ void qemu_init(int argc, char **argv, char **envp) } break; case QEMU_OPTION_kernel: - qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "kernel", optarg, &error_abort); break; case QEMU_OPTION_initrd: - qemu_opts_set(qemu_find_opts("machine"), 0, "initrd", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "initrd", optarg, &error_abort); break; case QEMU_OPTION_append: - qemu_opts_set(qemu_find_opts("machine"), 0, "append", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "append", optarg, &error_abort); break; case QEMU_OPTION_dtb: - qemu_opts_set(qemu_find_opts("machine"), 0, "dtb", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "dtb", optarg, &error_abort); break; case QEMU_OPTION_cdrom: @@ -3182,7 +3182,7 @@ void qemu_init(int argc, char **argv, char **envp) } break; case QEMU_OPTION_bios: - qemu_opts_set(qemu_find_opts("machine"), 0, "firmware", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "firmware", optarg, &error_abort); break; case QEMU_OPTION_singlestep: diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 90ffc5f3b1..9c256ab159 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5784,9 +5784,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, host_cpuid(index, 0, eax, ebx, ecx, edx); break; } - *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \ + *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); - *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ + *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); *ecx = encode_cache_cpuid80000005(env->cache_info_amd.l1d_cache); *edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache); @@ -5797,13 +5797,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, host_cpuid(index, 0, eax, ebx, ecx, edx); break; } - *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \ - (L2_DTLB_2M_ENTRIES << 16) | \ - (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \ + *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | + (L2_DTLB_2M_ENTRIES << 16) | + (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | (L2_ITLB_2M_ENTRIES); - *ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | \ - (L2_DTLB_4K_ENTRIES << 16) | \ - (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ + *ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | + (L2_DTLB_4K_ENTRIES << 16) | + (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | (L2_ITLB_4K_ENTRIES); encode_cache_cpuid80000006(env->cache_info_amd.l2_cache, cpu->enable_l3_cache ? @@ -6326,7 +6326,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) */ env->features[w] |= x86_cpu_get_supported_feature_word(w, cpu->migratable) & - ~env->user_features[w] & \ + ~env->user_features[w] & ~feature_word_info[w].no_autoenable_flags; } } diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index a2c2f271df..c9cf2364ca 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -163,14 +163,14 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) qemu_init_vcpu(cs); - env->pvr.regs[0] = PVR0_USE_EXC_MASK \ - | PVR0_USE_ICACHE_MASK \ + env->pvr.regs[0] = PVR0_USE_EXC_MASK + | PVR0_USE_ICACHE_MASK | PVR0_USE_DCACHE_MASK; - env->pvr.regs[2] = PVR2_D_OPB_MASK \ - | PVR2_D_LMB_MASK \ - | PVR2_I_OPB_MASK \ - | PVR2_I_LMB_MASK \ - | PVR2_FPU_EXC_MASK \ + env->pvr.regs[2] = PVR2_D_OPB_MASK + | PVR2_D_LMB_MASK + | PVR2_I_OPB_MASK + | PVR2_I_LMB_MASK + | PVR2_FPU_EXC_MASK | 0; version = cpu->cfg.version ? cpu->cfg.version : DEFAULT_CPU_VERSION; diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index e853164a86..fd763e588e 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -5210,7 +5210,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) PPC_FLOAT_STFIWX | PPC_WAIT | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | PPC_64B | PPC_POPCNTB | PPC_POPCNTWD; - pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \ + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_CM) | (1ull << MSR_GS) | @@ -5258,7 +5258,7 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data) PPC_FLOAT_STFIWX | PPC_WAIT | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | PPC_64B | PPC_POPCNTB | PPC_POPCNTWD | PPC_ALTIVEC; - pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \ + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | PPC2_FP_CVT_S64 | PPC2_ATOMIC_ISA206; pcc->msr_mask = (1ull << MSR_CM) | (1ull << MSR_GS) | diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index af28c92866..87eadb0889 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -36,7 +36,6 @@ #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-qom.h" -#include "qapi/qmp/qlist.h" void *fuzz_qos_obj; @@ -45,34 +44,19 @@ QGuestAllocator *fuzz_qos_alloc; static const char *fuzz_target_name; static char **fuzz_path_vec; -/* - * Replaced the qmp commands with direct qmp_marshal calls. - * Probably there is a better way to do this - */ static void qos_set_machines_devices_available(void) { - QDict *req = qdict_new(); - QObject *response; - QDict *args = qdict_new(); - QList *lst; - - qmp_marshal_query_machines(NULL, &response, &error_abort); - lst = qobject_to(QList, response); - apply_to_qlist(lst, true); - - qobject_unref(response); - + MachineInfoList *mach_info; + ObjectTypeInfoList *type_info; - qdict_put_str(req, "execute", "qom-list-types"); - qdict_put_str(args, "implements", "device"); - qdict_put_bool(args, "abstract", true); - qdict_put_obj(req, "arguments", (QObject *) args); + mach_info = qmp_query_machines(&error_abort); + machines_apply_to_node(mach_info); + qapi_free_MachineInfoList(mach_info); - qmp_marshal_qom_list_types(args, &response, &error_abort); - lst = qobject_to(QList, response); - apply_to_qlist(lst, false); - qobject_unref(response); - qobject_unref(req); + type_info = qmp_qom_list_types(true, "device", true, true, + &error_abort); + types_apply_to_node(type_info); + qapi_free_ObjectTypeInfoList(type_info); } static char **current_path; diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c index 398556dde0..9f5180e18d 100644 --- a/tests/qtest/libqos/qos_external.c +++ b/tests/qtest/libqos/qos_external.c @@ -29,66 +29,44 @@ #include "libqos/qgraph_internal.h" #include "libqos/qos_external.h" +static void machine_apply_to_node(const char *name) +{ + char *machine_name = g_strconcat(qtest_get_arch(), "/", name, NULL); + qos_graph_node_set_availability(machine_name, true); + g_free(machine_name); +} -void apply_to_node(const char *name, bool is_machine, bool is_abstract) +void machines_apply_to_node(MachineInfoList *mach_info) { - char *machine_name = NULL; - if (is_machine) { - const char *arch = qtest_get_arch(); - machine_name = g_strconcat(arch, "/", name, NULL); - name = machine_name; + MachineInfoList *tail; + + for (tail = mach_info; tail; tail = tail->next) { + machine_apply_to_node(tail->value->name); + if (tail->value->alias) { + machine_apply_to_node(tail->value->alias); + } } +} + +static void type_apply_to_node(const char *name, bool is_abstract) +{ qos_graph_node_set_availability(name, true); if (is_abstract) { qos_delete_cmd_line(name); } - g_free(machine_name); } -/** - * apply_to_qlist(): using QMP queries QEMU for a list of - * machines and devices available, and sets the respective node - * as true. If a node is found, also all its produced and contained - * child are marked available. - * - * See qos_graph_node_set_availability() for more info - */ -void apply_to_qlist(QList *list, bool is_machine) +void types_apply_to_node(ObjectTypeInfoList *type_info) { - const QListEntry *p; - const char *name; - bool abstract; - QDict *minfo; - QObject *qobj; - QString *qstr; - QBool *qbool; - - for (p = qlist_first(list); p; p = qlist_next(p)) { - minfo = qobject_to(QDict, qlist_entry_obj(p)); - qobj = qdict_get(minfo, "name"); - qstr = qobject_to(QString, qobj); - name = qstring_get_str(qstr); - - qobj = qdict_get(minfo, "abstract"); - if (qobj) { - qbool = qobject_to(QBool, qobj); - abstract = qbool_get_bool(qbool); - } else { - abstract = false; - } + ObjectTypeInfoList *tail; - apply_to_node(name, is_machine, abstract); - qobj = qdict_get(minfo, "alias"); - if (qobj) { - qstr = qobject_to(QString, qobj); - name = qstring_get_str(qstr); - apply_to_node(name, is_machine, abstract); - } + for (tail = type_info; tail; tail = tail->next) { + type_apply_to_node(tail->value->name, tail->value->abstract); } } -QGuestAllocator *get_machine_allocator(QOSGraphObject *obj) +static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj) { return obj->get_driver(obj, "memory"); } diff --git a/tests/qtest/libqos/qos_external.h b/tests/qtest/libqos/qos_external.h index 7b44930c55..72d7f91707 100644 --- a/tests/qtest/libqos/qos_external.h +++ b/tests/qtest/libqos/qos_external.h @@ -18,11 +18,13 @@ #ifndef QOS_EXTERNAL_H #define QOS_EXTERNAL_H -#include "libqos/qgraph.h" -void apply_to_node(const char *name, bool is_machine, bool is_abstract); -void apply_to_qlist(QList *list, bool is_machine); -QGuestAllocator *get_machine_allocator(QOSGraphObject *obj); +#include "libqos/malloc.h" +#include "qapi/qapi-types-machine.h" +#include "qapi/qapi-types-qom.h" + +void machines_apply_to_node(MachineInfoList *mach_info); +void types_apply_to_node(ObjectTypeInfoList *type_info); void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc); #endif diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c index ad193f43a5..3062a13557 100644 --- a/tests/qtest/qos-test.c +++ b/tests/qtest/qos-test.c @@ -19,11 +19,12 @@ #include "qemu/osdep.h" #include <getopt.h> #include "libqtest-single.h" +#include "qapi/error.h" #include "qapi/qmp/qdict.h" -#include "qapi/qmp/qbool.h" -#include "qapi/qmp/qstring.h" #include "qemu/module.h" -#include "qapi/qmp/qlist.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qapi-visit-machine.h" +#include "qapi/qapi-visit-qom.h" #include "libqos/malloc.h" #include "libqos/qgraph.h" #include "libqos/qgraph_internal.h" @@ -51,13 +52,20 @@ static void qos_set_machines_devices_available(void) { QDict *response; QDict *args = qdict_new(); - QList *list; + QObject *ret; + Visitor *v; + MachineInfoList *mach_info; + ObjectTypeInfoList *type_info; qtest_start("-machine none"); response = qmp("{ 'execute': 'query-machines' }"); - list = qdict_get_qlist(response, "return"); + ret = qdict_get(response, "return"); - apply_to_qlist(list, true); + v = qobject_input_visitor_new(ret); + visit_type_MachineInfoList(v, NULL, &mach_info, &error_abort); + visit_free(v); + machines_apply_to_node(mach_info); + qapi_free_MachineInfoList(mach_info); qobject_unref(response); @@ -66,10 +74,13 @@ static void qos_set_machines_devices_available(void) response = qmp("{'execute': 'qom-list-types'," " 'arguments': %p }", args); - g_assert(qdict_haskey(response, "return")); - list = qdict_get_qlist(response, "return"); + ret = qdict_get(response, "return"); - apply_to_qlist(list, false); + v = qobject_input_visitor_new(ret); + visit_type_ObjectTypeInfoList(v, NULL, &type_info, &error_abort); + visit_free(v); + types_apply_to_node(type_info); + qapi_free_ObjectTypeInfoList(type_info); qtest_end(); qobject_unref(response); diff --git a/tests/test-logging.c b/tests/test-logging.c index 6387e4933f..8580b82420 100644 --- a/tests/test-logging.c +++ b/tests/test-logging.c @@ -73,10 +73,10 @@ static void test_parse_range(void) g_assert(qemu_log_in_addr_range(UINT64_MAX)); g_assert_false(qemu_log_in_addr_range(UINT64_MAX - 1)); - qemu_set_dfilter_ranges("0..0xffffffffffffffff", &err); + qemu_set_dfilter_ranges("0..0xffffffffffffffff", &error_abort); g_assert(qemu_log_in_addr_range(0)); g_assert(qemu_log_in_addr_range(UINT64_MAX)); - + qemu_set_dfilter_ranges("2..1", &err); error_free_or_abort(&err); diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index ef96e84aed..2a0f42a09b 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -500,10 +500,10 @@ static void test_opts_parse(void) g_assert(!opts); /* TODO Cover .merge_lists = true */ - /* Buggy ID recognition */ + /* Buggy ID recognition (fixed) */ opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort); g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpstr(qemu_opts_id(opts), ==, "bar"); /* BUG */ + g_assert(!qemu_opts_id(opts)); g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar"); /* Anti-social ID */ @@ -728,6 +728,47 @@ static void test_opts_parse_size(void) qemu_opts_reset(&opts_list_02); } +static void test_has_help_option(void) +{ + static const struct { + const char *params; + /* expected value of qemu_opt_has_help_opt() with implied=false */ + bool expect; + /* expected value of qemu_opt_has_help_opt() with implied=true */ + bool expect_implied; + } test[] = { + { "help", true, false }, + { "?", true, false }, + { "helpme", false, false }, + { "?me", false, false }, + { "a,help", true, true }, + { "a,?", true, true }, + { "a=0,help,b", true, true }, + { "a=0,?,b", true, true }, + { "help,b=1", true, false }, + { "?,b=1", true, false }, + { "a,b,,help", true, true }, + { "a,b,,?", true, true }, + }; + int i; + QemuOpts *opts; + + for (i = 0; i < ARRAY_SIZE(test); i++) { + g_assert_cmpint(has_help_option(test[i].params), + ==, test[i].expect); + opts = qemu_opts_parse(&opts_list_03, test[i].params, false, + &error_abort); + g_assert_cmpint(qemu_opt_has_help_opt(opts), + ==, test[i].expect); + qemu_opts_del(opts); + opts = qemu_opts_parse(&opts_list_03, test[i].params, true, + &error_abort); + g_assert_cmpint(qemu_opt_has_help_opt(opts), + ==, test[i].expect_implied); + qemu_opts_del(opts); + } +} + static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping) { int i = 0; @@ -990,6 +1031,7 @@ int main(int argc, char *argv[]) g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool); g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number); g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size); + g_test_add_func("/qemu-opts/has_help_option", test_has_help_option); g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null); g_test_add_func("/qemu-opts/append", test_opts_append); g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic); diff --git a/util/qemu-option.c b/util/qemu-option.c index 97172b5eaa..9542988183 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -165,48 +165,6 @@ void parse_option_size(const char *name, const char *value, *ret = size; } -bool has_help_option(const char *param) -{ - const char *p = param; - bool result = false; - - while (*p && !result) { - char *value; - - p = get_opt_value(p, &value); - if (*p) { - p++; - } - - result = is_help_option(value); - g_free(value); - } - - return result; -} - -bool is_valid_option_list(const char *p) -{ - char *value = NULL; - bool result = false; - - while (*p) { - p = get_opt_value(p, &value); - if ((*p && !*++p) || - (!*value || *value == ',')) { - goto out; - } - - g_free(value); - value = NULL; - } - - result = true; -out: - g_free(value); - return result; -} - static const char *opt_type_to_string(enum QemuOptType type) { switch (type) { @@ -539,7 +497,7 @@ int qemu_opt_unset(QemuOpts *opts, const char *name) } static void opt_set(QemuOpts *opts, const char *name, char *value, - bool prepend, bool *invalidp, Error **errp) + bool prepend, bool *help_wanted, Error **errp) { QemuOpt *opt; const QemuOptDesc *desc; @@ -549,8 +507,8 @@ static void opt_set(QemuOpts *opts, const char *name, char *value, if (!desc && !opts_accepts_any(opts)) { g_free(value); error_setg(errp, QERR_INVALID_PARAMETER, name); - if (invalidp) { - *invalidp = true; + if (help_wanted && is_help_option(name)) { + *help_wanted = true; } return; } @@ -805,61 +763,108 @@ void qemu_opts_print(QemuOpts *opts, const char *separator) } } +static const char *get_opt_name_value(const char *params, + const char *firstname, + char **name, char **value) +{ + const char *p, *pe, *pc; + + pe = strchr(params, '='); + pc = strchr(params, ','); + + if (!pe || (pc && pc < pe)) { + /* found "foo,more" */ + if (firstname) { + /* implicitly named first option */ + *name = g_strdup(firstname); + p = get_opt_value(params, value); + } else { + /* option without value, must be a flag */ + p = get_opt_name(params, name, ','); + if (strncmp(*name, "no", 2) == 0) { + memmove(*name, *name + 2, strlen(*name + 2) + 1); + *value = g_strdup("off"); + } else { + *value = g_strdup("on"); + } + } + } else { + /* found "foo=bar,more" */ + p = get_opt_name(params, name, '='); + assert(*p == '='); + p++; + p = get_opt_value(p, value); + } + + assert(!*p || *p == ','); + if (*p == ',') { + p++; + } + return p; +} + static void opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, bool prepend, - bool *invalidp, Error **errp) + bool *help_wanted, Error **errp) { - char *option = NULL; - char *value = NULL; - const char *p,*pe,*pc; Error *local_err = NULL; + char *option, *value; + const char *p; - for (p = params; *p != '\0'; p++) { - pe = strchr(p, '='); - pc = strchr(p, ','); - if (!pe || (pc && pc < pe)) { - /* found "foo,more" */ - if (p == params && firstname) { - /* implicitly named first option */ - option = g_strdup(firstname); - p = get_opt_value(p, &value); - } else { - /* option without value, probably a flag */ - p = get_opt_name(p, &option, ','); - if (strncmp(option, "no", 2) == 0) { - memmove(option, option+2, strlen(option+2)+1); - value = g_strdup("off"); - } else { - value = g_strdup("on"); - } - } - } else { - /* found "foo=bar,more" */ - p = get_opt_name(p, &option, '='); - assert(*p == '='); - p++; - p = get_opt_value(p, &value); + for (p = params; *p;) { + p = get_opt_name_value(p, firstname, &option, &value); + firstname = NULL; + + if (!strcmp(option, "id")) { + g_free(option); + g_free(value); + continue; } - if (strcmp(option, "id") != 0) { - /* store and parse */ - opt_set(opts, option, value, prepend, invalidp, &local_err); - value = NULL; - if (local_err) { - error_propagate(errp, local_err); - goto cleanup; - } + + opt_set(opts, option, value, prepend, help_wanted, &local_err); + g_free(option); + if (local_err) { + error_propagate(errp, local_err); + return; } - if (*p != ',') { - break; + } +} + +static char *opts_parse_id(const char *params) +{ + const char *p; + char *name, *value; + + for (p = params; *p;) { + p = get_opt_name_value(p, NULL, &name, &value); + if (!strcmp(name, "id")) { + g_free(name); + return value; } - g_free(option); + g_free(name); g_free(value); - option = value = NULL; } - cleanup: - g_free(option); - g_free(value); + return NULL; +} + +bool has_help_option(const char *params) +{ + const char *p; + char *name, *value; + bool ret; + + for (p = params; *p;) { + p = get_opt_name_value(p, NULL, &name, &value); + ret = is_help_option(name); + g_free(name); + g_free(value); + if (ret) { + return true; + } + } + + return false; } /** @@ -876,23 +881,16 @@ void qemu_opts_do_parse(QemuOpts *opts, const char *params, static QemuOpts *opts_parse(QemuOptsList *list, const char *params, bool permit_abbrev, bool defaults, - bool *invalidp, Error **errp) + bool *help_wanted, Error **errp) { const char *firstname; - char *id = NULL; - const char *p; + char *id = opts_parse_id(params); QemuOpts *opts; Error *local_err = NULL; assert(!permit_abbrev || list->implied_opt_name); firstname = permit_abbrev ? list->implied_opt_name : NULL; - if (strncmp(params, "id=", 3) == 0) { - get_opt_value(params + 3, &id); - } else if ((p = strstr(params, ",id=")) != NULL) { - get_opt_value(p + 4, &id); - } - /* * This code doesn't work for defaults && !list->merge_lists: when * params has no id=, and list has an element with !opts->id, it @@ -908,7 +906,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, return NULL; } - opts_do_parse(opts, params, firstname, defaults, invalidp, &local_err); + opts_do_parse(opts, params, firstname, defaults, help_wanted, &local_err); if (local_err) { error_propagate(errp, local_err); qemu_opts_del(opts); @@ -944,11 +942,11 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params, { Error *err = NULL; QemuOpts *opts; - bool invalidp = false; + bool help_wanted = false; - opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err); + opts = opts_parse(list, params, permit_abbrev, false, &help_wanted, &err); if (err) { - if (invalidp && has_help_option(params)) { + if (help_wanted) { qemu_opts_print_help(list, true); error_free(err); } else { |