Miscellaneous patches for 2020-04-29

-----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAl6pIewSHGFybWJydUBy
 ZWRoYXQuY29tAAoJEDhwtADrkYZTY+wP/jN6QXjmqY3hOXWw90pOsroVPNcBqlIN
 dtMWMQ48TZ5kL87UZHvm8OZmmwM/UaFbtmTMkWWfZNzNhIUQfgWqIIWYX+gPu9M3
 5XSvzT8rqJGrZQ51JwXV7WXWi44MzXuEDlK3ghRxt9lE2QLacC0g/ZSp1eBR07RG
 +dDIFbQhU7ZkYN4CWCwUcq9vA/U9ZHCRlgx4Mi7FRdEPis4dtbvBxucK/c2gh5OR
 /GWfQ2okx7ybKlob9mK7VllR99nzybYR5GtYb/aVAR7iqtrWQbaCGnqWYae2ZbI2
 0YgjxzjRKBLWmfODVf2ER/DcEbwrrxjPDjHBk6t4JFMnUsZtJBTCo9MXiTfjmgpv
 WRl/3TjArVUCp/bIp5IRdIuV7ld1Vz08IFo39FaZCMiz2izbte9jQOTJaMVw8ZY2
 Ehl/ei8/+Qf+NBW0uGuH++qQFHol9YJpjq7cAlt3fYL/bW0nkIOQnfIPSL561rTU
 qUSIyQMjupuGgKhTSoZlpFn+03j6QSNdkFqvK4bRR2dGnRKrt//kkyNgLQRqnAoF
 4CAFBTiG5i6JjH3QZwvcbgsmo6QuRsEsi58fQawNzz/JSY1VUgmbWXpsXDGJ1uRF
 i8ADz35FCxjCOyxbTNnkPzMpr3EJFBoReOsaH0zn6XYqxxROJ94M418VanEGl48G
 SsEarm+K5mP3
 =zCqZ
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-misc-2020-04-29' into staging

Miscellaneous patches for 2020-04-29

# gpg: Signature made Wed 29 Apr 2020 07:42:52 BST
# gpg:                using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg:                issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-misc-2020-04-29: (32 commits)
  qemu-option: pass NULL rather than 0 to the id of qemu_opts_set()
  libqos: Give get_machine_allocator() internal linkage
  fuzz: Simplify how we compute available machines and types
  Makefile: Drop unused, broken target recurse-fuzz
  smbus: Fix spd_data_generate() for number of banks > 2
  bamboo, sam460ex: Tidy up error message for unsupported RAM size
  smbus: Fix spd_data_generate() error API violation
  sam460ex: Suppress useless warning on -m 32 and -m 64
  qga: Fix qmp_guest_suspend_{disk, ram}() error handling
  qga: Fix qmp_guest_get_memory_blocks() error handling
  tests/test-logging: Fix test for -dfilter 0..0xffffffffffffffff
  migration/colo: Fix qmp_xen_colo_do_checkpoint() error handling
  io: Fix qio_channel_socket_close() error handling
  xen/pt: Fix flawed conversion to realize()
  virtio-net: Fix duplex=... and speed=... error handling
  bochs-display: Fix vgamem=SIZE error handling
  fdc: Fix fallback=auto error handling
  arm/virt: Fix virt_machine_device_plug_cb() error API violation
  cpus: Proper range-checking for -icount shift=N
  cpus: Fix configure_icount() error API violation
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-04-29 15:07:33 +01:00
commit 648db19685
37 changed files with 391 additions and 361 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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 }

52
cpus.c
View File

@ -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 (align && !sleep) {
error_setg(errp, "align=on and sleep=off are incompatible");
return;
}
if (strcmp(option, "auto") != 0) {
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;
}
} 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 = qemu_opt_get_bool(opts, "align", false);
icount_align_option = align;
if (icount_align_option && !icount_sleep) {
error_setg(errp, "align=on and sleep=off are incompatible");
}
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)) {
error_setg(errp, "icount: Invalid shift value");
}
if (time_shift >= 0) {
timers_state.icount_time_shift = time_shift;
use_icount = 1;
return;
} else if (icount_align_option) {
error_setg(errp, "shift=auto and align=on are incompatible");
} else if (!icount_sleep) {
error_setg(errp, "shift=auto and sleep=off are incompatible");
}
use_icount = 2;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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,

View File

@ -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) {

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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),

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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) */

View File

@ -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;

View File

@ -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);
}

View File

@ -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)) {

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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) |

View File

@ -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;
MachineInfoList *mach_info;
ObjectTypeInfoList *type_info;
qmp_marshal_query_machines(NULL, &response, &error_abort);
lst = qobject_to(QList, response);
apply_to_qlist(lst, true);
mach_info = qmp_query_machines(&error_abort);
machines_apply_to_node(mach_info);
qapi_free_MachineInfoList(mach_info);
qobject_unref(response);
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);
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;

View File

@ -29,66 +29,44 @@
#include "libqos/qgraph_internal.h"
#include "libqos/qos_external.h"
void apply_to_node(const char *name, bool is_machine, bool is_abstract)
static void machine_apply_to_node(const char *name)
{
char *machine_name = NULL;
if (is_machine) {
const char *arch = qtest_get_arch();
machine_name = g_strconcat(arch, "/", name, NULL);
name = machine_name;
char *machine_name = g_strconcat(qtest_get_arch(), "/", name, NULL);
qos_graph_node_set_availability(machine_name, true);
g_free(machine_name);
}
void machines_apply_to_node(MachineInfoList *mach_info)
{
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;
ObjectTypeInfoList *tail;
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;
}
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");
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 void opts_do_parse(QemuOpts *opts, const char *params,
const char *firstname, bool prepend,
bool *invalidp, Error **errp)
static const char *get_opt_name_value(const char *params,
const char *firstname,
char **name, char **value)
{
char *option = NULL;
char *value = NULL;
const char *p,*pe,*pc;
Error *local_err = NULL;
const char *p, *pe, *pc;
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");
}
}
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 {
/* found "foo=bar,more" */
p = get_opt_name(p, &option, '=');
assert(*p == '=');
p++;
p = get_opt_value(p, &value);
}
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;
/* 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");
}
}
if (*p != ',') {
break;
}
g_free(option);
g_free(value);
option = value = NULL;
} else {
/* found "foo=bar,more" */
p = get_opt_name(params, name, '=');
assert(*p == '=');
p++;
p = get_opt_value(p, value);
}
cleanup:
g_free(option);
g_free(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 *help_wanted, Error **errp)
{
Error *local_err = NULL;
char *option, *value;
const char *p;
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;
}
opt_set(opts, option, value, prepend, help_wanted, &local_err);
g_free(option);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
}
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(name);
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 {