diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2010-03-17 09:44:37 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2010-03-17 09:44:37 -0500 |
commit | 4a39943bd1fd2ac7e3163f9d9b056394519661f3 (patch) | |
tree | eab01e0258d2344117873952b589bac333bb0ea3 | |
parent | 7d834c7450245335db0a7055ccdc783ccab21935 (diff) | |
parent | 8bc27249f0f62524887ea355a6604722edd276a9 (diff) |
Merge remote branch 'markus/qerror' into staging
-rw-r--r-- | Makefile.target | 1 | ||||
-rw-r--r-- | audio/audio.c | 4 | ||||
-rw-r--r-- | hw/pc.c | 35 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 14 | ||||
-rw-r--r-- | hw/pci.c | 14 | ||||
-rw-r--r-- | hw/qdev-properties.c | 36 | ||||
-rw-r--r-- | hw/qdev.c | 236 | ||||
-rw-r--r-- | hw/qdev.h | 2 | ||||
-rw-r--r-- | hw/scsi-bus.c | 4 | ||||
-rw-r--r-- | hw/scsi-disk.c | 7 | ||||
-rw-r--r-- | hw/scsi-generic.c | 9 | ||||
-rw-r--r-- | hw/usb-bus.c | 4 | ||||
-rw-r--r-- | hw/usb-msd.c | 4 | ||||
-rw-r--r-- | hw/usb-net.c | 2 | ||||
-rw-r--r-- | hw/usb-serial.c | 9 | ||||
-rw-r--r-- | hw/virtio-net.c | 5 | ||||
-rw-r--r-- | hw/virtio-pci.c | 4 | ||||
-rw-r--r-- | hw/virtio-serial-bus.c | 2 | ||||
-rw-r--r-- | monitor.c | 337 | ||||
-rw-r--r-- | monitor.h | 7 | ||||
-rw-r--r-- | net.c | 32 | ||||
-rw-r--r-- | net/dump.c | 5 | ||||
-rw-r--r-- | net/slirp.c | 28 | ||||
-rw-r--r-- | net/socket.c | 12 | ||||
-rw-r--r-- | net/tap-bsd.c | 7 | ||||
-rw-r--r-- | net/tap-linux.c | 9 | ||||
-rw-r--r-- | net/tap-solaris.c | 4 | ||||
-rw-r--r-- | net/tap-win32.c | 2 | ||||
-rw-r--r-- | net/tap.c | 3 | ||||
-rw-r--r-- | qemu-config.c | 56 | ||||
-rw-r--r-- | qemu-config.h | 3 | ||||
-rw-r--r-- | qemu-error.c | 227 | ||||
-rw-r--r-- | qemu-error.h | 47 | ||||
-rw-r--r-- | qemu-monitor.hx | 7 | ||||
-rw-r--r-- | qemu-option.c | 93 | ||||
-rw-r--r-- | qemu-option.h | 6 | ||||
-rw-r--r-- | qemu-tool.c | 30 | ||||
-rw-r--r-- | qerror.c | 83 | ||||
-rw-r--r-- | qerror.h | 51 | ||||
-rw-r--r-- | savevm.c | 27 | ||||
-rw-r--r-- | slirp/misc.c | 2 | ||||
-rw-r--r-- | sysemu.h | 13 | ||||
-rw-r--r-- | usb-linux.c | 8 | ||||
-rw-r--r-- | vl.c | 44 | ||||
-rw-r--r-- | vnc.c | 5 |
45 files changed, 1007 insertions, 533 deletions
diff --git a/Makefile.target b/Makefile.target index ab3c438fad..56c6652315 100644 --- a/Makefile.target +++ b/Makefile.target @@ -172,6 +172,7 @@ endif #CONFIG_BSD_USER ifdef CONFIG_SOFTMMU obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o +obj-y += qemu-error.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o diff --git a/audio/audio.c b/audio/audio.c index 2a20e5be1b..dbf0b96f33 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -330,10 +330,10 @@ void AUD_vlog (const char *cap, const char *fmt, va_list ap) { if (conf.log_to_monitor) { if (cap) { - monitor_printf(cur_mon, "%s: ", cap); + monitor_printf(default_mon, "%s: ", cap); } - monitor_vprintf(cur_mon, fmt, ap); + monitor_vprintf(default_mon, fmt, ap); } else { if (cap) { @@ -230,40 +230,40 @@ static int boot_device2nibble(char boot_device) return 0; } -/* copy/pasted from cmos_init, should be made a general function - and used there as well */ -static int pc_boot_set(void *opaque, const char *boot_device) +static int set_boot_dev(RTCState *s, const char *boot_device, int fd_bootchk) { - Monitor *mon = cur_mon; #define PC_MAX_BOOT_DEVICES 3 - RTCState *s = (RTCState *)opaque; int nbds, bds[3] = { 0, }; int i; nbds = strlen(boot_device); if (nbds > PC_MAX_BOOT_DEVICES) { - monitor_printf(mon, "Too many boot devices for PC\n"); + error_report("Too many boot devices for PC"); return(1); } for (i = 0; i < nbds; i++) { bds[i] = boot_device2nibble(boot_device[i]); if (bds[i] == 0) { - monitor_printf(mon, "Invalid boot device for PC: '%c'\n", - boot_device[i]); + error_report("Invalid boot device for PC: '%c'", + boot_device[i]); return(1); } } rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); - rtc_set_memory(s, 0x38, (bds[2] << 4)); + rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1)); return(0); } +static int pc_boot_set(void *opaque, const char *boot_device) +{ + return set_boot_dev(opaque, boot_device, 0); +} + /* hd_table must contain 4 block drivers */ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, DriveInfo **hd_table) { RTCState *s = rtc_state; - int nbds, bds[3] = { 0, }; int val; int fd0, fd1, nb; int i; @@ -302,22 +302,9 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, rtc_set_memory(s, 0x5f, smp_cpus - 1); /* set boot devices, and disable floppy signature check if requested */ -#define PC_MAX_BOOT_DEVICES 3 - nbds = strlen(boot_device); - if (nbds > PC_MAX_BOOT_DEVICES) { - fprintf(stderr, "Too many boot devices for PC\n"); + if (set_boot_dev(s, boot_device, fd_bootchk)) { exit(1); } - for (i = 0; i < nbds; i++) { - bds[i] = boot_device2nibble(boot_device[i]); - if (bds[i] == 0) { - fprintf(stderr, "Invalid boot device for PC: '%c'\n", - boot_device[i]); - exit(1); - } - } - rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); - rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1)); /* floppy type */ diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index bd82c6aab7..eb3701bc89 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -54,7 +54,7 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, return NULL; } - opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", NULL); + opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", 0); if (!opts) { monitor_printf(mon, "parsing network options '%s' failed\n", opts_str ? opts_str : ""); @@ -73,14 +73,15 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); } -static int scsi_hot_add(DeviceState *adapter, DriveInfo *dinfo, int printinfo) +static int scsi_hot_add(Monitor *mon, DeviceState *adapter, + DriveInfo *dinfo, int printinfo) { SCSIBus *scsibus; SCSIDevice *scsidev; scsibus = DO_UPCAST(SCSIBus, qbus, QLIST_FIRST(&adapter->child_bus)); if (!scsibus || strcmp(scsibus->qbus.info->name, "SCSI") != 0) { - qemu_error("Device is not a SCSI adapter\n"); + error_report("Device is not a SCSI adapter"); return -1; } @@ -97,7 +98,8 @@ static int scsi_hot_add(DeviceState *adapter, DriveInfo *dinfo, int printinfo) dinfo->unit = scsidev->id; if (printinfo) - qemu_error("OK bus %d, unit %d\n", scsibus->busnr, scsidev->id); + monitor_printf(mon, "OK bus %d, unit %d\n", + scsibus->busnr, scsidev->id); return 0; } @@ -131,7 +133,7 @@ void drive_hot_add(Monitor *mon, const QDict *qdict) monitor_printf(mon, "no pci device with address %s\n", pci_addr); goto err; } - if (scsi_hot_add(&dev->qdev, dinfo, 1) != 0) { + if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) { goto err; } break; @@ -203,7 +205,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, if (qdev_init(&dev->qdev) < 0) dev = NULL; if (dev && dinfo) { - if (scsi_hot_add(&dev->qdev, dinfo, 0) != 0) { + if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { qdev_unplug(&dev->qdev); dev = NULL; } @@ -589,12 +589,12 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, if (!bus->devices[devfn]) goto found; } - qemu_error("PCI: no devfn available for %s, all in use\n", name); + error_report("PCI: no devfn available for %s, all in use", name); return NULL; found: ; } else if (bus->devices[devfn]) { - qemu_error("PCI: devfn %d not available for %s, in use by %s\n", devfn, - name, bus->devices[devfn]->name); + error_report("PCI: devfn %d not available for %s, in use by %s", + devfn, name, bus->devices[devfn]->name); return NULL; } pci_dev->bus = bus; @@ -1476,8 +1476,8 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, bus = pci_get_bus_devfn(&devfn, devaddr); if (!bus) { - qemu_error("Invalid PCI device address %s for device %s\n", - devaddr, pci_nic_names[i]); + error_report("Invalid PCI device address %s for device %s", + devaddr, pci_nic_names[i]); return NULL; } @@ -1768,8 +1768,8 @@ static int pci_add_option_rom(PCIDevice *pdev) size = get_image_size(path); if (size < 0) { - qemu_error("%s: failed to find romfile \"%s\"\n", __FUNCTION__, - pdev->romfile); + error_report("%s: failed to find romfile \"%s\"", + __FUNCTION__, pdev->romfile); return -1; } if (size & (size - 1)) { diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 24671aff9f..92d6793747 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -402,17 +402,11 @@ PropertyInfo qdev_prop_vlan = { /* --- pointer --- */ -static int print_ptr(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - void **ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "<%p>", *ptr); -} - +/* Not a proper property, just for dirty hacks. TODO Remove it! */ PropertyInfo qdev_prop_ptr = { .name = "ptr", .type = PROP_TYPE_PTR, .size = sizeof(void*), - .print = print_ptr, }; /* --- mac address --- */ @@ -547,31 +541,31 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) int ret; prop = qdev_prop_find(dev, name); - if (!prop) { - fprintf(stderr, "property \"%s.%s\" not found\n", - dev->info->name, name); - return -1; - } - if (!prop->info->parse) { - fprintf(stderr, "property \"%s.%s\" has no parser\n", - dev->info->name, name); + /* + * TODO Properties without a parse method are just for dirty + * hacks. qdev_prop_ptr is the only such PropertyInfo. It's + * marked for removal. The test !prop->info->parse should be + * removed along with it. + */ + if (!prop || !prop->info->parse) { + qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name); return -1; } ret = prop->info->parse(dev, prop, value); if (ret < 0) { switch (ret) { case -EEXIST: - fprintf(stderr, "property \"%s.%s\": \"%s\" is already in use\n", - dev->info->name, name, value); + qerror_report(QERR_PROPERTY_VALUE_IN_USE, + dev->info->name, name, value); break; default: case -EINVAL: - fprintf(stderr, "property \"%s.%s\": failed to parse \"%s\"\n", - dev->info->name, name, value); + qerror_report(QERR_PROPERTY_VALUE_BAD, + dev->info->name, name, value); break; case -ENOENT: - fprintf(stderr, "property \"%s.%s\": could not find \"%s\"\n", - dev->info->name, name, value); + qerror_report(QERR_PROPERTY_VALUE_NOT_FOUND, + dev->info->name, name, value); break; } return -1; @@ -29,7 +29,6 @@ #include "qdev.h" #include "sysemu.h" #include "monitor.h" -#include "qerror.h" static int qdev_hotplug = 0; @@ -78,13 +77,32 @@ static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name) return NULL; } +static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info) +{ + DeviceState *dev; + + assert(bus->info == info->bus_info); + dev = qemu_mallocz(info->size); + dev->info = info; + dev->parent_bus = bus; + qdev_prop_set_defaults(dev, dev->info->props); + qdev_prop_set_defaults(dev, dev->parent_bus->info->props); + qdev_prop_set_globals(dev); + QLIST_INSERT_HEAD(&bus->children, dev, sibling); + if (qdev_hotplug) { + assert(bus->allow_hotplug); + dev->hotplugged = 1; + } + dev->state = DEV_STATE_CREATED; + return dev; +} + /* Create a new device. This only initializes the device state structure and allows properties to be set. qdev_init should be called to initialize the actual device emulation. */ DeviceState *qdev_create(BusState *bus, const char *name) { DeviceInfo *info; - DeviceState *dev; if (!bus) { if (!main_system_bus) { @@ -98,42 +116,23 @@ DeviceState *qdev_create(BusState *bus, const char *name) hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name); } - dev = qemu_mallocz(info->size); - dev->info = info; - dev->parent_bus = bus; - qdev_prop_set_defaults(dev, dev->info->props); - qdev_prop_set_defaults(dev, dev->parent_bus->info->props); - qdev_prop_set_globals(dev); - QLIST_INSERT_HEAD(&bus->children, dev, sibling); - if (qdev_hotplug) { - assert(bus->allow_hotplug); - dev->hotplugged = 1; - } - dev->state = DEV_STATE_CREATED; - return dev; + return qdev_create_from_info(bus, info); } -static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len) +static void qdev_print_devinfo(DeviceInfo *info) { - int pos = 0; - int ret; - - ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s", - info->name, info->bus_info->name); - pos += MIN(len-pos,ret); + error_printf("name \"%s\", bus %s", + info->name, info->bus_info->name); if (info->alias) { - ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias); - pos += MIN(len-pos,ret); + error_printf(", alias \"%s\"", info->alias); } if (info->desc) { - ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc); - pos += MIN(len-pos,ret); + error_printf(", desc \"%s\"", info->desc); } if (info->no_user) { - ret = snprintf(dest+pos, len-pos, ", no-user"); - pos += MIN(len-pos,ret); + error_printf(", no-user"); } - return pos; + error_printf("\n"); } static int set_property(const char *name, const char *value, void *opaque) @@ -146,8 +145,6 @@ static int set_property(const char *name, const char *value, void *opaque) return 0; if (qdev_prop_parse(dev, name, value) == -1) { - qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n", - name, value, dev->info->name); return -1; } return 0; @@ -157,14 +154,15 @@ int qdev_device_help(QemuOpts *opts) { const char *driver; DeviceInfo *info; - char msg[256]; Property *prop; driver = qemu_opt_get(opts, "driver"); if (driver && !strcmp(driver, "?")) { for (info = device_info_list; info != NULL; info = info->next) { - qdev_print_devinfo(info, msg, sizeof(msg)); - qemu_error("%s\n", msg); + if (info->no_user) { + continue; /* not available, don't show */ + } + qdev_print_devinfo(info); } return 1; } @@ -179,7 +177,16 @@ int qdev_device_help(QemuOpts *opts) } for (prop = info->props; prop && prop->name; prop++) { - qemu_error("%s.%s=%s\n", info->name, prop->name, prop->info->name); + /* + * TODO Properties without a parser are just for dirty hacks. + * qdev_prop_ptr is the only such PropertyInfo. It's marked + * for removal. This conditional should be removed along with + * it. + */ + if (!prop->info->parse) { + continue; /* no way to set it, don't show */ + } + error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name); } return 1; } @@ -193,19 +200,15 @@ DeviceState *qdev_device_add(QemuOpts *opts) driver = qemu_opt_get(opts, "driver"); if (!driver) { - qemu_error("-device: no driver specified\n"); + qerror_report(QERR_MISSING_PARAMETER, "driver"); return NULL; } /* find driver */ info = qdev_find_info(NULL, driver); - if (!info) { - qemu_error_new(QERR_DEVICE_NOT_FOUND, driver); - return NULL; - } - if (info->no_user) { - qemu_error("device \"%s\" can't be added via command line\n", - info->name); + if (!info || info->no_user) { + qerror_report(QERR_INVALID_PARAMETER, "driver"); + error_printf_unless_qmp("Try with argument '?' for a list.\n"); return NULL; } @@ -213,22 +216,29 @@ DeviceState *qdev_device_add(QemuOpts *opts) path = qemu_opt_get(opts, "bus"); if (path != NULL) { bus = qbus_find(path); + if (!bus) { + return NULL; + } + if (bus->info != info->bus_info) { + qerror_report(QERR_BAD_BUS_FOR_DEVICE, + driver, bus->info->name); + return NULL; + } } else { bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info); - } - if (!bus) { - qemu_error("Did not find %s bus for %s\n", - path ? path : info->bus_info->name, info->name); - return NULL; + if (!bus) { + qerror_report(QERR_NO_BUS_FOR_DEVICE, + info->name, info->bus_info->name); + return NULL; + } } if (qdev_hotplug && !bus->allow_hotplug) { - qemu_error("Bus %s does not support hotplugging\n", - bus->name); + qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); return NULL; } /* create device, set properties */ - qdev = qdev_create(bus, driver); + qdev = qdev_create_from_info(bus, info); id = qemu_opts_id(opts); if (id) { qdev->id = id; @@ -238,7 +248,7 @@ DeviceState *qdev_device_add(QemuOpts *opts) return NULL; } if (qdev_init(qdev) < 0) { - qemu_error("Error initializing device %s\n", driver); + qerror_report(QERR_DEVICE_INIT_FAILED, driver); return NULL; } qdev->opts = opts; @@ -277,8 +287,8 @@ int qdev_init(DeviceState *dev) int qdev_unplug(DeviceState *dev) { if (!dev->parent_bus->allow_hotplug) { - qemu_error("Bus %s does not support hotplugging\n", - dev->parent_bus->name); + error_report("Bus %s does not support hotplugging", + dev->parent_bus->name); return -1; } assert(dev->info->unplug != NULL); @@ -465,35 +475,33 @@ static DeviceState *qdev_find_recursive(BusState *bus, const char *id) return NULL; } -static void qbus_list_bus(DeviceState *dev, char *dest, int len) +static void qbus_list_bus(DeviceState *dev) { BusState *child; const char *sep = " "; - int pos = 0; - pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":", - dev->id ? dev->id : dev->info->name); + error_printf("child busses at \"%s\":", + dev->id ? dev->id : dev->info->name); QLIST_FOREACH(child, &dev->child_bus, sibling) { - pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name); + error_printf("%s\"%s\"", sep, child->name); sep = ", "; } + error_printf("\n"); } -static void qbus_list_dev(BusState *bus, char *dest, int len) +static void qbus_list_dev(BusState *bus) { DeviceState *dev; const char *sep = " "; - int pos = 0; - pos += snprintf(dest+pos, len-pos, "devices at \"%s\":", - bus->name); + error_printf("devices at \"%s\":", bus->name); QLIST_FOREACH(dev, &bus->children, sibling) { - pos += snprintf(dest+pos, len-pos, "%s\"%s\"", - sep, dev->info->name); + error_printf("%s\"%s\"", sep, dev->info->name); if (dev->id) - pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id); + error_printf("/\"%s\"", dev->id); sep = ", "; } + error_printf("\n"); } static BusState *qbus_find_bus(DeviceState *dev, char *elem) @@ -540,7 +548,7 @@ static BusState *qbus_find(const char *path) { DeviceState *dev; BusState *bus; - char elem[128], msg[256]; + char elem[128]; int pos, len; /* find start element */ @@ -549,62 +557,75 @@ static BusState *qbus_find(const char *path) pos = 0; } else { if (sscanf(path, "%127[^/]%n", elem, &len) != 1) { - qemu_error("path parse error (\"%s\")\n", path); - return NULL; + assert(!path[0]); + elem[0] = len = 0; } bus = qbus_find_recursive(main_system_bus, elem, NULL); if (!bus) { - qemu_error("bus \"%s\" not found\n", elem); + qerror_report(QERR_BUS_NOT_FOUND, elem); return NULL; } pos = len; } for (;;) { + assert(path[pos] == '/' || !path[pos]); + while (path[pos] == '/') { + pos++; + } if (path[pos] == '\0') { - /* we are done */ return bus; } /* find device */ - if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) { - qemu_error("path parse error (\"%s\" pos %d)\n", path, pos); - return NULL; + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; } pos += len; dev = qbus_find_dev(bus, elem); if (!dev) { - qbus_list_dev(bus, msg, sizeof(msg)); - qemu_error("device \"%s\" not found\n%s\n", elem, msg); + qerror_report(QERR_DEVICE_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_dev(bus); + } return NULL; } + + assert(path[pos] == '/' || !path[pos]); + while (path[pos] == '/') { + pos++; + } if (path[pos] == '\0') { /* last specified element is a device. If it has exactly * one child bus accept it nevertheless */ switch (dev->num_child_bus) { case 0: - qemu_error("device has no child bus (%s)\n", path); + qerror_report(QERR_DEVICE_NO_BUS, elem); return NULL; case 1: return QLIST_FIRST(&dev->child_bus); default: - qbus_list_bus(dev, msg, sizeof(msg)); - qemu_error("device has multiple child busses (%s)\n%s\n", - path, msg); + qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } return NULL; } } /* find bus */ - if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) { - qemu_error("path parse error (\"%s\" pos %d)\n", path, pos); - return NULL; + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; } pos += len; bus = qbus_find_bus(dev, elem); if (!bus) { - qbus_list_bus(dev, msg, sizeof(msg)); - qemu_error("child bus \"%s\" not found\n%s\n", elem, msg); + qerror_report(QERR_BUS_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } return NULL; } } @@ -684,6 +705,12 @@ static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, if (!props) return; while (props->name) { + /* + * TODO Properties without a print method are just for dirty + * hacks. qdev_prop_ptr is the only such PropertyInfo. It's + * marked for removal. The test props->info->print should be + * removed along with it. + */ if (props->info->print) { props->info->print(dev, props, buf, sizeof(buf)); qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf); @@ -735,25 +762,42 @@ void do_info_qtree(Monitor *mon) void do_info_qdm(Monitor *mon) { DeviceInfo *info; - char msg[256]; for (info = device_info_list; info != NULL; info = info->next) { - qdev_print_devinfo(info, msg, sizeof(msg)); - monitor_printf(mon, "%s\n", msg); + qdev_print_devinfo(info); } } -void do_device_add(Monitor *mon, const QDict *qdict) +/** + * do_device_add(): Add a device + * + * Argument qdict contains + * - "driver": the name of the new device's driver + * - "bus": the device's parent bus (device tree path) + * - "id": the device's ID (must be unique) + * - device properties + * + * Example: + * + * { "driver": "usb-net", "id": "eth1", "netdev": "netdev1" } + */ +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) { QemuOpts *opts; - opts = qemu_opts_parse(&qemu_device_opts, - qdict_get_str(qdict, "config"), "driver"); - if (opts) { - if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) { - qemu_opts_del(opts); - } + opts = qemu_opts_from_qdict(&qemu_device_opts, qdict); + if (!opts) { + return -1; + } + if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { + qemu_opts_del(opts); + return 0; + } + if (!qdev_device_add(opts)) { + qemu_opts_del(opts); + return -1; } + return 0; } void do_device_del(Monitor *mon, const QDict *qdict) @@ -763,7 +807,7 @@ void do_device_del(Monitor *mon, const QDict *qdict) dev = qdev_find_recursive(main_system_bus, id); if (NULL == dev) { - qemu_error("Device '%s' not found\n", id); + error_report("Device '%s' not found", id); return; } qdev_unplug(dev); @@ -175,7 +175,7 @@ void qbus_free(BusState *bus); void do_info_qtree(Monitor *mon); void do_info_qdm(Monitor *mon); -void do_device_add(Monitor *mon, const QDict *qdict); +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); void do_device_del(Monitor *mon, const QDict *qdict); /*** qdev-properties.c ***/ diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index a2f9cc1cc3..383240bc07 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1,5 +1,5 @@ #include "hw.h" -#include "sysemu.h" +#include "qemu-error.h" #include "scsi.h" #include "scsi-defs.h" #include "block.h" @@ -41,7 +41,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) } } if (dev->id >= bus->ndev) { - qemu_error("bad scsi device id: %d\n", dev->id); + error_report("bad scsi device id: %d", dev->id); goto err; } diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 8f7ffc143d..da56d2bc1c 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -19,8 +19,6 @@ * the host adapter emulator. */ -#include <qemu-common.h> -#include <sysemu.h> //#define DEBUG_SCSI #ifdef DEBUG_SCSI @@ -34,6 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "qemu-common.h" +#include "qemu-error.h" #include "block.h" #include "scsi.h" #include "scsi-defs.h" @@ -1026,13 +1025,13 @@ static int scsi_disk_initfn(SCSIDevice *dev) uint64_t nb_sectors; if (!s->qdev.conf.dinfo || !s->qdev.conf.dinfo->bdrv) { - qemu_error("scsi-disk: drive property not set\n"); + error_report("scsi-disk: drive property not set"); return -1; } s->bs = s->qdev.conf.dinfo->bdrv; if (bdrv_is_sg(s->bs)) { - qemu_error("scsi-disk: unwanted /dev/sg*\n"); + error_report("scsi-disk: unwanted /dev/sg*"); return -1; } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index de778efa3b..c9aa853cc4 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -12,6 +12,7 @@ */ #include "qemu-common.h" +#include "qemu-error.h" #include "block.h" #include "scsi.h" @@ -463,27 +464,27 @@ static int scsi_generic_initfn(SCSIDevice *dev) struct sg_scsi_id scsiid; if (!s->qdev.conf.dinfo || !s->qdev.conf.dinfo->bdrv) { - qemu_error("scsi-generic: drive property not set\n"); + error_report("scsi-generic: drive property not set"); return -1; } s->bs = s->qdev.conf.dinfo->bdrv; /* check we are really using a /dev/sg* file */ if (!bdrv_is_sg(s->bs)) { - qemu_error("scsi-generic: not /dev/sg*\n"); + error_report("scsi-generic: not /dev/sg*"); return -1; } /* check we are using a driver managing SG_IO (version 3 and after */ if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 || sg_version < 30000) { - qemu_error("scsi-generic: scsi generic interface too old\n"); + error_report("scsi-generic: scsi generic interface too old"); return -1; } /* get LUN of the /dev/sg? */ if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) { - qemu_error("scsi-generic: SG_GET_SCSI_ID ioctl failed\n"); + error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed"); return -1; } diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 7c823147ab..e2d87f2d1f 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -291,14 +291,14 @@ USBDevice *usbdevice_create(const char *cmdline) if (info == NULL) { #if 0 /* no error because some drivers are not converted (yet) */ - qemu_error("usbdevice %s not found\n", driver); + error_report("usbdevice %s not found", driver); #endif return NULL; } if (!usb->usbdevice_init) { if (params) { - qemu_error("usbdevice %s accepts no params\n", driver); + error_report("usbdevice %s accepts no params", driver); return NULL; } return usb_create_simple(bus, usb->qdev.name); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 1a11bc557e..e90a47e0e1 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -524,7 +524,7 @@ static int usb_msd_initfn(USBDevice *dev) MSDState *s = DO_UPCAST(MSDState, dev, dev); if (!s->conf.dinfo || !s->conf.dinfo->bdrv) { - qemu_error("usb-msd: drive property not set\n"); + error_report("usb-msd: drive property not set"); return -1; } @@ -535,7 +535,7 @@ static int usb_msd_initfn(USBDevice *dev) usb_msd_handle_reset(dev); if (bdrv_key_required(s->conf.dinfo->bdrv)) { - if (s->dev.qdev.hotplugged) { + if (cur_mon) { monitor_read_bdrv_key_start(cur_mon, s->conf.dinfo->bdrv, usb_msd_password_cb, s); s->dev.auto_attach = 0; diff --git a/hw/usb-net.c b/hw/usb-net.c index 6875f112fe..4c17435c84 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1478,7 +1478,7 @@ static USBDevice *usb_net_init(const char *cmdline) QemuOpts *opts; int idx; - opts = qemu_opts_parse(&qemu_net_opts, cmdline, NULL); + opts = qemu_opts_parse(&qemu_net_opts, cmdline, 0); if (!opts) { return NULL; } diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 1410b11b2b..69f0e44f11 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -9,6 +9,7 @@ */ #include "qemu-common.h" +#include "qemu-error.h" #include "usb.h" #include "qemu-char.h" @@ -564,26 +565,26 @@ static USBDevice *usb_serial_init(const char *filename) if (strstart(filename, "vendorid=", &p)) { vendorid = strtol(p, &e, 16); if (e == p || (*e && *e != ',' && *e != ':')) { - qemu_error("bogus vendor ID %s\n", p); + error_report("bogus vendor ID %s", p); return NULL; } filename = e; } else if (strstart(filename, "productid=", &p)) { productid = strtol(p, &e, 16); if (e == p || (*e && *e != ',' && *e != ':')) { - qemu_error("bogus product ID %s\n", p); + error_report("bogus product ID %s", p); return NULL; } filename = e; } else { - qemu_error("unrecognized serial USB option %s\n", filename); + error_report("unrecognized serial USB option %s", filename); return NULL; } while(*filename == ',') filename++; } if (!*filename) { - qemu_error("character device specification needed\n"); + error_report("character device specification needed"); return NULL; } filename++; diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 5c0093e879..be33c68bbc 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -15,6 +15,7 @@ #include "net.h" #include "net/checksum.h" #include "net/tap.h" +#include "qemu-error.h" #include "qemu-timer.h" #include "virtio-net.h" @@ -764,7 +765,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (version_id >= 7) { if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) { - qemu_error("virtio-net: saved image requires vnet_hdr=on\n"); + error_report("virtio-net: saved image requires vnet_hdr=on"); return -1; } @@ -793,7 +794,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (version_id >= 11) { if (qemu_get_byte(f) && !peer_has_ufo(n)) { - qemu_error("virtio-net: saved image requires TUN_F_UFO support\n"); + error_report("virtio-net: saved image requires TUN_F_UFO support"); return -1; } } diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 799f664d8e..6eb19cdf8c 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -19,7 +19,7 @@ #include "virtio-blk.h" #include "virtio-net.h" #include "pci.h" -#include "sysemu.h" +#include "qemu-error.h" #include "msix.h" #include "net.h" #include "block_int.h" @@ -459,7 +459,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) proxy->class_code = PCI_CLASS_STORAGE_SCSI; if (!proxy->block.dinfo) { - qemu_error("virtio-blk-pci: drive property not set\n"); + error_report("virtio-blk-pci: drive property not set"); return -1; } vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block); diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index d0e021932c..17c1ec1d06 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -485,7 +485,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0); if (port->vser->config.nr_ports == bus->max_nr_ports && !plugging_port0) { - qemu_error("virtio-serial-bus: Maximum device limit reached\n"); + error_report("virtio-serial-bus: Maximum device limit reached"); return -1; } dev->info = info; @@ -67,6 +67,11 @@ * 'F' filename * 'B' block device name * 's' string (accept optional quote) + * 'O' option string of the form NAME=VALUE,... + * parsed according to QemuOptsList given by its name + * Example: 'device:O' uses qemu_device_opts. + * Restriction: only lists with empty desc are supported + * TODO lift the restriction * 'i' 32 bit integer * 'l' target long (32 or 64 bit) * 'M' just like 'l', except in user mode the value is @@ -177,7 +182,8 @@ static QLIST_HEAD(mon_list, Monitor) mon_list; static const mon_cmd_t mon_cmds[]; static const mon_cmd_t info_cmds[]; -Monitor *cur_mon = NULL; +Monitor *cur_mon; +Monitor *default_mon; static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque); @@ -193,6 +199,12 @@ static inline int monitor_ctrl_mode(const Monitor *mon) return (mon->flags & MONITOR_USE_CONTROL); } +/* Return non-zero iff we have a current monitor, and it is in QMP mode. */ +int monitor_cur_is_qmp(void) +{ + return cur_mon && monitor_ctrl_mode(cur_mon); +} + static void monitor_read_command(Monitor *mon, int show_prompt) { if (!mon->rs) @@ -207,7 +219,7 @@ static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, void *opaque) { if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_MISSING_PARAMETER, "password"); + qerror_report(QERR_MISSING_PARAMETER, "password"); return -EINVAL; } else if (mon->rs) { readline_start(mon->rs, "Password: ", 1, readline_func, opaque); @@ -606,7 +618,7 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data) if (cmd->name == NULL) { if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, item); + qerror_report(QERR_COMMAND_NOT_FOUND, item); return -1; } goto help; @@ -638,7 +650,7 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data) } else { if (monitor_ctrl_mode(mon)) { /* handler not converted yet */ - qemu_error_new(QERR_COMMAND_NOT_FOUND, item); + qerror_report(QERR_COMMAND_NOT_FOUND, item); return -1; } else { cmd->mhandler.info(mon); @@ -960,7 +972,7 @@ static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data) { int index = qdict_get_int(qdict, "index"); if (mon_set_cpu(index) < 0) { - qemu_error_new(QERR_INVALID_PARAMETER, "index"); + qerror_report(QERR_INVALID_PARAMETER, "index"); return -1; } return 0; @@ -1013,12 +1025,12 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force) if (bdrv_is_inserted(bs)) { if (!force) { if (!bdrv_is_removable(bs)) { - qemu_error_new(QERR_DEVICE_NOT_REMOVABLE, + qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs)); return -1; } if (bdrv_is_locked(bs)) { - qemu_error_new(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); + qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); return -1; } } @@ -1035,7 +1047,7 @@ static int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) bs = bdrv_find(filename); if (!bs) { - qemu_error_new(QERR_DEVICE_NOT_FOUND, filename); + qerror_report(QERR_DEVICE_NOT_FOUND, filename); return -1; } return eject_device(mon, bs, force); @@ -1048,12 +1060,12 @@ static int do_block_set_passwd(Monitor *mon, const QDict *qdict, bs = bdrv_find(qdict_get_str(qdict, "device")); if (!bs) { - qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); + qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); return -1; } if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) { - qemu_error_new(QERR_INVALID_PASSWORD); + qerror_report(QERR_INVALID_PASSWORD); return -1; } @@ -1068,13 +1080,13 @@ static int do_change_block(Monitor *mon, const char *device, bs = bdrv_find(device); if (!bs) { - qemu_error_new(QERR_DEVICE_NOT_FOUND, device); + qerror_report(QERR_DEVICE_NOT_FOUND, device); return -1; } if (fmt) { drv = bdrv_find_whitelisted_format(fmt); if (!drv) { - qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt); + qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt); return -1; } } @@ -1090,7 +1102,7 @@ static int do_change_block(Monitor *mon, const char *device, static int change_vnc_password(const char *password) { if (vnc_display_password(NULL, password) < 0) { - qemu_error_new(QERR_SET_PASSWD_FAILED); + qerror_report(QERR_SET_PASSWD_FAILED); return -1; } @@ -1118,7 +1130,7 @@ static int do_change_vnc(Monitor *mon, const char *target, const char *arg) } } else { if (vnc_display_open(NULL, target) < 0) { - qemu_error_new(QERR_VNC_SERVER_FAILED, target); + qerror_report(QERR_VNC_SERVER_FAILED, target); return -1; } } @@ -1490,7 +1502,7 @@ static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data) f = fopen(filename, "wb"); if (!f) { - qemu_error_new(QERR_OPEN_FILE_FAILED, filename); + qerror_report(QERR_OPEN_FILE_FAILED, filename); return -1; } while (size != 0) { @@ -1526,7 +1538,7 @@ static int do_physical_memory_save(Monitor *mon, const QDict *qdict, f = fopen(filename, "wb"); if (!f) { - qemu_error_new(QERR_OPEN_FILE_FAILED, filename); + qerror_report(QERR_OPEN_FILE_FAILED, filename); return -1; } while (size != 0) { @@ -2300,13 +2312,13 @@ static int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque) int ret; if (kvm_enabled() && !kvm_has_sync_mmu()) { - qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); + qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); return -1; } ret = qemu_balloon_status(cb, opaque); if (!ret) { - qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon"); + qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); return -1; } @@ -2322,13 +2334,13 @@ static int do_balloon(Monitor *mon, const QDict *params, int ret; if (kvm_enabled() && !kvm_has_sync_mmu()) { - qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); + qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); return -1; } ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque); if (ret == 0) { - qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon"); + qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); return -1; } @@ -2469,21 +2481,21 @@ static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data) fd = qemu_chr_get_msgfd(mon->chr); if (fd == -1) { - qemu_error_new(QERR_FD_NOT_SUPPLIED); + qerror_report(QERR_FD_NOT_SUPPLIED); return -1; } if (qemu_isdigit(fdname[0])) { - qemu_error_new(QERR_INVALID_PARAMETER, "fdname"); + qerror_report(QERR_INVALID_PARAMETER, "fdname"); return -1; } fd = dup(fd); if (fd == -1) { if (errno == EMFILE) - qemu_error_new(QERR_TOO_MANY_FILES); + qerror_report(QERR_TOO_MANY_FILES); else - qemu_error_new(QERR_UNDEFINED_ERROR); + qerror_report(QERR_UNDEFINED_ERROR); return -1; } @@ -2522,7 +2534,7 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data) return 0; } - qemu_error_new(QERR_FD_NOT_FOUND, fdname); + qerror_report(QERR_FD_NOT_FOUND, fdname); return -1; } @@ -2533,7 +2545,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict) vm_stop(0); - if (load_vmstate(mon, name) >= 0 && saved_vm_running) + if (load_vmstate(name) >= 0 && saved_vm_running) vm_start(); } @@ -3638,6 +3650,31 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, qdict_put(qdict, key, qstring_from_str(buf)); } break; + case 'O': + { + QemuOptsList *opts_list; + QemuOpts *opts; + + opts_list = qemu_find_opts(key); + if (!opts_list || opts_list->desc->name) { + goto bad_type; + } + while (qemu_isspace(*p)) { + p++; + } + if (!*p) + break; + if (get_str(buf, sizeof(buf), &p) < 0) { + goto fail; + } + opts = qemu_opts_parse(opts_list, buf, 1); + if (!opts) { + goto fail; + } + qemu_opts_to_qdict(opts, qdict); + qemu_opts_del(opts); + } + break; case '/': { int count, format, size; @@ -3857,11 +3894,16 @@ fail: return NULL; } -static void monitor_print_error(Monitor *mon) +void monitor_set_error(Monitor *mon, QError *qerror) { - qerror_print(mon->error); - QDECREF(mon->error); - mon->error = NULL; + /* report only the first error */ + if (!mon->error) { + mon->error = qerror; + } else { + MON_DEBUG("Additional error report at %s:%d\n", + qerror->file, qerror->linenr); + QDECREF(qerror); + } } static int is_async_return(const QObject *data) @@ -3875,45 +3917,49 @@ static int is_async_return(const QObject *data) static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret) { - if (ret && !monitor_has_error(mon)) { - /* - * If it returns failure, it must have passed on error. - * - * Action: Report an internal error to the client if in QMP. - */ - if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_UNDEFINED_ERROR); + if (monitor_ctrl_mode(mon)) { + if (ret && !monitor_has_error(mon)) { + /* + * If it returns failure, it must have passed on error. + * + * Action: Report an internal error to the client if in QMP. + */ + qerror_report(QERR_UNDEFINED_ERROR); + MON_DEBUG("command '%s' returned failure but did not pass an error\n", + cmd->name); } - MON_DEBUG("command '%s' returned failure but did not pass an error\n", - cmd->name); - } #ifdef CONFIG_DEBUG_MONITOR - if (!ret && monitor_has_error(mon)) { - /* - * If it returns success, it must not have passed an error. - * - * Action: Report the passed error to the client. - */ - MON_DEBUG("command '%s' returned success but passed an error\n", - cmd->name); - } + if (!ret && monitor_has_error(mon)) { + /* + * If it returns success, it must not have passed an error. + * + * Action: Report the passed error to the client. + */ + MON_DEBUG("command '%s' returned success but passed an error\n", + cmd->name); + } - if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) { - /* - * Handlers should not call Monitor print functions. - * - * Action: Ignore them in QMP. - * - * (XXX: we don't check any 'info' or 'query' command here - * because the user print function _is_ called by do_info(), hence - * we will trigger this check. This problem will go away when we - * make 'query' commands real and kill do_info()) - */ - MON_DEBUG("command '%s' called print functions %d time(s)\n", - cmd->name, mon_print_count_get(mon)); - } + if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) { + /* + * Handlers should not call Monitor print functions. + * + * Action: Ignore them in QMP. + * + * (XXX: we don't check any 'info' or 'query' command here + * because the user print function _is_ called by do_info(), hence + * we will trigger this check. This problem will go away when we + * make 'query' commands real and kill do_info()) + */ + MON_DEBUG("command '%s' called print functions %d time(s)\n", + cmd->name, mon_print_count_get(mon)); + } #endif + } else { + assert(!monitor_has_error(mon)); + QDECREF(mon->error); + mon->error = NULL; + } } static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd, @@ -3958,8 +4004,6 @@ static void handle_user_command(Monitor *mon, const char *cmdline) if (!cmd) goto out; - qemu_errors_to_mon(mon); - if (monitor_handler_is_async(cmd)) { user_async_cmd_handler(mon, cmd, qdict); } else if (monitor_handler_ported(cmd)) { @@ -3968,11 +4012,6 @@ static void handle_user_command(Monitor *mon, const char *cmdline) cmd->mhandler.cmd(mon, qdict); } - if (monitor_has_error(mon)) - monitor_print_error(mon); - - qemu_errors_to_previous(); - out: QDECREF(qdict); } @@ -4209,7 +4248,7 @@ typedef struct CmdArgs { static int check_opt(const CmdArgs *cmd_args, const char *name, QDict *args) { if (!cmd_args->optional) { - qemu_error_new(QERR_MISSING_PARAMETER, name); + qerror_report(QERR_MISSING_PARAMETER, name); return -1; } @@ -4242,7 +4281,7 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) case 'B': case 's': if (qobject_type(value) != QTYPE_QSTRING) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "string"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "string"); return -1; } break; @@ -4253,11 +4292,11 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) for (i = 0; keys[i]; i++) { QObject *obj = qdict_get(args, keys[i]); if (!obj) { - qemu_error_new(QERR_MISSING_PARAMETER, name); + qerror_report(QERR_MISSING_PARAMETER, name); return -1; } if (qobject_type(obj) != QTYPE_QINT) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int"); return -1; } } @@ -4267,21 +4306,21 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) case 'l': case 'M': if (qobject_type(value) != QTYPE_QINT) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int"); return -1; } break; case 'b': case 'T': if (qobject_type(value) != QTYPE_QINT && qobject_type(value) != QTYPE_QFLOAT) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "number"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "number"); return -1; } break; case '-': if (qobject_type(value) != QTYPE_QINT && qobject_type(value) != QTYPE_QBOOL) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "bool"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "bool"); return -1; } if (qobject_type(value) == QTYPE_QBOOL) { @@ -4290,6 +4329,7 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) qint_from_int(qbool_get_int(qobject_to_qbool(value)))); } break; + case 'O': default: /* impossible */ abort(); @@ -4304,6 +4344,12 @@ static void cmd_args_init(CmdArgs *cmd_args) cmd_args->type = cmd_args->flag = cmd_args->optional = 0; } +static int check_opts(QemuOptsList *opts_list, QDict *args) +{ + assert(!opts_list->desc->name); + return 0; +} + /* * This is not trivial, we have to parse Monitor command's argument * type syntax to be able to check the arguments provided by clients. @@ -4316,6 +4362,7 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) int err; const char *p; CmdArgs cmd_args; + QemuOptsList *opts_list; if (cmd->args_type == NULL) { return (qdict_size(args) == 0 ? 0 : -1); @@ -4323,6 +4370,7 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) err = 0; cmd_args_init(&cmd_args); + opts_list = NULL; for (p = cmd->args_type;; p++) { if (*p == ':') { @@ -4331,16 +4379,23 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) if (cmd_args.type == '-') { cmd_args.flag = *p++; cmd_args.optional = 1; + } else if (cmd_args.type == 'O') { + opts_list = qemu_find_opts(qstring_get_str(cmd_args.name)); + assert(opts_list); } else if (*p == '?') { cmd_args.optional = 1; p++; } assert(*p == ',' || *p == '\0'); - err = check_arg(&cmd_args, args); - - QDECREF(cmd_args.name); - cmd_args_init(&cmd_args); + if (opts_list) { + err = check_opts(opts_list, args); + opts_list = NULL; + } else { + err = check_arg(&cmd_args, args); + QDECREF(cmd_args.name); + cmd_args_init(&cmd_args); + } if (err < 0) { break; @@ -4374,15 +4429,14 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) const char *cmd_name, *info_item; args = NULL; - qemu_errors_to_mon(mon); obj = json_parser_parse(tokens, NULL); if (!obj) { // FIXME: should be triggered in json_parser_parse() - qemu_error_new(QERR_JSON_PARSING); + qerror_report(QERR_JSON_PARSING); goto err_out; } else if (qobject_type(obj) != QTYPE_QDICT) { - qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "object"); + qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object"); qobject_decref(obj); goto err_out; } @@ -4394,17 +4448,17 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) obj = qdict_get(input, "execute"); if (!obj) { - qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "execute"); + qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute"); goto err_input; } else if (qobject_type(obj) != QTYPE_QSTRING) { - qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "string"); + qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "string"); goto err_input; } cmd_name = qstring_get_str(qobject_to_qstring(obj)); if (invalid_qmp_mode(mon, cmd_name)) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_input; } @@ -4413,7 +4467,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) * converted into 'query-' commands */ if (compare_cmd(cmd_name, "info")) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_input; } else if (strstart(cmd_name, "query-", &info_item)) { cmd = monitor_find_command("info"); @@ -4422,7 +4476,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) } else { cmd = monitor_find_command(cmd_name); if (!cmd || !monitor_handler_ported(cmd)) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_input; } } @@ -4455,7 +4509,6 @@ err_out: monitor_protocol_emitter(mon, NULL); out: QDECREF(args); - qemu_errors_to_previous(); } /** @@ -4624,8 +4677,8 @@ void monitor_init(CharDriverState *chr, int flags) } QLIST_INSERT_HEAD(&mon_list, mon, entry); - if (!cur_mon || (flags & MONITOR_IS_DEFAULT)) - cur_mon = mon; + if (!default_mon || (flags & MONITOR_IS_DEFAULT)) + default_mon = mon; } static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque) @@ -4656,7 +4709,7 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, } if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs)); + qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs)); return -1; } @@ -4673,99 +4726,3 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, return err; } - -typedef struct QemuErrorSink QemuErrorSink; -struct QemuErrorSink { - enum { - ERR_SINK_FILE, - ERR_SINK_MONITOR, - } dest; - union { - FILE *fp; - Monitor *mon; - }; - QemuErrorSink *previous; -}; - -static QemuErrorSink *qemu_error_sink; - -void qemu_errors_to_file(FILE *fp) -{ - QemuErrorSink *sink; - - sink = qemu_mallocz(sizeof(*sink)); - sink->dest = ERR_SINK_FILE; - sink->fp = fp; - sink->previous = qemu_error_sink; - qemu_error_sink = sink; -} - -void qemu_errors_to_mon(Monitor *mon) -{ - QemuErrorSink *sink; - - sink = qemu_mallocz(sizeof(*sink)); - sink->dest = ERR_SINK_MONITOR; - sink->mon = mon; - sink->previous = qemu_error_sink; - qemu_error_sink = sink; -} - -void qemu_errors_to_previous(void) -{ - QemuErrorSink *sink; - - assert(qemu_error_sink != NULL); - sink = qemu_error_sink; - qemu_error_sink = sink->previous; - qemu_free(sink); -} - -void qemu_error(const char *fmt, ...) -{ - va_list args; - - assert(qemu_error_sink != NULL); - switch (qemu_error_sink->dest) { - case ERR_SINK_FILE: - va_start(args, fmt); - vfprintf(qemu_error_sink->fp, fmt, args); - va_end(args); - break; - case ERR_SINK_MONITOR: - va_start(args, fmt); - monitor_vprintf(qemu_error_sink->mon, fmt, args); - va_end(args); - break; - } -} - -void qemu_error_internal(const char *file, int linenr, const char *func, - const char *fmt, ...) -{ - va_list va; - QError *qerror; - - assert(qemu_error_sink != NULL); - - va_start(va, fmt); - qerror = qerror_from_info(file, linenr, func, fmt, &va); - va_end(va); - - switch (qemu_error_sink->dest) { - case ERR_SINK_FILE: - qerror_print(qerror); - QDECREF(qerror); - break; - case ERR_SINK_MONITOR: - /* report only the first error */ - if (!qemu_error_sink->mon->error) { - qemu_error_sink->mon->error = qerror; - } else { - MON_DEBUG("Additional error report at %s:%d\n", qerror->file, - qerror->linenr); - QDECREF(qerror); - } - break; - } -} @@ -3,10 +3,13 @@ #include "qemu-common.h" #include "qemu-char.h" +#include "qemu-error.h" +#include "qerror.h" #include "qdict.h" #include "block.h" extern Monitor *cur_mon; +extern Monitor *default_mon; /* flags for monitor_init */ #define MONITOR_IS_DEFAULT 0x01 @@ -28,6 +31,8 @@ typedef enum MonitorEvent { QEVENT_MAX, } MonitorEvent; +int monitor_cur_is_qmp(void); + void monitor_protocol_event(MonitorEvent event, QObject *data); void monitor_init(CharDriverState *chr, int flags); @@ -48,4 +53,6 @@ void monitor_flush(Monitor *mon); typedef void (MonitorCompletion)(void *opaque, QObject *ret_data); +void monitor_set_error(Monitor *mon, QError *qerror); + #endif /* !MONITOR_H */ @@ -733,7 +733,7 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, return i; } - qemu_error("qemu: Unsupported NIC model: %s\n", nd->model); + error_report("qemu: Unsupported NIC model: %s", nd->model); return -1; } @@ -744,7 +744,7 @@ int net_handle_fd_param(Monitor *mon, const char *param) fd = monitor_get_fd(mon, param); if (fd == -1) { - qemu_error("No file descriptor named %s found", param); + error_report("No file descriptor named %s found", param); return -1; } @@ -765,7 +765,7 @@ static int net_init_nic(QemuOpts *opts, idx = nic_get_free_idx(); if (idx == -1 || nb_nics >= MAX_NICS) { - qemu_error("Too Many NICs\n"); + error_report("Too Many NICs"); return -1; } @@ -776,7 +776,7 @@ static int net_init_nic(QemuOpts *opts, if ((netdev = qemu_opt_get(opts, "netdev"))) { nd->netdev = qemu_find_netdev(netdev); if (!nd->netdev) { - qemu_error("netdev '%s' not found\n", netdev); + error_report("netdev '%s' not found", netdev); return -1; } } else { @@ -802,7 +802,7 @@ static int net_init_nic(QemuOpts *opts, if (qemu_opt_get(opts, "macaddr") && net_parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) { - qemu_error("invalid syntax for ethernet address\n"); + error_report("invalid syntax for ethernet address"); return -1; } @@ -810,7 +810,7 @@ static int net_init_nic(QemuOpts *opts, DEV_NVECTORS_UNSPECIFIED); if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && (nd->nvectors < 0 || nd->nvectors > 0x7ffffff)) { - qemu_error("invalid # of vectors: %d\n", nd->nvectors); + error_report("invalid # of vectors: %d", nd->nvectors); return -1; } @@ -1060,12 +1060,12 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) if (!is_netdev) { if (!type) { - qemu_error("No type specified for -net\n"); + error_report("No type specified for -net"); return -1; } } else { if (!type) { - qemu_error("No type specified for -netdev\n"); + error_report("No type specified for -netdev"); return -1; } @@ -1077,21 +1077,21 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) strcmp(type, "vde") != 0 && #endif strcmp(type, "socket") != 0) { - qemu_error("The '%s' network backend type is not valid with -netdev\n", - type); + error_report("The '%s' network backend type is not valid with -netdev", + type); return -1; } if (qemu_opt_get(opts, "vlan")) { - qemu_error("The 'vlan' parameter is not valid with -netdev\n"); + error_report("The 'vlan' parameter is not valid with -netdev"); return -1; } if (qemu_opt_get(opts, "name")) { - qemu_error("The 'name' parameter is not valid with -netdev\n"); + error_report("The 'name' parameter is not valid with -netdev"); return -1; } if (!qemu_opts_id(opts)) { - qemu_error("The id= parameter is required with -netdev\n"); + error_report("The id= parameter is required with -netdev"); return -1; } } @@ -1124,7 +1124,7 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) } } - qemu_error("Invalid -net type '%s'\n", type); + error_report("Invalid -net type '%s'", type); return -1; } @@ -1159,7 +1159,7 @@ void net_host_device_add(Monitor *mon, const QDict *qdict) return; } - opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", NULL); + opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", 0); if (!opts) { monitor_printf(mon, "parsing network options '%s' failed\n", opts_str ? opts_str : ""); @@ -1364,7 +1364,7 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg) } #endif - if (!qemu_opts_parse(opts_list, optarg, "type")) { + if (!qemu_opts_parse(opts_list, optarg, 1)) { return -1; } diff --git a/net/dump.c b/net/dump.c index d50b4eeac4..6db7ecf959 100644 --- a/net/dump.c +++ b/net/dump.c @@ -25,6 +25,7 @@ #include "dump.h" #include "qemu-common.h" #include "sysemu.h" +#include "qemu-error.h" #include "qemu-log.h" typedef struct DumpState { @@ -107,7 +108,7 @@ static int net_dump_init(VLANState *vlan, const char *device, fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); if (fd < 0) { - qemu_error("-net dump: can't open %s\n", filename); + error_report("-net dump: can't open %s", filename); return -1; } @@ -120,7 +121,7 @@ static int net_dump_init(VLANState *vlan, const char *device, hdr.linktype = 1; if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { - qemu_error("-net dump write error: %s\n", strerror(errno)); + error_report("-net dump write error: %s", strerror(errno)); close(fd); return -1; } diff --git a/net/slirp.c b/net/slirp.c index 7f846ec6f9..b41c60a39b 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -413,14 +413,14 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, guest_port) < 0) { - qemu_error("could not set up host forwarding rule '%s'\n", - redir_str); + error_report("could not set up host forwarding rule '%s'", + redir_str); return -1; } return 0; fail_syntax: - qemu_error("invalid host forwarding rule '%s'\n", redir_str); + error_report("invalid host forwarding rule '%s'", redir_str); return -1; } @@ -473,10 +473,10 @@ static void slirp_smb_cleanup(SlirpState *s) snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); ret = system(cmd); if (ret == -1 || !WIFEXITED(ret)) { - qemu_error("'%s' failed.\n", cmd); + error_report("'%s' failed.", cmd); } else if (WEXITSTATUS(ret)) { - qemu_error("'%s' failed. Error code: %d\n", - cmd, WEXITSTATUS(ret)); + error_report("'%s' failed. Error code: %d", + cmd, WEXITSTATUS(ret)); } s->smb_dir[0] = '\0'; } @@ -493,7 +493,7 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d", (long)getpid(), instance++); if (mkdir(s->smb_dir, 0700) < 0) { - qemu_error("could not create samba server dir '%s'\n", s->smb_dir); + error_report("could not create samba server dir '%s'", s->smb_dir); return -1; } snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); @@ -501,8 +501,8 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, f = fopen(smb_conf, "w"); if (!f) { slirp_smb_cleanup(s); - qemu_error("could not create samba server configuration file '%s'\n", - smb_conf); + error_report("could not create samba server configuration file '%s'", + smb_conf); return -1; } fprintf(f, @@ -533,7 +533,7 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { slirp_smb_cleanup(s); - qemu_error("conflicting/invalid smbserver address\n"); + error_report("conflicting/invalid smbserver address"); return -1; } return 0; @@ -618,14 +618,14 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port); fwd->hd = qemu_chr_open(buf, p, NULL); if (!fwd->hd) { - qemu_error("could not open guest forwarding device '%s'\n", buf); + error_report("could not open guest forwarding device '%s'", buf); qemu_free(fwd); return -1; } if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { - qemu_error("conflicting/invalid host:port in guest forwarding " - "rule '%s'\n", config_str); + error_report("conflicting/invalid host:port in guest forwarding " + "rule '%s'", config_str); qemu_free(fwd); return -1; } @@ -638,7 +638,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, return 0; fail_syntax: - qemu_error("invalid guest forwarding rule '%s'\n", config_str); + error_report("invalid guest forwarding rule '%s'", config_str); return -1; } diff --git a/net/socket.c b/net/socket.c index 442a9c790c..1c4e153e3f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -28,9 +28,9 @@ #include "net.h" #include "qemu-char.h" #include "qemu-common.h" +#include "qemu-error.h" #include "qemu-option.h" #include "qemu_socket.h" -#include "sysemu.h" typedef struct NetSocketState { VLANClientState nc; @@ -506,7 +506,7 @@ int net_init_socket(QemuOpts *opts, if (qemu_opt_get(opts, "listen") || qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "mcast")) { - qemu_error("listen=, connect= and mcast= is invalid with fd=\n"); + error_report("listen=, connect= and mcast= is invalid with fd="); return -1; } @@ -525,7 +525,7 @@ int net_init_socket(QemuOpts *opts, if (qemu_opt_get(opts, "fd") || qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "mcast")) { - qemu_error("fd=, connect= and mcast= is invalid with listen=\n"); + error_report("fd=, connect= and mcast= is invalid with listen="); return -1; } @@ -540,7 +540,7 @@ int net_init_socket(QemuOpts *opts, if (qemu_opt_get(opts, "fd") || qemu_opt_get(opts, "listen") || qemu_opt_get(opts, "mcast")) { - qemu_error("fd=, listen= and mcast= is invalid with connect=\n"); + error_report("fd=, listen= and mcast= is invalid with connect="); return -1; } @@ -555,7 +555,7 @@ int net_init_socket(QemuOpts *opts, if (qemu_opt_get(opts, "fd") || qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "listen")) { - qemu_error("fd=, connect= and listen= is invalid with mcast=\n"); + error_report("fd=, connect= and listen= is invalid with mcast="); return -1; } @@ -565,7 +565,7 @@ int net_init_socket(QemuOpts *opts, return -1; } } else { - qemu_error("-socket requires fd=, listen=, connect= or mcast=\n"); + error_report("-socket requires fd=, listen=, connect= or mcast="); return -1; } diff --git a/net/tap-bsd.c b/net/tap-bsd.c index 815997dc7b..e51d06848d 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -69,7 +69,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required } } if (fd < 0) { - qemu_error("warning: could not open %s (%s): no virtual network emulation\n", dname, strerror(errno)); + error_report("warning: could not open %s (%s): no virtual network emulation", + dname, strerror(errno)); return -1; } #else @@ -89,8 +90,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required *vnet_hdr = 0; if (vnet_hdr_required && !*vnet_hdr) { - qemu_error("vnet_hdr=1 requested, but no kernel " - "support for IFF_VNET_HDR available"); + error_report("vnet_hdr=1 requested, but no kernel " + "support for IFF_VNET_HDR available"); close(fd); return -1; } diff --git a/net/tap-linux.c b/net/tap-linux.c index 6af9e824d3..03b83012f8 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -31,6 +31,7 @@ #include "sysemu.h" #include "qemu-common.h" +#include "qemu-error.h" int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) { @@ -57,8 +58,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required } if (vnet_hdr_required && !*vnet_hdr) { - qemu_error("vnet_hdr=1 requested, but no kernel " - "support for IFF_VNET_HDR available"); + error_report("vnet_hdr=1 requested, but no kernel " + "support for IFF_VNET_HDR available"); close(fd); return -1; } @@ -96,7 +97,7 @@ int tap_set_sndbuf(int fd, QemuOpts *opts) } if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && qemu_opt_get(opts, "sndbuf")) { - qemu_error("TUNSETSNDBUF ioctl failed: %s\n", strerror(errno)); + error_report("TUNSETSNDBUF ioctl failed: %s", strerror(errno)); return -1; } return 0; @@ -107,7 +108,7 @@ int tap_probe_vnet_hdr(int fd) struct ifreq ifr; if (ioctl(fd, TUNGETIFF, &ifr) != 0) { - qemu_error("TUNGETIFF ioctl() failed: %s\n", strerror(errno)); + error_report("TUNGETIFF ioctl() failed: %s", strerror(errno)); return 0; } diff --git a/net/tap-solaris.c b/net/tap-solaris.c index 0b428617bd..50d127ad3f 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -186,8 +186,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required *vnet_hdr = 0; if (vnet_hdr_required && !*vnet_hdr) { - qemu_error("vnet_hdr=1 requested, but no kernel " - "support for IFF_VNET_HDR available"); + error_report("vnet_hdr=1 requested, but no kernel " + "support for IFF_VNET_HDR available"); close(fd); return -1; } diff --git a/net/tap-win32.c b/net/tap-win32.c index 8370c803bf..a5c2ce9e32 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -706,7 +706,7 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan ifname = qemu_opt_get(opts, "ifname"); if (!ifname) { - qemu_error("tap: no interface name\n"); + error_report("tap: no interface name"); return -1; } @@ -38,6 +38,7 @@ #include "sysemu.h" #include "qemu-char.h" #include "qemu-common.h" +#include "qemu-error.h" #include "net/tap-linux.h" @@ -393,7 +394,7 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan qemu_opt_get(opts, "script") || qemu_opt_get(opts, "downscript") || qemu_opt_get(opts, "vnet_hdr")) { - qemu_error("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=\n"); + error_report("ifname=, script=, downscript= and vnet_hdr= is invalid with fd="); return -1; } diff --git a/qemu-config.c b/qemu-config.c index 246fae6f99..150157ca7c 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -1,4 +1,5 @@ #include "qemu-common.h" +#include "qemu-error.h" #include "qemu-option.h" #include "qemu-config.h" #include "sysemu.h" @@ -85,6 +86,7 @@ QemuOptsList qemu_drive_opts = { QemuOptsList qemu_chardev_opts = { .name = "chardev", + .implied_opt_name = "backend", .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head), .desc = { { @@ -151,6 +153,7 @@ QemuOptsList qemu_chardev_opts = { QemuOptsList qemu_device_opts = { .name = "device", + .implied_opt_name = "driver", .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head), .desc = { /* @@ -164,6 +167,7 @@ QemuOptsList qemu_device_opts = { QemuOptsList qemu_netdev_opts = { .name = "netdev", + .implied_opt_name = "type", .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), .desc = { /* @@ -176,6 +180,7 @@ QemuOptsList qemu_netdev_opts = { QemuOptsList qemu_net_opts = { .name = "net", + .implied_opt_name = "type", .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), .desc = { /* @@ -226,6 +231,7 @@ QemuOptsList qemu_global_opts = { QemuOptsList qemu_mon_opts = { .name = "mon", + .implied_opt_name = "chardev", .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), .desc = { { @@ -303,7 +309,7 @@ static QemuOptsList *lists[] = { NULL, }; -static QemuOptsList *find_list(const char *group) +QemuOptsList *qemu_find_opts(const char *group) { int i; @@ -312,7 +318,7 @@ static QemuOptsList *find_list(const char *group) break; } if (lists[i] == NULL) { - qemu_error("there is no option group \"%s\"\n", group); + error_report("there is no option group \"%s\"", group); } return lists[i]; } @@ -326,19 +332,19 @@ int qemu_set_option(const char *str) rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset); if (rc < 3 || str[offset] != '=') { - qemu_error("can't parse: \"%s\"\n", str); + error_report("can't parse: \"%s\"", str); return -1; } - list = find_list(group); + list = qemu_find_opts(group); if (list == NULL) { return -1; } opts = qemu_opts_find(list, id); if (!opts) { - qemu_error("there is no %s \"%s\" defined\n", - list->name, id); + error_report("there is no %s \"%s\" defined", + list->name, id); return -1; } @@ -356,7 +362,7 @@ int qemu_global_option(const char *str) rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); if (rc < 2 || str[offset] != '=') { - qemu_error("can't parse: \"%s\"\n", str); + error_report("can't parse: \"%s\"", str); return -1; } @@ -424,13 +430,17 @@ void qemu_config_write(FILE *fp) } } -int qemu_config_parse(FILE *fp) +int qemu_config_parse(FILE *fp, const char *fname) { char line[1024], group[64], id[64], arg[64], value[1024]; + Location loc; QemuOptsList *list = NULL; QemuOpts *opts = NULL; + int res = -1, lno = 0; + loc_push_none(&loc); while (fgets(line, sizeof(line), fp) != NULL) { + loc_set_file(fname, ++lno); if (line[0] == '\n') { /* skip empty lines */ continue; @@ -441,35 +451,41 @@ int qemu_config_parse(FILE *fp) } if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { /* group with id */ - list = find_list(group); + list = qemu_find_opts(group); if (list == NULL) - return -1; + goto out; opts = qemu_opts_create(list, id, 1); continue; } if (sscanf(line, "[%63[^]]]", group) == 1) { /* group without id */ - list = find_list(group); + list = qemu_find_opts(group); if (list == NULL) - return -1; + goto out; opts = qemu_opts_create(list, NULL, 0); continue; } if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) { /* arg = value */ if (opts == NULL) { - fprintf(stderr, "no group defined\n"); - return -1; + error_report("no group defined"); + goto out; } if (qemu_opt_set(opts, arg, value) != 0) { - fprintf(stderr, "failed to set \"%s\" for %s\n", - arg, group); - return -1; + error_report("failed to set \"%s\" for %s", arg, group); + goto out; } continue; } - fprintf(stderr, "parse error: %s\n", line); - return -1; + error_report("parse error"); + goto out; } - return 0; + if (ferror(fp)) { + error_report("error reading file"); + goto out; + } + res = 0; +out: + loc_pop(&loc); + return res; } diff --git a/qemu-config.h b/qemu-config.h index b335c42926..f217c589f7 100644 --- a/qemu-config.h +++ b/qemu-config.h @@ -11,11 +11,12 @@ extern QemuOptsList qemu_global_opts; extern QemuOptsList qemu_mon_opts; extern QemuOptsList qemu_cpudef_opts; +QemuOptsList *qemu_find_opts(const char *group); int qemu_set_option(const char *str); int qemu_global_option(const char *str); void qemu_add_globals(void); void qemu_config_write(FILE *fp); -int qemu_config_parse(FILE *fp); +int qemu_config_parse(FILE *fp, const char *fname); #endif /* QEMU_CONFIG_H */ diff --git a/qemu-error.c b/qemu-error.c new file mode 100644 index 0000000000..5d5fe3742f --- /dev/null +++ b/qemu-error.c @@ -0,0 +1,227 @@ +/* + * Error reporting + * + * Copyright (C) 2010 Red Hat Inc. + * + * Authors: + * Markus Armbruster <armbru@redhat.com>, + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <stdio.h> +#include "monitor.h" +#include "sysemu.h" + +/* + * Print to current monitor if we have one, else to stderr. + * TODO should return int, so callers can calculate width, but that + * requires surgery to monitor_vprintf(). Left for another day. + */ +void error_vprintf(const char *fmt, va_list ap) +{ + if (cur_mon) { + monitor_vprintf(cur_mon, fmt, ap); + } else { + vfprintf(stderr, fmt, ap); + } +} + +/* + * Print to current monitor if we have one, else to stderr. + * TODO just like error_vprintf() + */ +void error_printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + error_vprintf(fmt, ap); + va_end(ap); +} + +void error_printf_unless_qmp(const char *fmt, ...) +{ + va_list ap; + + if (!monitor_cur_is_qmp()) { + va_start(ap, fmt); + error_vprintf(fmt, ap); + va_end(ap); + } +} + +static Location std_loc = { + .kind = LOC_NONE +}; +static Location *cur_loc = &std_loc; + +/* + * Push location saved in LOC onto the location stack, return it. + * The top of that stack is the current location. + * Needs a matching loc_pop(). + */ +Location *loc_push_restore(Location *loc) +{ + assert(!loc->prev); + loc->prev = cur_loc; + cur_loc = loc; + return loc; +} + +/* + * Initialize *LOC to "nowhere", push it onto the location stack. + * The top of that stack is the current location. + * Needs a matching loc_pop(). + * Return LOC. + */ +Location *loc_push_none(Location *loc) +{ + loc->kind = LOC_NONE; + loc->prev = NULL; + return loc_push_restore(loc); +} + +/* + * Pop the location stack. + * LOC must be the current location, i.e. the top of the stack. + */ +Location *loc_pop(Location *loc) +{ + assert(cur_loc == loc && loc->prev); + cur_loc = loc->prev; + loc->prev = NULL; + return loc; +} + +/* + * Save the current location in LOC, return LOC. + */ +Location *loc_save(Location *loc) +{ + *loc = *cur_loc; + loc->prev = NULL; + return loc; +} + +/* + * Change the current location to the one saved in LOC. + */ +void loc_restore(Location *loc) +{ + Location *prev = cur_loc->prev; + assert(!loc->prev); + *cur_loc = *loc; + cur_loc->prev = prev; +} + +/* + * Change the current location to "nowhere in particular". + */ +void loc_set_none(void) +{ + cur_loc->kind = LOC_NONE; +} + +/* + * Change the current location to argument ARGV[IDX..IDX+CNT-1]. + */ +void loc_set_cmdline(char **argv, int idx, int cnt) +{ + cur_loc->kind = LOC_CMDLINE; + cur_loc->num = cnt; + cur_loc->ptr = argv + idx; +} + +/* + * Change the current location to file FNAME, line LNO. + */ +void loc_set_file(const char *fname, int lno) +{ + assert (fname || cur_loc->kind == LOC_FILE); + cur_loc->kind = LOC_FILE; + cur_loc->num = lno; + if (fname) { + cur_loc->ptr = fname; + } +} + +static const char *progname; + +/* + * Set the program name for error_print_loc(). + */ +void error_set_progname(const char *argv0) +{ + const char *p = strrchr(argv0, '/'); + progname = p ? p + 1 : argv0; +} + +/* + * Print current location to current monitor if we have one, else to stderr. + */ +void error_print_loc(void) +{ + const char *sep = ""; + int i; + const char *const *argp; + + if (!cur_mon) { + fprintf(stderr, "%s:", progname); + sep = " "; + } + switch (cur_loc->kind) { + case LOC_CMDLINE: + argp = cur_loc->ptr; + for (i = 0; i < cur_loc->num; i++) { + error_printf("%s%s", sep, argp[i]); + sep = " "; + } + error_printf(": "); + break; + case LOC_FILE: + error_printf("%s:", (const char *)cur_loc->ptr); + if (cur_loc->num) { + error_printf("%d:", cur_loc->num); + } + error_printf(" "); + break; + default: + error_printf(sep); + } +} + +/* + * Print an error message to current monitor if we have one, else to stderr. + * Prepend the current location and append a newline. + * It's wrong to call this in a QMP monitor. Use qerror_report() there. + */ +void error_report(const char *fmt, ...) +{ + va_list ap; + + error_print_loc(); + va_start(ap, fmt); + error_vprintf(fmt, ap); + va_end(ap); + error_printf("\n"); +} + +void qerror_report_internal(const char *file, int linenr, const char *func, + const char *fmt, ...) +{ + va_list va; + QError *qerror; + + va_start(va, fmt); + qerror = qerror_from_info(file, linenr, func, fmt, &va); + va_end(va); + + if (monitor_cur_is_qmp()) { + monitor_set_error(cur_mon, qerror); + } else { + qerror_print(qerror); + QDECREF(qerror); + } +} diff --git a/qemu-error.h b/qemu-error.h new file mode 100644 index 0000000000..e63c6ab31d --- /dev/null +++ b/qemu-error.h @@ -0,0 +1,47 @@ +/* + * Error reporting + * + * Copyright (C) 2010 Red Hat Inc. + * + * Authors: + * Markus Armbruster <armbru@redhat.com>, + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_ERROR_H +#define QEMU_ERROR_H + +typedef struct Location { + /* all members are private to qemu-error.c */ + enum { LOC_NONE, LOC_CMDLINE, LOC_FILE } kind; + int num; + const void *ptr; + struct Location *prev; +} Location; + +Location *loc_push_restore(Location *loc); +Location *loc_push_none(Location *loc); +Location *loc_pop(Location *loc); +Location *loc_save(Location *loc); +void loc_restore(Location *loc); +void loc_set_none(void); +void loc_set_cmdline(char **argv, int idx, int cnt); +void loc_set_file(const char *fname, int lno); + +void error_vprintf(const char *fmt, va_list ap); +void error_printf(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); +void error_printf_unless_qmp(const char *fmt, ...) + __attribute__ ((format(printf, 1, 2))); +void error_print_loc(void); +void error_set_progname(const char *argv0); +void error_report(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); +void qerror_report_internal(const char *file, int linenr, const char *func, + const char *fmt, ...) + __attribute__ ((format(printf, 4, 5))); + +#define qerror_report(fmt, ...) \ + qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__) + +#endif diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 7f9d261cd9..5308f364e7 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -570,10 +570,11 @@ ETEXI { .name = "device_add", - .args_type = "config:s", - .params = "device", + .args_type = "device:O", + .params = "driver[,prop=value][,...]", .help = "add device, like -device on the command line", - .mhandler.cmd = do_device_add, + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_device_add, }, STEXI diff --git a/qemu-option.c b/qemu-option.c index de40bffc7d..dc340b8dc7 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -27,6 +27,8 @@ #include <string.h> #include "qemu-common.h" +#include "qemu-error.h" +#include "qemu-objects.h" #include "qemu-option.h" /* @@ -483,6 +485,7 @@ struct QemuOpt { struct QemuOpts { char *id; QemuOptsList *list; + Location loc; QTAILQ_HEAD(QemuOptHead, QemuOpt) head; QTAILQ_ENTRY(QemuOpts) next; }; @@ -653,6 +656,7 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exist opts->id = qemu_strdup(id); } opts->list = list; + loc_save(&opts->loc); QTAILQ_INIT(&opts->head); QTAILQ_INSERT_TAIL(&list->head, opts, next); return opts; @@ -749,12 +753,17 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname return 0; } -QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname) +QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, + int permit_abbrev) { + const char *firstname; char value[1024], *id = NULL; const char *p; QemuOpts *opts; + assert(!permit_abbrev || list->implied_opt_name); + firstname = permit_abbrev ? list->implied_opt_name : NULL; + if (strncmp(params, "id=", 3) == 0) { get_opt_value(value, sizeof(value), params+3); id = qemu_strdup(value); @@ -774,6 +783,84 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *fi return opts; } +static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) +{ + char buf[32]; + const char *value; + int n; + + if (!strcmp(key, "id")) { + return; + } + + switch (qobject_type(obj)) { + case QTYPE_QSTRING: + value = qstring_get_str(qobject_to_qstring(obj)); + break; + case QTYPE_QINT: + n = snprintf(buf, sizeof(buf), "%" PRId64, + qint_get_int(qobject_to_qint(obj))); + assert(n < sizeof(buf)); + value = buf; + break; + case QTYPE_QFLOAT: + n = snprintf(buf, sizeof(buf), "%.17g", + qfloat_get_double(qobject_to_qfloat(obj))); + assert(n < sizeof(buf)); + value = buf; + break; + case QTYPE_QBOOL: + strcpy(buf, qbool_get_int(qobject_to_qbool(obj)) ? "on" : "off"); + value = buf; + break; + default: + return; + } + qemu_opt_set(opaque, key, value); +} + +/* + * Create QemuOpts from a QDict. + * Use value of key "id" as ID if it exists and is a QString. + * Only QStrings, QInts, QFloats and QBools are copied. Entries with + * other types are silently ignored. + */ +QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict) +{ + QemuOpts *opts; + + opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1); + if (opts == NULL) + return NULL; + + qdict_iter(qdict, qemu_opts_from_qdict_1, opts); + return opts; +} + +/* + * Convert from QemuOpts to QDict. + * The QDict values are of type QString. + * TODO We'll want to use types appropriate for opt->desc->type, but + * this is enough for now. + */ +QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict) +{ + QemuOpt *opt; + QObject *val; + + if (!qdict) { + qdict = qdict_new(); + } + if (opts->id) { + qdict_put(qdict, "id", qstring_from_str(opts->id)); + } + QTAILQ_FOREACH(opt, &opts->head, next) { + val = QOBJECT(qstring_from_str(opt->str)); + qdict_put_obj(qdict, opt->name, val); + } + return qdict; +} + /* Validate parsed opts against descriptions where no * descriptions were provided in the QemuOptsList. */ @@ -810,13 +897,17 @@ int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc) int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, int abort_on_failure) { + Location loc; QemuOpts *opts; int rc = 0; + loc_push_none(&loc); QTAILQ_FOREACH(opts, &list->head, next) { + loc_restore(&opts->loc); rc |= func(opts, opaque); if (abort_on_failure && rc != 0) break; } + loc_pop(&loc); return rc; } diff --git a/qemu-option.h b/qemu-option.h index f3f1de755d..58136f3032 100644 --- a/qemu-option.h +++ b/qemu-option.h @@ -28,6 +28,7 @@ #include <stdint.h> #include "qemu-queue.h" +#include "qdict.h" enum QEMUOptionParType { OPT_FLAG, @@ -96,6 +97,7 @@ typedef struct QemuOptDesc { struct QemuOptsList { const char *name; + const char *implied_opt_name; QTAILQ_HEAD(, QemuOpts) head; QemuOptDesc desc[]; }; @@ -117,7 +119,9 @@ const char *qemu_opts_id(QemuOpts *opts); void qemu_opts_del(QemuOpts *opts); int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc); int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname); -QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname); +QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev); +QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict); +QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict); typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque); int qemu_opts_print(QemuOpts *opts, void *dummy); diff --git a/qemu-tool.c b/qemu-tool.c index 18b48af319..97ca949964 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -13,9 +13,9 @@ #include "qemu-common.h" #include "monitor.h" -#include "sysemu.h" #include "qemu-timer.h" #include "qemu-log.h" +#include "qemu-error.h" #include <sys/time.h> @@ -33,8 +33,6 @@ void qemu_service_io(void) { } -Monitor *cur_mon; - void monitor_printf(Monitor *mon, const char *fmt, ...) { } @@ -106,7 +104,31 @@ int64_t qemu_get_clock(QEMUClock *clock) return (tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000)) / 1000000; } -void qemu_error(const char *fmt, ...) +Location *loc_push_restore(Location *loc) +{ + return loc; +} + +Location *loc_push_none(Location *loc) +{ + return loc; +} + +Location *loc_pop(Location *loc) +{ + return loc; +} + +Location *loc_save(Location *loc) +{ + return loc; +} + +void loc_restore(Location *loc) +{ +} + +void error_report(const char *fmt, ...) { va_list args; @@ -12,8 +12,8 @@ #include "qjson.h" #include "qerror.h" #include "qstring.h" -#include "sysemu.h" #include "qemu-common.h" +#include "qemu-error.h" static void qerror_destroy_obj(QObject *obj); @@ -41,48 +41,68 @@ static const QType qerror_type = { */ static const QErrorStringTable qerror_table[] = { { + .error_fmt = QERR_BAD_BUS_FOR_DEVICE, + .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus", + }, + { + .error_fmt = QERR_BUS_NOT_FOUND, + .desc = "Bus '%(bus)' not found", + }, + { + .error_fmt = QERR_BUS_NO_HOTPLUG, + .desc = "Bus '%(bus)' does not support hotplugging", + }, + { .error_fmt = QERR_COMMAND_NOT_FOUND, .desc = "The command %(name) has not been found", }, { .error_fmt = QERR_DEVICE_ENCRYPTED, - .desc = "The %(device) is encrypted", + .desc = "Device '%(device)' is encrypted", + }, + { + .error_fmt = QERR_DEVICE_INIT_FAILED, + .desc = "Device '%(device)' could not be initialized", }, { .error_fmt = QERR_DEVICE_LOCKED, - .desc = "Device %(device) is locked", + .desc = "Device '%(device)' is locked", + }, + { + .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES, + .desc = "Device '%(device)' has multiple child busses", }, { .error_fmt = QERR_DEVICE_NOT_ACTIVE, - .desc = "The %(device) device has not been activated by the guest", + .desc = "Device '%(device)' has not been activated by the guest", }, { .error_fmt = QERR_DEVICE_NOT_FOUND, - .desc = "The %(device) device has not been found", + .desc = "Device '%(device)' not found", }, { .error_fmt = QERR_DEVICE_NOT_REMOVABLE, - .desc = "Device %(device) is not removable", + .desc = "Device '%(device)' is not removable", + }, + { + .error_fmt = QERR_DEVICE_NO_BUS, + .desc = "Device '%(device)' has no child bus", }, { .error_fmt = QERR_FD_NOT_FOUND, - .desc = "Failed to find file descriptor named %(name)", + .desc = "File descriptor named '%(name)' not found", }, { .error_fmt = QERR_FD_NOT_SUPPLIED, .desc = "No file descriptor supplied via SCM_RIGHTS", }, { - .error_fmt = QERR_OPEN_FILE_FAILED, - .desc = "Could not open '%(filename)'", - }, - { .error_fmt = QERR_INVALID_BLOCK_FORMAT, - .desc = "Invalid block format %(name)", + .desc = "Invalid block format '%(name)'", }, { .error_fmt = QERR_INVALID_PARAMETER, - .desc = "Invalid parameter %(name)", + .desc = "Invalid parameter '%(name)'", }, { .error_fmt = QERR_INVALID_PARAMETER_TYPE, @@ -90,7 +110,7 @@ static const QErrorStringTable qerror_table[] = { }, { .error_fmt = QERR_INVALID_PASSWORD, - .desc = "The entered password is invalid", + .desc = "Password incorrect", }, { .error_fmt = QERR_JSON_PARSING, @@ -102,7 +122,31 @@ static const QErrorStringTable qerror_table[] = { }, { .error_fmt = QERR_MISSING_PARAMETER, - .desc = "Parameter %(name) is missing", + .desc = "Parameter '%(name)' is missing", + }, + { + .error_fmt = QERR_NO_BUS_FOR_DEVICE, + .desc = "No '%(bus)' bus found for device '%(device)'", + }, + { + .error_fmt = QERR_OPEN_FILE_FAILED, + .desc = "Could not open '%(filename)'", + }, + { + .error_fmt = QERR_PROPERTY_NOT_FOUND, + .desc = "Property '%(device).%(property)' not found", + }, + { + .error_fmt = QERR_PROPERTY_VALUE_BAD, + .desc = "Property '%(device).%(property)' doesn't take value '%(value)'", + }, + { + .error_fmt = QERR_PROPERTY_VALUE_IN_USE, + .desc = "Property '%(device).%(property)' can't take value '%(value)', it's in use", + }, + { + .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND, + .desc = "Property '%(device).%(property)' can't find value '%(value)'", }, { .error_fmt = QERR_QMP_BAD_INPUT_OBJECT, @@ -224,6 +268,7 @@ QError *qerror_from_info(const char *file, int linenr, const char *func, QError *qerr; qerr = qerror_new(); + loc_save(&qerr->loc); qerr->linenr = linenr; qerr->file = file; qerr->func = func; @@ -318,13 +363,15 @@ QString *qerror_human(const QError *qerror) * qerror_print(): Print QError data * * This function will print the member 'desc' of the specified QError object, - * it uses qemu_error() for this, so that the output is routed to the right + * it uses error_report() for this, so that the output is routed to the right * place (ie. stderr or Monitor's device). */ -void qerror_print(const QError *qerror) +void qerror_print(QError *qerror) { QString *qstring = qerror_human(qerror); - qemu_error("%s\n", qstring_get_str(qstring)); + loc_push_restore(&qerror->loc); + error_report("%s", qstring_get_str(qstring)); + loc_pop(&qerror->loc); QDECREF(qstring); } @@ -14,6 +14,7 @@ #include "qdict.h" #include "qstring.h" +#include "qemu-error.h" #include <stdarg.h> typedef struct QErrorStringTable { @@ -24,6 +25,7 @@ typedef struct QErrorStringTable { typedef struct QError { QObject_HEAD; QDict *error; + Location loc; int linenr; const char *file; const char *func; @@ -34,21 +36,36 @@ QError *qerror_new(void); QError *qerror_from_info(const char *file, int linenr, const char *func, const char *fmt, va_list *va); QString *qerror_human(const QError *qerror); -void qerror_print(const QError *qerror); +void qerror_print(QError *qerror); QError *qobject_to_qerror(const QObject *obj); /* * QError class list */ +#define QERR_BAD_BUS_FOR_DEVICE \ + "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" + +#define QERR_BUS_NOT_FOUND \ + "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }" + +#define QERR_BUS_NO_HOTPLUG \ + "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }" + #define QERR_COMMAND_NOT_FOUND \ "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" #define QERR_DEVICE_ENCRYPTED \ "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }" -#define QERR_DEVICE_LOCKED \ +#define QERR_DEVICE_INIT_FAILED \ + "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" + +#define QERR_DEVICE_LOCKED \ "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" +#define QERR_DEVICE_MULTIPLE_BUSSES \ + "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }" + #define QERR_DEVICE_NOT_ACTIVE \ "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" @@ -58,15 +75,15 @@ QError *qobject_to_qerror(const QObject *obj); #define QERR_DEVICE_NOT_REMOVABLE \ "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" +#define QERR_DEVICE_NO_BUS \ + "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }" + #define QERR_FD_NOT_FOUND \ "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" #define QERR_FD_NOT_SUPPLIED \ "{ 'class': 'FdNotSupplied', 'data': {} }" -#define QERR_OPEN_FILE_FAILED \ - "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" - #define QERR_INVALID_BLOCK_FORMAT \ "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" @@ -88,18 +105,36 @@ QError *qobject_to_qerror(const QObject *obj); #define QERR_MISSING_PARAMETER \ "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" +#define QERR_NO_BUS_FOR_DEVICE \ + "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }" + +#define QERR_OPEN_FILE_FAILED \ + "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" + +#define QERR_PROPERTY_NOT_FOUND \ + "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }" + +#define QERR_PROPERTY_VALUE_BAD \ + "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + +#define QERR_PROPERTY_VALUE_IN_USE \ + "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + +#define QERR_PROPERTY_VALUE_NOT_FOUND \ + "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + #define QERR_QMP_BAD_INPUT_OBJECT \ "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" #define QERR_SET_PASSWD_FAILED \ "{ 'class': 'SetPasswdFailed', 'data': {} }" -#define QERR_UNDEFINED_ERROR \ - "{ 'class': 'UndefinedError', 'data': {} }" - #define QERR_TOO_MANY_FILES \ "{ 'class': 'TooManyFiles', 'data': {} }" +#define QERR_UNDEFINED_ERROR \ + "{ 'class': 'UndefinedError', 'data': {} }" + #define QERR_VNC_SERVER_FAILED \ "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" @@ -1737,7 +1737,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) vm_start(); } -int load_vmstate(Monitor *mon, const char *name) +int load_vmstate(const char *name) { DriveInfo *dinfo; BlockDriverState *bs, *bs1; @@ -1747,7 +1747,7 @@ int load_vmstate(Monitor *mon, const char *name) bs = get_bs_snapshots(); if (!bs) { - monitor_printf(mon, "No block device supports snapshots\n"); + error_report("No block device supports snapshots"); return -EINVAL; } @@ -1759,22 +1759,21 @@ int load_vmstate(Monitor *mon, const char *name) if (bdrv_has_snapshot(bs1)) { ret = bdrv_snapshot_goto(bs1, name); if (ret < 0) { - if (bs != bs1) - monitor_printf(mon, "Warning: "); switch(ret) { case -ENOTSUP: - monitor_printf(mon, - "Snapshots not supported on device '%s'\n", - bdrv_get_device_name(bs1)); + error_report("%sSnapshots not supported on device '%s'", + bs != bs1 ? "Warning: " : "", + bdrv_get_device_name(bs1)); break; case -ENOENT: - monitor_printf(mon, "Could not find snapshot '%s' on " - "device '%s'\n", - name, bdrv_get_device_name(bs1)); + error_report("%sCould not find snapshot '%s' on device '%s'", + bs != bs1 ? "Warning: " : "", + name, bdrv_get_device_name(bs1)); break; default: - monitor_printf(mon, "Error %d while activating snapshot on" - " '%s'\n", ret, bdrv_get_device_name(bs1)); + error_report("%sError %d while activating snapshot on '%s'", + bs != bs1 ? "Warning: " : "", + ret, bdrv_get_device_name(bs1)); break; } /* fatal on snapshot block device */ @@ -1792,13 +1791,13 @@ int load_vmstate(Monitor *mon, const char *name) /* restore the VM state */ f = qemu_fopen_bdrv(bs, 0); if (!f) { - monitor_printf(mon, "Could not open VM state file\n"); + error_report("Could not open VM state file"); return -EINVAL; } ret = qemu_loadvm_state(f); qemu_fclose(f); if (ret < 0) { - monitor_printf(mon, "Error %d while loading VM state\n", ret); + error_report("Error %d while loading VM state", ret); return ret; } return 0; diff --git a/slirp/misc.c b/slirp/misc.c index dcb1dc117b..1aeb401082 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -260,7 +260,7 @@ void lprint(const char *format, ...) va_list args; va_start(args, format); - monitor_vprintf(cur_mon, format, args); + monitor_vprintf(default_mon, format, args); va_end(args); } @@ -54,7 +54,7 @@ extern qemu_irq qemu_system_powerdown; void qemu_system_reset(void); void do_savevm(Monitor *mon, const QDict *qdict); -int load_vmstate(Monitor *mon, const char *name); +int load_vmstate(const char *name); void do_delvm(Monitor *mon, const QDict *qdict); void do_info_snapshots(Monitor *mon); @@ -73,17 +73,6 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f); void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f); int qemu_loadvm_state(QEMUFile *f); -void qemu_errors_to_file(FILE *fp); -void qemu_errors_to_mon(Monitor *mon); -void qemu_errors_to_previous(void); -void qemu_error(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); -void qemu_error_internal(const char *file, int linenr, const char *func, - const char *fmt, ...) - __attribute__ ((format(printf, 4, 5))); - -#define qemu_error_new(fmt, ...) \ - qemu_error_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__) - #ifdef _WIN32 /* Polling handling */ diff --git a/usb-linux.c b/usb-linux.c index a9c15c6d1d..d0d7cff496 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -1188,9 +1188,6 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func) */ static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name) { -#if 0 - Monitor *mon = cur_mon; -#endif FILE *f; int ret = 0; char filename[PATH_MAX]; @@ -1201,11 +1198,6 @@ static int usb_host_read_file(char *line, size_t line_size, const char *device_f if (f) { ret = fgets(line, line_size, f) != NULL; fclose(f); -#if 0 - } else { - if (mon) - monitor_printf(mon, "husb: could not open %s\n", filename); -#endif } return ret; @@ -1813,7 +1813,7 @@ QemuOpts *drive_add(const char *file, const char *fmt, ...) vsnprintf(optstr, sizeof(optstr), fmt, ap); va_end(ap); - opts = qemu_opts_parse(&qemu_drive_opts, optstr, NULL); + opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0); if (!opts) { fprintf(stderr, "%s: huh? duplicate? (%s)\n", __FUNCTION__, optstr); @@ -2539,7 +2539,7 @@ void do_usb_add(Monitor *mon, const QDict *qdict) { const char *devname = qdict_get_str(qdict, "devname"); if (usb_device_add(devname, 1) < 0) { - qemu_error("could not add USB device '%s'\n", devname); + error_report("could not add USB device '%s'", devname); } } @@ -2547,7 +2547,7 @@ void do_usb_del(Monitor *mon, const QDict *qdict) { const char *devname = qdict_get_str(qdict, "devname"); if (usb_device_del(devname) < 0) { - qemu_error("could not delete USB device '%s'\n", devname); + error_report("could not delete USB device '%s'", devname); } } @@ -4370,7 +4370,7 @@ static int balloon_parse(const char *arg) if (!strncmp(arg, "virtio", 6)) { if (arg[6] == ',') { /* have params -> parse them */ - opts = qemu_opts_parse(&qemu_device_opts, arg+7, NULL); + opts = qemu_opts_parse(&qemu_device_opts, arg+7, 0); if (!opts) return -1; } else { @@ -4796,6 +4796,7 @@ static const QEMUOption *lookup_opt(int argc, char **argv, char *r = argv[optind]; const char *optarg; + loc_set_cmdline(argv, optind, 1); optind++; /* Treat --foo the same as -foo. */ if (r[1] == '-') @@ -4803,8 +4804,7 @@ static const QEMUOption *lookup_opt(int argc, char **argv, popt = qemu_options; for(;;) { if (!popt->name) { - fprintf(stderr, "%s: invalid option -- '%s'\n", - argv[0], r); + error_report("invalid option"); exit(1); } if (!strcmp(popt->name, r + 1)) @@ -4813,11 +4813,11 @@ static const QEMUOption *lookup_opt(int argc, char **argv, } if (popt->flags & HAS_ARG) { if (optind >= argc) { - fprintf(stderr, "%s: option '%s' requires an argument\n", - argv[0], r); + error_report("requires an argument"); exit(1); } optarg = argv[optind++]; + loc_set_cmdline(argv, optind - 2, 2); } else { optarg = NULL; } @@ -4862,9 +4862,10 @@ int main(int argc, char **argv, char **envp) int show_vnc_port = 0; int defconfig = 1; + error_set_progname(argv[0]); + init_clocks(); - qemu_errors_to_file(stderr); qemu_cache_utils_init(envp); QLIST_INIT (&vm_change_state_head); @@ -4940,18 +4941,22 @@ int main(int argc, char **argv, char **envp) } if (defconfig) { + const char *fname; FILE *fp; - fp = fopen(CONFIG_QEMU_CONFDIR "/qemu.conf", "r"); + + fname = CONFIG_QEMU_CONFDIR "/qemu.conf"; + fp = fopen(fname, "r"); if (fp) { - if (qemu_config_parse(fp) != 0) { + if (qemu_config_parse(fp, fname) != 0) { exit(1); } fclose(fp); } - fp = fopen(CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf", "r"); + fname = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf"; + fp = fopen(fname, "r"); if (fp) { - if (qemu_config_parse(fp) != 0) { + if (qemu_config_parse(fp, fname) != 0) { exit(1); } fclose(fp); @@ -5360,7 +5365,7 @@ int main(int argc, char **argv, char **envp) default_monitor = 0; break; case QEMU_OPTION_mon: - opts = qemu_opts_parse(&qemu_mon_opts, optarg, "chardev"); + opts = qemu_opts_parse(&qemu_mon_opts, optarg, 1); if (!opts) { fprintf(stderr, "parse error: %s\n", optarg); exit(1); @@ -5368,7 +5373,7 @@ int main(int argc, char **argv, char **envp) default_monitor = 0; break; case QEMU_OPTION_chardev: - opts = qemu_opts_parse(&qemu_chardev_opts, optarg, "backend"); + opts = qemu_opts_parse(&qemu_chardev_opts, optarg, 1); if (!opts) { fprintf(stderr, "parse error: %s\n", optarg); exit(1); @@ -5471,7 +5476,7 @@ int main(int argc, char **argv, char **envp) add_device_config(DEV_USB, optarg); break; case QEMU_OPTION_device: - if (!qemu_opts_parse(&qemu_device_opts, optarg, "driver")) { + if (!qemu_opts_parse(&qemu_device_opts, optarg, 1)) { exit(1); } break; @@ -5580,7 +5585,7 @@ int main(int argc, char **argv, char **envp) configure_rtc_date_offset(optarg, 1); break; case QEMU_OPTION_rtc: - opts = qemu_opts_parse(&qemu_rtc_opts, optarg, NULL); + opts = qemu_opts_parse(&qemu_rtc_opts, optarg, 0); if (!opts) { fprintf(stderr, "parse error: %s\n", optarg); exit(1); @@ -5641,7 +5646,7 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "open %s: %s\n", optarg, strerror(errno)); exit(1); } - if (qemu_config_parse(fp) != 0) { + if (qemu_config_parse(fp, optarg) != 0) { exit(1); } fclose(fp); @@ -5666,6 +5671,7 @@ int main(int argc, char **argv, char **envp) } } } + loc_set_none(); /* If no data_dir is specified then try to find it relative to the executable path. */ @@ -6081,7 +6087,7 @@ int main(int argc, char **argv, char **envp) qemu_system_reset(); if (loadvm) { - if (load_vmstate(cur_mon, loadvm) < 0) { + if (load_vmstate(loadvm) < 0) { autostart = 0; } } @@ -1046,11 +1046,10 @@ static void audio_capture(void *opaque, void *buf, int size) static void audio_add(VncState *vs) { - Monitor *mon = cur_mon; struct audio_capture_ops ops; if (vs->audio_cap) { - monitor_printf(mon, "audio already running\n"); + monitor_printf(default_mon, "audio already running\n"); return; } @@ -1060,7 +1059,7 @@ static void audio_add(VncState *vs) vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs); if (!vs->audio_cap) { - monitor_printf(mon, "Failed to add audio capture\n"); + monitor_printf(default_mon, "Failed to add audio capture\n"); } } |